/* * Copyright (C) 2007-2019 Xagasoft, All rights reserved. * * This file is part of the libbu++ library and is released under the * terms of the license contained in the file LICENSE. */ #include "bu/bzip2.h" #include "bu/trace.h" #ifdef BU_HAS_BZIP2 #include #define pState ((bz_stream *)prState) using namespace Bu; Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) : Bu::Filter( rNext ), prState( NULL ), nCompression( nCompression ), sTotalOut( 0 ) { TRACE( nCompression ); start(); } Bu::BZip2::~BZip2() { TRACE(); stop(); } void Bu::BZip2::start() { TRACE(); prState = new bz_stream; pState->state = NULL; pState->bzalloc = NULL; pState->bzfree = NULL; pState->opaque = NULL; nBufSize = 64*1024; pBuf = new char[nBufSize]; } Bu::size Bu::BZip2::stop() { TRACE(); if( !pState ) return 0; if( pState->state ) { if( bReading ) { BZ2_bzDecompressEnd( pState ); delete[] pBuf; pBuf = NULL; delete pState; prState = NULL; return 0; } else { // Bu::size sTotal = 0; for(;;) { pState->next_in = NULL; pState->avail_in = 0; pState->avail_out = nBufSize; pState->next_out = pBuf; int res = BZ2_bzCompress( pState, BZ_FINISH ); if( pState->avail_out < nBufSize ) { sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); } if( res == BZ_STREAM_END ) break; } BZ2_bzCompressEnd( pState ); delete[] pBuf; pBuf = NULL; delete pState; prState = NULL; return sTotalOut; } } return 0; } void Bu::BZip2::bzError( int code ) { TRACE( code ); switch( code ) { case BZ_OK: case BZ_RUN_OK: case BZ_FLUSH_OK: case BZ_FINISH_OK: return; case BZ_CONFIG_ERROR: throw ExceptionBase("BZip2: Library configured improperly, reinstall."); case BZ_SEQUENCE_ERROR: throw ExceptionBase("BZip2: Functions were called in an invalid sequence."); case BZ_PARAM_ERROR: throw ExceptionBase("BZip2: Invalid parameter was passed into a function."); case BZ_MEM_ERROR: throw ExceptionBase("BZip2: Couldn't allocate sufficient memory."); case BZ_DATA_ERROR: throw ExceptionBase("BZip2: Data was corrupted before decompression."); case BZ_DATA_ERROR_MAGIC: throw ExceptionBase("BZip2: Stream does not appear to be bzip2 data."); case BZ_IO_ERROR: throw ExceptionBase("BZip2: File couldn't be read from / written to."); case BZ_UNEXPECTED_EOF: throw ExceptionBase("BZip2: End of file encountered before end of stream."); case BZ_OUTBUFF_FULL: throw ExceptionBase("BZip2: Buffer not large enough to accomidate data."); default: throw ExceptionBase("BZip2: Unknown error encountered."); } } Bu::size Bu::BZip2::read( void *pData, Bu::size nBytes ) { TRACE( pData, nBytes ); if( !pState->state ) { bReading = true; BZ2_bzDecompressInit( pState, 0, 0 ); pState->next_in = pBuf; pState->avail_in = 0; } if( bReading == false ) throw ExceptionBase("This bzip2 filter is in writing mode, you can't read."); int nRead = 0; int nReadTotal = pState->total_out_lo32; pState->next_out = (char *)pData; pState->avail_out = nBytes; for(;;) { int ret = BZ2_bzDecompress( pState ); nReadTotal += nRead-pState->avail_out; if( ret == BZ_STREAM_END ) { if( pState->avail_in > 0 ) { if( rNext.isSeekable() ) { rNext.seek( -(Bu::size)pState->avail_in ); } } return nBytes-pState->avail_out; } bzError( ret ); if( pState->avail_out ) { if( pState->avail_in == 0 ) { nRead = rNext.read( pBuf, nBufSize ); if( nRead == 0 && rNext.isEos() ) { throw Bu::ExceptionBase("Premature end of underlying " "stream found reading bzip2 stream."); } pState->next_in = pBuf; pState->avail_in = nRead; } } else { return nBytes-pState->avail_out; } } return 0; } Bu::size Bu::BZip2::write( const void *pData, Bu::size nBytes ) { TRACE( pData, nBytes ); if( !pState->state ) { bReading = false; BZ2_bzCompressInit( pState, nCompression, 0, 30 ); } if( bReading == true ) throw ExceptionBase("This bzip2 filter is in reading mode, you can't write."); // Bu::size sTotalOut = 0; pState->next_in = (char *)pData; pState->avail_in = nBytes; for(;;) { pState->avail_out = nBufSize; pState->next_out = pBuf; bzError( BZ2_bzCompress( pState, BZ_RUN ) ); if( pState->avail_out < nBufSize ) { sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); } if( pState->avail_in == 0 ) break; } return nBytes; } bool Bu::BZip2::isOpen() { TRACE(); return (pState->state != NULL); } Bu::size Bu::BZip2::getCompressedSize() { return sTotalOut; } #endif