package pt.tumba.parser.swf; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; /** * Output Stream Wrapper * *@author unknown *@created 15 de Setembro de 2002 */ public class OutStream { protected OutputStream out; protected long bytesWritten = 0L; //--Bit buffer.. protected int bitBuf; protected int bitPos; /** * Constructor for the OutStream object * *@param out Description of the Parameter */ public OutStream(OutputStream out) { this.out = out; bitBuf = 0; bitPos = 0; } /** * Gets the bytesWritten attribute of the OutStream object * *@return The bytesWritten value */ public long getBytesWritten() { return bytesWritten; } /** * Sets the bytesWritten attribute of the OutStream object * *@param written The new bytesWritten value */ public void setBytesWritten(long written) { bytesWritten = written; } /** * Write a signed value to the output stream in the given number of bits. * The value must actually fit in that number of bits or it will be garbled * *@param numBits Description of the Parameter *@param value Description of the Parameter *@exception IOException Description of the Exception */ public void writeSBits(int numBits, int value) throws IOException { //--Mask out any sign bit long lval = value & 0x7FFFFFFF; if (value < 0) { //add the sign bit lval |= 1L << (numBits - 1); } //--Write the bits as if unsigned writeUBits(numBits, lval); } /** * Description of the Method * *@exception IOException Description of the Exception */ public void flush() throws IOException { flushBits(); out.flush(); } /** * Description of the Method * *@exception IOException Description of the Exception */ public void close() throws IOException { flushBits(); out.close(); } /** * Flush the bit buffer to the output stream and reset values * *@exception IOException Description of the Exception */ public void flushBits() throws IOException { if (bitPos == 0) { return; } //nothing to flush out.write(bitBuf); bitBuf = 0; bitPos = 0; bytesWritten++; } /** * Write an unsigned value to the output stream in the given number of bits * *@param numBits Description of the Parameter *@param value Description of the Parameter *@exception IOException Description of the Exception */ public void writeUBits(int numBits, long value) throws IOException { if (numBits == 0) { return; } if (bitPos == 0) { bitPos = 8; } //bitBuf was empty int bitNum = numBits; while (bitNum > 0) { //write all bits while (bitPos > 0 && bitNum > 0) { //write into all position of the bit buffer if (getBit(bitNum, value)) { bitBuf = setBit(bitPos, bitBuf); } bitNum--; bitPos--; } if (bitPos == 0) { //bit buffer is full - write it writeUI8(bitBuf); bitBuf = 0; if (bitNum > 0) { bitPos = 8; } //prepare for more bits } } } /** * Get the given bit (where lowest bit is numbered 1) * *@param bitNum Description of the Parameter *@param value Description of the Parameter *@return The bit value */ public static boolean getBit(int bitNum, long value) { return (value & (1L << (bitNum - 1))) != 0; } /** * Set the given bit (where lowest bit is numbered 1) * *@param bitNum The new bit value *@param value The new bit value *@return Description of the Return Value */ public static int setBit(int bitNum, int value) { return value | (1 << (bitNum - 1)); } /** * Write the given bytes to the output stream * *@param bytes Description of the Parameter *@exception IOException Description of the Exception */ public void write(byte[] bytes) throws IOException { flushBits(); if (bytes != null && bytes.length > 0) { out.write(bytes); bytesWritten += bytes.length; } } /** * Write the given bytes to the output stream * *@param bytes Description of the Parameter *@param start Description of the Parameter *@param length Description of the Parameter *@exception IOException Description of the Exception */ public void write(byte[] bytes, int start, int length) throws IOException { flushBits(); if (bytes != null && length > 0) { out.write(bytes, start, length); bytesWritten += length; } } /** * Write an 8 bit unsigned value to the out stream * *@param value Description of the Parameter *@exception IOException Description of the Exception */ public void writeUI8(int value) throws IOException { flushBits(); out.write(value); bytesWritten++; } /** * Write a 16 bit unsigned value to the out stream * *@param value Description of the Parameter *@exception IOException Description of the Exception */ public void writeUI16(int value) throws IOException { flushBits(); out.write(value & 0xff); out.write(value >> 8); bytesWritten += 2; } /** * Write a 16 bit signed value to the out stream * *@param value Description of the Parameter *@exception IOException Description of the Exception */ public void writeSI16(short value) throws IOException { flushBits(); out.write(value & 0xff); out.write(value >> 8); bytesWritten += 2; } /** * Write a 32 bit unsigned value to the out stream * *@param value Description of the Parameter *@exception IOException Description of the Exception */ public void writeUI32(long value) throws IOException { flushBits(); out.write((int) (value & 0xff)); out.write((int) (value >> 8)); out.write((int) (value >> 16)); out.write((int) (value >> 24)); bytesWritten += 4; } /** * Write a string to the output stream using the default encoding and add * terminating null * *@param s Description of the Parameter *@exception IOException Description of the Exception */ public void writeString(String s2) throws IOException { String s = s2; if (s == null) { s = ""; } writeString(s.getBytes()); } /** * Write a string to the output stream and add terminating null * *@param string Description of the Parameter *@exception IOException Description of the Exception */ public void writeString(byte[] string) throws IOException { flushBits(); if (string != null) { out.write(string); } out.write(0); //terminate string bytesWritten += string.length + 1; } /** * Calculate the byte length of a string as it would be written to the * output stream * *@param string Description of the Parameter *@return The stringLength value */ public static int getStringLength(byte[] string) { if (string == null) { return 1; } return string.length + 1; //to include the terminating null } /** * Calculate the byte length of a string as it would be written to the * output stream using the default character encoding * *@param string Description of the Parameter *@return The stringLength value */ public static int getStringLength(String string) { if (string == null) { return 1; } byte[] bytes = string.getBytes(); return bytes.length + 1; //to include the terminating null } /** * Reset the bit buffer */ protected void initBits() { bitBuf = 0; bitPos = 0; } /** * Determine the minimum number of bits required to hold the given signed * value * *@param value Description of the Parameter *@return Description of the Return Value */ public static int determineSignedBitSize(int value) { if (value >= 0) { return determineUnsignedBitSize(value) + 1; } //--This is probably a really bad way of doing this... int topBit = 31; long mask = 0x40000000L; while (topBit > 0) { if ((value & mask) == 0) { break; } mask >>= 1; topBit--; } if (topBit == 0) { return 2; } //must have been -1 //HACK: Flash represents -16 as 110000 rather than 10000 etc.. int val2 = value & ((1 << topBit) - 1); if (val2 == 0) { topBit++; } return topBit + 1; } /** * Determine the minimum number of bits required to hold the given unsigned * value (may be zero) * *@param value Description of the Parameter *@return Description of the Return Value */ public static int determineUnsignedBitSize(long value) { //--This is probably a really bad way of doing this... int topBit = 32; long mask = 0x80000000L; while (topBit > 0) { if ((value & mask) != 0) { return topBit; } mask >>= 1; topBit--; } return 0; } /** * Write a float value * *@param value Description of the Parameter *@exception IOException Description of the Exception */ public void writeFloat(float value) throws IOException { writeSI32(Float.floatToIntBits(value)); } /** * Write a double value * *@param value Description of the Parameter *@exception IOException Description of the Exception */ public void writeDouble(double value) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream(baos); dout.writeDouble(value); dout.flush(); byte[] bytes = baos.toByteArray(); byte[] bytes2 = new byte[8]; bytes2[0] = bytes[3]; bytes2[1] = bytes[2]; bytes2[2] = bytes[1]; bytes2[3] = bytes[0]; bytes2[4] = bytes[7]; bytes2[5] = bytes[6]; bytes2[6] = bytes[5]; bytes2[7] = bytes[4]; write(bytes2); } /** * Write a 32 bit signed value * *@param value Description of the Parameter *@exception IOException Description of the Exception */ public void writeSI32(int value) throws IOException { flushBits(); out.write(value & 0xff); out.write(value >> 8); out.write(value >> 16); out.write(value >> 24); bytesWritten += 4; } /** * Util to convert a signed int to 2 bytes * *@param value Description of the Parameter *@return Description of the Return Value */ public static byte[] sintTo2Bytes(int value) { return new byte[] { uintToByte(value & 0xff), uintToByte(value >> 8) }; } /** * Util to convert an unsigned int to 2 bytes * *@param value Description of the Parameter *@return Description of the Return Value */ public static byte[] uintTo2Bytes(int value) { return new byte[] { uintToByte(value & 0xff), uintToByte(value >> 8) }; } /** * Util to convert an unsigned int to 4 bytes * *@param value Description of the Parameter *@return Description of the Return Value */ public static byte[] uintTo4Bytes(int value) { return new byte[] { uintToByte(value & 0xff), uintToByte(value >> 8), uintToByte(value >> 16), uintToByte(value >> 24) }; } /** * Util to convert an unsigned int to an unsigned byte * *@param value Description of the Parameter *@return Description of the Return Value */ public static byte uintToByte(int value2) { int value = value2; int lowbit = value & 1; value >>= 1; byte b = (byte) value; b <<= 1; b |= (byte) lowbit; return b; } }