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