Merging upstream version 1.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
270325f71d
commit
0d06ac25e1
20 changed files with 207 additions and 138 deletions
129
lzd.cc
129
lzd.cc
|
@ -1,25 +1,25 @@
|
|||
/* Lzd - Educational decompressor for the lzip format
|
||||
Copyright (C) 2013-2019 Antonio Diaz Diaz.
|
||||
/* Lzd - Educational decompressor for the lzip format
|
||||
Copyright (C) 2013-2021 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software. Redistribution and use in source and
|
||||
binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
This program is free software. Redistribution and use in source and
|
||||
binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions, and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions, and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
This program 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.
|
||||
This program 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.
|
||||
*/
|
||||
/*
|
||||
Exit status: 0 for a normal exit, 1 for environmental problems
|
||||
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
|
||||
corrupt or invalid input file.
|
||||
Exit status: 0 for a normal exit, 1 for environmental problems
|
||||
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
|
||||
corrupt or invalid input file.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -47,7 +47,7 @@ public:
|
|||
|
||||
void set_char()
|
||||
{
|
||||
static const int next[states] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 };
|
||||
const int next[states] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 };
|
||||
st = next[st];
|
||||
}
|
||||
void set_match() { st = ( st < 7 ) ? 7 : 10; }
|
||||
|
@ -69,7 +69,7 @@ enum {
|
|||
dis_slot_bits = 6,
|
||||
start_dis_model = 4,
|
||||
end_dis_model = 14,
|
||||
modeled_distances = 1 << (end_dis_model / 2), // 128
|
||||
modeled_distances = 1 << ( end_dis_model / 2 ), // 128
|
||||
dis_align_bits = 4,
|
||||
dis_align_size = 1 << dis_align_bits,
|
||||
|
||||
|
@ -130,8 +130,9 @@ public:
|
|||
const CRC32 crc32;
|
||||
|
||||
|
||||
typedef uint8_t Lzip_header[6]; // 0-3 magic, 4 version, 5 coded_dict_size
|
||||
|
||||
typedef uint8_t Lzip_header[6]; // 0-3 magic bytes
|
||||
// 4 version
|
||||
// 5 coded dictionary size
|
||||
typedef uint8_t Lzip_trailer[20];
|
||||
// 0-3 CRC32 of the uncompressed data
|
||||
// 4-11 size of the uncompressed data
|
||||
|
@ -139,16 +140,18 @@ typedef uint8_t Lzip_trailer[20];
|
|||
|
||||
class Range_decoder
|
||||
{
|
||||
unsigned long long member_pos;
|
||||
uint32_t code;
|
||||
uint32_t range;
|
||||
|
||||
public:
|
||||
Range_decoder() : code( 0 ), range( 0xFFFFFFFFU )
|
||||
Range_decoder() : member_pos( 6 ), code( 0 ), range( 0xFFFFFFFFU )
|
||||
{
|
||||
for( int i = 0; i < 5; ++i ) code = (code << 8) | get_byte();
|
||||
for( int i = 0; i < 5; ++i ) code = ( code << 8 ) | get_byte();
|
||||
}
|
||||
|
||||
uint8_t get_byte() { return std::getc( stdin ); }
|
||||
uint8_t get_byte() { ++member_pos; return std::getc( stdin ); }
|
||||
unsigned long long member_position() const { return member_pos; }
|
||||
|
||||
unsigned decode( const int num_bits )
|
||||
{
|
||||
|
@ -159,7 +162,7 @@ public:
|
|||
symbol <<= 1;
|
||||
if( code >= range ) { code -= range; symbol |= 1; }
|
||||
if( range <= 0x00FFFFFFU ) // normalize
|
||||
{ range <<= 8; code = (code << 8) | get_byte(); }
|
||||
{ range <<= 8; code = ( code << 8 ) | get_byte(); }
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
@ -171,7 +174,8 @@ public:
|
|||
if( code < 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;
|
||||
}
|
||||
else
|
||||
|
@ -182,7 +186,7 @@ public:
|
|||
symbol = 1;
|
||||
}
|
||||
if( range <= 0x00FFFFFFU ) // normalize
|
||||
{ range <<= 8; code = (code << 8) | get_byte(); }
|
||||
{ range <<= 8; code = ( code << 8 ) | get_byte(); }
|
||||
return symbol;
|
||||
}
|
||||
|
||||
|
@ -191,7 +195,7 @@ public:
|
|||
unsigned symbol = 1;
|
||||
for( int i = 0; i < num_bits; ++i )
|
||||
symbol = ( symbol << 1 ) | decode_bit( bm[symbol] );
|
||||
return symbol - (1 << num_bits);
|
||||
return symbol - ( 1 << num_bits );
|
||||
}
|
||||
|
||||
unsigned decode_tree_reversed( Bit_model bm[], const int num_bits )
|
||||
|
@ -278,7 +282,11 @@ public:
|
|||
~LZ_decoder() { delete[] buffer; }
|
||||
|
||||
unsigned crc() const { return crc_ ^ 0xFFFFFFFFU; }
|
||||
unsigned long long data_position() const { return partial_data_pos + pos; }
|
||||
unsigned long long data_position() const
|
||||
{ return partial_data_pos + pos; }
|
||||
uint8_t get_byte() { return rdec.get_byte(); }
|
||||
unsigned long long member_position() const
|
||||
{ return rdec.member_position(); }
|
||||
|
||||
bool decode_member();
|
||||
};
|
||||
|
@ -290,7 +298,6 @@ void LZ_decoder::flush_data()
|
|||
{
|
||||
const unsigned size = pos - stream_pos;
|
||||
crc32.update_buf( crc_, buffer + stream_pos, size );
|
||||
errno = 0;
|
||||
if( std::fwrite( buffer + stream_pos, 1, size, stdout ) != size )
|
||||
{ std::fprintf( stderr, "Write error: %s\n", std::strerror( errno ) );
|
||||
std::exit( 1 ); }
|
||||
|
@ -301,7 +308,7 @@ void LZ_decoder::flush_data()
|
|||
}
|
||||
|
||||
|
||||
bool LZ_decoder::decode_member() // Returns false if error
|
||||
bool LZ_decoder::decode_member() // Returns false if error
|
||||
{
|
||||
Bit_model bm_literal[1<<literal_context_bits][0x300];
|
||||
Bit_model bm_match[State::states][pos_states];
|
||||
|
@ -381,7 +388,8 @@ bool LZ_decoder::decode_member() // Returns false if error
|
|||
direct_bits );
|
||||
else
|
||||
{
|
||||
rep0 += rdec.decode( direct_bits - dis_align_bits ) << dis_align_bits;
|
||||
rep0 +=
|
||||
rdec.decode( direct_bits - dis_align_bits ) << dis_align_bits;
|
||||
rep0 += rdec.decode_tree_reversed( bm_align, dis_align_bits );
|
||||
if( rep0 == 0xFFFFFFFFU ) // marker found
|
||||
{
|
||||
|
@ -403,20 +411,21 @@ bool LZ_decoder::decode_member() // Returns false if error
|
|||
|
||||
int main( const int argc, const char * const argv[] )
|
||||
{
|
||||
if( argc > 1 )
|
||||
if( argc > 2 || ( argc == 2 && std::strcmp( argv[1], "-d" ) != 0 ) )
|
||||
{
|
||||
std::printf( "Lzd %s - Educational decompressor for the lzip format.\n",
|
||||
PROGVERSION );
|
||||
std::printf( "Study the source to learn how a lzip decompressor works.\n"
|
||||
"See the lzip manual for an explanation of the code.\n"
|
||||
"It is not safe to use lzd for any real work.\n"
|
||||
"\nUsage: %s < file.lz > file\n", argv[0] );
|
||||
std::printf( "Lzd decompresses from standard input to standard output.\n"
|
||||
"\nCopyright (C) 2019 Antonio Diaz Diaz.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"Report bugs to lzip-bug@nongnu.org\n"
|
||||
"Lzd home page: http://www.nongnu.org/lzip/lzd.html\n" );
|
||||
std::printf(
|
||||
"Lzd %s - Educational decompressor for the lzip format.\n"
|
||||
"Study the source to learn how a lzip decompressor works.\n"
|
||||
"See the lzip manual for an explanation of the code.\n"
|
||||
"\nUsage: %s [-d] < file.lz > file\n"
|
||||
"Lzd decompresses from standard input to standard output.\n"
|
||||
"\nCopyright (C) 2021 Antonio Diaz Diaz.\n"
|
||||
"License 2-clause BSD.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"Report bugs to lzip-bug@nongnu.org\n"
|
||||
"Lzd home page: http://www.nongnu.org/lzip/lzd.html\n",
|
||||
PROGVERSION, argv[0] );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -432,9 +441,9 @@ int main( const int argc, const char * const argv[] )
|
|||
if( std::feof( stdin ) || std::memcmp( header, "LZIP\x01", 5 ) != 0 )
|
||||
{
|
||||
if( first_member )
|
||||
{ std::fputs( "Bad magic number (file not in lzip format).\n", stderr );
|
||||
return 2; }
|
||||
break;
|
||||
{ std::fputs( "Bad magic number (file not in lzip format).\n",
|
||||
stderr ); return 2; }
|
||||
break; // ignore trailing data
|
||||
}
|
||||
unsigned dict_size = 1 << ( header[5] & 0x1F );
|
||||
dict_size -= ( dict_size / 16 ) * ( ( header[5] >> 5 ) & 7 );
|
||||
|
@ -447,17 +456,29 @@ int main( const int argc, const char * const argv[] )
|
|||
{ std::fputs( "Data error\n", stderr ); return 2; }
|
||||
|
||||
Lzip_trailer trailer; // verify trailer
|
||||
for( int i = 0; i < 20; ++i ) trailer[i] = std::getc( stdin );
|
||||
for( int i = 0; i < 20; ++i ) trailer[i] = decoder.get_byte();
|
||||
int retval = 0;
|
||||
unsigned crc = 0;
|
||||
for( int i = 3; i >= 0; --i ) { crc <<= 8; crc += trailer[i]; }
|
||||
for( int i = 3; i >= 0; --i ) crc = ( crc << 8 ) + trailer[i];
|
||||
if( crc != decoder.crc() )
|
||||
{ std::fputs( "CRC mismatch\n", stderr ); retval = 2; }
|
||||
|
||||
unsigned long long data_size = 0;
|
||||
for( int i = 11; i >= 4; --i ) { data_size <<= 8; data_size += trailer[i]; }
|
||||
if( crc != decoder.crc() || data_size != decoder.data_position() )
|
||||
{ std::fputs( "CRC error\n", stderr ); return 2; }
|
||||
for( int i = 11; i >= 4; --i )
|
||||
data_size = ( data_size << 8 ) + trailer[i];
|
||||
if( data_size != decoder.data_position() )
|
||||
{ std::fputs( "Data size mismatch\n", stderr ); retval = 2; }
|
||||
|
||||
unsigned long long member_size = 0;
|
||||
for( int i = 19; i >= 12; --i )
|
||||
member_size = ( member_size << 8 ) + trailer[i];
|
||||
if( member_size != decoder.member_position() )
|
||||
{ std::fputs( "Member size mismatch\n", stderr ); retval = 2; }
|
||||
if( retval ) return retval;
|
||||
}
|
||||
|
||||
if( std::fclose( stdout ) != 0 )
|
||||
{ std::fprintf( stderr, "Error closing stdout: %s\n", std::strerror( errno ) );
|
||||
return 1; }
|
||||
{ std::fprintf( stderr, "Error closing stdout: %s\n",
|
||||
std::strerror( errno ) ); return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue