Adding upstream version 0.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
2e28a50fca
commit
62f856b64f
16 changed files with 536 additions and 317 deletions
14
ChangeLog
14
ChangeLog
|
@ -1,15 +1,23 @@
|
||||||
2009-05-03 Antonio Diaz <ant_diaz@teleline.es>
|
2009-06-03 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||||
|
|
||||||
|
* Version 0.4 released.
|
||||||
|
* Added new function LZ_compress_sync_flush.
|
||||||
|
* Added new function LZ_compress_write_size.
|
||||||
|
* Decompression speed has been improved.
|
||||||
|
* Added chapter "Buffering" to the manual.
|
||||||
|
|
||||||
|
2009-05-03 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||||
|
|
||||||
* Version 0.3 released.
|
* Version 0.3 released.
|
||||||
* Lzilib is now built as a shared library (in addition to static).
|
* Lzilib is now built as a shared library (in addition to static).
|
||||||
|
|
||||||
2009-04-26 Antonio Diaz <ant_diaz@teleline.es>
|
2009-04-26 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||||
|
|
||||||
* Version 0.2 released.
|
* Version 0.2 released.
|
||||||
* Fixed a segfault when decompressing trailing garbage.
|
* Fixed a segfault when decompressing trailing garbage.
|
||||||
* Fixed a false positive in LZ_(de)compress_finished.
|
* Fixed a false positive in LZ_(de)compress_finished.
|
||||||
|
|
||||||
2009-04-21 Antonio Diaz <ant_diaz@teleline.es>
|
2009-04-21 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||||
|
|
||||||
* Version 0.1 released.
|
* Version 0.1 released.
|
||||||
|
|
||||||
|
|
15
Makefile.in
15
Makefile.in
|
@ -12,9 +12,9 @@ sh_lib_objs = sh_decoder.o sh_encoder.o sh_lzlib.o
|
||||||
objs = arg_parser.o main.o
|
objs = arg_parser.o main.o
|
||||||
|
|
||||||
|
|
||||||
.PHONY : all doc check install install-info \
|
.PHONY : all install install-info install-man install-strip \
|
||||||
uninstall uninstall-info \
|
uninstall uninstall-info uninstall-man \
|
||||||
dist clean distclean
|
doc info man check dist clean distclean
|
||||||
|
|
||||||
all : $(progname) $(progname_shared)
|
all : $(progname) $(progname_shared)
|
||||||
|
|
||||||
|
@ -60,15 +60,17 @@ arg_parser.o : Makefile arg_parser.h
|
||||||
main.o : Makefile arg_parser.h lzlib.h $(libname).a
|
main.o : Makefile arg_parser.h lzlib.h $(libname).a
|
||||||
|
|
||||||
|
|
||||||
doc : info $(VPATH)/doc/$(progname).1
|
doc : info man
|
||||||
|
|
||||||
info : $(VPATH)/doc/$(pkgname).info
|
info : $(VPATH)/doc/$(pkgname).info
|
||||||
|
|
||||||
$(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
|
$(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
|
||||||
cd $(VPATH)/doc && makeinfo $(pkgname).texinfo
|
cd $(VPATH)/doc && makeinfo $(pkgname).texinfo
|
||||||
|
|
||||||
|
man : $(VPATH)/doc/$(progname).1
|
||||||
|
|
||||||
$(VPATH)/doc/$(progname).1 : $(progname)
|
$(VPATH)/doc/$(progname).1 : $(progname)
|
||||||
help2man -o $(VPATH)/doc/$(progname).1 ./$(progname)
|
help2man -o $(VPATH)/doc/$(progname).1 --no-info ./$(progname)
|
||||||
|
|
||||||
Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
|
Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
|
||||||
./config.status
|
./config.status
|
||||||
|
@ -96,6 +98,9 @@ install-info :
|
||||||
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info $(DESTDIR)$(infodir)/$(pkgname).info
|
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info $(DESTDIR)$(infodir)/$(pkgname).info
|
||||||
-install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$(pkgname).info
|
-install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$(pkgname).info
|
||||||
|
|
||||||
|
install-strip : all
|
||||||
|
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
|
||||||
|
|
||||||
uninstall : uninstall-info
|
uninstall : uninstall-info
|
||||||
-rm -f $(DESTDIR)$(includedir)/$(pkgname).h
|
-rm -f $(DESTDIR)$(includedir)/$(pkgname).h
|
||||||
-rm -f $(DESTDIR)$(libdir)/$(libname).a
|
-rm -f $(DESTDIR)$(libdir)/$(libname).a
|
||||||
|
|
11
NEWS
11
NEWS
|
@ -1,3 +1,10 @@
|
||||||
Changes in version 0.3:
|
Changes in version 0.4:
|
||||||
|
|
||||||
Lzilib is now built as a shared library (in addition to static).
|
Partial flush of the compressed data has been implemented with the
|
||||||
|
function LZ_compress_sync_flush.
|
||||||
|
|
||||||
|
The function LZ_compress_write_size has been added.
|
||||||
|
|
||||||
|
Decompression speed has been improved.
|
||||||
|
|
||||||
|
The chapter "Buffering" has been added to the manual.
|
||||||
|
|
4
README
4
README
|
@ -1,7 +1,7 @@
|
||||||
Description
|
Description
|
||||||
|
|
||||||
The lzlib compression library provides in-memory LZMA compression and
|
Lzlib is a data compression library providing in-memory LZMA compression
|
||||||
decompression functions, including integrity checking of the
|
and decompression functions, including integrity checking of the
|
||||||
uncompressed data. The compressed data format used by the library is the
|
uncompressed data. The compressed data format used by the library is the
|
||||||
lzip format.
|
lzip format.
|
||||||
|
|
||||||
|
|
6
configure
vendored
6
configure
vendored
|
@ -5,13 +5,13 @@
|
||||||
# This configure script is free software: you have unlimited permission
|
# This configure script is free software: you have unlimited permission
|
||||||
# to copy, distribute and modify it.
|
# to copy, distribute and modify it.
|
||||||
#
|
#
|
||||||
# Date of this version: 2009-05-03
|
# Date of this version: 2009-06-03
|
||||||
|
|
||||||
invocation_name=$0
|
invocation_name=$0
|
||||||
args=
|
args=
|
||||||
no_create=
|
no_create=
|
||||||
pkgname=lzlib
|
pkgname=lzlib
|
||||||
pkgversion=0.3
|
pkgversion=0.4
|
||||||
soversion=0
|
soversion=0
|
||||||
progname=minilzip
|
progname=minilzip
|
||||||
progname_shared=${progname}_shared
|
progname_shared=${progname}_shared
|
||||||
|
@ -115,7 +115,7 @@ while [ x"$1" != x ] ; do
|
||||||
CXXFLAGS=*) CXXFLAGS=${optarg} ;;
|
CXXFLAGS=*) CXXFLAGS=${optarg} ;;
|
||||||
LDFLAGS=*) LDFLAGS=${optarg} ;;
|
LDFLAGS=*) LDFLAGS=${optarg} ;;
|
||||||
|
|
||||||
--build=* | --enable-* | --with-* | --*dir=* | *=* | *-*-*) ;;
|
--* | *=* | *-*-*) ;;
|
||||||
*)
|
*)
|
||||||
echo "configure: Unrecognized option: \"${option}\"; use --help for usage." 1>&2
|
echo "configure: Unrecognized option: \"${option}\"; use --help for usage." 1>&2
|
||||||
exit 1 ;;
|
exit 1 ;;
|
||||||
|
|
34
decoder.cc
34
decoder.cc
|
@ -51,7 +51,7 @@ int Circular_buffer::read_data( uint8_t * const out_buffer, const int out_size )
|
||||||
size = std::min( buffer_size - get, out_size );
|
size = std::min( buffer_size - get, out_size );
|
||||||
if( size > 0 )
|
if( size > 0 )
|
||||||
{
|
{
|
||||||
std::memmove( out_buffer, buffer + get, size );
|
std::memcpy( out_buffer, buffer + get, size );
|
||||||
get += size;
|
get += size;
|
||||||
if( get >= buffer_size ) get = 0;
|
if( get >= buffer_size ) get = 0;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ int Circular_buffer::read_data( uint8_t * const out_buffer, const int out_size )
|
||||||
const int size2 = std::min( put - get, out_size - size );
|
const int size2 = std::min( put - get, out_size - size );
|
||||||
if( size2 > 0 )
|
if( size2 > 0 )
|
||||||
{
|
{
|
||||||
std::memmove( out_buffer + size, buffer + get, size2 );
|
std::memcpy( out_buffer + size, buffer + get, size2 );
|
||||||
get += size2;
|
get += size2;
|
||||||
size += size2;
|
size += size2;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ int Circular_buffer::write_data( uint8_t * const in_buffer, const int in_size )
|
||||||
size = std::min( buffer_size - put - (get == 0), in_size );
|
size = std::min( buffer_size - put - (get == 0), in_size );
|
||||||
if( size > 0 )
|
if( size > 0 )
|
||||||
{
|
{
|
||||||
std::memmove( buffer + put, in_buffer, size );
|
std::memcpy( buffer + put, in_buffer, size );
|
||||||
put += size;
|
put += size;
|
||||||
if( put >= buffer_size ) put = 0;
|
if( put >= buffer_size ) put = 0;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ int Circular_buffer::write_data( uint8_t * const in_buffer, const int in_size )
|
||||||
const int size2 = std::min( get - put - 1, in_size - size );
|
const int size2 = std::min( get - put - 1, in_size - size );
|
||||||
if( size2 > 0 )
|
if( size2 > 0 )
|
||||||
{
|
{
|
||||||
std::memmove( buffer + put, in_buffer + size, size2 );
|
std::memcpy( buffer + put, in_buffer + size, size2 );
|
||||||
put += size2;
|
put += size2;
|
||||||
size += size2;
|
size += size2;
|
||||||
}
|
}
|
||||||
|
@ -104,8 +104,9 @@ bool LZ_decoder::verify_trailer()
|
||||||
const int trailer_size = trailer.size( format_version );
|
const int trailer_size = trailer.size( format_version );
|
||||||
for( int i = 0; i < trailer_size && !error; ++i )
|
for( int i = 0; i < trailer_size && !error; ++i )
|
||||||
{
|
{
|
||||||
if( range_decoder.finished() ) error = true;
|
if( !range_decoder.finished() )
|
||||||
((uint8_t *)&trailer)[i] = range_decoder.get_byte();
|
((uint8_t *)&trailer)[i] = range_decoder.get_byte();
|
||||||
|
else error = true;
|
||||||
}
|
}
|
||||||
if( format_version == 0 ) trailer.member_size( member_position() );
|
if( format_version == 0 ) trailer.member_size( member_position() );
|
||||||
if( trailer.data_crc() != crc() ) error = true;
|
if( trailer.data_crc() != crc() ) error = true;
|
||||||
|
@ -120,14 +121,12 @@ bool LZ_decoder::verify_trailer()
|
||||||
int LZ_decoder::decode_member()
|
int LZ_decoder::decode_member()
|
||||||
{
|
{
|
||||||
if( member_finished_ ) return 0;
|
if( member_finished_ ) return 0;
|
||||||
|
if( !range_decoder.try_reload() ) return 0;
|
||||||
while( true )
|
while( true )
|
||||||
{
|
{
|
||||||
if( range_decoder.available_bytes() <= 0 ||
|
|
||||||
( !range_decoder.at_stream_end() &&
|
|
||||||
range_decoder.available_bytes() < min_available_bytes ) )
|
|
||||||
return 0; // need more data
|
|
||||||
if( free_bytes() < max_match_len ) return 0;
|
|
||||||
if( range_decoder.finished() ) return 2;
|
if( range_decoder.finished() ) return 2;
|
||||||
|
if( !range_decoder.enough_available_bytes() || !enough_free_bytes() )
|
||||||
|
return 0;
|
||||||
const int pos_state = data_position() & pos_state_mask;
|
const int pos_state = data_position() & pos_state_mask;
|
||||||
if( range_decoder.decode_bit( bm_match[state()][pos_state] ) == 0 )
|
if( range_decoder.decode_bit( bm_match[state()][pos_state] ) == 0 )
|
||||||
{
|
{
|
||||||
|
@ -173,9 +172,8 @@ int LZ_decoder::decode_member()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rep3 = rep2; rep2 = rep1; rep1 = rep0;
|
unsigned int rep0_saved = rep0;
|
||||||
len = min_match_len + len_decoder.decode( range_decoder, pos_state );
|
len = min_match_len + len_decoder.decode( range_decoder, pos_state );
|
||||||
state.set_match();
|
|
||||||
const int dis_slot = range_decoder.decode_tree( bm_dis_slot[get_dis_state(len)], dis_slot_bits );
|
const int dis_slot = range_decoder.decode_tree( bm_dis_slot[get_dis_state(len)], dis_slot_bits );
|
||||||
if( dis_slot < start_dis_model ) rep0 = dis_slot;
|
if( dis_slot < start_dis_model ) rep0 = dis_slot;
|
||||||
else
|
else
|
||||||
|
@ -190,17 +188,27 @@ int LZ_decoder::decode_member()
|
||||||
rep0 += range_decoder.decode_tree_reversed( bm_align, dis_align_bits );
|
rep0 += range_decoder.decode_tree_reversed( bm_align, dis_align_bits );
|
||||||
if( rep0 == 0xFFFFFFFF ) // Marker found
|
if( rep0 == 0xFFFFFFFF ) // Marker found
|
||||||
{
|
{
|
||||||
|
rep0 = rep0_saved;
|
||||||
|
range_decoder.normalize();
|
||||||
if( len == min_match_len ) // End Of Stream marker
|
if( len == min_match_len ) // End Of Stream marker
|
||||||
{
|
{
|
||||||
member_finished_ = true;
|
member_finished_ = true;
|
||||||
if( verify_trailer() ) return 0; else return 3;
|
if( verify_trailer() ) return 0; else return 3;
|
||||||
}
|
}
|
||||||
|
if( len == min_match_len + 1 ) // Sync Flush marker
|
||||||
|
{
|
||||||
|
if( range_decoder.try_reload( true ) ) continue;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
if( rep0 >= (unsigned int)dictionary_size ) return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rep3 = rep2; rep2 = rep1; rep1 = rep0_saved;
|
||||||
|
state.set_match();
|
||||||
}
|
}
|
||||||
if( !copy_block( rep0, len ) ) return 1;
|
copy_block( rep0, len );
|
||||||
prev_byte = get_byte( 0 );
|
prev_byte = get_byte( 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
112
decoder.h
112
decoder.h
|
@ -25,10 +25,9 @@
|
||||||
Public License.
|
Public License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const int min_available_bytes = 8 + sizeof( File_trailer );
|
|
||||||
|
|
||||||
class Input_buffer : public Circular_buffer
|
class Input_buffer : public Circular_buffer
|
||||||
{
|
{
|
||||||
|
enum { min_available_bytes = 8 + sizeof( File_trailer ) };
|
||||||
bool at_stream_end_;
|
bool at_stream_end_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -42,6 +41,12 @@ public:
|
||||||
bool finished() const throw() { return at_stream_end_ && !used_bytes(); }
|
bool finished() const throw() { return at_stream_end_ && !used_bytes(); }
|
||||||
void purge() throw() { at_stream_end_ = true; Circular_buffer::reset(); }
|
void purge() throw() { at_stream_end_ = true; Circular_buffer::reset(); }
|
||||||
|
|
||||||
|
bool enough_available_bytes() const throw()
|
||||||
|
{
|
||||||
|
return ( used_bytes() > 0 &&
|
||||||
|
( at_stream_end_ || used_bytes() >= min_available_bytes ) );
|
||||||
|
}
|
||||||
|
|
||||||
int write_data( uint8_t * const in_buffer, const int in_size ) throw()
|
int write_data( uint8_t * const in_buffer, const int in_size ) throw()
|
||||||
{
|
{
|
||||||
if( at_stream_end_ || in_size <= 0 ) return 0;
|
if( at_stream_end_ || in_size <= 0 ) return 0;
|
||||||
|
@ -55,6 +60,7 @@ class Range_decoder
|
||||||
mutable long long member_pos;
|
mutable long long member_pos;
|
||||||
uint32_t code;
|
uint32_t code;
|
||||||
uint32_t range;
|
uint32_t range;
|
||||||
|
bool reload_pending;
|
||||||
Input_buffer & ibuf;
|
Input_buffer & ibuf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -63,62 +69,86 @@ public:
|
||||||
member_pos( header_size ),
|
member_pos( header_size ),
|
||||||
code( 0 ),
|
code( 0 ),
|
||||||
range( 0xFFFFFFFF ),
|
range( 0xFFFFFFFF ),
|
||||||
|
reload_pending( false ),
|
||||||
ibuf( buf )
|
ibuf( buf )
|
||||||
{ for( int i = 0; i < 5; ++i ) code = (code << 8) | get_byte(); }
|
{ for( int i = 0; i < 5; ++i ) code = (code << 8) | get_byte(); }
|
||||||
|
|
||||||
|
bool at_stream_end() const throw() { return ibuf.at_stream_end(); }
|
||||||
|
int available_bytes() const throw() { return ibuf.used_bytes(); }
|
||||||
|
bool enough_available_bytes() const throw()
|
||||||
|
{ return ibuf.enough_available_bytes(); }
|
||||||
|
bool finished() const throw() { return ibuf.finished(); }
|
||||||
|
long long member_position() const throw() { return member_pos; }
|
||||||
|
|
||||||
uint8_t get_byte() const
|
uint8_t get_byte() const
|
||||||
{
|
{
|
||||||
++member_pos;
|
++member_pos;
|
||||||
return ibuf.get_byte();
|
return ibuf.get_byte();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool at_stream_end() const throw() { return ibuf.at_stream_end(); }
|
bool try_reload( const bool force = false ) throw()
|
||||||
int available_bytes() const throw() { return ibuf.used_bytes(); }
|
{
|
||||||
bool finished() const throw() { return ibuf.finished(); }
|
if( force ) reload_pending = true;
|
||||||
long long member_position() const throw() { return member_pos; }
|
if( reload_pending && available_bytes() >= 5 )
|
||||||
|
{
|
||||||
|
code = 0;
|
||||||
|
range = 0xFFFFFFFF;
|
||||||
|
reload_pending = false;
|
||||||
|
for( int i = 0; i < 5; ++i ) code = (code << 8) | get_byte();
|
||||||
|
}
|
||||||
|
return !reload_pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
void normalize()
|
||||||
|
{
|
||||||
|
if( range <= 0x00FFFFFF )
|
||||||
|
{ range <<= 8; code = (code << 8) | get_byte(); }
|
||||||
|
}
|
||||||
|
|
||||||
int decode( const int num_bits )
|
int decode( const int num_bits )
|
||||||
{
|
{
|
||||||
int symbol = 0;
|
int symbol = 0;
|
||||||
for( int i = num_bits - 1; i >= 0; --i )
|
for( int i = num_bits; i > 0; --i )
|
||||||
|
{
|
||||||
|
symbol <<= 1;
|
||||||
|
if( range <= 0x00FFFFFF )
|
||||||
|
{
|
||||||
|
range <<= 7; code = (code << 8) | get_byte();
|
||||||
|
if( code >= range ) { code -= range; symbol |= 1; }
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
range >>= 1;
|
range >>= 1;
|
||||||
symbol <<= 1;
|
if( code >= range ) { code -= range; symbol |= 1; }
|
||||||
if( code >= range )
|
}
|
||||||
{ code -= range; symbol |= 1; }
|
|
||||||
if( range <= 0x00FFFFFF )
|
|
||||||
{ range <<= 8; code = (code << 8) | get_byte(); }
|
|
||||||
}
|
}
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
int decode_bit( Bit_model & bm )
|
int decode_bit( Bit_model & bm )
|
||||||
{
|
{
|
||||||
int symbol;
|
normalize();
|
||||||
const uint32_t bound = ( range >> bit_model_total_bits ) * bm.probability;
|
const uint32_t bound = ( range >> bit_model_total_bits ) * bm.probability;
|
||||||
if( code < bound )
|
if( code < bound )
|
||||||
{
|
{
|
||||||
range = bound;
|
range = bound;
|
||||||
bm.probability += (bit_model_total - bm.probability) >> bit_model_move_bits;
|
bm.probability += (bit_model_total - bm.probability) >> bit_model_move_bits;
|
||||||
symbol = 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
range -= bound;
|
range -= bound;
|
||||||
code -= bound;
|
code -= bound;
|
||||||
bm.probability -= bm.probability >> bit_model_move_bits;
|
bm.probability -= bm.probability >> bit_model_move_bits;
|
||||||
symbol = 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if( range <= 0x00FFFFFF )
|
|
||||||
{ range <<= 8; code = (code << 8) | get_byte(); }
|
|
||||||
return symbol;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int decode_tree( Bit_model bm[], const int num_bits )
|
int decode_tree( Bit_model bm[], const int num_bits )
|
||||||
{
|
{
|
||||||
int model = 1;
|
int model = 1;
|
||||||
for( int i = num_bits; i > 0; --i )
|
for( int i = num_bits; i > 0; --i )
|
||||||
model = ( model << 1 ) | decode_bit( bm[model-1] );
|
model = ( model << 1 ) | decode_bit( bm[model] );
|
||||||
return model - (1 << num_bits);
|
return model - (1 << num_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,27 +156,31 @@ public:
|
||||||
{
|
{
|
||||||
int model = 1;
|
int model = 1;
|
||||||
int symbol = 0;
|
int symbol = 0;
|
||||||
for( int i = 1; i < (1 << num_bits); i <<= 1 )
|
for( int i = 0; i < num_bits; ++i )
|
||||||
{
|
{
|
||||||
const int bit = decode_bit( bm[model-1] );
|
const int bit = decode_bit( bm[model] );
|
||||||
model = ( model << 1 ) | bit;
|
model <<= 1;
|
||||||
if( bit ) symbol |= i;
|
if( bit ) { model |= 1; symbol |= (1 << i); }
|
||||||
}
|
}
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
int decode_matched( Bit_model bm[], const int match_byte )
|
int decode_matched( Bit_model bm[], const int match_byte )
|
||||||
{
|
{
|
||||||
|
Bit_model *bm1 = bm + 0x100;
|
||||||
int symbol = 1;
|
int symbol = 1;
|
||||||
for( int i = 7; i >= 0; --i )
|
for( int i = 1; i <= 8; ++i )
|
||||||
{
|
{
|
||||||
const int match_bit = ( match_byte >> i ) & 1;
|
const int match_bit = ( match_byte << i ) & 0x100;
|
||||||
const int bit = decode_bit( bm[(match_bit<<8)+symbol+0xFF] );
|
const int bit = decode_bit( bm1[match_bit+symbol] );
|
||||||
symbol = ( symbol << 1 ) | bit;
|
symbol = ( symbol << 1 ) | bit;
|
||||||
if( match_bit != bit ) break;
|
if( ( match_bit && !bit ) || ( !match_bit && bit ) )
|
||||||
|
{
|
||||||
|
while( ++i <= 8 )
|
||||||
|
symbol = ( symbol << 1 ) | decode_bit( bm[symbol] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while( symbol < 0x100 )
|
|
||||||
symbol = ( symbol << 1 ) | decode_bit( bm[symbol-1] );
|
|
||||||
return symbol & 0xFF;
|
return symbol & 0xFF;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -193,6 +227,7 @@ public:
|
||||||
|
|
||||||
class LZ_decoder : public Circular_buffer
|
class LZ_decoder : public Circular_buffer
|
||||||
{
|
{
|
||||||
|
enum { min_free_bytes = max_match_len };
|
||||||
long long partial_data_pos;
|
long long partial_data_pos;
|
||||||
const int format_version;
|
const int format_version;
|
||||||
const int dictionary_size;
|
const int dictionary_size;
|
||||||
|
@ -220,7 +255,6 @@ class LZ_decoder : public Circular_buffer
|
||||||
Len_decoder rep_match_len_decoder;
|
Len_decoder rep_match_len_decoder;
|
||||||
Literal_decoder literal_decoder;
|
Literal_decoder literal_decoder;
|
||||||
|
|
||||||
// using Circular_buffer::get_byte;
|
|
||||||
uint8_t get_byte( const int distance ) const throw()
|
uint8_t get_byte( const int distance ) const throw()
|
||||||
{
|
{
|
||||||
int i = put - distance - 1;
|
int i = put - distance - 1;
|
||||||
|
@ -235,20 +269,23 @@ class LZ_decoder : public Circular_buffer
|
||||||
if( ++put >= buffer_size ) { partial_data_pos += put; put = 0; }
|
if( ++put >= buffer_size ) { partial_data_pos += put; put = 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
bool copy_block( const int distance, int len )
|
void copy_block( const int distance, int len )
|
||||||
{
|
{
|
||||||
if( distance < 0 || distance >= dictionary_size ||
|
|
||||||
len <= 0 || len > max_match_len ) return false;
|
|
||||||
int i = put - distance - 1;
|
int i = put - distance - 1;
|
||||||
if( i < 0 ) i += buffer_size;
|
if( i < 0 ) i += buffer_size;
|
||||||
for( ; len > 0 ; --len )
|
if( len < buffer_size - std::max( put, i ) && len <= distance )
|
||||||
|
{
|
||||||
|
crc32.update( crc_, buffer + i, len );
|
||||||
|
std::memcpy( buffer + put, buffer + i, len );
|
||||||
|
put += len;
|
||||||
|
}
|
||||||
|
else for( ; len > 0 ; --len )
|
||||||
{
|
{
|
||||||
crc32.update( crc_, buffer[i] );
|
crc32.update( crc_, buffer[i] );
|
||||||
buffer[put] = buffer[i];
|
buffer[put] = buffer[i];
|
||||||
if( ++put >= buffer_size ) { partial_data_pos += put; put = 0; }
|
if( ++put >= buffer_size ) { partial_data_pos += put; put = 0; }
|
||||||
if( ++i >= buffer_size ) i = 0;
|
if( ++i >= buffer_size ) i = 0;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verify_trailer();
|
bool verify_trailer();
|
||||||
|
@ -256,7 +293,7 @@ class LZ_decoder : public Circular_buffer
|
||||||
public:
|
public:
|
||||||
LZ_decoder( const File_header & header, Input_buffer & ibuf )
|
LZ_decoder( const File_header & header, Input_buffer & ibuf )
|
||||||
:
|
:
|
||||||
Circular_buffer( std::max( 65536, header.dictionary_size() ) + max_match_len ),
|
Circular_buffer( std::max( 65536, header.dictionary_size() ) + min_free_bytes ),
|
||||||
partial_data_pos( 0 ),
|
partial_data_pos( 0 ),
|
||||||
format_version( header.version ),
|
format_version( header.version ),
|
||||||
dictionary_size( header.dictionary_size() ),
|
dictionary_size( header.dictionary_size() ),
|
||||||
|
@ -270,6 +307,9 @@ public:
|
||||||
range_decoder( sizeof header, ibuf ),
|
range_decoder( sizeof header, ibuf ),
|
||||||
literal_decoder() {}
|
literal_decoder() {}
|
||||||
|
|
||||||
|
bool enough_free_bytes() const throw()
|
||||||
|
{ return free_bytes() >= min_free_bytes; }
|
||||||
|
|
||||||
uint32_t crc() const throw() { return crc_ ^ 0xFFFFFFFF; }
|
uint32_t crc() const throw() { return crc_ ^ 0xFFFFFFFF; }
|
||||||
int decode_member();
|
int decode_member();
|
||||||
bool member_finished() const throw()
|
bool member_finished() const throw()
|
||||||
|
|
104
doc/lzlib.info
104
doc/lzlib.info
|
@ -12,12 +12,13 @@ File: lzlib.info, Node: Top, Next: Introduction, Up: (dir)
|
||||||
Lzlib
|
Lzlib
|
||||||
*****
|
*****
|
||||||
|
|
||||||
This manual is for Lzlib (version 0.3, 3 May 2009).
|
This manual is for Lzlib (version 0.4, 3 June 2009).
|
||||||
|
|
||||||
* Menu:
|
* Menu:
|
||||||
|
|
||||||
* Introduction:: Purpose and features of Lzlib
|
* Introduction:: Purpose and features of Lzlib
|
||||||
* Library Version:: Checking library version
|
* Library Version:: Checking library version
|
||||||
|
* Buffering:: Sizes of Lzlib's buffers
|
||||||
* Compression Functions:: Descriptions of the compression functions
|
* Compression Functions:: Descriptions of the compression functions
|
||||||
* Decompression Functions:: Descriptions of the decompression functions
|
* Decompression Functions:: Descriptions of the decompression functions
|
||||||
* Error Codes:: Meaning of codes returned by functions
|
* Error Codes:: Meaning of codes returned by functions
|
||||||
|
@ -38,8 +39,8 @@ File: lzlib.info, Node: Introduction, Next: Library Version, Prev: Top, Up:
|
||||||
1 Introduction
|
1 Introduction
|
||||||
**************
|
**************
|
||||||
|
|
||||||
The lzlib compression library provides in-memory LZMA compression and
|
Lzlib is a data compression library providing in-memory LZMA compression
|
||||||
decompression functions, including integrity checking of the
|
and decompression functions, including integrity checking of the
|
||||||
uncompressed data. The compressed data format used by the library is the
|
uncompressed data. The compressed data format used by the library is the
|
||||||
lzip format.
|
lzip format.
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ Igor Pavlov. For a description of the LZMA algorithm, see the Lzip
|
||||||
manual.
|
manual.
|
||||||
|
|
||||||
|
|
||||||
File: lzlib.info, Node: Library Version, Next: Compression Functions, Prev: Introduction, Up: Top
|
File: lzlib.info, Node: Library Version, Next: Buffering, Prev: Introduction, Up: Top
|
||||||
|
|
||||||
2 Library Version
|
2 Library Version
|
||||||
*****************
|
*****************
|
||||||
|
@ -88,9 +89,37 @@ application.
|
||||||
error( "bad library version" );
|
error( "bad library version" );
|
||||||
|
|
||||||
|
|
||||||
File: lzlib.info, Node: Compression Functions, Next: Decompression Functions, Prev: Library Version, Up: Top
|
File: lzlib.info, Node: Buffering, Next: Compression Functions, Prev: Library Version, Up: Top
|
||||||
|
|
||||||
3 Compression Functions
|
3 Buffering
|
||||||
|
***********
|
||||||
|
|
||||||
|
Lzlib internal functions need access to a memory chunk at least as large
|
||||||
|
as the dictionary size (sliding window). For efficiency reasons, the
|
||||||
|
input buffer for compression is twice as large as the dictionary size.
|
||||||
|
Finally, for security reasons, lzlib uses two more internal buffers.
|
||||||
|
|
||||||
|
These are the four buffers used by lzlib, and their guaranteed
|
||||||
|
minimum sizes:
|
||||||
|
|
||||||
|
* Input compression buffer. Written to by the `LZ_compress_write'
|
||||||
|
function. Its size is two times the dictionary size set with the
|
||||||
|
`LZ_compress_open' function or 128KiB, whichever is larger.
|
||||||
|
|
||||||
|
* Output compression buffer. Read from by the `LZ_compress_read'
|
||||||
|
function. Its size is 64KiB.
|
||||||
|
|
||||||
|
* Input decompression buffer. Written to by the
|
||||||
|
`LZ_decompress_write' function. Its size is 64KiB.
|
||||||
|
|
||||||
|
* Output decompression buffer. Read from by the `LZ_decompress_read'
|
||||||
|
function. Its size is the dictionary size set with the
|
||||||
|
`LZ_decompress_open' function or 64KiB, whichever is larger.
|
||||||
|
|
||||||
|
|
||||||
|
File: lzlib.info, Node: Compression Functions, Next: Decompression Functions, Prev: Buffering, Up: Top
|
||||||
|
|
||||||
|
4 Compression Functions
|
||||||
***********************
|
***********************
|
||||||
|
|
||||||
These are the functions used to compress data. In case of error, all of
|
These are the functions used to compress data. In case of error, all of
|
||||||
|
@ -123,6 +152,13 @@ verified by calling `LZ_compress_errno' before using it.
|
||||||
stream, give MEMBER_SIZE a value larger than the amount of data to
|
stream, give MEMBER_SIZE a value larger than the amount of data to
|
||||||
be produced, for example LLONG_MAX.
|
be produced, for example LLONG_MAX.
|
||||||
|
|
||||||
|
-- Function: int LZ_compress_restart_member ( void * const ENCODER,
|
||||||
|
const long long MEMBER_SIZE )
|
||||||
|
Use this function to start a new member, in a multimember data
|
||||||
|
stream. Call this function only after
|
||||||
|
`LZ_compress_member_finished' indicates that the current member
|
||||||
|
has been fully read (with the `LZ_compress_read' function).
|
||||||
|
|
||||||
-- Function: int LZ_compress_close ( void * const ENCODER )
|
-- Function: int LZ_compress_close ( void * const ENCODER )
|
||||||
Frees all dynamically allocated data structures for this stream.
|
Frees all dynamically allocated data structures for this stream.
|
||||||
This function discards any unprocessed input and does not flush
|
This function discards any unprocessed input and does not flush
|
||||||
|
@ -133,17 +169,11 @@ verified by calling `LZ_compress_errno' before using it.
|
||||||
Use this function to tell `lzlib' that all the data for this stream
|
Use this function to tell `lzlib' that all the data for this stream
|
||||||
has already been written (with the `LZ_compress_write' function).
|
has already been written (with the `LZ_compress_write' function).
|
||||||
|
|
||||||
-- Function: int LZ_compress_finish_member ( void * const ENCODER )
|
-- Function: int LZ_compress_sync_flush ( void * const ENCODER )
|
||||||
Use this function to tell `lzlib' that all the data for the current
|
Use this function to make available to `LZ_compress_read' all the
|
||||||
member, in a multimember data stream, has already been written
|
data already written with the `LZ_compress_write' function.
|
||||||
(with the `LZ_compress_write' function).
|
Repeated use of `LZ_compress_sync_flush' may degrade compression
|
||||||
|
ratio, so use it only when needed.
|
||||||
-- Function: int LZ_compress_restart_member ( void * const ENCODER,
|
|
||||||
const long long MEMBER_SIZE )
|
|
||||||
Use this function to start a new member, in a multimember data
|
|
||||||
stream. Call this function only after
|
|
||||||
`LZ_compress_member_finished' indicates that the current member
|
|
||||||
has been fully read (with the `LZ_compress_read' function).
|
|
||||||
|
|
||||||
-- Function: int LZ_compress_read ( void * const ENCODER, uint8_t *
|
-- Function: int LZ_compress_read ( void * const ENCODER, uint8_t *
|
||||||
const BUFFER, const int SIZE )
|
const BUFFER, const int SIZE )
|
||||||
|
@ -165,6 +195,14 @@ verified by calling `LZ_compress_errno' before using it.
|
||||||
might be less than SIZE. Note that writing less than SIZE bytes is
|
might be less than SIZE. Note that writing less than SIZE bytes is
|
||||||
not an error.
|
not an error.
|
||||||
|
|
||||||
|
-- Function: int LZ_compress_write_size ( void * const ENCODER )
|
||||||
|
The `LZ_compress_write_size' function returns the maximum number of
|
||||||
|
bytes that can be inmediately written through the
|
||||||
|
`LZ_compress_write' function.
|
||||||
|
|
||||||
|
It is guaranteed that an inmediate call to `LZ_compress_write' will
|
||||||
|
accept a SIZE up to the returned number of bytes.
|
||||||
|
|
||||||
-- Function: enum LZ_errno LZ_compress_errno ( void * const ENCODER )
|
-- Function: enum LZ_errno LZ_compress_errno ( void * const ENCODER )
|
||||||
Returns the current error code for ENCODER (*note Error Codes::)
|
Returns the current error code for ENCODER (*note Error Codes::)
|
||||||
|
|
||||||
|
@ -199,7 +237,7 @@ verified by calling `LZ_compress_errno' before using it.
|
||||||
|
|
||||||
File: lzlib.info, Node: Decompression Functions, Next: Error Codes, Prev: Compression Functions, Up: Top
|
File: lzlib.info, Node: Decompression Functions, Next: Error Codes, Prev: Compression Functions, Up: Top
|
||||||
|
|
||||||
4 Decompression Functions
|
5 Decompression Functions
|
||||||
*************************
|
*************************
|
||||||
|
|
||||||
These are the functions used to decompress data. In case of error, all
|
These are the functions used to decompress data. In case of error, all
|
||||||
|
@ -275,7 +313,7 @@ be verified by calling `LZ_decompress_errno' before using it.
|
||||||
|
|
||||||
File: lzlib.info, Node: Error Codes, Next: Data Format, Prev: Decompression Functions, Up: Top
|
File: lzlib.info, Node: Error Codes, Next: Data Format, Prev: Decompression Functions, Up: Top
|
||||||
|
|
||||||
5 Error Codes
|
6 Error Codes
|
||||||
*************
|
*************
|
||||||
|
|
||||||
Most library functions return -1 to indicate that they have failed. But
|
Most library functions return -1 to indicate that they have failed. But
|
||||||
|
@ -286,7 +324,7 @@ what kind of error it was, you need to verify the error code by calling
|
||||||
Library functions do not change the value returned by
|
Library functions do not change the value returned by
|
||||||
`LZ_(de)compress_errno' when they succeed; thus, the value returned by
|
`LZ_(de)compress_errno' when they succeed; thus, the value returned by
|
||||||
`LZ_(de)compress_errno' after a successful call is not necessarily
|
`LZ_(de)compress_errno' after a successful call is not necessarily
|
||||||
zero, and you should not use `LZ_(de)compress_errno' to determine
|
LZ_ok, and you should not use `LZ_(de)compress_errno' to determine
|
||||||
whether a call failed. If the call failed, then you can examine
|
whether a call failed. If the call failed, then you can examine
|
||||||
`LZ_(de)compress_errno'.
|
`LZ_(de)compress_errno'.
|
||||||
|
|
||||||
|
@ -327,7 +365,7 @@ whether a call failed. If the call failed, then you can examine
|
||||||
|
|
||||||
File: lzlib.info, Node: Data Format, Next: Examples, Prev: Error Codes, Up: Top
|
File: lzlib.info, Node: Data Format, Next: Examples, Prev: Error Codes, Up: Top
|
||||||
|
|
||||||
6 Data Format
|
7 Data Format
|
||||||
*************
|
*************
|
||||||
|
|
||||||
In the diagram below, a box like this:
|
In the diagram below, a box like this:
|
||||||
|
@ -389,7 +427,7 @@ with no additional information before, between, or after them.
|
||||||
|
|
||||||
File: lzlib.info, Node: Examples, Next: Problems, Prev: Data Format, Up: Top
|
File: lzlib.info, Node: Examples, Next: Problems, Prev: Data Format, Up: Top
|
||||||
|
|
||||||
7 A small tutorial with examples
|
8 A small tutorial with examples
|
||||||
********************************
|
********************************
|
||||||
|
|
||||||
This chaper shows the order in which the library functions should be
|
This chaper shows the order in which the library functions should be
|
||||||
|
@ -437,7 +475,7 @@ Example 3: Multimember compression (MEMBER_SIZE < total output).
|
||||||
|
|
||||||
File: lzlib.info, Node: Problems, Next: Concept Index, Prev: Examples, Up: Top
|
File: lzlib.info, Node: Problems, Next: Concept Index, Prev: Examples, Up: Top
|
||||||
|
|
||||||
8 Reporting Bugs
|
9 Reporting Bugs
|
||||||
****************
|
****************
|
||||||
|
|
||||||
There are probably bugs in Lzlib. There are certainly errors and
|
There are probably bugs in Lzlib. There are certainly errors and
|
||||||
|
@ -459,6 +497,7 @@ Concept Index
|
||||||
|