diff options
Diffstat (limited to 'decompress.cc')
-rw-r--r-- | decompress.cc | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/decompress.cc b/decompress.cc new file mode 100644 index 0000000..0a125d0 --- /dev/null +++ b/decompress.cc @@ -0,0 +1,123 @@ +/* Plzip - A parallel compressor compatible with lzip + Copyright (C) 2009 Laszlo Ersek. + Copyright (C) 2009, 2010 Antonio Diaz Diaz. + + This program 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 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. 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/>. +*/ + +#define _FILE_OFFSET_BITS 64 + +#include <algorithm> +#include <cerrno> +#include <climits> +#include <csignal> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <queue> +#include <string> +#include <vector> +#include <pthread.h> +#include <stdint.h> +#include <unistd.h> +#include <lzlib.h> + +#include "plzip.h" + + +namespace { + +int do_decompress( LZ_Decoder * const decoder, const int infd, const int outfd, + const Pretty_print & pp, const bool testing ) + { + const int in_buffer_size = 65536, out_buffer_size = 8 * in_buffer_size; + uint8_t in_buffer[in_buffer_size], out_buffer[out_buffer_size]; + + while( true ) + { + int in_size = std::min( LZ_decompress_write_size( decoder ), in_buffer_size ); + if( in_size > 0 ) + { + const int max_in_size = in_size; + in_size = readblock( infd, in_buffer, max_in_size ); + if( in_size != max_in_size && errno ) + { pp(); show_error( "read error", errno ); return 1; } + if( in_size == 0 ) LZ_decompress_finish( decoder ); + else if( in_size != LZ_decompress_write( decoder, in_buffer, in_size ) ) + internal_error( "library error (LZ_decompress_write)" ); + } + int out_size = LZ_decompress_read( decoder, out_buffer, out_buffer_size ); +// std::fprintf( stderr, "%5d in_size, %6d out_size.\n", in_size, out_size ); + if( out_size < 0 ) + { + const LZ_Errno lz_errno = LZ_decompress_errno( decoder ); + if( lz_errno == LZ_header_error ) + { + if( LZ_decompress_total_out_size( decoder ) > 0 ) + break; // trailing garbage + pp( "error reading member header" ); + return 1; + } + if( lz_errno == LZ_mem_error ) + { + pp( "not enough memory. Find a machine with more memory" ); + return 1; + } + pp(); + if( lz_errno == LZ_unexpected_eof ) + { + if( verbosity >= 0 ) + std::fprintf( stderr, "file ends unexpectedly at pos %lld\n", + LZ_decompress_total_in_size( decoder ) ); + return 2; + } + if( verbosity >= 0 ) + std::fprintf( stderr, "LZ_decompress_read error: %s.\n", + LZ_strerror( LZ_decompress_errno( decoder ) ) ); + return 1; + } + else if( out_size > 0 && outfd >= 0 ) + { + const int wr = writeblock( outfd, out_buffer, out_size ); + if( wr != out_size ) + { pp(); show_error( "write error", errno ); return 1; } + } + if( LZ_decompress_finished( decoder ) == 1 ) break; + if( in_size == 0 && out_size == 0 ) + internal_error( "library error (LZ_decompress_read)" ); + } + if( verbosity >= 1 ) + { if( testing ) std::fprintf( stderr, "ok\n" ); + else std::fprintf( stderr, "done\n" ); } + return 0; + } + +} // end namespace + + +int decompress( const int infd, const int outfd, const Pretty_print & pp, + const bool testing ) + { + LZ_Decoder * const decoder = LZ_decompress_open(); + int retval; + + if( !decoder || LZ_decompress_errno( decoder ) != LZ_ok ) + { + pp( "not enough memory" ); + retval = 1; + } + else retval = do_decompress( decoder, infd, outfd, pp, testing ); + LZ_decompress_close( decoder ); + return retval; + } |