blob: 4913f99cb9f4e3d9b61fcd3dd9aa8eafdd85bed3 [file] [log] [blame]
/*
* 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 <decaf/io/DataInputStream.h>
#include <decaf/io/PushbackInputStream.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#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<char> 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<unsigned char> buffer(utfLength);
std::vector<unsigned char> 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<PushbackInputStream*>(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<PushbackInputStream*>(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)
}