blob: b158188f663bcd4ee56d3c523070c8d43c0110aa [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 "InflaterInputStream.h"
#include <decaf/lang/Math.h>
#include <decaf/io/EOFException.h>
using namespace decaf;
using namespace decaf::io;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
using namespace decaf::util;
using namespace decaf::util::zip;
////////////////////////////////////////////////////////////////////////////////
const int InflaterInputStream::DEFAULT_BUFFER_SIZE = 512;
////////////////////////////////////////////////////////////////////////////////
InflaterInputStream::InflaterInputStream(InputStream* inputStream, bool own ) :
FilterInputStream(inputStream, own),
inflater(new Inflater()), buff(), length(0), ownInflater(true), atEOF(false) {
this->buff.resize( DEFAULT_BUFFER_SIZE );
}
////////////////////////////////////////////////////////////////////////////////
InflaterInputStream::InflaterInputStream(InputStream* inputStream, Inflater* inflater, bool own, bool ownInflater) :
FilterInputStream(inputStream, own),
inflater(inflater), buff(), length(0), ownInflater(ownInflater), atEOF(false) {
if (inflater == NULL) {
throw NullPointerException(
__FILE__, __LINE__, "Inflater passed was NULL.");
}
this->buff.resize( DEFAULT_BUFFER_SIZE );
}
////////////////////////////////////////////////////////////////////////////////
InflaterInputStream::InflaterInputStream(InputStream* inputStream, Inflater* inflater,
int bufferSize, bool own, bool ownInflater) :
FilterInputStream(inputStream, own),
inflater(inflater), buff(), length(0), ownInflater(ownInflater), atEOF(false) {
if (inflater == NULL) {
throw NullPointerException(
__FILE__, __LINE__, "Inflater passed was NULL.");
}
if (bufferSize <= 0) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Cannot create a zero sized buffer.");
}
this->buff.resize(bufferSize);
}
////////////////////////////////////////////////////////////////////////////////
InflaterInputStream::~InflaterInputStream() {
try {
this->close();
if (ownInflater) {
delete inflater;
}
}
DECAF_CATCH_NOTHROW(Exception)
DECAF_CATCHALL_NOTHROW()
}
////////////////////////////////////////////////////////////////////////////////
bool InflaterInputStream::markSupported() const {
return false;
}
////////////////////////////////////////////////////////////////////////////////
void InflaterInputStream::reset() {
throw IOException(
__FILE__, __LINE__, "Not Supported for this class.");
}
////////////////////////////////////////////////////////////////////////////////
void InflaterInputStream::mark(int readLimit DECAF_UNUSED) {
// No-op
}
////////////////////////////////////////////////////////////////////////////////
long long InflaterInputStream::skip(long long num) {
try {
if (num <= 0) {
return 0;
}
long long count = 0;
long long remaining = (std::size_t) Math::min(num, (long long) buff.size());
std::vector<unsigned char> buffer((std::size_t) remaining);
while (count < num) {
int x = read(&buffer[0], (int) buffer.size(), 0, (int) remaining);
if (x == -1) {
return count;
}
count += x;
remaining = (num - count) < (long long) buffer.size() ? num - count : buffer.size();
}
return count;
}
DECAF_CATCH_RETHROW(IOException)
DECAF_CATCHALL_THROW(IOException)
}
////////////////////////////////////////////////////////////////////////////////
void InflaterInputStream::close() {
try {
if (!isClosed()) {
inflater->end();
this->atEOF = true;
FilterInputStream::close();
}
}
DECAF_CATCH_RETHROW(IOException)
DECAF_CATCHALL_THROW(IOException)
}
////////////////////////////////////////////////////////////////////////////////
int InflaterInputStream::available() const {
try {
if (isClosed()) {
throw IOException(
__FILE__, __LINE__, "Stream already closed.");
}
if (atEOF) {
return 0;
}
return 1;
}
DECAF_CATCH_RETHROW(IOException)
DECAF_CATCHALL_THROW(IOException)
}
////////////////////////////////////////////////////////////////////////////////
int InflaterInputStream::doReadByte() {
try {
unsigned char buffer[1];
if (doReadArrayBounded(buffer, 1, 0, 1) < 0) {
return -1;
}
return (int) buffer[0];
}
DECAF_CATCH_RETHROW(IOException)
DECAF_CATCHALL_THROW(IOException)
}
////////////////////////////////////////////////////////////////////////////////
int InflaterInputStream::doReadArrayBounded(unsigned char* buffer, int size, int offset, int length) {
try{
if (buffer == NULL) {
throw NullPointerException(
__FILE__, __LINE__, "Buffer passed was 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);
}
if (length == 0) {
return 0;
}
if (isClosed()) {
throw IOException(
__FILE__, __LINE__, "Stream already closed.");
}
if (atEOF) {
return -1;
}
do {
if (inflater->needsInput()) {
this->fill();
}
// Invariant: if reading returns -1 or throws, eof must be true.
// It may also be true if the next read() should return -1.
try {
int result = inflater->inflate(buffer, size, offset, length);
atEOF = inflater->finished();
if (result > 0) {
return result;
} else if (atEOF) {
return -1;
} else if (inflater->needsDictionary()) {
atEOF = true;
return -1;
} else if (this->length == -1) {
atEOF = true;
throw EOFException(
__FILE__, __LINE__, "Reached end of Input.");
}
} catch (DataFormatException& e) {
atEOF = true;
if (this->length == -1) {
throw EOFException(
__FILE__, __LINE__, "Reached end of Input." );
}
IOException ex(__FILE__, __LINE__, "Error from Inflater");
ex.initCause(e.clone());
throw ex;
}
} while (true);
}
DECAF_CATCH_RETHROW(IOException)
DECAF_CATCH_RETHROW(IndexOutOfBoundsException)
DECAF_CATCH_RETHROW(NullPointerException)
DECAF_CATCHALL_THROW(IOException)
}
////////////////////////////////////////////////////////////////////////////////
void InflaterInputStream::fill() {
try{
if (isClosed()) {
throw IOException(
__FILE__, __LINE__, "Stream already closed.");
}
// Try and fill the input buffer, whatever we get goes into the inflater.
length = inputStream->read(&buff[0], (int) buff.size(), 0, (int) buff.size());
if (length > 0) {
inflater->setInput(&buff[0], (int) buff.size(), 0, length);
}
}
DECAF_CATCH_RETHROW(IOException)
DECAF_CATCHALL_THROW(IOException)
}