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