package weka.classifiers.rules; import java.io.*; public class BinaryFile { /** * Use this constant to specify big-endian integers. */ public static final short BIG_ENDIAN = 1; /** * Use this constant to specify litte-endian constants. */ public static final short LITTLE_ENDIAN = 2; /** * The underlying file. */ protected RandomAccessFile _file; /** * Are we in LITTLE_ENDIAN or BIG_ENDIAN mode. */ protected short _endian; /** * Are we reading signed or unsigned numbers. */ protected boolean _signed; /** * The constructor. Use to specify the underlying file. * * @param f The file to read/write from/to. */ public BinaryFile(RandomAccessFile f) { _file = f; _endian = LITTLE_ENDIAN; _signed = false; } /** * Set the endian mode for reading integers. * * @param i Specify either LITTLE_ENDIAN or BIG_ENDIAN. * @exception java.lang.Exception Will be thrown if this method is not passed either BinaryFile.LITTLE_ENDIAN or BinaryFile.BIG_ENDIAN. */ public void setEndian(short i) throws Exception { if ((i == BIG_ENDIAN) || (i == LITTLE_ENDIAN)) _endian = i; else throw (new Exception( "Must be BinaryFile.LITTLE_ENDIAN or BinaryFile.BIG_ENDIAN")); } /** * Returns the endian mode. Will be either BIG_ENDIAN or LITTLE_ENDIAN. * * @return BIG_ENDIAN or LITTLE_ENDIAN to specify the current endian mode. */ public int getEndian() { return _endian; } /** * Sets the signed or unsigned mode for integers. true for signed, false for unsigned. * * @param b True if numbers are to be read/written as signed, false if unsigned. */ public void setSigned(boolean b) { _signed = b; } /** * Returns the signed mode. * * @return Returns true for signed, false for unsigned. */ public boolean getSigned() { return _signed; } /** * Reads a fixed length ASCII string. * * @param length How long of a string to read. * @return The number of bytes read. * @exception java.io.IOException If an IO exception occurs. */ public String readFixedString(int length) throws java.io.IOException { String rtn = ""; for (int i = 0; i < length; i++) rtn += (char) _file.readByte(); return rtn; } /** * Writes a fixed length ASCII string. Will truncate the string if it does not fit in the specified buffer. * * @param str The string to be written. * @param length The length of the area to write to. Should be larger than the length of the string being written. * @exception java.io.IOException If an IO exception occurs. */ public void writeFixedString(String str, int length) throws java.io.IOException { int i; // trim the string back some if needed if (str.length() > length) str = str.substring(0, length); // write the string for (i = 0; i < str.length(); i++) _file.write(str.charAt(i)); // buffer extra space if needed i = length - str.length(); while ((i--) > 0) _file.write(0); } /** * Reads a string that stores one length byte before the string. This string can be up to 255 characters long. Pascal stores strings this way. * * @return The string that was read. * @exception java.io.IOException If an IO exception occurs. */ public String readLengthPrefixString() throws java.io.IOException { short len = readUnsignedByte(); return readFixedString(len); } /** * Writes a string that is prefixed by a single byte that specifies the length of the string. This is how Pascal usually stores strings. * * @param str The string to be written. * @exception java.io.IOException If an IO exception occurs. */ public void writeLengthPrefixString(String str) throws java.io.IOException { writeByte((byte) str.length()); for (int i = 0; i < str.length(); i++) _file.write(str.charAt(i)); } /** * Reads a fixed length string that is zero(NULL) terminated. This is a type of string used by C/C++. For example char str[80]. * * @param length The length of the string. * @return The string that was read. * @exception java.io.IOException If an IO exception occurs. */ public String readFixedZeroString(int length) throws java.io.IOException { String rtn = readFixedString(length); int i = rtn.indexOf(0); if (i != -1) rtn = rtn.substring(0, i); return rtn; } /** * Writes a fixed length string that is zero terminated. This is the format generally used by C/C++ for string storage. * * @param str The string to be written. * @param length The length of the buffer to receive the string. * @exception java.io.IOException If an IO exception occurs. */ public void writeFixedZeroString(String str, int length) throws java.io.IOException { writeFixedString(str, length); } /** * Reads an unlimited length zero(null) terminated string. * * @return The string that was read. * @exception java.io.IOException If an IO exception occurs. */ public String readZeroString() throws java.io.IOException { String rtn = ""; char ch; do { ch = (char) _file.read(); if (ch != 0) rtn += ch; } while (ch != 0); return rtn; } /** * Writes an unlimited zero(NULL) terminated string to the file. * * @param str The string to be written. * @exception java.io.IOException If an IO exception occurs. */ public void writeZeroString(String str) throws java.io.IOException { for (int i = 0; i < str.length(); i++) _file.write(str.charAt(i)); writeByte((byte) 0); } /** * Internal function used to read an unsigned byte. External classes should use the readByte function. * * @return The byte, unsigned, as a short. * @exception java.io.IOException If an IO exception occurs. */ protected short readUnsignedByte() throws java.io.IOException { return (short) (_file.readByte() & 0xff); } /** * Reads an 8-bit byte. Can be signed or unsigned depending on the signed property. * * @return A byte stored in a short. * @exception java.io.IOException If an IO exception occurs. */ public short readByte() throws java.io.IOException { if (_signed) return (short) _file.readByte(); else return (short) _file.readUnsignedByte(); } /** * Writes a single byte to the file. * * @param b The byte to be written. * @exception java.io.IOException If an IO exception occurs. */ public void writeByte(short b) throws java.io.IOException { _file.write(b & 0xff); } /** * Reads a 16-bit word. Can be signed or unsigned depending on the signed property. Can be little or big endian depending on the endian property. * * @return A word stored in an int. * @exception java.io.IOException If an IO exception occurs. */ public int readWord() throws java.io.IOException { short a, b; int result; a = readUnsignedByte(); b = readUnsignedByte(); if (_endian == BIG_ENDIAN) result = ((a << 8) | b); else result = (a | (b << 8)); if (_signed) if ((result & 0x8000) == 0x8000) result = -(0x10000 - result); return result; } /** * Write a word to the file. * * @param w The word to be written to the file. * @exception java.io.IOException If an IO exception occurs. */ public void writeWord(int w) throws java.io.IOException { if (_endian == BIG_ENDIAN) { _file.write((w & 0xff00) >> 8); _file.write(w & 0xff); } else { _file.write(w & 0xff); _file.write((w & 0xff00) >> 8); } } /** * Reads a 32-bit double word. Can be signed or unsigned depending on the signed property. Can be little or big endian depending on the endian property. * * @return A double world stored in a long. * @exception java.io.IOException If an IO exception occurs. */ public long readDWord() throws java.io.IOException { short a, b, c, d; long result; a = readUnsignedByte(); b = readUnsignedByte(); c = readUnsignedByte(); d = readUnsignedByte(); if (_endian == BIG_ENDIAN) result = ((a << 24) | (b << 16) | (c << 8) | d); else result = (a | (b << 8) | (c << 16) | (d << 24)); if (_signed) if ((result & 0x80000000L) == 0x80000000L) result = -(0x100000000L - result); return result; } /** * Writes a double word to the file. * * @param d The double word to be written to the file. * @exception java.io.IOException If an IO exception occurs. */ public void writeDWord(long d) throws java.io.IOException { if (_endian == BIG_ENDIAN) { _file.write((int) (d & 0xff000000) >> 24); _file.write((int) (d & 0xff0000) >> 16); _file.write((int) (d & 0xff00) >> 8); _file.write((int) (d & 0xff)); } else { _file.write((int) (d & 0xff)); _file.write((int) (d & 0xff00) >> 8); _file.write((int) (d & 0xff0000) >> 16); _file.write((int) (d & 0xff000000) >> 24); } } /** * Allows the file to be aligned to a specified byte boundary. For example, if a 4(double word) is specified, the file pointer will be moved to the next double word boundary. * * @param a The byte-boundary to align to. * @exception java.io.IOException If an IO exception occurs. */ public void align(int a) throws java.io.IOException { if ((_file.getFilePointer() % a) > 0) { long pos = _file.getFilePointer() / a; _file.seek((pos + 1) * a); } } }