summaryrefslogtreecommitdiffstats
path: root/decoder.h
diff options
context:
space:
mode:
Diffstat (limited to 'decoder.h')
-rw-r--r--decoder.h41
1 files changed, 36 insertions, 5 deletions
diff --git a/decoder.h b/decoder.h
index 063511b..118fe23 100644
--- a/decoder.h
+++ b/decoder.h
@@ -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;