From 4256d9a69e8bc3923dc23de1eac87245a749cbf4 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 25 Jan 2021 14:41:07 +0100 Subject: Merging upstream version 1.2. Signed-off-by: Daniel Baumann --- lzd.cc | 129 ++++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 75 insertions(+), 54 deletions(-) (limited to 'lzd.cc') diff --git a/lzd.cc b/lzd.cc index 503bc36..f7572b2 100644 --- a/lzd.cc +++ b/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 @@ -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< 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; } -- cgit v1.2.3