/* * CVS identifier: * * $Id: ISRandomAccessIO.java,v 1.2 2001/04/09 16:58:15 grosbois Exp $ * * Class: ISRandomAccessIO * * Description: Turns an InsputStream into a read-only * RandomAccessIO, using buffering. * * * * COPYRIGHT: * * This software module was originally developed by Raphaël Grosbois and * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research * Centre France S.A) in the course of development of the JPEG2000 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This * software module is an implementation of a part of the JPEG 2000 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio * Systems AB and Canon Research Centre France S.A (collectively JJ2000 * Partners) agree not to assert against ISO/IEC and users of the JPEG * 2000 Standard (Users) any of their rights under the copyright, not * including other intellectual property rights, for this software module * with respect to the usage by ISO/IEC and Users of this software module * or modifications thereof for use in hardware or software products * claiming conformance to the JPEG 2000 Standard. Those intending to use * this software module in hardware or software products are advised that * their use may infringe existing patents. The original developers of * this software module, JJ2000 Partners and ISO/IEC assume no liability * for use of this software module or modifications thereof. No license * or right to this software module is granted for non JPEG 2000 Standard * conforming products. JJ2000 Partners have full right to use this * software module for his/her own purpose, assign or donate this * software module to any third party and to inhibit third parties from * using this software module for non JPEG 2000 Standard conforming * products. This copyright notice must be included in all copies or * derivative works of this software module. * * Copyright (c) 1999/2000 JJ2000 Partners. * */ using System; using CSJ2K.j2k.io; namespace CSJ2K.j2k.util { /// This class implements a wrapper to turn an InputStream into a /// RandomAccessIO. To provide random access, the input data from the /// InputStream is cached in an in-memory buffer. The in-memory buffer size can /// be limited to a specified size. The data is read into the cache on a as /// needed basis, blocking only when necessary. /// ///

The cache grows automatically as necessary. However, if the data length /// is known prior to the creation of a ISRandomAccessIO object, it is best to /// specify that as the initial in-memory buffer size. That will minimize data /// copying and multiple allocation.

/// ///

Multi-byte data is read in big-endian order. The in-memory buffer /// storage is released when 'close()' is called. This class can only be used /// for data input, not output. The wrapped InputStream is closed when all the /// input data is cached or when 'close()' is called.

/// ///

If an out of memory condition is encountered when growing the in-memory /// buffer an IOException is thrown instead of an OutOfMemoryError. The /// exception message is "Out of memory to cache input data".

/// ///

This class is intended for use as a "quick and dirty" way to give /// network connectivity to RandomAccessIO based classes. It is not intended as /// an efficient means of implementing network connectivity. Doing such /// requires reimplementing the RandomAccessIO based classes to directly use /// network connections.

/// ///

This class does not use temporary files as buffers, because that would /// preclude the use in unsigned applets.

/// ///
public class ISRandomAccessIO : RandomAccessIO { /// Returns the current position in the stream, which is the position from /// where the next byte of data would be read. The first byte in the stream /// is in position 0. /// /// /// If an I/O error occurred. /// /// virtual public int Pos { get { return pos; } } /// Returns the endianess (i.e., byte ordering) of multi-byte I/O /// operations. Always EndianType.BIG_ENDIAN since this class implements /// only big-endian. /// /// /// Always EndianType.BIG_ENDIAN. /// /// /// /// /// virtual public int ByteOrdering { get { return CSJ2K.j2k.io.EndianType_Fields.BIG_ENDIAN; } } /// The InputStream that is wrapped private System.IO.Stream is_Renamed; /* Tha maximum size, in bytes, of the in memory buffer. The maximum size * includes the EOF. */ private int maxsize; /* The increment, in bytes, for the in-memory buffer size */ private int inc; /* The in-memory buffer to cache received data */ private byte[] buf; /* The length of the already received data */ private int len; /* The position of the next byte to be read from the in-memory buffer */ private int pos; /* Flag to indicate if all the data has been received. That is, if the EOF * has been reached. */ private bool complete; /// Creates a new RandomAccessIO wrapper for the given InputStream /// 'is'. The internal cache buffer will have size 'size' and will /// increment by 'inc' each time it is needed. The maximum buffer size is /// limited to 'maxsize'. /// /// /// The input from where to get the data. /// /// /// The initial size for the cache buffer, in bytes. /// /// /// The size increment for the cache buffer, in bytes. /// /// /// The maximum size for the cache buffer, in bytes. /// /// public ISRandomAccessIO(System.IO.Stream is_Renamed, int size, int inc, int maxsize) { if (size < 0 || inc <= 0 || maxsize <= 0 || is_Renamed == null) { throw new System.ArgumentException(); } this.is_Renamed = is_Renamed; // Increase size by one to count in EOF if (size < System.Int32.MaxValue) size++; buf = new byte[size]; this.inc = inc; // The maximum size is one byte more, to allow reading the EOF. if (maxsize < System.Int32.MaxValue) maxsize++; this.maxsize = maxsize; pos = 0; len = 0; complete = false; } /// Creates a new RandomAccessIO wrapper for the given InputStream /// 'is'. The internal cache buffer size and increment is to to 256 kB. The /// maximum buffer size is set to Integer.MAX_VALUE (2 GB). /// /// /// The input from where to get the data. /// /// public ISRandomAccessIO(System.IO.Stream is_Renamed):this(is_Renamed, 1 << 18, 1 << 18, System.Int32.MaxValue) { } /// Grows the cache buffer by 'inc', upto a maximum of 'maxsize'. The /// buffer size will be increased by at least one byte, if no exception is /// thrown. /// /// /// If the maximum cache size is reached or if not /// enough memory is available to grow the buffer. /// /// private void growBuffer() { byte[] newbuf; int effinc; // effective increment effinc = inc; if (buf.Length + effinc > maxsize) effinc = maxsize - buf.Length; if (effinc <= 0) { throw new System.IO.IOException("Reached maximum cache size (" + maxsize + ")"); } try { newbuf = new byte[buf.Length + inc]; } catch (System.OutOfMemoryException) { throw new System.IO.IOException("Out of memory to cache input data"); } Array.Copy(buf, 0, newbuf, 0, len); buf = newbuf; } /// Reads data from the wrapped InputStream and places it in the cache /// buffer. Reads all input data that will not cause it to block, but at /// least on byte is read (even if it blocks), unless EOF is reached. This /// method can not be called if EOF has been already reached /// (i.e. 'complete' is true). The wrapped InputStream is closed if the EOF /// is reached. /// /// /// An I/O error occurred, out of meory to grow /// cache or maximum cache size reached. /// /// private void readInput() { int n; //int b; int k; if (complete) { throw new System.ArgumentException("Already reached EOF"); } long available; available = is_Renamed.Length - is_Renamed.Position; n = (int) available; /* how much can we read without blocking? */ if (n == 0) n = 1; /* read at least one byte (even if it blocks) */ while (len + n > buf.Length) { /* Ensure buffer size */ growBuffer(); } /* Read the data. Loop to be sure that we do read 'n' bytes */ do { // CONVERSION PROBLEM? OPTIMIZE!!! k = is_Renamed.Read(buf, len, n); if (k > 0) { /* Some data was read */ len += k; n -= k; } } while (n > 0 && k > 0); if (k <= 0) { /* we reached EOF */ complete = true; is_Renamed.Close(); is_Renamed = null; } } /// Closes this object for reading as well as the wrapped InputStream, if /// not already closed. The memory used by the cache is released. /// /// /// If an I/O error occurs while closing the /// underlying InputStream. /// /// public virtual void close() { buf = null; if (!complete) { is_Renamed.Close(); is_Renamed = null; } } /// Moves the current position for the next read operation to offset. The /// offset is measured from the beginning of the stream. If the offset is /// set beyond the currently cached data, the missing data will be read /// only when a read operation is performed. Setting the offset beyond the /// end of the data will cause an EOFException only if the data length is /// currently known, otherwise an IOException will occur when a read /// operation is attempted at that position. /// /// /// The offset where to move to. /// /// /// If seeking beyond EOF and the data length is /// known. /// /// /// If an I/O error ocurred. /// /// public virtual void seek(int off) { if (complete) { /* we know the length, check seek is within length */ if (off > len) { throw new System.IO.EndOfStreamException(); } } pos = off; } /// Returns the length of the stream. This will cause all the data to be /// read. This method will block until all the data is read, which can be /// lengthy across the network. /// /// /// The length of the stream, in bytes. /// /// /// If an I/O error ocurred. /// /// public virtual int length() { while (!complete) { /* read until we reach EOF */ readInput(); } return len; } /// Reads a byte of data from the stream. /// /// /// The byte read, as an int in the range [0-255]. /// /// /// If the end-of file was reached. /// /// /// If an I/O error ocurred. /// /// public virtual byte readByte() { return read(); } public virtual byte read() { if (pos < len) { // common, fast case return buf[pos++]; } // general case while (!complete && pos >= len) { readInput(); } if (pos == len) { throw new System.IO.EndOfStreamException(); } else if (pos > len) { throw new System.IO.IOException("Position beyond EOF"); } return buf[pos++]; } /// Reads 'len' bytes of data from this file into an array of bytes. This /// method reads repeatedly from the stream until all the bytes are /// read. This method blocks until all the bytes are read, the end of the /// stream is detected, or an exception is thrown. /// /// /// The buffer into which the data is to be read. It must be long /// enough. /// /// /// The index in 'b' where to place the first byte read. /// /// /// The number of bytes to read. /// /// /// If the end-of file was reached before getting /// all the necessary data. /// /// /// If an I/O error ocurred. /// /// public virtual void readFully(byte[] b, int off, int n) { if (pos + n <= len) { // common, fast case Array.Copy(buf, pos, b, off, n); pos += n; return ; } // general case while (!complete && pos + n > len) { readInput(); } if (pos + n > len) { throw new System.IO.EndOfStreamException(); } Array.Copy(buf, pos, b, off, n); pos += n; } /// Reads an unsigned byte (8 bit) from the input. /// /// /// The next byte-aligned unsigned byte (8 bit) from the input. /// /// /// If the end-of file was reached before getting /// all the necessary data. /// /// /// If an I/O error ocurred. /// /// public virtual byte readUnsignedByte() { if (pos < len) { // common, fast case return buf[pos++]; } // general case return read(); } /// Reads a signed short (16 bit) from the input. /// /// /// The next byte-aligned signed short (16 bit) from the input. /// /// /// If the end-of file was reached before getting /// all the necessary data. /// /// /// If an I/O error ocurred. /// /// public virtual short readShort() { if (pos + 1 < len) { // common, fast case return (short) ((buf[pos++] << 8) | (0xFF & buf[pos++])); } // general case return (short) ((read() << 8) | read()); } /// Reads an unsigned short (16 bit) from the input. /// /// /// The next byte-aligned unsigned short (16 bit) from the input. /// /// /// If the end-of file was reached before getting /// all the necessary data. /// /// /// If an I/O error ocurred. /// /// public virtual int readUnsignedShort() { if (pos + 1 < len) { // common, fast case return ((0xFF & buf[pos++]) << 8) | (0xFF & buf[pos++]); } // general case return (read() << 8) | read(); } /// Reads a signed int (32 bit) from the input. /// /// /// The next byte-aligned signed int (32 bit) from the /// input. /// /// /// If the end-of file was reached before getting /// all the necessary data. /// /// /// If an I/O error ocurred. /// /// public virtual int readInt() { if (pos + 3 < len) { // common, fast case return ((buf[pos++] << 24) | ((0xFF & buf[pos++]) << 16) | ((0xFF & buf[pos++]) << 8) | (0xFF & buf[pos++])); } // general case return (read() << 24) | (read() << 16) | (read() << 8) | read(); } /// Reads a unsigned int (32 bit) from the input. /// /// /// The next byte-aligned unsigned int (32 bit) from the input. /// /// /// If the end-of file was reached before getting /// all the necessary data. /// /// /// If an I/O error ocurred. /// /// public virtual long readUnsignedInt() { if (pos + 3 < len) { // common, fast case return (unchecked((int) 0xFFFFFFFFL) & (long) ((buf[pos++] << 24) | ((0xFF & buf[pos++]) << 16) | ((0xFF & buf[pos++]) << 8) | (0xFF & buf[pos++]))); } // general case return (unchecked((int) 0xFFFFFFFFL) & (long) ((read() << 24) | (read() << 16) | (read() << 8) | read())); } /// Reads a signed long (64 bit) from the input. /// /// /// The next byte-aligned signed long (64 bit) from the input. /// /// /// If the end-of file was reached before getting /// all the necessary data. /// /// /// If an I/O error ocurred. /// /// public virtual long readLong() { if (pos + 7 < len) { // common, fast case return (((long) buf[pos++] << 56) | ((long) buf[pos++] << 48) | ((long) buf[pos++] << 40) | ((long) buf[pos++] << 32) | ((long) buf[pos++] << 24) | ((long) buf[pos++] << 16) | ((long) buf[pos++] << 8) | (long) buf[pos++]); } // general case return (((long) read() << 56) | ((long) read() << 48) | ((long) read() << 40) | ((long) read() << 32) | ((long) read() << 24) | ((long) read() << 16) | ((long) read() << 8) | (long) read()); } /// Reads an IEEE single precision (i.e., 32 bit) floating-point number /// from the input. /// /// /// The next byte-aligned IEEE float (32 bit) from the input. /// /// /// If the end-of file was reached before getting /// all the necessary data. /// /// /// If an I/O error ocurred. /// /// public virtual float readFloat() { // CONVERSION PROBLEM? BIGENDIAN int floatint; if (pos + 3 < len) floatint = (buf[pos++] << 24) | ((0xFF & buf[pos++]) << 16) | ((0xFF & buf[pos++]) << 8) | (0xFF & buf[pos++]); else floatint = (read() << 24) | (read() << 16) | (read() << 8) | read(); return BitConverter.ToSingle(BitConverter.GetBytes(floatint), 0); /* if (pos + 3 < len) { // common, fast case //UPGRADE_ISSUE: Method 'java.lang.Float.intBitsToFloat' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangFloatintBitsToFloat_int'" return Float.intBitsToFloat((buf[pos++] << 24) | ((0xFF & buf[pos++]) << 16) | ((0xFF & buf[pos++]) << 8) | (0xFF & buf[pos++])); } // general case //UPGRADE_ISSUE: Method 'java.lang.Float.intBitsToFloat' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangFloatintBitsToFloat_int'" return Float.intBitsToFloat((read() << 24) | (read() << 16) | (read() << 8) | read()); */ } /// Reads an IEEE double precision (i.e., 64 bit) floating-point number /// from the input. /// /// /// The next byte-aligned IEEE double (64 bit) from the input. /// /// /// If the end-of file was reached before getting /// all the necessary data. /// /// /// If an I/O error ocurred. /// /// public virtual double readDouble() { // CONVERSION PROBLEM? BIGENDIAN long doublelong; if (pos + 7 < len) doublelong = ((long)buf[pos++] << 56) | ((long)buf[pos++] << 48) | ((long)buf[pos++] << 40) | ((long)buf[pos++] << 32) | ((long)buf[pos++] << 24) | ((long)buf[pos++] << 16) | ((long)buf[pos++] << 8) | (long)buf[pos++]; else doublelong = ((long)read() << 56) | ((long)read() << 48) | ((long)read() << 40) | ((long)read() << 32) | ((long)read() << 24) | ((long)read() << 16) | ((long)read() << 8) | (long)read(); return BitConverter.ToDouble(BitConverter.GetBytes(doublelong), 0); /* if (pos + 7 < len) { // common, fast case //UPGRADE_ISSUE: Method 'java.lang.Double.longBitsToDouble' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangDoublelongBitsToDouble_long'" return Double.longBitsToDouble(((long) buf[pos++] << 56) | ((long) (0xFF & buf[pos++]) << 48) | ((long) (0xFF & buf[pos++]) << 40) | ((long) (0xFF & buf[pos++]) << 32) | ((long) (0xFF & buf[pos++]) << 24) | ((long) (0xFF & buf[pos++]) << 16) | ((long) (0xFF & buf[pos++]) << 8) | (long) (0xFF & buf[pos++])); } // general case //UPGRADE_ISSUE: Method 'java.lang.Double.longBitsToDouble' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangDoublelongBitsToDouble_long'" return Double.longBitsToDouble(((long) read() << 56) | ((long) read() << 48) | ((long) read() << 40) | ((long) read() << 32) | ((long) read() << 24) | ((long) read() << 16) | ((long) read() << 8) | (long) read()); */ } /// Skips 'n' bytes from the input. /// /// /// The number of bytes to skip /// /// /// Always n. /// /// /// If the end-of file was reached before all the /// bytes could be skipped. /// /// /// If an I/O error ocurred. /// /// public virtual int skipBytes(int n) { if (complete) { /* we know the length, check skip is within length */ if (pos + n > len) { throw new System.IO.EndOfStreamException(); } } pos += n; return n; } /// Does nothing since this class does not implement data output. /// /// public virtual void flush() { /* no-op */ } /// Throws an IOException since this class does not implement data output. /// /// public virtual void write(byte b) { throw new System.IO.IOException("read-only"); } /// Throws an IOException since this class does not implement data output. /// /// public virtual void writeByte(int v) { throw new System.IO.IOException("read-only"); } /// Throws an IOException since this class does not implement data output. /// /// public virtual void writeShort(int v) { throw new System.IO.IOException("read-only"); } /// Throws an IOException since this class does not implement data output. /// /// public virtual void writeInt(int v) { throw new System.IO.IOException("read-only"); } /// Throws an IOException since this class does not implement data output. /// /// public virtual void writeLong(long v) { throw new System.IO.IOException("read-only"); } /// Throws an IOException since this class does not implement data output. /// /// public virtual void writeFloat(float v) { throw new System.IO.IOException("read-only"); } /// Throws an IOException since this class does not implement data output. /// /// public virtual void writeDouble(double v) { throw new System.IO.IOException("read-only"); } } }