diff options
Diffstat (limited to 'decoder.h')
-rw-r--r-- | decoder.h | 41 |
1 files changed, 36 insertions, 5 deletions
@@ -85,6 +85,7 @@ static inline void Rd_load( struct Range_decoder * const rdec ) for( i = 0; i < 5; ++i ) rdec->code = (rdec->code << 8) | Rd_get_byte( rdec ); rdec->range = 0xFFFFFFFFU; + rdec->code &= rdec->range; /* make sure that first byte is discarded */ } static inline void Rd_normalize( struct Range_decoder * const rdec ) @@ -259,6 +260,9 @@ void LZd_flush_data( struct LZ_decoder * const decoder ); bool LZd_verify_trailer( struct LZ_decoder * const decoder, struct Pretty_print * const pp ); +int seek_read( const int fd, uint8_t * const buf, const int size, + const int offset ); + static inline uint8_t LZd_get_prev_byte( const struct LZ_decoder * const decoder ) { const int i = @@ -269,9 +273,14 @@ static inline uint8_t LZd_get_prev_byte( const struct LZ_decoder * const decoder static inline uint8_t LZd_get_byte( const struct LZ_decoder * const decoder, const int distance ) { - int i = decoder->pos - distance - 1; - if( i < 0 ) i += decoder->buffer_size; - return decoder->buffer[i]; + uint8_t b; + const int i = decoder->pos - distance - 1; + if( i >= 0 ) b = decoder->buffer[i]; + else if( i + decoder->buffer_size >= decoder->pos ) + b = decoder->buffer[i+decoder->buffer_size]; + else if( seek_read( decoder->outfd, &b, 1, i - decoder->stream_pos ) != 1 ) + { show_error( "Seek error", errno, false ); cleanup_and_fail( 1 ); } + return b; } static inline void LZd_put_byte( struct LZ_decoder * const decoder, @@ -300,13 +309,35 @@ static inline void LZd_copy_block( struct LZ_decoder * const decoder, } } +static inline void LZd_copy_block2( struct LZ_decoder * const decoder, + const int distance, int len ) + { + if( distance < decoder->buffer_size ) /* block is in buffer */ + { LZd_copy_block( decoder, distance, len ); return; } + if( len < decoder->buffer_size - decoder->pos ) /* no wrap */ + { + const int offset = decoder->pos - decoder->stream_pos - distance - 1; + if( len <= -offset ) /* block is in file */ + { + if( seek_read( decoder->outfd, decoder->buffer + decoder->pos, len, offset ) != len ) + { show_error( "Seek error", errno, false ); cleanup_and_fail( 1 ); } + decoder->pos += len; + return; + } + } + for( ; len > 0; --len ) + LZd_put_byte( decoder, LZd_get_byte( decoder, distance ) ); + } + static inline bool LZd_init( struct LZ_decoder * const decoder, const File_header header, - struct Range_decoder * const rde, const int ofd ) + struct Range_decoder * const rde, + const int buffer_size, const int ofd ) { decoder->partial_data_pos = 0; decoder->dictionary_size = Fh_get_dictionary_size( header ); - decoder->buffer_size = max( 65536, decoder->dictionary_size ); + decoder->buffer_size = + min( buffer_size, max( 65536, decoder->dictionary_size ) ); decoder->buffer = (uint8_t *)malloc( decoder->buffer_size ); if( !decoder->buffer ) return false; decoder->pos = 0; |