/* * CVS Identifier: * * $Id: BufferedRandomAccessFile.java,v 1.21 2001/04/15 14:34:29 grosbois Exp $ * * Interface: RandomAccessIO.java * * Description: Abstract class for buffered random access I/O. * * * * 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; namespace CSJ2K.j2k.io { /// This class defines a Buffered Random Access File. It implements the /// BinaryDataInput and BinaryDataOutput interfaces so that /// binary data input/output can be performed. This class is abstract since no /// assumption is done about the byte ordering type (little Endian, big /// Endian). So subclasses will have to implement methods like /// readShort(), writeShort(), readFloat(), ... /// ///

BufferedRandomAccessFile (BRAF for short) is a /// RandomAccessFile containing an extra buffer. When the BRAF is /// accessed, it checks if the requested part of the file is in the buffer or /// not. If that is the case, the read/write is done on the buffer. If not, the /// file is uppdated to reflect the current status of the buffer and the file /// is then accessed for a new buffer containing the requested byte/bit. /// ///

/// /// /// /// /// /// /// /// /// public abstract class BufferedRandomAccessFile : RandomAccessIO, EndianType { /// Returns the current offset in the file /// /// virtual public int Pos { get { return (offset + position); } } /// Returns the endianess (i.e., byte ordering) of the implementing /// class. Note that an implementing class may implement only one /// type of endianness or both, which would be decided at creation /// time. /// /// /// Either EndianType.BIG_ENDIAN or /// EndianType.LITTLE_ENDIAN /// /// /// /// /// virtual public int ByteOrdering { get { return byte_Ordering; } } /// The name of the current file private System.String fileName; /// Whether the opened file is read only or not (defined by the constructor /// arguments) /// /// private bool isReadOnly = true; /// The RandomAccessFile associated with the buffer /// /// //UPGRADE_TODO: Class 'java.io.RandomAccessFile' was converted to 'System.IO.FileStream' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioRandomAccessFile'" private System.IO.FileStream theFile; /// Buffer of bytes containing the part of the file that is currently being /// accessed /// /// protected internal byte[] byteBuffer; /// Boolean keeping track of whether the byte buffer has been changed since /// it was read. /// /// protected internal bool byteBufferChanged; /// The current offset of the buffer (which will differ from the offset of /// the file) /// /// protected internal int offset; /// The current position in the byte-buffer /// /// protected internal int position; /// The maximum number of bytes that can be read from the buffer /// /// protected internal int maxByte; /// Whether the end of the file is in the current buffer or not /// /// protected internal bool isEOFInBuffer; /* The endianess of the class */ protected internal int byte_Ordering; /// Constructor. Always needs a size for the buffer. /// /// /// The file associated with the buffer /// /// /// "r" for read, "rw" or "rw+" for read and write mode ("rw+" /// opens the file for update whereas "rw" removes it /// before. So the 2 modes are different only if the file /// already exists). /// /// /// The number of bytes to buffer /// /// /// If an I/O error ocurred. /// /// protected internal BufferedRandomAccessFile(System.IO.FileInfo file, System.String mode, int bufferSize) { fileName = file.Name; if (mode.Equals("rw") || mode.Equals("rw+")) { // mode read / write isReadOnly = false; if (mode.Equals("rw")) { // mode read / (over)write bool tmpBool; if (System.IO.File.Exists(file.FullName)) tmpBool = true; else tmpBool = System.IO.Directory.Exists(file.FullName); if (tmpBool) // Output file already exists { bool tmpBool2; if (System.IO.File.Exists(file.FullName)) { System.IO.File.Delete(file.FullName); tmpBool2 = true; } else if (System.IO.Directory.Exists(file.FullName)) { System.IO.Directory.Delete(file.FullName); tmpBool2 = true; } else tmpBool2 = false; bool generatedAux = tmpBool2; } } mode = "rw"; } theFile = SupportClass.RandomAccessFileSupport.CreateRandomAccessFile(file, mode); byteBuffer = new byte[bufferSize]; readNewBuffer(0); } /// Constructor. Uses the default value for the byte-buffer /// size (512 bytes). /// /// /// The file associated with the buffer /// /// /// "r" for read, "rw" or "rw+" for read and write mode /// ("rw+" opens the file for update whereas "rw" removes /// it before. So the 2 modes are different only if the /// file already exists). /// /// /// If an I/O error ocurred. /// /// protected internal BufferedRandomAccessFile(System.IO.FileInfo file, System.String mode):this(file, mode, 512) { } /// Constructor. Always needs a size for the buffer. /// /// /// The name of the file associated with the buffer /// /// /// "r" for read, "rw" or "rw+" for read and write mode /// ("rw+" opens the file for update whereas "rw" removes /// it before. So the 2 modes are different only if the /// file already exists). /// /// /// The number of bytes to buffer /// /// /// If an I/O error ocurred. /// /// protected internal BufferedRandomAccessFile(System.String name, System.String mode, int bufferSize):this(new System.IO.FileInfo(name), mode, bufferSize) { } /// Constructor. Uses the default value for the byte-buffer /// size (512 bytes). /// /// /// The name of the file associated with the buffer /// /// /// "r" for read, "rw" or "rw+" for read and write mode /// ("rw+" opens the file for update whereas "rw" removes /// it before. So the 2 modes are different only if the /// file already exists). /// /// /// If an I/O error ocurred. /// /// protected internal BufferedRandomAccessFile(System.String name, System.String mode):this(name, mode, 512) { } /// Reads a new buffer from the file. If there has been any /// changes made since the buffer was read, the buffer is /// first written to the file. /// /// /// The offset where to move to. /// /// /// If an I/O error ocurred. /// /// protected internal void readNewBuffer(int off) { /* If the buffer have changed. We need to write it to * the file before reading a new buffer. */ if (byteBufferChanged) { flush(); } // Don't allow to seek beyond end of file if reading only if (isReadOnly && off >= theFile.Length) { throw new System.IO.EndOfStreamException(); } // Set new offset offset = off; theFile.Seek(offset, System.IO.SeekOrigin.Begin); maxByte = theFile.Read(byteBuffer, 0, byteBuffer.Length); position = 0; if (maxByte < byteBuffer.Length) { // Not enough data in input file. isEOFInBuffer = true; if (maxByte == - 1) { maxByte++; } } else { isEOFInBuffer = false; } } /// Closes the buffered random access file /// /// /// If an I/O error ocurred. /// /// public virtual void close() { /* If the buffer has been changed, it need to be saved before * closing */ flush(); byteBuffer = null; // Release the byte-buffer reference theFile.Close(); } /// Returns the current length of the stream, in bytes, taking into /// account any buffering. /// /// /// The length of the stream, in bytes. /// /// /// If an I/O error ocurred. /// /// public virtual int length() { int len; len = (int) theFile.Length; // If the position in the buffer is not past the end of the file, // the length of theFile is the length of the stream if ((offset + maxByte) <= len) { return (len); } else { // If not, the file is extended due to the buffering return (offset + maxByte); } } /// Moves the current position to the given offset at which the /// next read or write occurs. The offset is measured from the /// beginning of the stream. /// /// /// The offset where to move to. /// /// /// If in read-only and seeking beyond EOF. /// /// /// If an I/O error ocurred. /// /// public virtual void seek(int off) { /* If the new offset is within the buffer, only the pos value needs * to be modified. Else, the buffer must be moved. */ if ((off >= offset) && (off < (offset + byteBuffer.Length))) { if (isReadOnly && isEOFInBuffer && off > offset + maxByte) { // We are seeking beyond EOF in read-only mode! throw new System.IO.EndOfStreamException(); } position = off - offset; } else { readNewBuffer(off); } } /// Reads an unsigned byte of data from the stream. Prior to reading, the /// stream is realigned at the byte level. /// /// /// The byte read. /// /// /// If an I/O error ocurred. /// /// /// If the end of file was reached /// /// public byte readByte() { return read(); } public byte readUnsignedByte() { return read(); } public byte read() { if (position < maxByte) { // The byte can be read from the buffer // In Java, the bytes are always signed. return (byteBuffer[position++]); } else if (isEOFInBuffer) { // EOF is reached position = maxByte + 1; // Set position to EOF throw new System.IO.EndOfStreamException(); } else { // End of the buffer is reached readNewBuffer(offset + position); return read(); } } /// Reads up to 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 void readFully(byte[] b, int off, int len) { int clen; // current length to read while (len > 0) { // There still is some data to read if (position < maxByte) { // We can read some data from buffer clen = maxByte - position; if (clen > len) clen = len; Array.Copy(byteBuffer, position, b, off, clen); position += clen; off += clen; len -= clen; } else if (isEOFInBuffer) { position = maxByte + 1; // Set position to EOF throw new System.IO.EndOfStreamException(); } else { // Buffer empty => get more data readNewBuffer(offset + position); } } } /// Writes a byte to the stream. Prior to writing, the stream is /// realigned at the byte level. /// /// /// The byte to write. The lower 8 bits of b are /// written. /// /// /// If an I/O error ocurred. /// /// public void write(int b) { // As long as pos is less than the length of the buffer we can write // to the buffer. If the position is after the buffer a new buffer is // needed if (position < byteBuffer.Length) { if (isReadOnly) throw new System.IO.IOException("File is read only"); byteBuffer[position] = (byte) b; if (position >= maxByte) { maxByte = position + 1; } position++; byteBufferChanged = true; } else { readNewBuffer(offset + position); write(b); } } /// Writes a byte to the stream. Prior to writing, the stream is /// realigned at the byte level. /// /// /// The byte to write. /// /// /// If an I/O error ocurred. /// /// public void write(byte b) { // As long as pos is less than the length of the buffer we can write // to the buffer. If the position is after the buffer a new buffer is // needed if (position < byteBuffer.Length) { if (isReadOnly) throw new System.IO.IOException("File is read only"); byteBuffer[position] = b; if (position >= maxByte) { maxByte = position + 1; } position++; byteBufferChanged = true; } else { readNewBuffer(offset + position); write(b); } } /// Writes aan array of bytes to the stream. Prior to writing, the stream is /// realigned at the byte level. /// /// /// The array of bytes to write. /// /// /// The first byte in b to write /// /// /// The number of bytes from b to write /// /// /// If an I/O error ocurred. /// /// public void write(byte[] b, int offset, int length) { int i, stop; stop = offset + length; if (stop > b.Length) throw new System. IndexOutOfRangeException("Index of bound " + b.Length); for (i = offset; i < stop; i++) { write(b[i]); } } /// Writes the byte value of v (i.e., 8 least /// significant bits) to the output. Prior to writing, the output /// should be realigned at the byte level. /// ///

Signed or unsigned data can be written. To write a signed /// value just pass the byte value as an argument. To /// write unsigned data pass the int value as an argument /// (it will be automatically casted, and only the 8 least /// significant bits will be written). /// ///

/// The value to write to the output /// /// /// If an I/O error ocurred. /// /// public void writeByte(int v) { write(v); } /// Any data that has been buffered must be written (including /// buffering at the bit level), and the stream should be realigned /// at the byte level. /// /// /// If an I/O error ocurred. /// /// public void flush() { if (byteBufferChanged) { theFile.Seek(offset, System.IO.SeekOrigin.Begin); theFile.Write(byteBuffer, 0, maxByte); byteBufferChanged = false; } } /* /// Reads a signed byte (i.e., 8 bit) from the input. Prior to /// reading, the input should be realigned at the byte level. /// /// /// The next byte-aligned signed 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 byte readByte() { if (pos < maxByte) { // The byte can be read from the buffer // In Java, the bytes are always signed. return byteBuffer[pos++]; } else if (isEOFInBuffer) { // EOF is reached pos = maxByte + 1; // Set position to EOF throw new System.IO.EndOfStreamException(); } else { // End of the buffer is reached readNewBuffer(offset + pos); return readByte(); } } /// Reads an unsigned byte (i.e., 8 bit) from the input. It is /// returned as an int since Java does not have an /// unsigned byte type. Prior to reading, the input should be /// realigned at the byte level. /// /// /// The next byte-aligned unsigned byte (8 bit) from the /// input, as an int. /// /// /// If the end-of file was reached before /// getting all the necessary data. /// /// /// If an I/O error ocurred. /// /// public int readUnsignedByte() { return read(); } */ /// Skips n bytes from the input. Prior to skipping, the /// input should be realigned at the byte level. /// /// /// The number of bytes to skip /// /// /// 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 (n < 0) throw new System.ArgumentException("Can not skip negative number " + "of bytes"); if (n <= (maxByte - position)) { position += n; return n; } else { seek(offset + position + n); return n; } } /// Returns a string of information about the file /// /// public override System.String ToString() { return "BufferedRandomAccessFile: " + fileName + " (" + ((isReadOnly)?"read only":"read/write") + ")"; } public abstract int readUnsignedShort(); public abstract void writeLong(long param1); public abstract void writeShort(int param1); public abstract float readFloat(); public abstract short readShort(); public abstract double readDouble(); public abstract int readInt(); public abstract long readLong(); public abstract long readUnsignedInt(); public abstract void writeDouble(double param1); public abstract void writeFloat(float param1); public abstract void writeInt(int param1); } }