diff options
Diffstat (limited to '')
-rw-r--r-- | archive_reader.h | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/archive_reader.h b/archive_reader.h new file mode 100644 index 0000000..a867c0f --- /dev/null +++ b/archive_reader.h @@ -0,0 +1,122 @@ +/* Tarlz - Archiver with multimember lzip compression + Copyright (C) 2013-2020 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 2 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/>. +*/ + +struct Archive_descriptor + { + const std::string name; + const char * const namep; // printable archive name + const int infd; + const Lzip_index lzip_index; + const bool seekable; + const bool indexed; + + Archive_descriptor( const std::string & archive_name ) + : name( archive_name ), namep( name.empty() ? "(stdin)" : name.c_str() ), + infd( name.empty() ? STDIN_FILENO : open_instream( name ) ), + lzip_index( infd, true, false ), + seekable( lseek( infd, 0, SEEK_SET ) == 0 ), + indexed( seekable && lzip_index.retval() == 0 ) {} + }; + + +class Archive_reader_base // base of serial and indexed readers + { +public: + const Archive_descriptor & ad; +protected: + LZ_Decoder * decoder; // destructor closes it if needed + const char * e_msg_; // message for show_file_error + int e_code_; // copy of errno + int e_size_; // partial size read in case of read error + bool e_skip_; // corrupt header skipped + bool fatal_; + + int err( const int retval, const char * const msg = "", const int code = 0, + const int size = 0, const bool skip = false ) + { e_msg_ = msg; e_code_ = code; e_size_ = size; e_skip_ = skip; + if( retval == 2 ) { fatal_ = true; } return retval; } + + Archive_reader_base( const Archive_descriptor & d ) + : ad( d ), decoder( 0 ), e_msg_( "" ), e_code_( 0 ), e_size_( 0 ), + e_skip_( false ), fatal_( false ) {} + +public: + virtual ~Archive_reader_base() + { if( decoder != 0 ) LZ_decompress_close( decoder ); } + + const char * e_msg() const { return e_msg_; } + int e_code() const { return e_code_; } + int e_size() const { return e_size_; } + bool e_skip() const { return e_skip_; } + bool fatal() const { return fatal_; } + + /* Read 'size' uncompressed bytes, decompressing the input if needed. + Return value: 0 = OK, 1 = damaged member, 2 = fatal error. + If !OK, fills all the e_* variables. */ + virtual int read( uint8_t * const buf, const int size ) = 0; + + int parse_records( Extended & extended, const Tar_header header, + Resizable_buffer & rbuf, const bool permissive ); + }; + + +class Archive_reader : public Archive_reader_base // serial reader + { + bool first_read; + bool uncompressed_seekable; // value set by first read call + bool at_eof; + +public: + Archive_reader( const Archive_descriptor & d ) + : Archive_reader_base( d ), first_read( true ), + uncompressed_seekable( false ), at_eof( false ) {} + + int read( uint8_t * const buf, const int size ); + int skip_member( const Extended & extended ); + }; + + +/* If the archive is compressed seekable (indexed), several indexed readers + can be constructed sharing the same Archive_descriptor, for example to + decode the archive in parallel. +*/ +class Archive_reader_i : public Archive_reader_base // indexed reader + { + long long data_pos_; + long long mdata_end; + long long archive_pos; // current position in archive for pread + long member_id; // current member unless reading beyond + +public: + Archive_reader_i( const Archive_descriptor & d ) + : Archive_reader_base( d ), + data_pos_( 0 ), mdata_end( 0 ), archive_pos( 0 ), member_id( 0 ) + { + decoder = LZ_decompress_open(); + if( !decoder || LZ_decompress_errno( decoder ) != LZ_ok ) + { LZ_decompress_close( decoder ); decoder = 0; fatal_ = true; } + } + + long long data_pos() const { return data_pos_; } + bool at_member_end() const { return data_pos_ == mdata_end; } + + // Resets decoder and sets position to the start of the member. + void set_member( const long i ); + + int read( uint8_t * const buf, const int size ); + int skip_member( const Extended & extended ); + }; |