#include "../../Platform/stdafx.h" #include "DataInputStream.h" #include #include // Creates a DataInputStream that uses the specified underlying InputStream. // Parameters: // in - the specified input stream DataInputStream::DataInputStream(InputStream* in) : stream(in) {} // Reads the next byte of data from this input stream. The value byte is // returned as an int in the range 0 to 255. If no byte is available because the // end of the stream has been reached, the value -1 is returned. This method // blocks until input data is available, the end of the stream is detected, or // an exception is thrown. This method simply performs in.read() and returns the // result. int DataInputStream::read() { if (stream == NULL) { app.DebugPrintf( "DataInputStream::read() called but underlying stream is NULL\n"); return -1; } return stream->read(); } // Reads some number of bytes from the contained input stream and stores them // into the buffer array b. The number of bytes actually read is returned as an // integer. This method blocks until input data is available, end of file is // detected, or an exception is thrown. If b is null, a NullPointerException is // thrown. If the length of b is zero, then no bytes are read and 0 is returned; // otherwise, there is an attempt to read at least one byte. If no byte is // available because the stream is at end of file, the value -1 is returned; // otherwise, at least one byte is read and stored into b. // // The first byte read is stored into element b[0], the next one into b[1], and // so on. The number of bytes read is, at most, equal to the length of b. Let k // be the number of bytes actually read; these bytes will be stored in elements // b[0] through b[k-1], leaving elements b[k] through b[b.length-1] unaffected. // // The read(b) method has the same effect as: // // read(b, 0, b.length) // // Overrides: // read in class FilterInputStream // Parameters: // b - the buffer into which the data is read. // Returns: // the total number of bytes read into the buffer, or -1 if there is no more // data because the end of the stream has been reached. int DataInputStream::read(byteArray b) { if (stream == NULL) { app.DebugPrintf( "DataInputStream::read(byteArray) called but underlying stream is " "NULL\n"); return -1; } return read(b, 0, b.length); } // Reads up to len bytes of data from the contained input stream into an array // of bytes. An attempt is made to read as many as len bytes, but a smaller // number may be read, possibly zero. The number of bytes actually read is // returned as an integer. This method blocks until input data is available, end // of file is detected, or an exception is thrown. // // If len is zero, then no bytes are read and 0 is returned; otherwise, there is // an attempt to read at least one byte. If no byte is available because the // stream is at end of file, the value -1 is returned; otherwise, at least one // byte is read and stored into b. // // The first byte read is stored into element b[off], the next one into // b[off+1], and so on. The number of bytes read is, at most, equal to len. Let // k be the number of bytes actually read; these bytes will be stored in // elements b[off] through b[off+k-1], leaving elements b[off+k] through // b[off+len-1] unaffected. // // In every case, elements b[0] through b[off] and elements b[off+len] through // b[b.length-1] are unaffected. // // Overrides: // read in class FilterInputStream // Parameters: // b - the buffer into which the data is read. // off - the start offset in the destination array b // len - the maximum number of bytes read. // Returns: // the total number of bytes read into the buffer, or -1 if there is no more // data because the end of the stream has been reached. int DataInputStream::read(byteArray b, unsigned int offset, unsigned int length) { if (stream == NULL) { app.DebugPrintf( "DataInputStream::read(byteArray,offset,length) called but " "underlying stream is NULL\n"); return -1; } return stream->read(b, offset, length); } // Closes this input stream and releases any system resources associated with // the stream. This method simply performs in.close() void DataInputStream::close() { if (stream == NULL) { app.DebugPrintf( "DataInputStream::close() called but underlying stream is NULL\n"); return; } stream->close(); } // Reads one input byte and returns true if that byte is nonzero, false if that // byte is zero. This method is suitable for reading the byte written by the // writeBoolean method of interface DataOutput. Returns: the boolean value read. bool DataInputStream::readBoolean() { if (stream == NULL) { app.DebugPrintf( "DataInputStream::readBoolean() but underlying stream is NULL\n"); return false; } return stream->read() != 0; } // Reads and returns one input byte. The byte is treated as a signed value in // the range -128 through 127, inclusive. This method is suitable for reading // the byte written by the writeByte method of interface DataOutput. Returns: // the 8-bit value read. uint8_t DataInputStream::readByte() { if (stream == NULL) { app.DebugPrintf( "DataInputStream::readByte() but underlying stream is NULL\n"); return 0; } return (uint8_t)stream->read(); } unsigned char DataInputStream::readUnsignedByte() { if (stream == NULL) { app.DebugPrintf( "DataInputStream::readUnsignedByte() but underlying stream is " "NULL\n"); return 0; } return (unsigned char)stream->read(); } // Reads two input bytes and returns a char value. Let a be the first byte read // and b be the second byte. The value returned is: (char)((a << 8) | (b & // 0xff)) // // This method is suitable for reading bytes written by the writeChar method of // interface DataOutput. Returns: the char value read. wchar_t DataInputStream::readChar() { if (stream == NULL) { app.DebugPrintf( "DataInputStream::readChar() but underlying stream is NULL\n"); return 0; } int a = stream->read(); int b = stream->read(); return (wchar_t)((a << 8) | (b & 0xff)); } // Reads some bytes from an input stream and stores them into the buffer array // b. The number of bytes read is equal to the length of b. This method blocks // until one of the following conditions occurs: // // b.length bytes of input data are available, in which case a normal return is // made. End of file is detected, in which case an EOFException is thrown. An // I/O error occurs, in which case an IOException other than EOFException is // thrown. If b is null, a NullPointerException is thrown. If b.length is zero, // then no bytes are read. Otherwise, the first byte read is stored into element // b[0], the next one into b[1], and so on. If an exception is thrown from this // method, then it may be that some but not all bytes of b have been updated // with data from the input stream. // // Parameters: // b - the buffer into which the data is read. bool DataInputStream::readFully(byteArray b) { // TODO 4J Stu - I am not entirely sure if this matches the implementation // of the Java library // TODO 4J Stu - Need to handle exceptions here is we throw them in other // InputStreams if (stream == NULL) { app.DebugPrintf( "DataInputStream::readFully(byteArray) but underlying stream is " "NULL\n"); return false; } for (unsigned int i = 0; i < b.length; i++) { int byteRead = stream->read(); if (byteRead == -1) { return false; } else { b[i] = static_cast(byteRead); } } return true; } bool DataInputStream::readFully(charArray b) { // TODO 4J Stu - I am not entirely sure if this matches the implementation // of the Java library // TODO 4J Stu - Need to handle exceptions here is we throw them in other // InputStreams if (stream == NULL) { app.DebugPrintf( "DataInputStream::readFully(charArray) but underlying stream is " "NULL\n"); return false; } for (unsigned int i = 0; i < b.length; i++) { int byteRead = stream->read(); if (byteRead == -1) { return false; } else { b[i] = byteRead; } } return true; } // Reads eight input bytes and returns a double value. It does this by first // constructing a long value in exactly the manner of the readlong method, then // converting this long value to a double in exactly the manner of the method // Double.longBitsToDouble. This method is suitable for reading bytes written by // the writeDouble method of interface DataOutput. Returns: the double value // read. double DataInputStream::readDouble() { int64_t bits = readLong(); return std::bit_cast(bits); } // Reads four input bytes and returns a float value. It does this by first // constructing an int value in exactly the manner of the readInt method, then // converting this int value to a float in exactly the manner of the method // Float.intBitsToFloat. This method is suitable for reading bytes written by // the writeFloat method of interface DataOutput. Returns: the float value read. float DataInputStream::readFloat() { int bits = readInt(); return std::bit_cast(bits); } // Reads four input bytes and returns an int value. Let a-d be the first through // fourth bytes read. The value returned is: // // (((a & 0xff) << 24) | ((b & 0xff) << 16) | // ((c & 0xff) << 8) | (d & 0xff)) // // This method is suitable for reading bytes written by the writeInt method of // interface DataOutput. Returns: the int value read. int DataInputStream::readInt() { if (stream == NULL) { app.DebugPrintf( "DataInputStream::readInt() but underlying stream is NULL\n"); return 0; } int a = stream->read(); int b = stream->read(); int c = stream->read(); int d = stream->read(); int bits = (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff)); return bits; } // Reads eight input bytes and returns a long value. Let a-h be the first // through eighth bytes read. The value returned is: // // (((long)(a & 0xff) << 56) | // ((long)(b & 0xff) << 48) | // ((long)(c & 0xff) << 40) | // ((long)(d & 0xff) << 32) | // ((long)(e & 0xff) << 24) | // ((long)(f & 0xff) << 16) | // ((long)(g & 0xff) << 8) | // ((long)(h & 0xff))) // // This method is suitable for reading bytes written by the writeLong method of // interface DataOutput. // // Returns: // the long value read. int64_t DataInputStream::readLong() { if (stream == NULL) { app.DebugPrintf( "DataInputStream::readLong() but underlying stream is NULL\n"); return 0; } int64_t a = stream->read(); int64_t b = stream->read(); int64_t c = stream->read(); int64_t d = stream->read(); int64_t e = stream->read(); int64_t f = stream->read(); int64_t g = stream->read(); int64_t h = stream->read(); int64_t bits = (((a & 0xff) << 56) | ((b & 0xff) << 48) | ((c & 0xff) << 40) | ((d & 0xff) << 32) | ((e & 0xff) << 24) | ((f & 0xff) << 16) | ((g & 0xff) << 8) | ((h & 0xff))); return bits; } // Reads two input bytes and returns a short value. Let a be the first byte read // and b be the second byte. The value returned is: (short)((a << 8) | (b & // 0xff)) // // This method is suitable for reading the bytes written by the writeShort // method of interface DataOutput. Returns: the 16-bit value read. short DataInputStream::readShort() { if (stream == NULL) { app.DebugPrintf( "DataInputStream::readShort() but underlying stream is NULL\n"); return 0; } int a = stream->read(); int b = stream->read(); return (short)((a << 8) | (b & 0xff)); } unsigned short DataInputStream::readUnsignedShort() { if (stream == NULL) { app.DebugPrintf( "DataInputStream::readUnsignedShort() but underlying stream is " "NULL\n"); return 0; } int a = stream->read(); int b = stream->read(); return static_cast(((a & 0xff) << 8) | (b & 0xff)); } // Reads in a string that has been encoded using a modified UTF-8 format. The // general contract of readUTF is that it reads a representation of a Unicode // character string encoded in modified UTF-8 format; this string of characters // is then returned as a String. First, two bytes are read and used to construct // an unsigned 16-bit integer in exactly the manner of the readUnsignedShort // method . This integer value is called the UTF length and specifies the number // of additional bytes to be read. These bytes are then converted to characters // by considering them in groups. The length of each group is computed from the // value of the first byte of the group. The byte following a group, if any, is // the first byte of the next group. // // If the first byte of a group matches the bit pattern 0xxxxxxx (where x means // "may be 0 or 1"), then the group consists of just that byte. The byte is // zero-extended to form a character. // // If the first byte of a group matches the bit pattern 110xxxxx, then the group // consists of that byte a and a second byte b. If there is no byte b (because // byte a was the last of the bytes to be read), or if byte b does not match the // bit pattern 10xxxxxx, then a UTFDataFormatException is thrown. Otherwise, the // group is converted to the character: // //(char)(((a& 0x1F) << 6) | (b & 0x3F)) // // If the first byte of a group matches the bit pattern 1110xxxx, then the group // consists of that byte a and two more bytes b and c. If there is no byte c // (because byte a was one of the last two of the bytes to be read), or either // byte b or byte c does not match the bit pattern 10xxxxxx, then a // UTFDataFormatException is thrown. Otherwise, the group is converted to the // character: // // (char)(((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F)) // // If the first byte of a group matches the pattern 1111xxxx or the pattern // 10xxxxxx, then a UTFDataFormatException is thrown. If end of file is // encountered at any time during this entire process, then an EOFException is // thrown. // // After every group has been converted to a character by this process, the // characters are gathered, in the same order in which their corresponding // groups were read from the input stream, to form a String, which is returned. // // The writeUTF method of interface DataOutput may be used to write data that is // suitable for reading by this method. // // Returns: // a Unicode string. std::wstring DataInputStream::readUTF() { std::wstring outputString; if (stream == NULL) { app.DebugPrintf( "DataInputStream::readUTF() but underlying stream is NULL\n"); return outputString; } int a = stream->read(); int b = stream->read(); unsigned short UTFLength = (unsigned short)(((a & 0xff) << 8) | (b & 0xff)); //// 4J Stu - I decided while writing DataOutputStream that we didn't need /// to bother using the UTF8 format / used in the java libs, and just write /// in/out as wchar_t all the time /*for( unsigned short i = 0; i < UTFLength; i++) { wchar_t theChar = readChar(); outputString.push_back(theChar); }*/ unsigned short currentByteIndex = 0; while (currentByteIndex < UTFLength) { int firstByte = stream->read(); currentByteIndex++; if (firstByte == -1) // TODO 4J Stu - EOFException break; // Masking patterns: // 10000000 = 0x80 // Match only highest bit // 11000000 = 0xC0 // Match only highest two bits // 11100000 = 0xE0 // Match only highest three bits // 11110000 = 0xF0 // Match only highest four bits // Matching patterns: // 10xxxxxx = 0x80 // ERROR, or second/third byte // 1111xxxx = 0xF0 //ERROR // 0xxxxxxx = 0x00 // One byte UTF // 110xxxxx = 0xC0 // Two byte UTF // 1110xxxx = 0xE0 // Three byte UTF if (((firstByte & 0xC0) == 0x80) || ((firstByte & 0xF0) == 0xF0)) { // TODO 4J Stu - UTFDataFormatException break; } else if ((firstByte & 0x80) == 0x00) { // One byte UTF wchar_t readChar = (wchar_t)firstByte; outputString.push_back(readChar); continue; } else if ((firstByte & 0xE0) == 0xC0) { // Two byte UTF // No more bytes to read if (!(currentByteIndex < UTFLength)) { // TODO 4J Stu - UTFDataFormatException break; } int secondByte = stream->read(); currentByteIndex++; // No second byte if (secondByte == -1) { // TODO 4J Stu - EOFException break; } // Incorrect second byte pattern else if ((secondByte & 0xC0) != 0x80) { // TODO 4J Stu - UTFDataFormatException break; } wchar_t readChar = (wchar_t)(((firstByte & 0x1F) << 6) | (secondByte & 0x3F)); outputString.push_back(readChar); continue; } else if ((firstByte & 0xF0) == 0xE0) { // Three byte UTF // No more bytes to read if (!(currentByteIndex < UTFLength)) { // TODO 4J Stu - UTFDataFormatException break; } int secondByte = stream->read(); currentByteIndex++; // No second byte if (secondByte == -1) { // TODO 4J Stu - EOFException break; } // No more bytes to read if (!(currentByteIndex < UTFLength)) { // TODO 4J Stu - UTFDataFormatException break; } int thirdByte = stream->read(); currentByteIndex++; // No third byte if (thirdByte == -1) { // TODO 4J Stu - EOFException break; } // Incorrect second or third byte pattern else if (((secondByte & 0xC0) != 0x80) || ((thirdByte & 0xC0) != 0x80)) { // TODO 4J Stu - UTFDataFormatException break; } wchar_t readChar = (wchar_t)(((firstByte & 0x0F) << 12) | ((secondByte & 0x3F) << 6) | (thirdByte & 0x3F)); outputString.push_back(readChar); continue; } } return outputString; } int DataInputStream::readUTFChar() { int returnValue = -1; if (stream == NULL) { app.DebugPrintf( "DataInputStream::readUTFChar() but underlying stream is NULL\n"); return returnValue; } int firstByte = stream->read(); if (firstByte == -1) // TODO 4J Stu - EOFException return returnValue; // Masking patterns: // 10000000 = 0x80 // Match only highest bit // 11000000 = 0xC0 // Match only highest two bits // 11100000 = 0xE0 // Match only highest three bits // 11110000 = 0xF0 // Match only highest four bits // Matching patterns: // 10xxxxxx = 0x80 // ERROR, or second/third byte // 1111xxxx = 0xF0 //ERROR // 0xxxxxxx = 0x00 // One byte UTF // 110xxxxx = 0xC0 // Two byte UTF // 1110xxxx = 0xE0 // Three byte UTF if (((firstByte & 0xC0) == 0x80) || ((firstByte & 0xF0) == 0xF0)) { // TODO 4J Stu - UTFDataFormatException return returnValue; } else if ((firstByte & 0x80) == 0x00) { // One byte UTF returnValue = firstByte; } else if ((firstByte & 0xE0) == 0xC0) { // Two byte UTF int secondByte = stream->read(); // No second byte if (secondByte == -1) { // TODO 4J Stu - EOFException return returnValue; } // Incorrect second byte pattern else if ((secondByte & 0xC0) != 0x80) { // TODO 4J Stu - UTFDataFormatException return returnValue; } returnValue = ((firstByte & 0x1F) << 6) | (secondByte & 0x3F); } else if ((firstByte & 0xF0) == 0xE0) { // Three byte UTF int secondByte = stream->read(); // No second byte if (secondByte == -1) { // TODO 4J Stu - EOFException return returnValue; } int thirdByte = stream->read(); // No third byte if (thirdByte == -1) { // TODO 4J Stu - EOFException return returnValue; } // Incorrect second or third byte pattern else if (((secondByte & 0xC0) != 0x80) || ((thirdByte & 0xC0) != 0x80)) { // TODO 4J Stu - UTFDataFormatException return returnValue; } returnValue = (((firstByte & 0x0F) << 12) | ((secondByte & 0x3F) << 6) | (thirdByte & 0x3F)); } return returnValue; } // 4J Added PlayerUID DataInputStream::readPlayerUID() { PlayerUID returnValue; #if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) for (int idPos = 0; idPos < sizeof(PlayerUID); idPos++) ((char*)&returnValue)[idPos] = readByte(); #elif defined(_DURANGO) returnValue = readUTF(); #else returnValue = readLong(); #endif // PS3 return returnValue; } void DataInputStream::deleteChildStream() { delete stream; } // Skips n bytes of input from this input stream. Fewer bytes might be skipped // if the end of the input stream is reached. The actual number k of bytes to be // skipped is equal to the smaller of n and count-pos. The value k is added into // pos and k is returned. Overrides: skip in class InputStream Parameters: n - // the number of bytes to be skipped. Returns: the actual number of bytes // skipped. int64_t DataInputStream::skip(int64_t n) { return stream->skip(n); } int DataInputStream::skipBytes(int n) { return skip(n); }