| /* |
| * 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) |
| } |