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: */
048: package jj2000.j2k.util;
049:
050: import java.io.*;
051: import 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: * */
084: public 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,
124: int maxsize) {
125: if (size < 0 || inc <= 0 || maxsize <= 0 || is == null) {
126: throw new IllegalArgumentException();
127: }
128: this .is = is;
129: // Increase size by one to count in EOF
130: if (size < Integer.MAX_VALUE)
131: size++;
132: buf = new byte[size];
133: this .inc = inc;
134: // The maximum size is one byte more, to allow reading the EOF.
135: if (maxsize < Integer.MAX_VALUE)
136: maxsize++;
137: this .maxsize = maxsize;
138: pos = 0;
139: len = 0;
140: complete = false;
141: }
142:
143: /**
144: * Creates a new RandomAccessIO wrapper for the given InputStream
145: * 'is'. The internal cache buffer size and increment is to to 256 kB. The
146: * maximum buffer size is set to Integer.MAX_VALUE (2 GB).
147: *
148: * @param is The input from where to get the data.
149: *
150: */
151: public ISRandomAccessIO(InputStream is) {
152: this (is, 1 << 18, 1 << 18, Integer.MAX_VALUE);
153: }
154:
155: /**
156: * Grows the cache buffer by 'inc', upto a maximum of 'maxsize'. The
157: * buffer size will be increased by at least one byte, if no exception is
158: * thrown.
159: *
160: * @exception IOException If the maximum cache size is reached or if not
161: * enough memory is available to grow the buffer.
162: */
163: private void growBuffer() throws IOException {
164: byte newbuf[];
165: int effinc; // effective increment
166:
167: effinc = inc;
168: if (buf.length + effinc > maxsize)
169: effinc = maxsize - buf.length;
170: if (effinc <= 0) {
171: throw new IOException("Reached maximum cache size ("
172: + maxsize + ")");
173: }
174: try {
175: newbuf = new byte[buf.length + inc];
176: } catch (OutOfMemoryError e) {
177: throw new IOException("Out of memory to cache input data");
178: }
179: System.arraycopy(buf, 0, newbuf, 0, len);
180: buf = newbuf;
181: }
182:
183: /**
184: * Reads data from the wrapped InputStream and places it in the cache
185: * buffer. Reads all input data that will not cause it to block, but at
186: * least on byte is read (even if it blocks), unless EOF is reached. This
187: * method can not be called if EOF has been already reached
188: * (i.e. 'complete' is true).
189: *
190: * @exception IOException An I/O error occurred, out of meory to grow
191: * cache or maximum cache size reached.
192: * */
193: private void readInput() throws IOException {
194: int n;
195: int b;
196: int k;
197:
198: if (complete) {
199: throw new IllegalArgumentException("Already reached EOF");
200: }
201: // may need reflection to call this method
202: // n = is.available(); /* how much can we read without blocking? */
203: n = 0; /* how much can we read without blocking? */
204: if (n == 0)
205: n = 1; /* read at least one byte (even if it blocks) */
206: while (len + n > buf.length) { /* Ensure buffer size */
207: growBuffer();
208: }
209: /* Read the data. Loop to be sure that we do read 'n' bytes */
210: do {
211: k = is.read(buf, len, n);
212: if (k > 0) { /* Some data was read */
213: len += k;
214: n -= k;
215: }
216: } while (n > 0 && k > 0);
217: if (k <= 0) { /* we reached EOF */
218: complete = true;
219: is = null;
220: }
221: }
222:
223: /**
224: * Closes this object for reading as well as the wrapped InputStream, if
225: * not already closed. The memory used by the cache is released.
226: *
227: * @exception IOException If an I/O error occurs while closing the
228: * underlying InputStream. */
229: public void close() throws IOException {
230: buf = null;
231: if (!complete) {
232: is.close();
233: is = null;
234: }
235: }
236:
237: /**
238: * Returns the current position in the stream, which is the
239: * position from where the next byte of data would be read. The first
240: * byte in the stream is in position 0.
241: *
242: * @exception IOException If an I/O error occurred.
243: * */
244: public int getPos() throws IOException {
245: return pos;
246: }
247:
248: /**
249: * Moves the current position for the next read operation to
250: * offset. The offset is measured from the beginning of the stream. If the
251: * offset is set beyond the currently cached data, the missing data will
252: * be read only when a read operation is performed. Setting
253: * the offset beyond the end of the data will cause an EOFException only
254: * if the data length is currently known, otherwise an IOException will
255: * occur when a read operation is attempted at that position.
256: *
257: * @param off The offset where to move to.
258: *
259: * @exception EOFException If seeking beyond EOF and the data length is
260: * known.
261: *
262: * @exception IOException If an I/O error ocurred.
263: * */
264: public void seek(int off) throws IOException {
265: if (complete) { /* we know the length, check seek is within length */
266: if (off > len) {
267: throw new EOFException();
268: }
269: }
270: pos = off;
271: }
272:
273: /**
274: * Returns the length of the stream. This will cause all the data to be
275: * read. This method will block until all the data is read, which can be
276: * lengthy across the network.
277: *
278: * @return The length of the stream, in bytes.
279: *
280: * @exception IOException If an I/O error ocurred.
281: */
282: public int length() throws IOException {
283: if (Integer.MAX_VALUE != maxsize)
284: return maxsize - 1;
285: while (!complete) { // read until we reach EOF
286: readInput();
287: }
288: return len;
289: }
290:
291: /**
292: * Reads a byte of data from the stream.
293: *
294: * @return The byte read, as an int in the range [0-255].
295: *
296: * @exception EOFException If the end-of file was reached.
297: *
298: * @exception IOException If an I/O error ocurred.
299: *
300: */
301: public int read() throws IOException {
302: if (pos < len) { // common, fast case
303: return 0xFF & (int) buf[pos++];
304: }
305: // general case
306: while (!complete && pos >= len) {
307: readInput();
308: }
309: if (pos == len) {
310: throw new EOFException();
311: } else if (pos > len) {
312: throw new IOException("Position beyond EOF");
313: }
314: return 0xFF & (int) buf[pos++];
315: }
316:
317: /**
318: * Reads 'len' bytes of data from this file into an array of bytes. This
319: * method reads repeatedly from the stream until all the bytes are
320: * read. This method blocks until all the bytes are read, the end of the
321: * stream is detected, or an exception is thrown.
322: *
323: * @param b The buffer into which the data is to be read. It must be long
324: * enough.
325: *
326: * @param off The index in 'b' where to place the first byte read.
327: *
328: * @param len The number of bytes to read.
329: *
330: * @exception EOFException If the end-of file was reached before
331: * getting all the necessary data.
332: *
333: * @exception IOException If an I/O error ocurred.
334: *
335: * */
336: public void readFully(byte b[], int off, int n) throws IOException {
337: if (pos + n <= len) { // common, fast case
338: System.arraycopy(buf, pos, b, off, n);
339: pos += n;
340: return;
341: }
342: // general case
343: while (!complete && pos + n > len) {
344: readInput();
345: }
346: if (pos + n > len) {
347: throw new EOFException();
348: }
349: System.arraycopy(buf, pos, b, off, n);
350: pos += n;
351: }
352:
353: /**
354: * Returns the endianess (i.e., byte ordering) of multi-byte I/O
355: * operations. Always EndianType.BIG_ENDIAN since this class implements
356: * only big-endian.
357: *
358: * @return Always EndianType.BIG_ENDIAN.
359: *
360: * @see EndianType
361: *
362: */
363: public int getByteOrdering() {
364: return EndianType.BIG_ENDIAN;
365: }
366:
367: /**
368: * Reads a signed byte (8 bit) from the input.
369: *
370: * @return The next byte-aligned signed byte (8 bit) from the
371: * input.
372: *
373: * @exception EOFException If the end-of file was reached before
374: * getting all the necessary data.
375: *
376: * @exception IOException If an I/O error ocurred.
377: * */
378: public byte readByte() throws IOException {
379: if (pos < len) { // common, fast case
380: return buf[pos++];
381: }
382: // general case
383: return (byte) read();
384: }
385:
386: /**
387: * Reads an unsigned byte (8 bit) from the input.
388: *
389: * @return The next byte-aligned unsigned byte (8 bit) from the
390: * input.
391: *
392: * @exception EOFException If the end-of file was reached before
393: * getting all the necessary data.
394: *
395: * @exception IOException If an I/O error ocurred.
396: * */
397: public int readUnsignedByte() throws IOException {
398: if (pos < len) { // common, fast case
399: return 0xFF & buf[pos++];
400: }
401: // general case
402: return read();
403: }
404:
405: /**
406: * Reads a signed short (16 bit) from the input.
407: *
408: * @return The next byte-aligned signed short (16 bit) from the
409: * input.
410: *
411: * @exception EOFException If the end-of file was reached before
412: * getting all the necessary data.
413: *
414: * @exception IOException If an I/O error ocurred.
415: * */
416: public short readShort() throws IOException {
417: if (pos + 1 < len) { // common, fast case
418: return (short) ((buf[pos++] << 8) | (0xFF & buf[pos++]));
419: }
420: // general case
421: return (short) ((read() << 8) | read());
422: }
423:
424: /**
425: * Reads an unsigned short (16 bit) from the input.
426: *
427: * @return The next byte-aligned unsigned short (16 bit) from the
428: * input.
429: *
430: * @exception EOFException If the end-of file was reached before
431: * getting all the necessary data.
432: *
433: * @exception IOException If an I/O error ocurred.
434: * */
435: public int readUnsignedShort() throws IOException {
436: if (pos + 1 < len) { // common, fast case
437: return ((0xFF & buf[pos++]) << 8) | (0xFF & buf[pos++]);
438: }
439: // general case
440: return (read() << 8) | read();
441: }
442:
443: /**
444: * Reads a signed int (32 bit) from the input.
445: *
446: * @return The next byte-aligned signed int (32 bit) from the
447: * input.
448: *
449: * @exception EOFException If the end-of file was reached before
450: * getting all the necessary data.
451: *
452: * @exception IOException If an I/O error ocurred.
453: * */
454: public int readInt() throws IOException {
455: if (pos + 3 < len) { // common, fast case
456: return ((buf[pos++] << 24) | ((0xFF & buf[pos++]) << 16)
457: | ((0xFF & buf[pos++]) << 8) | (0xFF & buf[pos++]));
458: }
459: // general case
460: return (read() << 24) | (read() << 16) | (read() << 8) | read();
461: }
462:
463: /**
464: * Reads a unsigned int (32 bit) from the input.
465: *
466: * @return The next byte-aligned unsigned int (32 bit) from the
467: * input.
468: *
469: * @exception EOFException If the end-of file was reached before
470: * getting all the necessary data.
471: *
472: * @exception IOException If an I/O error ocurred.
473: * */
474: public long readUnsignedInt() throws IOException {
475: if (pos + 3 < len) { // common, fast case
476: return (0xFFFFFFFFL & (long) ((buf[pos++] << 24)
477: | ((0xFF & buf[pos++]) << 16)
478: | ((0xFF & buf[pos++]) << 8) | (0xFF & buf[pos++])));
479: }
480: // general case
481: return (0xFFFFFFFFL & (long) ((read() << 24) | (read() << 16)
482: | (read() << 8) | read()));
483: }
484:
485: /**
486: * Reads a signed long (64 bit) from the input.
487: *
488: * @return The next byte-aligned signed long (64 bit) from the
489: * input.
490: *
491: * @exception EOFException If the end-of file was reached before
492: * getting all the necessary data.
493: *
494: * @exception IOException If an I/O error ocurred.
495: * */
496: public long readLong() throws IOException {
497: if (pos + 7 < len) { // common, fast case
498: return (((long) buf[pos++] << 56)
499: | ((long) (0xFF & buf[pos++]) << 48)
500: | ((long) (0xFF & buf[pos++]) << 40)
501: | ((long) (0xFF & buf[pos++]) << 32)
502: | ((long) (0xFF & buf[pos++]) << 24)
503: | ((long) (0xFF & buf[pos++]) << 16)
504: | ((long) (0xFF & buf[pos++]) << 8) | (long) (0xFF & buf[pos++]));
505: }
506: // general case
507: return (((long) read() << 56) | ((long) read() << 48)
508: | ((long) read() << 40) | ((long) read() << 32)
509: | ((long) read() << 24) | ((long) read() << 16)
510: | ((long) read() << 8) | (long) read());
511: }
512:
513: /**
514: * Reads an IEEE single precision (i.e., 32 bit) floating-point number
515: * from the input.
516: *
517: * @return The next byte-aligned IEEE float (32 bit) from the input.
518: *
519: * @exception EOFException If the end-of file was reached before
520: * getting all the necessary data.
521: *
522: * @exception IOException If an I/O error ocurred.
523: * */
524: public float readFloat() throws IOException {
525: if (pos + 3 < len) { // common, fast case
526: return Float.intBitsToFloat((buf[pos++] << 24)
527: | ((0xFF & buf[pos++]) << 16)
528: | ((0xFF & buf[pos++]) << 8) | (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) | ((long) read() << 40)
560: | ((long) read() << 32) | ((long) read() << 24)
561: | ((long) read() << 16) | ((long) read() << 8)
562: | (long) read());
563: }
564:
565: /**
566: * Skips 'n' bytes from the input.
567: *
568: * @param n The number of bytes to skip
569: *
570: * @return Always n.
571: *
572: * @exception EOFException If the end-of file was reached before
573: * all the bytes could be skipped.
574: *
575: * @exception IOException If an I/O error ocurred.
576: * */
577: public int skipBytes(int n) throws IOException {
578: if (complete) { /* we know the length, check skip is within length */
579: if (pos + n > len) {
580: throw new EOFException();
581: }
582: }
583: pos += n;
584: return n;
585: }
586:
587: /**
588: * Does nothing since this class does not implement data output.
589: */
590: public void flush() { /* no-op */
591: }
592:
593: /**
594: * Throws an IOException since this class does not implement data output.
595: */
596: public void write(int b) throws IOException {
597: throw new IOException("read-only");
598: }
599:
600: /**
601: * Throws an IOException since this class does not implement data output.
602: */
603: public void writeByte(int v) 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 writeShort(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 writeInt(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 writeLong(long 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 writeFloat(float 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 writeDouble(double v) throws IOException {
639: throw new IOException("read-only");
640: }
641: }
|