summaryrefslogtreecommitdiffstats
path: root/lzlib.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lzlib.cc406
1 files changed, 406 insertions, 0 deletions
diff --git a/lzlib.cc b/lzlib.cc
new file mode 100644
index 0000000..d3f9777
--- /dev/null
+++ b/lzlib.cc
@@ -0,0 +1,406 @@
+/* Lzlib - A compression library for lzip files
+ Copyright (C) 2009 Antonio Diaz Diaz.
+
+ This library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ As a special exception, you may use this file as part of a free
+ software library without restriction. Specifically, if other files
+ instantiate templates or use macros or inline functions from this
+ file, or you compile this file and link it with other files to
+ produce an executable, this file does not by itself cause the
+ resulting executable to be covered by the GNU General Public
+ License. This exception does not however invalidate any other
+ reasons why the executable file might be covered by the GNU General
+ Public License.
+*/
+
+#include <algorithm>
+#include <cstring>
+#include <vector>
+#include <stdint.h>
+
+#include "lzlib.h"
+#include "lzip.h"
+#include "decoder.h"
+#include "encoder.h"
+
+
+namespace {
+
+struct Encoder
+ {
+ long long partial_in_size;
+ long long partial_out_size;
+ Matchfinder * matchfinder;
+ LZ_encoder * lz_encoder;
+ LZ_errno lz_errno;
+ const File_header member_header;
+
+ Encoder( const File_header & header ) throw()
+ :
+ partial_in_size( 0 ),
+ partial_out_size( 0 ),
+ matchfinder( 0 ),
+ lz_encoder( 0 ),
+ lz_errno( LZ_ok ),
+ member_header( header )
+ {}
+ };
+
+
+bool verify_encoder( void * const encoder )
+ {
+ if( !encoder ) return false;
+ Encoder & e = *(Encoder *)encoder;
+ if( !e.matchfinder || !e.lz_encoder )
+ { e.lz_errno = LZ_bad_argument; return false; }
+ return true;
+ }
+
+
+struct Decoder
+ {
+ long long partial_in_size;
+ long long partial_out_size;
+ Input_buffer * ibuf;
+ LZ_decoder * lz_decoder;
+ LZ_errno lz_errno;
+
+ Decoder() throw()
+ :
+ partial_in_size( 0 ),
+ partial_out_size( 0 ),
+ ibuf( 0 ),
+ lz_decoder( 0 ),
+ lz_errno( LZ_ok )
+ {}
+ };
+
+
+bool verify_decoder( void * const decoder )
+ {
+ if( !decoder ) return false;
+ if( !((Decoder *)decoder)->ibuf )
+ { ((Decoder *)decoder)->lz_errno = LZ_bad_argument; return false; }
+ return true;
+ }
+
+} // end namespace
+
+
+
+
+const char * LZ_version() { return LZ_version_string; }
+
+
+void * LZ_compress_open( const int dictionary_size, const int match_len_limit,
+ const long long member_size )
+ {
+ File_header header;
+ header.set_magic();
+ const bool error = ( !header.dictionary_size( dictionary_size ) ||
+ match_len_limit < 5 || match_len_limit > max_match_len );
+
+ Encoder * encoder = new( std::nothrow ) Encoder( header );
+ if( !encoder ) return 0;
+ Encoder & e = *encoder;
+ if( error ) e.lz_errno = LZ_bad_argument;
+ else
+ {
+ try {
+ e.matchfinder = new Matchfinder( header.dictionary_size(), match_len_limit );
+ }
+ catch( std::bad_alloc ) { e.matchfinder = 0; }
+ if( e.matchfinder )
+ {
+ try {
+ e.lz_encoder = new LZ_encoder( *e.matchfinder, header, member_size );
+ }
+ catch( std::bad_alloc )
+ {
+ delete e.matchfinder;
+ e.matchfinder = 0;
+ e.lz_encoder = 0;
+ }
+ }
+ if( !e.lz_encoder ) e.lz_errno = LZ_mem_error;
+ }
+ return encoder;
+ }
+
+
+int LZ_compress_close( void * const encoder )
+ {
+ if( !encoder ) return -1;
+ Encoder & e = *(Encoder *)encoder;
+ if( e.lz_encoder ) delete e.lz_encoder;
+ if( e.matchfinder ) delete e.matchfinder;
+ delete (Encoder *)encoder;
+ return 0;
+ }
+
+
+int LZ_compress_finish( void * const encoder )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ ((Encoder *)encoder)->matchfinder->finish();
+ return 0;
+ }
+
+
+int LZ_compress_finish_member( void * const encoder )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ ((Encoder *)encoder)->lz_encoder->finish_member();
+ return 0;
+ }
+
+
+int LZ_compress_restart_member( void * const encoder,
+ const long long member_size )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ Encoder & e = *(Encoder *)encoder;
+ if( !e.lz_encoder->member_finished() )
+ { e.lz_errno = LZ_sequence_error; return -1; }
+
+ e.partial_in_size += e.matchfinder->data_position();
+ e.partial_out_size += e.lz_encoder->member_position();
+ if( !e.matchfinder->reset() )
+ { e.lz_errno = LZ_library_error; return -1; }
+
+ delete e.lz_encoder;
+ try {
+ e.lz_encoder = new LZ_encoder( *e.matchfinder, e.member_header, member_size );
+ }
+ catch( std::bad_alloc )
+ { e.lz_encoder = 0; e.lz_errno = LZ_mem_error; return -1; }
+ return 0;
+ }
+
+
+int LZ_compress_read( void * const encoder, uint8_t * const buffer,
+ const int size )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ Encoder & e = *(Encoder *)encoder;
+ if( !e.lz_encoder->encode_member() )
+ { e.lz_errno = LZ_library_error; return -1; }
+ return e.lz_encoder->read_data( buffer, size );
+ }
+
+
+int LZ_compress_write( void * const encoder, uint8_t * const buffer,
+ const int size )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ return ((Encoder *)encoder)->matchfinder->write_data( buffer, size );
+ }
+
+
+enum LZ_errno LZ_compress_errno( void * const encoder )
+ {
+ if( !encoder ) return LZ_bad_argument;
+ return ((Encoder *)encoder)->lz_errno;
+ }
+
+
+int LZ_compress_finished( void * const encoder )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ Encoder & e = *(Encoder *)encoder;
+ return ( e.matchfinder->finished() && e.lz_encoder->member_finished() );
+ }
+
+
+int LZ_compress_member_finished( void * const encoder )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ return ((Encoder *)encoder)->lz_encoder->member_finished();
+ }
+
+
+long long LZ_compress_data_position( void * const encoder )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ return ((Encoder *)encoder)->matchfinder->data_position();
+ }
+
+
+long long LZ_compress_member_position( void * const encoder )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ return ((Encoder *)encoder)->lz_encoder->member_position();
+ }
+
+
+long long LZ_compress_total_in_size( void * const encoder )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ Encoder & e = *(Encoder *)encoder;
+ return e.partial_in_size + e.matchfinder->data_position();
+ }
+
+
+long long LZ_compress_total_out_size( void * const encoder )
+ {
+ if( !verify_encoder( encoder ) ) return -1;
+ Encoder & e = *(Encoder *)encoder;
+ return e.partial_out_size + e.lz_encoder->member_position();
+ }
+
+
+void * LZ_decompress_open()
+ {
+ Decoder * decoder = new( std::nothrow ) Decoder();
+ if( !decoder ) return 0;
+
+ try { decoder->ibuf = new Input_buffer(); }
+ catch( std::bad_alloc )
+ { decoder->ibuf = 0; decoder->lz_errno = LZ_mem_error; }
+ return decoder;
+ }
+
+
+int LZ_decompress_close( void * const decoder )
+ {
+ if( !decoder ) return -1;
+ Decoder & d = *(Decoder *)decoder;
+ if( d.lz_decoder ) delete d.lz_decoder;
+ if( d.ibuf ) delete d.ibuf;
+ delete (Decoder *)decoder;
+ return 0;
+ }
+
+
+int LZ_decompress_finish( void * const decoder )
+ {
+ if( !verify_decoder( decoder ) ) return -1;
+ ((Decoder *)decoder)->ibuf->finish();
+ return 0;
+ }
+
+
+int LZ_decompress_read( void * const decoder, uint8_t * const buffer,
+ const int size )
+ {
+ if( !verify_decoder( decoder ) ) return -1;
+ Decoder & d = *(Decoder *)decoder;
+ if( d.lz_decoder && d.lz_decoder->member_finished() )
+ {
+ d.partial_in_size += d.lz_decoder->member_position();
+ d.partial_out_size += d.lz_decoder->data_position();
+ delete d.lz_decoder;
+ d.lz_decoder = 0;
+ }
+ if( !d.lz_decoder )
+ {
+ if( d.ibuf->used_bytes() < 5 + (int)sizeof( File_header ) )
+ {
+ if( !d.ibuf->at_stream_end() || d.ibuf->finished() ) return 0;
+ d.ibuf->purge();
+ d.lz_errno = LZ_header_error;
+ return -1;
+ }
+ File_header header;
+ for( unsigned int i = 0; i < sizeof header; ++i )
+ ((uint8_t *)&header)[i] = d.ibuf->get_byte();
+ if( !header.verify_magic() || !header.verify_version() ||
+ header.dictionary_size() < min_dictionary_size ||
+ header.dictionary_size() > max_dictionary_size )
+ {
+ d.ibuf->purge();
+ d.lz_errno = LZ_header_error;
+ return -1;
+ }
+ try { d.lz_decoder = new LZ_decoder( header, *d.ibuf ); }
+ catch( std::bad_alloc )
+ {
+ d.ibuf->purge();
+ d.lz_decoder = 0;
+ d.lz_errno = LZ_mem_error;
+ return -1;
+ }
+ }
+ const int result = d.lz_decoder->decode_member();
+ if( result != 0 )
+ {
+ if( result == 2 ) d.lz_errno = LZ_unexpected_eof;
+ else d.lz_errno = LZ_data_error;
+ return -1;
+ }
+ return d.lz_decoder->read_data( buffer, size );
+ }
+
+
+int LZ_decompress_write( void * const decoder, uint8_t * const buffer,
+ const int size )
+ {
+ if( !verify_decoder( decoder ) ) return -1;
+ return ((Decoder *)decoder)->ibuf->write_data( buffer, size );
+ }
+
+
+enum LZ_errno LZ_decompress_errno( void * const decoder )
+ {
+ if( !decoder ) return LZ_bad_argument;
+ return ((Decoder *)decoder)->lz_errno;
+ }
+
+
+int LZ_decompress_finished( void * const decoder )
+ {
+ if( !verify_decoder( decoder ) ) return -1;
+ Decoder & d = *(Decoder *)decoder;
+ return ( d.ibuf->finished() &&
+ ( !d.lz_decoder || d.lz_decoder->member_finished() ) );
+ }
+
+
+long long LZ_decompress_data_position( void * const decoder )
+ {
+ if( !verify_decoder( decoder ) ) return -1;
+ if( ((Decoder *)decoder)->lz_decoder )
+ return ((Decoder *)decoder)->lz_decoder->data_position();
+ else return 0;
+ }
+
+
+long long LZ_decompress_member_position( void * const decoder )
+ {
+ if( !verify_decoder( decoder ) ) return -1;
+ if( ((Decoder *)decoder)->lz_decoder )
+ return ((Decoder *)decoder)->lz_decoder->member_position();
+ else return 0;
+ }
+
+
+long long LZ_decompress_total_in_size( void * const decoder )
+ {
+ if( !verify_decoder( decoder ) ) return -1;
+ Decoder & d = *(Decoder *)decoder;
+ if( d.lz_decoder )
+ return d.partial_in_size + d.lz_decoder->member_position();
+ return d.partial_in_size;
+ }
+
+
+long long LZ_decompress_total_out_size( void * const decoder )
+ {
+ if( !verify_decoder( decoder ) ) return -1;
+ Decoder & d = *(Decoder *)decoder;
+ if( d.lz_decoder )
+ return d.partial_out_size + d.lz_decoder->data_position();
+ return d.partial_out_size;
+ }