/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STRINGS_H #include #endif using namespace std; using namespace decaf; using namespace decaf::io; using namespace decaf::util; using namespace decaf::lang; using namespace decaf::lang::exceptions; //////////////////////////////////////////////////////////////////////////////// DataInputStream::DataInputStream(InputStream* inputStream, bool own) : FilterInputStream(inputStream, own), buffer() { } //////////////////////////////////////////////////////////////////////////////// DataInputStream::~DataInputStream() { } //////////////////////////////////////////////////////////////////////////////// bool DataInputStream::readBoolean() { try { readAllData(buffer, sizeof(char)); return (bool) (buffer[0] != 0); } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// char DataInputStream::readByte() { try { readAllData(buffer, sizeof(unsigned char)); return (char) (buffer[0]); } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// unsigned char DataInputStream::readUnsignedByte() { try { readAllData(buffer, sizeof(unsigned char)); return buffer[0]; } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// char DataInputStream::readChar() { try { readAllData(buffer, sizeof(unsigned char)); return (char) (buffer[0]); } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// short DataInputStream::readShort() { try { short value = 0; readAllData(buffer, sizeof(short)); value |= (short) (buffer[0] << 8 | buffer[1] << 0); return value; } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// unsigned short DataInputStream::readUnsignedShort() { try { unsigned short value = 0; readAllData(buffer, sizeof(unsigned short)); value |= (unsigned short) (buffer[0] << 8 | buffer[1] << 0); return value; } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// int DataInputStream::readInt() { try { unsigned int value = 0; readAllData(buffer, sizeof(int)); value |= (buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3] << 0); return value; } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// double DataInputStream::readDouble() { try { unsigned long long lvalue = this->readLong(); double value = 0.0; memcpy(&value, &lvalue, sizeof(unsigned long long)); return value; } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// float DataInputStream::readFloat() { try { unsigned int lvalue = this->readInt(); float value = 0.0f; memcpy(&value, &lvalue, sizeof(unsigned int)); return value; } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// long long DataInputStream::readLong() { try { unsigned long long value = 0; readAllData(buffer, sizeof(long long)); // Have to do it this way because on Solaris and Cygwin we get all // kinds of warnings when shifting a byte up into a long long. unsigned long long byte1 = buffer[0] & 0x00000000000000FFULL; unsigned long long byte2 = buffer[1] & 0x00000000000000FFULL; unsigned long long byte3 = buffer[2] & 0x00000000000000FFULL; unsigned long long byte4 = buffer[3] & 0x00000000000000FFULL; unsigned long long byte5 = buffer[4] & 0x00000000000000FFULL; unsigned long long byte6 = buffer[5] & 0x00000000000000FFULL; unsigned long long byte7 = buffer[6] & 0x00000000000000FFULL; unsigned long long byte8 = buffer[7] & 0x00000000000000FFULL; value = (byte1 << 56 | byte2 << 48 | byte3 << 40 | byte4 << 32 | byte5 << 24 | byte6 << 16 | byte7 << 8 | byte8 << 0); return value; } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// std::string DataInputStream::readString() { try { if (inputStream == NULL) { throw IOException(__FILE__, __LINE__, "DataInputStream::readFully - Base input stream is null"); } int size = 1024; std::vector buffer; buffer.resize(size); int pos = 0; while (true) { if (inputStream->read((unsigned char*) (&buffer[0]), size, pos, 1) == -1) { throw EOFException(__FILE__, __LINE__, "DataInputStream::readString - Reached EOF"); } // if null is found we are done if (buffer[pos] == '\0') { break; } // Resize to hold more if we exceed current size if (++pos >= size) { buffer.resize((size *= 2)); } } return &buffer[0]; } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// std::string DataInputStream::readUTF() { try { if (inputStream == NULL) { throw IOException(__FILE__, __LINE__, "DataInputStream::readFully - Base input stream is null"); } unsigned short utfLength = readUnsignedShort(); if (utfLength == 0) { return ""; } std::vector buffer(utfLength); std::vector result(utfLength); this->readFully(&buffer[0], utfLength); std::size_t count = 0; std::size_t index = 0; unsigned char a = 0; while (count < utfLength) { if ((result[index] = buffer[count++]) < 0x80) { index++; } else if (((a = result[index]) & 0xE0) == 0xC0) { if (count >= utfLength) { throw UTFDataFormatException(__FILE__, __LINE__, "Invalid UTF-8 encoding found, start of two byte char found at end."); } unsigned char b = buffer[count++]; if ((b & 0xC0) != 0x80) { throw UTFDataFormatException(__FILE__, __LINE__, "Invalid UTF-8 encoding found, byte two does not start with 0x80."); } // 2-byte UTF8 encoding: 110X XXxx 10xx xxxx // Bits set at 'X' means we have encountered a UTF8 encoded value // greater than 255, which is not supported. if (a & 0x1C) { throw UTFDataFormatException(__FILE__, __LINE__, "Invalid 2 byte UTF-8 encoding found, " "This method only supports encoded ASCII values of (0-255)."); } result[index++] = (unsigned char) (((a & 0x1F) << 6) | (b & 0x3F)); } else if ((a & 0xF0) == 0xE0) { if (count + 1 >= utfLength) { throw UTFDataFormatException(__FILE__, __LINE__, "Invalid UTF-8 encoding found, start of three byte char found at end."); } else { throw UTFDataFormatException(__FILE__, __LINE__, "Invalid 3 byte UTF-8 encoding found, " "This method only supports encoded ASCII values of (0-255)."); } // If we were to support multibyte strings in the future this would be // the remainder of this method decoding logic. // //int b = buffer[count++]; //int c = buffer[count++]; //if( ( ( b & 0xC0 ) != 0x80 ) || ( ( c & 0xC0 ) != 0x80 ) ) { // throw UTFDataFormatException( // __FILE__, __LINE__, // "Invalid UTF-8 encoding found, byte two does not start with 0x80." ); //} // //result[inde++] = ( ( a & 0x0F ) << 12 ) | // ( ( b & 0x3F ) << 6 ) | ( c & 0x3F ); } else { throw UTFDataFormatException(__FILE__, __LINE__, "Invalid UTF-8 encoding found, aborting."); } } return std::string((char*) (&result[0]), index); } DECAF_CATCH_RETHROW(UTFDataFormatException) DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// void DataInputStream::readFully(unsigned char* buffer, int size) { try { if (size == 0) { return; } this->readFully(buffer, size, 0, size); } DECAF_CATCH_RETHROW(IndexOutOfBoundsException) DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// std::string DataInputStream::readLine() { try { std::string line; bool foundTerminator = false; while (true) { int nextByte = inputStream->read(); if (nextByte == -1) { if (line.length() == 0 && !foundTerminator) { return ""; } return line; } else if (nextByte == (unsigned char) '\r') { PushbackInputStream* pbStream = dynamic_cast(inputStream); if (foundTerminator) { if (pbStream == NULL) { throw IOException(__FILE__, __LINE__, "State is not valid, parse failed."); } pbStream->unread((unsigned char) nextByte); return line; } foundTerminator = true; // Have to be able to peek ahead one byte to see if its an newline. if (pbStream == NULL) { inputStream = new PushbackInputStream(inputStream, own); own = true; } } else if (nextByte == (unsigned char) '\n') { return line; } else { if (foundTerminator) { PushbackInputStream* pbStream = dynamic_cast(inputStream); if (pbStream == NULL) { throw IOException(__FILE__, __LINE__, "State is not valid, parse failed."); } pbStream->unread((unsigned char) nextByte); return line; } line += (char) nextByte; } } } DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// void DataInputStream::readFully(unsigned char* buffer, int size, int offset, int length) { try { if (length == 0) { return; } if (buffer == NULL) { throw NullPointerException(__FILE__, __LINE__, "Buffer is null"); } if (inputStream == NULL) { throw NullPointerException(__FILE__, __LINE__, "Base input stream is null"); } if (size < 0) { throw IndexOutOfBoundsException(__FILE__, __LINE__, "size parameter out of Bounds: %d.", size); } if (offset > size || offset < 0) { throw IndexOutOfBoundsException(__FILE__, __LINE__, "offset parameter out of Bounds: %d.", offset); } if (length < 0 || length > size - offset) { throw IndexOutOfBoundsException(__FILE__, __LINE__, "length parameter out of Bounds: %d.", length); } int n = 0; while (n < length) { int count = inputStream->read(buffer, length, offset + n, length - n); if (count == -1) { throw EOFException(__FILE__, __LINE__, "Reached EOF"); } n += count; } } DECAF_CATCH_RETHROW(NullPointerException) DECAF_CATCH_RETHROW(IndexOutOfBoundsException) DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// long long DataInputStream::skipBytes(long long num) { try { if (inputStream == NULL) { throw IOException(__FILE__, __LINE__, "DataInputStream::readFully - Base input stream is null"); } long long total = 0; long long cur = 0; while ((total < num) && ((cur = inputStream->skip(num - total)) > 0)) { total += cur; } return total; } DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) } //////////////////////////////////////////////////////////////////////////////// void DataInputStream::readAllData(unsigned char* buffer, int length) { try { int n = 0; do { int count = inputStream->read(buffer, length, n, length - n); if (count == -1) { throw EOFException(__FILE__, __LINE__, "DataInputStream::readLong - Reached EOF"); } n += count; } while (n < length); } DECAF_CATCH_RETHROW(EOFException) DECAF_CATCH_RETHROW(IOException) DECAF_CATCHALL_THROW(IOException) }