From e2fbc414b932ae9fd305c8e9fc315a306a876a09 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 24 Oct 2011 16:19:09 +0000 Subject: Lzma filter added. Now we're really getting somewhere. Libbu++ now supports all major, common compression algorithms. --- default.bld | 5 ++ src/deflate.h | 2 +- src/lzma.cpp | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lzma.h | 56 ++++++++++++ src/tests/lzma.cpp | 53 ++++++++++++ 5 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 src/lzma.cpp create mode 100644 src/lzma.h create mode 100644 src/tests/lzma.cpp diff --git a/default.bld b/default.bld index 1b6eb4d..18a2d72 100644 --- a/default.bld +++ b/default.bld @@ -172,6 +172,11 @@ target ["tests/deflate"] LDFLAGS += "-lz"; } +target ["tests/lzma"] +{ + LDFLAGS += "-llzma"; +} + target ["tests/itoserver", "tests/socketblock", "tests/itoheap", "tests/itoqueue1", "tests/itoqueue2", "tests/conduit"] { diff --git a/src/deflate.h b/src/deflate.h index cab9b51..8ce283b 100644 --- a/src/deflate.h +++ b/src/deflate.h @@ -34,7 +34,7 @@ namespace Bu AutoGzip = 0x04|0x03 }; - Deflate( Bu::Stream &rNext, int nCompression=9, Format eFmt=AutoRaw ); + Deflate( Bu::Stream &rNext, int nCompression=-1, Format eFmt=AutoRaw ); virtual ~Deflate(); virtual void start(); diff --git a/src/lzma.cpp b/src/lzma.cpp new file mode 100644 index 0000000..6ed0806 --- /dev/null +++ b/src/lzma.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2007-2011 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/lzma.h" +#include "bu/trace.h" + +#include + +#define pState ((lzma_stream *)prState) + +using namespace Bu; + +Bu::Lzma::Lzma( Bu::Stream &rNext, int nCompression, Format eFmt ) : + Bu::Filter( rNext ), + prState( NULL ), + nCompression( nCompression ), + sTotalOut( 0 ), + eFmt( eFmt ), + bEos( false ) +{ + TRACE( nCompression ); + start(); +} + +Bu::Lzma::~Lzma() +{ + TRACE(); + stop(); +} + +void Bu::Lzma::start() +{ + TRACE(); + nBufSize = 64*1024; + pBuf = new char[nBufSize]; +} + +Bu::size Bu::Lzma::stop() +{ + TRACE(); + if( pState ) + { + if( bReading ) + { + lzma_end( pState ); + delete[] pBuf; + pBuf = NULL; + delete pState; + prState = NULL; + return 0; + } + else + { + for(;;) + { + pState->next_in = NULL; + pState->avail_in = 0; + pState->avail_out = nBufSize; + pState->next_out = (uint8_t *)pBuf; + int res = lzma_code( pState, LZMA_FINISH ); + if( pState->avail_out < nBufSize ) + { + sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); + } + if( res == LZMA_STREAM_END ) + break; + } + lzma_end( pState ); + delete[] pBuf; + pBuf = NULL; + delete pState; + prState = NULL; + return sTotalOut; + } + } + return 0; +} + +void Bu::Lzma::lzmaError( int code ) +{ + TRACE( code ); + switch( code ) + { + case LZMA_OK: + case LZMA_STREAM_END: + case LZMA_NO_CHECK: + case LZMA_UNSUPPORTED_CHECK: + break; + + case LZMA_MEM_ERROR: + throw ExceptionBase("Lzma: Memory allocation error."); + + case LZMA_MEMLIMIT_ERROR: + throw ExceptionBase("Lzma: Memory usage limit was reached."); + + case LZMA_FORMAT_ERROR: + throw ExceptionBase("Lzma: File format not recognized."); + + case LZMA_OPTIONS_ERROR: + throw ExceptionBase("Lzma: Invalid or unsupported options."); + + case LZMA_DATA_ERROR: + throw ExceptionBase("Lzma: Data is corrupt."); + + case LZMA_BUF_ERROR: + throw ExceptionBase("Lzma: No progress is possible."); + + case LZMA_PROG_ERROR: + throw ExceptionBase("Lzma: Programming error."); + + default: + throw ExceptionBase("Lzma: Unknown error encountered." ); + } +} + +Bu::size Bu::Lzma::read( void *pData, Bu::size nBytes ) +{ + TRACE( pData, nBytes ); + if( !pState ) + { + prState = new ::lzma_stream; + lzma_stream zEmpty = LZMA_STREAM_INIT; + Bu::memcpy( prState, &zEmpty, sizeof(lzma_stream) ); + + bReading = true; + lzmaError( lzma_auto_decoder( pState, UINT64_MAX, 0 ) ); + pState->next_in = (uint8_t *)pBuf; + pState->avail_in = 0; + } + if( bReading == false ) + throw ExceptionBase("This lzma filter is in writing mode, you can't read."); + + int nRead = 0; + int nReadTotal = pState->total_out; + pState->next_out = (uint8_t *)pData; + pState->avail_out = nBytes; + for(;;) + { + int ret = lzma_code( pState, LZMA_RUN ); + printf("inflate returned %d; avail in=%d, out=%d\n", ret, + pState->avail_in, pState->avail_out ); + + nReadTotal += nRead-pState->avail_out; + + if( ret == LZMA_STREAM_END ) + { + bEos = true; + if( pState->avail_in > 0 ) + { + if( rNext.isSeekable() ) + { + rNext.seek( -pState->avail_in ); + } + } + return nBytes-pState->avail_out; + } +// if( ret != LZMA_BUF_ERROR ) + lzmaError( 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 deflate stream."); + } + pState->next_in = (uint8_t *)pBuf; + pState->avail_in = nRead; + } + } + else + { + return nBytes-pState->avail_out; + } + } + return 0; +} + +Bu::size Bu::Lzma::write( const void *pData, Bu::size nBytes ) +{ + TRACE( pData, nBytes ); + if( !pState ) + { + prState = new ::lzma_stream; + lzma_stream zEmpty = LZMA_STREAM_INIT; + Bu::memcpy( prState, &zEmpty, sizeof(lzma_stream) ); + + bReading = false; + if( eFmt == Xz ) + lzmaError( + lzma_easy_encoder( pState, nCompression, LZMA_CHECK_CRC64 ) + ); + else if( eFmt == LzmaAlone ) + { + lzma_options_lzma opt; + lzma_lzma_preset( &opt, nCompression ); + lzmaError( lzma_alone_encoder( pState, &opt ) ); + } + else + throw Bu::ExceptionBase("Invalid format for lzma."); + } + if( bReading == true ) + throw ExceptionBase("This lzma filter is in reading mode, you can't write."); + + pState->next_in = (uint8_t *)pData; + pState->avail_in = nBytes; + for(;;) + { + pState->avail_out = nBufSize; + pState->next_out = (uint8_t *)pBuf; + + lzmaError( lzma_code( pState, LZMA_RUN ) ); + + if( pState->avail_out < nBufSize ) + { + sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); + } + if( pState->avail_in == 0 ) + break; + } + + return nBytes; +} + +bool Bu::Lzma::isOpen() +{ + TRACE(); + return (pState != NULL); +} + +bool Bu::Lzma::isEos() +{ + TRACE(); + return bEos; +} + +Bu::size Bu::Lzma::getCompressedSize() +{ + return sTotalOut; +} + diff --git a/src/lzma.h b/src/lzma.h new file mode 100644 index 0000000..21da6e8 --- /dev/null +++ b/src/lzma.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2007-2011 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. + */ + +#ifndef BU_LZMA_H +#define BU_LZMA_H + +#include + +#include "bu/filter.h" + +namespace Bu +{ + /** + * + *@ingroup Streams + */ + class Lzma : public Bu::Filter + { + public: + enum Format + { + Xz = 0x01, + LzmaAlone = 0x02, + }; + + Lzma( Bu::Stream &rNext, int nCompression=6, Format eFmt=Xz ); + virtual ~Lzma(); + + virtual void start(); + virtual Bu::size stop(); + virtual Bu::size read( void *pBuf, Bu::size nBytes ); + virtual Bu::size write( const void *pBuf, Bu::size nBytes ); + + virtual bool isOpen(); + virtual bool isEos(); + + Bu::size getCompressedSize(); + + private: + void lzmaError( int code ); + void *prState; + bool bReading; + int nCompression; + char *pBuf; + uint32_t nBufSize; + Bu::size sTotalOut; + Format eFmt; + bool bEos; + }; +} + +#endif diff --git a/src/tests/lzma.cpp b/src/tests/lzma.cpp new file mode 100644 index 0000000..752357a --- /dev/null +++ b/src/tests/lzma.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007-2011 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/lzma.h" +#include "bu/file.h" + +int main( int argc, char *argv[] ) +{ + if( argc < 3 ) + { + printf("usage: %s \n", argv[0] ); + return -1; + } + + char buf[1024]; + size_t nRead; + + /* + Bu::File fin( argv[1], Bu::File::Read ); + fin.seek( 4 ); + Bu::Deflate def( fin ); + + Bu::File f( argv[2], Bu::File::WriteNew ); + + for(;;) + { + nRead = def.read( buf, 1024 ); + if( nRead > 0 ) + f.write( buf, nRead ); + if( def.isEos() ) + break; + } + */ + + Bu::File fin( argv[1], Bu::File::Read ); + + Bu::File f( argv[2], Bu::File::WriteNew ); + Bu::Lzma def( f, 9 ); + + for(;;) + { + nRead = fin.read( buf, 1024 ); + if( nRead > 0 ) + def.write( buf, nRead ); + if( fin.isEos() ) + break; + } +} + -- cgit v1.2.3