1
0
Fork 0

Merging upstream version 1.2.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-20 15:06:26 +01:00
parent 270325f71d
commit 0d06ac25e1
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
20 changed files with 207 additions and 138 deletions

129
lzd.cc
View file

@ -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;
}