001/* 002 * $RCSfile: ISRandomAccessIO.java,v $ 003 * $Revision: 1.1 $ 004 * $Date: 2005/02/11 05:02:25 $ 005 * $State: Exp $ 006 * 007 * Class: ISRandomAccessIO 008 * 009 * Description: Turns an InsputStream into a read-only 010 * RandomAccessIO, using buffering. 011 * 012 * 013 * 014 * COPYRIGHT: 015 * 016 * This software module was originally developed by Raphaël Grosbois and 017 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel 018 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David 019 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research 020 * Centre France S.A) in the course of development of the JPEG2000 021 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This 022 * software module is an implementation of a part of the JPEG 2000 023 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio 024 * Systems AB and Canon Research Centre France S.A (collectively JJ2000 025 * Partners) agree not to assert against ISO/IEC and users of the JPEG 026 * 2000 Standard (Users) any of their rights under the copyright, not 027 * including other intellectual property rights, for this software module 028 * with respect to the usage by ISO/IEC and Users of this software module 029 * or modifications thereof for use in hardware or software products 030 * claiming conformance to the JPEG 2000 Standard. Those intending to use 031 * this software module in hardware or software products are advised that 032 * their use may infringe existing patents. The original developers of 033 * this software module, JJ2000 Partners and ISO/IEC assume no liability 034 * for use of this software module or modifications thereof. No license 035 * or right to this software module is granted for non JPEG 2000 Standard 036 * conforming products. JJ2000 Partners have full right to use this 037 * software module for his/her own purpose, assign or donate this 038 * software module to any third party and to inhibit third parties from 039 * using this software module for non JPEG 2000 Standard conforming 040 * products. This copyright notice must be included in all copies or 041 * derivative works of this software module. 042 * 043 * Copyright (c) 1999/2000 JJ2000 Partners. 044 * 045 * 046 * 047 */ 048package jj2000.j2k.util; 049 050import java.io.*; 051import jj2000.j2k.io.*; 052 053/** 054 * This class implements a wrapper to turn an InputStream into a 055 * RandomAccessIO. To provide random access the input data from the 056 * InputStream is cached in an in-memory buffer. The in-memory buffer size can 057 * be limited to a specified size. The data is read into the cache on a as 058 * needed basis, blocking only when necessary. 059 * 060 * <P>The cache grows automatically as necessary. However, if the data length 061 * is known prior to the creation of a ISRandomAccessIO object, it is best to 062 * specify that as the initial in-memory buffer size. That will minimize data 063 * copying and multiple allocation. 064 * 065 * <P>Multi-byte data is read in big-endian order. The in-memory buffer 066 * storage is released when 'close()' is called. This class can only be used 067 * for data input, not output. The wrapped InputStream is closed when all the 068 * input data is cached or when 'close()' is called. 069 * 070 * <P>If an out of memory condition is encountered when growing the 071 * in-memory buffer an IOException is thrown instead of an 072 * OutOfMemoryError. The exception message is "Out of memory to cache input 073 * data". 074 * 075 * <P>This class is intended for use as a "quick and dirty" way to give 076 * network connectivity to RandomAccessIO based classes. It is not intended as 077 * an efficient means of implementing network connectivity. Doing such 078 * requires reimplementing the RandomAccessIO based classes to directly use 079 * network connections. 080 * 081 * <P>This class does not use temporary files as buffers, because that would 082 * preclude the use in unsigned applets. 083 * */ 084public class ISRandomAccessIO implements RandomAccessIO { 085 086 /** The InputStream that is wrapped */ 087 private InputStream is; 088 089 /* Tha maximum size, in bytes, of the in memory buffer. The maximum size 090 * includes the EOF. */ 091 private int maxsize; 092 093 /* The increment, in bytes, for the in-memory buffer size */ 094 private int inc; 095 096 /* The in-memory buffer to cache received data */ 097 private byte buf[]; 098 099 /* The length of the already received data */ 100 private int len; 101 102 /* The position of the next byte to be read from the in-memory buffer */ 103 private int pos; 104 105 /* Flag to indicate if all the data has been received. That is, if the EOF 106 * has been reached. */ 107 private boolean complete; 108 109 /** 110 * Creates a new RandomAccessIO wrapper for the given InputStream 111 * 'is'. The internal cache buffer will have size 'size' and will 112 * increment by 'inc' each time it is needed. The maximum buffer size is 113 * limited to 'maxsize'. 114 * 115 * @param is The input from where to get the data. 116 * 117 * @param size The initial size for the cache buffer, in bytes. 118 * 119 * @param inc The size increment for the cache buffer, in bytes. 120 * 121 * @param maxsize The maximum size for the cache buffer, in bytes. 122 */ 123 public ISRandomAccessIO(InputStream is, int size, int inc, int maxsize) { 124 if (size < 0 || inc <= 0 || maxsize <= 0 || is == null) { 125 throw new IllegalArgumentException(); 126 } 127 this.is = is; 128 // Increase size by one to count in EOF 129 if (size < Integer.MAX_VALUE) size++; 130 buf = new byte[size]; 131 this.inc = inc; 132 // The maximum size is one byte more, to allow reading the EOF. 133 if (maxsize < Integer.MAX_VALUE) maxsize++; 134 this.maxsize = maxsize; 135 pos = 0; 136 len = 0; 137 complete = false; 138 } 139 140 /** 141 * Creates a new RandomAccessIO wrapper for the given InputStream 142 * 'is'. The internal cache buffer size and increment is to to 256 kB. The 143 * maximum buffer size is set to Integer.MAX_VALUE (2 GB). 144 * 145 * @param is The input from where to get the data. 146 * 147 */ 148 public ISRandomAccessIO(InputStream is) { 149 this(is,1<<18,1<<18,Integer.MAX_VALUE); 150 } 151 152 /** 153 * Grows the cache buffer by 'inc', upto a maximum of 'maxsize'. The 154 * buffer size will be increased by at least one byte, if no exception is 155 * thrown. 156 * 157 * @exception IOException If the maximum cache size is reached or if not 158 * enough memory is available to grow the buffer. 159 */ 160 private void growBuffer() throws IOException { 161 byte newbuf[]; 162 int effinc; // effective increment 163 164 effinc = inc; 165 if (buf.length+effinc > maxsize) effinc = maxsize-buf.length; 166 if (effinc <= 0) { 167 throw new IOException("Reached maximum cache size ("+maxsize+")"); 168 } 169 try { 170 newbuf = new byte[buf.length+inc]; 171 } catch (OutOfMemoryError e) { 172 throw new IOException("Out of memory to cache input data"); 173 } 174 System.arraycopy(buf,0,newbuf,0,len); 175 buf = newbuf; 176 } 177 178 /** 179 * Reads data from the wrapped InputStream and places it in the cache 180 * buffer. Reads all input data that will not cause it to block, but at 181 * least on byte is read (even if it blocks), unless EOF is reached. This 182 * method can not be called if EOF has been already reached 183 * (i.e. 'complete' is true). 184 * 185 * @exception IOException An I/O error occurred, out of meory to grow 186 * cache or maximum cache size reached. 187 * */ 188 private void readInput() throws IOException { 189 int n; 190 int b; 191 int k; 192 193 if (complete) { 194 throw new IllegalArgumentException("Already reached EOF"); 195 } 196// may need reflection to call this method 197// n = is.available(); /* how much can we read without blocking? */ 198 n = 0; /* how much can we read without blocking? */ 199 if (n == 0) n = 1; /* read at least one byte (even if it blocks) */ 200 while (len+n > buf.length) { /* Ensure buffer size */ 201 growBuffer(); 202 } 203 /* Read the data. Loop to be sure that we do read 'n' bytes */ 204 do { 205 k = is.read(buf,len,n); 206 if (k > 0) { /* Some data was read */ 207 len += k; 208 n -= k; 209 } 210 } while (n > 0 && k > 0); 211 if (k <= 0) { /* we reached EOF */ 212 complete = true; 213 is = null; 214 } 215 } 216 217 /** 218 * Closes this object for reading as well as the wrapped InputStream, if 219 * not already closed. The memory used by the cache is released. 220 * 221 * @exception IOException If an I/O error occurs while closing the 222 * underlying InputStream. */ 223 public void close() throws IOException { 224 buf = null; 225 if (!complete) { 226 is.close(); 227 is = null; 228 } 229 } 230 231 /** 232 * Returns the current position in the stream, which is the 233 * position from where the next byte of data would be read. The first 234 * byte in the stream is in position 0. 235 * 236 * @exception IOException If an I/O error occurred. 237 * */ 238 public int getPos() throws IOException { 239 return pos; 240 } 241 242 /** 243 * Moves the current position for the next read operation to 244 * offset. The offset is measured from the beginning of the stream. If the 245 * offset is set beyond the currently cached data, the missing data will 246 * be read only when a read operation is performed. Setting 247 * the offset beyond the end of the data will cause an EOFException only 248 * if the data length is currently known, otherwise an IOException will 249 * occur when a read operation is attempted at that position. 250 * 251 * @param off The offset where to move to. 252 * 253 * @exception EOFException If seeking beyond EOF and the data length is 254 * known. 255 * 256 * @exception IOException If an I/O error ocurred. 257 * */ 258 public void seek(int off) throws IOException { 259 if (complete) { /* we know the length, check seek is within length */ 260 if (off > len) { 261 throw new EOFException(); 262 } 263 } 264 pos = off; 265 } 266 267 /** 268 * Returns the length of the stream. This will cause all the data to be 269 * read. This method will block until all the data is read, which can be 270 * lengthy across the network. 271 * 272 * @return The length of the stream, in bytes. 273 * 274 * @exception IOException If an I/O error ocurred. 275 */ 276 public int length() throws IOException { 277 if (Integer.MAX_VALUE != maxsize) 278 return maxsize - 1; 279 while (!complete) { // read until we reach EOF 280 readInput(); 281 } 282 return len; 283 } 284 285 /** 286 * Reads a byte of data from the stream. 287 * 288 * @return The byte read, as an int in the range [0-255]. 289 * 290 * @exception EOFException If the end-of file was reached. 291 * 292 * @exception IOException If an I/O error ocurred. 293 * 294 */ 295 public int read() throws IOException { 296 if (pos < len) { // common, fast case 297 return 0xFF & (int)buf[pos++]; 298 } 299 // general case 300 while (!complete && pos >= len) { 301 readInput(); 302 } 303 if (pos == len) { 304 throw new EOFException(); 305 } else if (pos > len) { 306 throw new IOException("Position beyond EOF"); 307 } 308 return 0xFF & (int)buf[pos++]; 309 } 310 311 /** 312 * Reads 'len' bytes of data from this file into an array of bytes. This 313 * method reads repeatedly from the stream until all the bytes are 314 * read. This method blocks until all the bytes are read, the end of the 315 * stream is detected, or an exception is thrown. 316 * 317 * @param b The buffer into which the data is to be read. It must be long 318 * enough. 319 * 320 * @param off The index in 'b' where to place the first byte read. 321 * 322 * @param len The number of bytes to read. 323 * 324 * @exception EOFException If the end-of file was reached before 325 * getting all the necessary data. 326 * 327 * @exception IOException If an I/O error ocurred. 328 * 329 * */ 330 public void readFully(byte b[], int off, int n) throws IOException { 331 if (pos+n <= len) { // common, fast case 332 System.arraycopy(buf,pos,b,off,n); 333 pos += n; 334 return; 335 } 336 // general case 337 while (!complete && pos+n > len) { 338 readInput(); 339 } 340 if (pos+n > len) { 341 throw new EOFException(); 342 } 343 System.arraycopy(buf,pos,b,off,n); 344 pos += n; 345 } 346 347 /** 348 * Returns the endianess (i.e., byte ordering) of multi-byte I/O 349 * operations. Always EndianType.BIG_ENDIAN since this class implements 350 * only big-endian. 351 * 352 * @return Always EndianType.BIG_ENDIAN. 353 * 354 * @see EndianType 355 * 356 */ 357 public int getByteOrdering() { 358 return EndianType.BIG_ENDIAN; 359 } 360 361 /** 362 * Reads a signed byte (8 bit) from the input. 363 * 364 * @return The next byte-aligned signed byte (8 bit) from the 365 * input. 366 * 367 * @exception EOFException If the end-of file was reached before 368 * getting all the necessary data. 369 * 370 * @exception IOException If an I/O error ocurred. 371 * */ 372 public byte readByte() throws IOException { 373 if (pos < len) { // common, fast case 374 return buf[pos++]; 375 } 376 // general case 377 return (byte) read(); 378 } 379 380 /** 381 * Reads an unsigned byte (8 bit) from the input. 382 * 383 * @return The next byte-aligned unsigned byte (8 bit) from the 384 * input. 385 * 386 * @exception EOFException If the end-of file was reached before 387 * getting all the necessary data. 388 * 389 * @exception IOException If an I/O error ocurred. 390 * */ 391 public int readUnsignedByte() throws IOException { 392 if (pos < len) { // common, fast case 393 return 0xFF & buf[pos++]; 394 } 395 // general case 396 return read(); 397 } 398 399 /** 400 * Reads a signed short (16 bit) from the input. 401 * 402 * @return The next byte-aligned signed short (16 bit) from the 403 * input. 404 * 405 * @exception EOFException If the end-of file was reached before 406 * getting all the necessary data. 407 * 408 * @exception IOException If an I/O error ocurred. 409 * */ 410 public short readShort() throws IOException { 411 if (pos+1 < len) { // common, fast case 412 return (short) ((buf[pos++]<<8) | (0xFF & buf[pos++])); 413 } 414 // general case 415 return (short) ((read()<<8) | read()); 416 } 417 418 /** 419 * Reads an unsigned short (16 bit) from the input. 420 * 421 * @return The next byte-aligned unsigned short (16 bit) from the 422 * input. 423 * 424 * @exception EOFException If the end-of file was reached before 425 * getting all the necessary data. 426 * 427 * @exception IOException If an I/O error ocurred. 428 * */ 429 public int readUnsignedShort() throws IOException { 430 if (pos+1 < len) { // common, fast case 431 return ((0xFF & buf[pos++])<<8) | (0xFF & buf[pos++]); 432 } 433 // general case 434 return (read()<<8) | read(); 435 } 436 437 /** 438 * Reads a signed int (32 bit) from the input. 439 * 440 * @return The next byte-aligned signed int (32 bit) from the 441 * input. 442 * 443 * @exception EOFException If the end-of file was reached before 444 * getting all the necessary data. 445 * 446 * @exception IOException If an I/O error ocurred. 447 * */ 448 public int readInt() throws IOException { 449 if (pos+3 < len) { // common, fast case 450 return ((buf[pos++]<<24) | ((0xFF & buf[pos++])<<16) 451 | ((0xFF & buf[pos++])<<8) | (0xFF & buf[pos++])); 452 } 453 // general case 454 return (read()<<24) | (read()<<16) | (read()<<8) | read(); 455 } 456 457 /** 458 * Reads a unsigned int (32 bit) from the input. 459 * 460 * @return The next byte-aligned unsigned int (32 bit) from the 461 * input. 462 * 463 * @exception EOFException If the end-of file was reached before 464 * getting all the necessary data. 465 * 466 * @exception IOException If an I/O error ocurred. 467 * */ 468 public long readUnsignedInt() throws IOException { 469 if (pos+3 < len) { // common, fast case 470 return (0xFFFFFFFFL 471 & (long)((buf[pos++]<<24) | ((0xFF & buf[pos++])<<16) 472 | ((0xFF & buf[pos++])<<8) | (0xFF & buf[pos++]))); 473 } 474 // general case 475 return (0xFFFFFFFFL 476 & (long)((read()<<24) | (read()<<16) | (read()<<8) | read())); 477 } 478 479 /** 480 * Reads a signed long (64 bit) from the input. 481 * 482 * @return The next byte-aligned signed long (64 bit) from the 483 * input. 484 * 485 * @exception EOFException If the end-of file was reached before 486 * getting all the necessary data. 487 * 488 * @exception IOException If an I/O error ocurred. 489 * */ 490 public long readLong() throws IOException { 491 if (pos+7 < len) { // common, fast case 492 return (((long)buf[pos++]<<56) 493 | ((long)(0xFF&buf[pos++])<<48) 494 | ((long)(0xFF&buf[pos++])<<40) 495 | ((long)(0xFF&buf[pos++])<<32) 496 | ((long)(0xFF&buf[pos++])<<24) 497 | ((long)(0xFF&buf[pos++])<<16) 498 | ((long)(0xFF&buf[pos++])<<8) 499 | (long)(0xFF&buf[pos++])); 500 } 501 // general case 502 return (((long)read()<<56) 503 | ((long)read()<<48) 504 | ((long)read()<<40) 505 | ((long)read()<<32) 506 | ((long)read()<<24) 507 | ((long)read()<<16) 508 | ((long)read()<<8) 509 | (long)read()); 510 } 511 512 /** 513 * Reads an IEEE single precision (i.e., 32 bit) floating-point number 514 * from the input. 515 * 516 * @return The next byte-aligned IEEE float (32 bit) from the input. 517 * 518 * @exception EOFException If the end-of file was reached before 519 * getting all the necessary data. 520 * 521 * @exception IOException If an I/O error ocurred. 522 * */ 523 public float readFloat() throws IOException { 524 if (pos+3 < len) { // common, fast case 525 return Float.intBitsToFloat((buf[pos++]<<24) 526 | ((0xFF & buf[pos++])<<16) 527 | ((0xFF & buf[pos++])<<8) 528 | (0xFF & buf[pos++])); 529 } 530 // general case 531 return Float.intBitsToFloat((read()<<24) | (read()<<16) 532 | (read()<<8) | read()); 533 } 534 535 /** 536 * Reads an IEEE double precision (i.e., 64 bit) floating-point number 537 * from the input. 538 * 539 * @return The next byte-aligned IEEE double (64 bit) from the input. 540 * 541 * @exception EOFException If the end-of file was reached before 542 * getting all the necessary data. 543 * 544 * @exception IOException If an I/O error ocurred. 545 * */ 546 public double readDouble() throws IOException { 547 if (pos+7 < len) { // common, fast case 548 return Double.longBitsToDouble(((long)buf[pos++]<<56) 549 | ((long)(0xFF&buf[pos++])<<48) 550 | ((long)(0xFF&buf[pos++])<<40) 551 | ((long)(0xFF&buf[pos++])<<32) 552 | ((long)(0xFF&buf[pos++])<<24) 553 | ((long)(0xFF&buf[pos++])<<16) 554 | ((long)(0xFF&buf[pos++])<<8) 555 | (long)(0xFF&buf[pos++])); 556 } 557 // general case 558 return Double.longBitsToDouble(((long)read()<<56) 559 | ((long)read()<<48) 560 | ((long)read()<<40) 561 | ((long)read()<<32) 562 | ((long)read()<<24) 563 | ((long)read()<<16) 564 | ((long)read()<<8) 565 | (long)read()); 566 } 567 568 /** 569 * Skips 'n' bytes from the input. 570 * 571 * @param n The number of bytes to skip 572 * 573 * @return Always n. 574 * 575 * @exception EOFException If the end-of file was reached before 576 * all the bytes could be skipped. 577 * 578 * @exception IOException If an I/O error ocurred. 579 * */ 580 public int skipBytes(int n) throws IOException { 581 if (complete) { /* we know the length, check skip is within length */ 582 if (pos+n > len) { 583 throw new EOFException(); 584 } 585 } 586 pos += n; 587 return n; 588 } 589 590 /** 591 * Does nothing since this class does not implement data output. 592 */ 593 public void flush() { /* no-op */ 594 } 595 596 /** 597 * Throws an IOException since this class does not implement data output. 598 */ 599 public void write(int b) throws IOException { 600 throw new IOException("read-only"); 601 } 602 603 /** 604 * Throws an IOException since this class does not implement data output. 605 */ 606 public void writeByte(int v) throws IOException { 607 throw new IOException("read-only"); 608 } 609 610 /** 611 * Throws an IOException since this class does not implement data output. 612 */ 613 public void writeShort(int v) throws IOException { 614 throw new IOException("read-only"); 615 } 616 617 /** 618 * Throws an IOException since this class does not implement data output. 619 */ 620 public void writeInt(int v) throws IOException { 621 throw new IOException("read-only"); 622 } 623 624 /** 625 * Throws an IOException since this class does not implement data output. 626 */ 627 public void writeLong(long v) throws IOException { 628 throw new IOException("read-only"); 629 } 630 631 /** 632 * Throws an IOException since this class does not implement data output. 633 */ 634 public void writeFloat(float v) throws IOException { 635 throw new IOException("read-only"); 636 } 637 638 /** 639 * Throws an IOException since this class does not implement data output. 640 */ 641 public void writeDouble(double v) throws IOException { 642 throw new IOException("read-only"); 643 } 644}