summaryrefslogtreecommitdiffstats
path: root/decoder.h
diff options
context:
space:
mode:
Diffstat (limited to 'decoder.h')
-rw-r--r--decoder.h97
1 files changed, 55 insertions, 42 deletions
diff --git a/decoder.h b/decoder.h
index ab921dd..aaf85a6 100644
--- a/decoder.h
+++ b/decoder.h
@@ -40,7 +40,7 @@ public:
bool finished() const throw() { return at_stream_end && pos >= stream_pos; }
- uint8_t read_byte()
+ uint8_t get_byte()
{
if( pos >= stream_pos && !read_block() ) return 0;
return buffer[pos++];
@@ -62,59 +62,68 @@ public:
code( 0 ),
range( 0xFFFFFFFF ),
ibuf( buf )
- { for( int i = 0; i < 5; ++i ) code = (code << 8) | read_byte(); }
+ { for( int i = 0; i < 5; ++i ) code = (code << 8) | get_byte(); }
- uint8_t read_byte() const
+ bool finished() const throw() { return ibuf.finished(); }
+ long long member_position() const throw() { return member_pos; }
+
+ uint8_t get_byte() const
{
++member_pos;
- return ibuf.read_byte();
+ return ibuf.get_byte();
}
- long long member_position() const throw() { return member_pos; }
- bool finished() const throw() { return ibuf.finished(); }
+ void normalize()
+ {
+ if( range <= 0x00FFFFFF )
+ { range <<= 8; code = (code << 8) | get_byte(); }
+ }
int decode( const int num_bits )
{
int symbol = 0;
- for( int i = num_bits - 1; i >= 0; --i )
+ for( int i = num_bits; i > 0; --i )
{
- range >>= 1;
symbol <<= 1;
- if( code >= range )
- { code -= range; symbol |= 1; }
if( range <= 0x00FFFFFF )
- { range <<= 8; code = (code << 8) | read_byte(); }
+ {
+ range <<= 7; code = (code << 8) | get_byte();
+ if( code >= range ) { code -= range; symbol |= 1; }
+ }
+ else
+ {
+ range >>= 1;
+ if( code >= range ) { code -= range; symbol |= 1; }
+ }
}
return symbol;
}
int decode_bit( Bit_model & bm )
{
- int symbol;
+ if( range <= 0x00FFFFFF )
+ { range <<= 8; code = (code << 8) | get_byte(); }
const uint32_t bound = ( range >> bit_model_total_bits ) * bm.probability;
if( code < bound )
{
range = bound;
bm.probability += (bit_model_total - bm.probability) >> bit_model_move_bits;
- symbol = 0;
+ return 0;
}
else
{
range -= bound;
code -= bound;
bm.probability -= bm.probability >> bit_model_move_bits;
- symbol = 1;
+ return 1;
}
- if( range <= 0x00FFFFFF )
- { range <<= 8; code = (code << 8) | read_byte(); }
- return symbol;
}
int decode_tree( Bit_model bm[], const int num_bits )
{
int model = 1;
for( int i = num_bits; i > 0; --i )
- model = ( model << 1 ) | decode_bit( bm[model-1] );
+ model = ( model << 1 ) | decode_bit( bm[model] );
return model - (1 << num_bits);
}
@@ -122,27 +131,31 @@ public:
{
int model = 1;
int symbol = 0;
- for( int i = 1; i < (1 << num_bits); i <<= 1 )
+ for( int i = 0; i < num_bits; ++i )
{
- const int bit = decode_bit( bm[model-1] );
- model = ( model << 1 ) | bit;
- if( bit ) symbol |= i;
+ const int bit = decode_bit( bm[model] );
+ model <<= 1;
+ if( bit ) { model |= 1; symbol |= (1 << i); }
}
return symbol;
}
int decode_matched( Bit_model bm[], const int match_byte )
{
+ Bit_model *bm1 = bm + 0x100;
int symbol = 1;
- for( int i = 7; i >= 0; --i )
+ for( int i = 1; i <= 8; ++i )
{
- const int match_bit = ( match_byte >> i ) & 1;
- const int bit = decode_bit( bm[(match_bit<<8)+symbol+0xFF] );
+ const int match_bit = ( match_byte << i ) & 0x100;
+ const int bit = decode_bit( bm1[match_bit+symbol] );
symbol = ( symbol << 1 ) | bit;
- if( match_bit != bit ) break;
+ if( ( match_bit && !bit ) || ( !match_bit && bit ) )
+ {
+ while( ++i <= 8 )
+ symbol = ( symbol << 1 ) | decode_bit( bm[symbol] );
+ break;
+ }
}
- while( symbol < 0x100 )
- symbol = ( symbol << 1 ) | decode_bit( bm[symbol-1] );
return symbol & 0xFF;
}
};
@@ -215,32 +228,32 @@ class LZ_decoder
uint8_t get_byte( const int distance ) const throw()
{
- int newpos = pos - distance - 1;
- if( newpos < 0 ) newpos += buffer_size;
- return buffer[newpos];
+ int i = pos - distance - 1;
+ if( i < 0 ) i += buffer_size;
+ return buffer[i];
}
void put_byte( const uint8_t b )
{
- crc32.update( crc_, b );
buffer[pos] = b;
if( ++pos >= buffer_size ) flush_data();
}
- bool copy_block( const int distance, int len )
+ void copy_block( const int distance, int len )
{
- if( distance < 0 || distance >= buffer_size ||
- len <= 0 || len > max_match_len ) return false;
- int newpos = pos - distance - 1;
- if( newpos < 0 ) newpos += buffer_size;
- for( ; len > 0 ; --len )
+ int i = pos - distance - 1;
+ if( i < 0 ) i += buffer_size;
+ if( len < buffer_size - std::max( pos, i ) && len <= distance )
+ {
+ std::memcpy( buffer + pos, buffer + i, len );
+ pos += len;
+ }
+ else for( ; len > 0 ; --len )
{
- crc32.update( crc_, buffer[newpos] );
- buffer[pos] = buffer[newpos];
+ buffer[pos] = buffer[i];
if( ++pos >= buffer_size ) flush_data();
- if( ++newpos >= buffer_size ) newpos = 0;
+ if( ++i >= buffer_size ) i = 0;
}
- return true;
}
void flush_data();