You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1106 lines
23 KiB
1106 lines
23 KiB
/*M/////////////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
|
// |
|
// By downloading, copying, installing or using the software you agree to this license. |
|
// If you do not agree to this license, do not download, install, |
|
// copy or use the software. |
|
// |
|
// |
|
// Intel License Agreement |
|
// For Open Source Computer Vision Library |
|
// |
|
// Copyright (C) 2000, Intel Corporation, all rights reserved. |
|
// Third party copyrights are property of their respective owners. |
|
// |
|
// Redistribution and use in source and binary forms, with or without modification, |
|
// are permitted provided that the following conditions are met: |
|
// |
|
// * Redistribution's of source code must retain the above copyright notice, |
|
// this list of conditions and the following disclaimer. |
|
// |
|
// * Redistribution's in binary form must reproduce the above copyright notice, |
|
// this list of conditions and the following disclaimer in the documentation |
|
// and/or other materials provided with the distribution. |
|
// |
|
// * The name of Intel Corporation may not be used to endorse or promote products |
|
// derived from this software without specific prior written permission. |
|
// |
|
// This software is provided by the copyright holders and contributors "as is" and |
|
// any express or implied warranties, including, but not limited to, the implied |
|
// warranties of merchantability and fitness for a particular purpose are disclaimed. |
|
// In no event shall the Intel Corporation or contributors be liable for any direct, |
|
// indirect, incidental, special, exemplary, or consequential damages |
|
// (including, but not limited to, procurement of substitute goods or services; |
|
// loss of use, data, or profits; or business interruption) however caused |
|
// and on any theory of liability, whether in contract, strict liability, |
|
// or tort (including negligence or otherwise) arising in any way out of |
|
// the use of this software, even if advised of the possibility of such damage. |
|
// |
|
//M*/ |
|
|
|
#include "_highgui.h" |
|
#include "bitstrm.h" |
|
|
|
#define BS_DEF_BLOCK_SIZE (1<<15) |
|
|
|
const ulong bs_bit_mask[] = { |
|
0, |
|
0x00000001, 0x00000003, 0x00000007, 0x0000000F, |
|
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, |
|
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, |
|
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, |
|
0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, |
|
0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, |
|
0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, |
|
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF |
|
}; |
|
|
|
void bsBSwapBlock( uchar *start, uchar *end ) |
|
{ |
|
ulong* data = (ulong*)start; |
|
int i, size = (int)(end - start+3)/4; |
|
|
|
for( i = 0; i < size; i++ ) |
|
{ |
|
ulong temp = data[i]; |
|
temp = BSWAP( temp ); |
|
data[i] = temp; |
|
} |
|
} |
|
|
|
bool bsIsBigEndian( void ) |
|
{ |
|
return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0; |
|
} |
|
|
|
///////////////////////// RBaseStream //////////////////////////// |
|
|
|
bool RBaseStream::IsOpened() |
|
{ |
|
return m_is_opened; |
|
} |
|
|
|
void RBaseStream::Allocate() |
|
{ |
|
if( !m_start ) |
|
{ |
|
m_start = new uchar[m_block_size + m_unGetsize]; |
|
m_start+= m_unGetsize; |
|
} |
|
m_end = m_start + m_block_size; |
|
m_current = m_end; |
|
} |
|
|
|
|
|
RBaseStream::RBaseStream() |
|
{ |
|
m_start = m_end = m_current = 0; |
|
m_file = 0; |
|
m_block_size = BS_DEF_BLOCK_SIZE; |
|
m_unGetsize = 4; // 32 bits |
|
m_is_opened = false; |
|
m_jmp_set = false; |
|
} |
|
|
|
|
|
RBaseStream::~RBaseStream() |
|
{ |
|
Close(); // Close files |
|
Release(); // free buffers |
|
} |
|
|
|
|
|
void RBaseStream::ReadBlock() |
|
{ |
|
size_t readed; |
|
assert( m_file != 0 ); |
|
|
|
// copy unget buffer |
|
if( m_start ) |
|
{ |
|
memcpy( m_start - m_unGetsize, m_end - m_unGetsize, m_unGetsize ); |
|
} |
|
|
|
SetPos( GetPos() ); // normalize position |
|
|
|
fseek( m_file, m_block_pos, SEEK_SET ); |
|
readed = fread( m_start, 1, m_block_size, m_file ); |
|
m_end = m_start + readed; |
|
m_current -= m_block_size; |
|
m_block_pos += m_block_size; |
|
|
|
if( readed == 0 || m_current >= m_end ) |
|
{ |
|
if( m_jmp_set ) |
|
longjmp( m_jmp_buf, RBS_THROW_EOS ); |
|
} |
|
} |
|
|
|
|
|
bool RBaseStream::Open( const char* filename ) |
|
{ |
|
Close(); |
|
Allocate(); |
|
|
|
m_file = fopen( filename, "rb" ); |
|
|
|
if( m_file ) |
|
{ |
|
m_is_opened = true; |
|
SetPos(0); |
|
} |
|
return m_file != 0; |
|
} |
|
|
|
void RBaseStream::Close() |
|
{ |
|
if( m_file ) |
|
{ |
|
fclose( m_file ); |
|
m_file = 0; |
|
} |
|
m_is_opened = false; |
|
} |
|
|
|
|
|
void RBaseStream::Release() |
|
{ |
|
if( m_start ) |
|
{ |
|
delete[] (m_start - m_unGetsize); |
|
} |
|
m_start = m_end = m_current = 0; |
|
} |
|
|
|
|
|
void RBaseStream::SetBlockSize( int block_size, int unGetsize ) |
|
{ |
|
assert( unGetsize >= 0 && block_size > 0 && |
|
(block_size & (block_size-1)) == 0 ); |
|
|
|
if( m_start && block_size == m_block_size && unGetsize == m_unGetsize ) return; |
|
Release(); |
|
m_block_size = block_size; |
|
m_unGetsize = unGetsize; |
|
Allocate(); |
|
} |
|
|
|
|
|
void RBaseStream::SetPos( int pos ) |
|
{ |
|
int offset = pos & (m_block_size - 1); |
|
int block_pos = pos - offset; |
|
|
|
assert( IsOpened() && pos >= 0 ); |
|
|
|
if( m_current < m_end && block_pos == m_block_pos - m_block_size ) |
|
{ |
|
m_current = m_start + offset; |
|
} |
|
else |
|
{ |
|
m_block_pos = block_pos; |
|
m_current = m_start + m_block_size + offset; |
|
} |
|
} |
|
|
|
|
|
int RBaseStream::GetPos() |
|
{ |
|
assert( IsOpened() ); |
|
return m_block_pos - m_block_size + (int)(m_current - m_start); |
|
} |
|
|
|
void RBaseStream::Skip( int bytes ) |
|
{ |
|
assert( bytes >= 0 ); |
|
m_current += bytes; |
|
} |
|
|
|
jmp_buf& RBaseStream::JmpBuf() |
|
{ |
|
m_jmp_set = true; |
|
return m_jmp_buf; |
|
} |
|
|
|
///////////////////////// RLByteStream //////////////////////////// |
|
|
|
RLByteStream::~RLByteStream() |
|
{ |
|
} |
|
|
|
int RLByteStream::GetByte() |
|
{ |
|
uchar *current = m_current; |
|
int val; |
|
|
|
if( current >= m_end ) |
|
{ |
|
ReadBlock(); |
|
current = m_current; |
|
} |
|
|
|
val = *((uchar*)current); |
|
m_current = current + 1; |
|
return val; |
|
} |
|
|
|
|
|
void RLByteStream::GetBytes( void* buffer, int count, int* readed ) |
|
{ |
|
uchar* data = (uchar*)buffer; |
|
assert( count >= 0 ); |
|
|
|
if( readed) *readed = 0; |
|
|
|
while( count > 0 ) |
|
{ |
|
int l; |
|
|
|
for(;;) |
|
{ |
|
l = (int)(m_end - m_current); |
|
if( l > count ) l = count; |
|
if( l > 0 ) break; |
|
ReadBlock(); |
|
} |
|
memcpy( data, m_current, l ); |
|
m_current += l; |
|
data += l; |
|
count -= l; |
|
if( readed ) *readed += l; |
|
} |
|
} |
|
|
|
|
|
//////////// RLByteStream & RMByteStream <Get[d]word>s //////////////// |
|
|
|
RMByteStream::~RMByteStream() |
|
{ |
|
} |
|
|
|
|
|
int RLByteStream::GetWord() |
|
{ |
|
uchar *current = m_current; |
|
int val; |
|
|
|
if( current+1 < m_end ) |
|
{ |
|
val = current[0] + (current[1] << 8); |
|
m_current = current + 2; |
|
} |
|
else |
|
{ |
|
val = GetByte(); |
|
val|= GetByte() << 8; |
|
} |
|
return val; |
|
} |
|
|
|
|
|
int RLByteStream::GetDWord() |
|
{ |
|
uchar *current = m_current; |
|
int val; |
|
|
|
if( current+3 < m_end ) |
|
{ |
|
val = current[0] + (current[1] << 8) + |
|
(current[2] << 16) + (current[3] << 24); |
|
m_current = current + 4; |
|
} |
|
else |
|
{ |
|
val = GetByte(); |
|
val |= GetByte() << 8; |
|
val |= GetByte() << 16; |
|
val |= GetByte() << 24; |
|
} |
|
return val; |
|
} |
|
|
|
|
|
int RMByteStream::GetWord() |
|
{ |
|
uchar *current = m_current; |
|
int val; |
|
|
|
if( current+1 < m_end ) |
|
{ |
|
val = (current[0] << 8) + current[1]; |
|
m_current = current + 2; |
|
} |
|
else |
|
{ |
|
val = GetByte() << 8; |
|
val|= GetByte(); |
|
} |
|
return val; |
|
} |
|
|
|
|
|
int RMByteStream::GetDWord() |
|
{ |
|
uchar *current = m_current; |
|
int val; |
|
|
|
if( current+3 < m_end ) |
|
{ |
|
val = (current[0] << 24) + (current[1] << 16) + |
|
(current[2] << 8) + current[3]; |
|
m_current = current + 4; |
|
} |
|
else |
|
{ |
|
val = GetByte() << 24; |
|
val |= GetByte() << 16; |
|
val |= GetByte() << 8; |
|
val |= GetByte(); |
|
} |
|
return val; |
|
} |
|
|
|
|
|
///////////////////////// RLBitStream //////////////////////////// |
|
|
|
RLBitStream::~RLBitStream() |
|
{ |
|
} |
|
|
|
|
|
void RLBitStream::ReadBlock() |
|
{ |
|
RBaseStream::ReadBlock(); |
|
if( bsIsBigEndian() ) |
|
bsBSwapBlock( m_start, m_end ); |
|
} |
|
|
|
|
|
void RLBitStream::SetPos( int pos ) |
|
{ |
|
RBaseStream::SetPos(pos); |
|
int offset = (int)(m_current - m_end); |
|
m_current = m_end + (offset & -4); |
|
m_bit_idx = (offset&3)*8; |
|
} |
|
|
|
|
|
int RLBitStream::GetPos() |
|
{ |
|
return RBaseStream::GetPos() + (m_bit_idx >> 3); |
|
} |
|
|
|
|
|
int RLBitStream::Get( int bits ) |
|
{ |
|
int bit_idx = m_bit_idx; |
|
int new_bit_idx = bit_idx + bits; |
|
int mask = new_bit_idx >= 32 ? -1 : 0; |
|
ulong* current = (ulong*)m_current; |
|
|
|
assert( (unsigned)bits < 32 ); |
|
|
|
if( (m_current = (uchar*)(current - mask)) >= m_end ) |
|
{ |
|
ReadBlock(); |
|
current = ((ulong*)m_current) + mask; |
|
} |
|
m_bit_idx = new_bit_idx & 31; |
|
return ((current[0] >> bit_idx) | |
|
((current[1] <<-bit_idx) & mask)) & bs_bit_mask[bits]; |
|
} |
|
|
|
int RLBitStream::Show( int bits ) |
|
{ |
|
int bit_idx = m_bit_idx; |
|
int new_bit_idx = bit_idx + bits; |
|
int mask = new_bit_idx >= 32 ? -1 : 0; |
|
ulong* current = (ulong*)m_current; |
|
|
|
assert( (unsigned)bits < 32 ); |
|
|
|
if( (uchar*)(current - mask) >= m_end ) |
|
{ |
|
ReadBlock(); |
|
current = ((ulong*)m_current) + mask; |
|
m_current = (uchar*)current; |
|
} |
|
return ((current[0] >> bit_idx) | |
|
((current[1] <<-bit_idx) & mask)) & bs_bit_mask[bits]; |
|
} |
|
|
|
|
|
void RLBitStream::Move( int shift ) |
|
{ |
|
int new_bit_idx = m_bit_idx + shift; |
|
m_current += (new_bit_idx >> 5) << 2; |
|
m_bit_idx = new_bit_idx & 31; |
|
} |
|
|
|
|
|
int RLBitStream::GetHuff( const short* table ) |
|
{ |
|
int val; |
|
int code_bits; |
|
|
|
for(;;) |
|
{ |
|
int table_bits = table[0]; |
|
val = table[Show(table_bits) + 2]; |
|
code_bits = val & 15; |
|
val >>= 4; |
|
|
|
if( code_bits != 0 ) break; |
|
table += val*2; |
|
Move( table_bits ); |
|
} |
|
|
|
Move( code_bits ); |
|
if( val == RBS_HUFF_FORB ) |
|
{ |
|
if( m_jmp_set ) |
|
longjmp( m_jmp_buf, RBS_THROW_FORB ); |
|
} |
|
|
|
return val; |
|
} |
|
|
|
void RLBitStream::Skip( int bytes ) |
|
{ |
|
Move( bytes*8 ); |
|
} |
|
|
|
///////////////////////// RMBitStream //////////////////////////// |
|
|
|
|
|
RMBitStream::~RMBitStream() |
|
{ |
|
} |
|
|
|
|
|
void RMBitStream::ReadBlock() |
|
{ |
|
RBaseStream::ReadBlock(); |
|
if( !bsIsBigEndian() ) |
|
bsBSwapBlock( m_start, m_end ); |
|
} |
|
|
|
|
|
void RMBitStream::SetPos( int pos ) |
|
{ |
|
RBaseStream::SetPos(pos); |
|
int offset = (int)(m_current - m_end); |
|
m_current = m_end + ((offset - 1) & -4); |
|
m_bit_idx = (32 - (offset&3)*8) & 31; |
|
} |
|
|
|
|
|
int RMBitStream::GetPos() |
|
{ |
|
return RBaseStream::GetPos() + ((32 - m_bit_idx) >> 3); |
|
} |
|
|
|
|
|
int RMBitStream::Get( int bits ) |
|
{ |
|
int bit_idx = m_bit_idx - bits; |
|
int mask = bit_idx >> 31; |
|
ulong* current = ((ulong*)m_current) - mask; |
|
|
|
assert( (unsigned)bits < 32 ); |
|
|
|
if( (m_current = (uchar*)current) >= m_end ) |
|
{ |
|
ReadBlock(); |
|
current = (ulong*)m_current; |
|
} |
|
m_bit_idx = bit_idx &= 31; |
|
return (((current[-1] << -bit_idx) & mask)| |
|
(current[0] >> bit_idx)) & bs_bit_mask[bits]; |
|
} |
|
|
|
|
|
int RMBitStream::Show( int bits ) |
|
{ |
|
int bit_idx = m_bit_idx - bits; |
|
int mask = bit_idx >> 31; |
|
ulong* current = ((ulong*)m_current) - mask; |
|
|
|
assert( (unsigned)bits < 32 ); |
|
|
|
if( ((uchar*)current) >= m_end ) |
|
{ |
|
m_current = (uchar*)current; |
|
ReadBlock(); |
|
current = (ulong*)m_current; |
|
m_current -= 4; |
|
} |
|
return (((current[-1]<<-bit_idx) & mask)| |
|
(current[0] >> bit_idx)) & bs_bit_mask[bits]; |
|
} |
|
|
|
|
|
int RMBitStream::GetHuff( const short* table ) |
|
{ |
|
int val; |
|
int code_bits; |
|
|
|
for(;;) |
|
{ |
|
int table_bits = table[0]; |
|
val = table[Show(table_bits) + 1]; |
|
code_bits = val & 15; |
|
val >>= 4; |
|
|
|
if( code_bits != 0 ) break; |
|
table += val; |
|
Move( table_bits ); |
|
} |
|
|
|
Move( code_bits ); |
|
if( val == RBS_HUFF_FORB ) |
|
{ |
|
if( m_jmp_set ) |
|
longjmp( m_jmp_buf, RBS_THROW_FORB ); |
|
} |
|
|
|
return val; |
|
} |
|
|
|
|
|
void RMBitStream::Move( int shift ) |
|
{ |
|
int new_bit_idx = m_bit_idx - shift; |
|
m_current -= (new_bit_idx >> 5)<<2; |
|
m_bit_idx = new_bit_idx & 31; |
|
} |
|
|
|
|
|
void RMBitStream::Skip( int bytes ) |
|
{ |
|
Move( bytes*8 ); |
|
} |
|
|
|
|
|
static const int huff_val_shift = 20, huff_code_mask = (1 << huff_val_shift) - 1; |
|
|
|
bool bsCreateDecodeHuffmanTable( const int* src, short* table, int max_size ) |
|
{ |
|
const int forbidden_entry = (RBS_HUFF_FORB << 4)|1; |
|
int first_bits = src[0]; |
|
struct |
|
{ |
|
int bits; |
|
int offset; |
|
} |
|
sub_tables[1 << 11]; |
|
int size = (1 << first_bits) + 1; |
|
int i, k; |
|
|
|
/* calc bit depths of sub tables */ |
|
memset( sub_tables, 0, ((size_t)1 << first_bits)*sizeof(sub_tables[0]) ); |
|
for( i = 1, k = 1; src[k] >= 0; i++ ) |
|
{ |
|
int code_count = src[k++]; |
|
int sb = i - first_bits; |
|
|
|
if( sb <= 0 ) |
|
k += code_count; |
|
else |
|
for( code_count += k; k < code_count; k++ ) |
|
{ |
|
int code = src[k] & huff_code_mask; |
|
sub_tables[code >> sb].bits = sb; |
|
} |
|
} |
|
|
|
/* calc offsets of sub tables and whole size of table */ |
|
for( i = 0; i < (1 << first_bits); i++ ) |
|
{ |
|
int b = sub_tables[i].bits; |
|
if( b > 0 ) |
|
{ |
|
b = 1 << b; |
|
sub_tables[i].offset = size; |
|
size += b + 1; |
|
} |
|
} |
|
|
|
if( size > max_size ) |
|
{ |
|
assert(0); |
|
return false; |
|
} |
|
|
|
/* fill first table and subtables with forbidden values */ |
|
for( i = 0; i < size; i++ ) |
|
{ |
|
table[i] = (short)forbidden_entry; |
|
} |
|
|
|
/* write header of first table */ |
|
table[0] = (short)first_bits; |
|
|
|
/* fill first table and sub tables */ |
|
for( i = 1, k = 1; src[k] >= 0; i++ ) |
|
{ |
|
int code_count = src[k++]; |
|
for( code_count += k; k < code_count; k++ ) |
|
{ |
|
int table_bits= first_bits; |
|
int code_bits = i; |
|
int code = src[k] & huff_code_mask; |
|
int val = src[k] >>huff_val_shift; |
|
int j, offset = 0; |
|
|
|
if( code_bits > table_bits ) |
|
{ |
|
int idx = code >> (code_bits -= table_bits); |
|
code &= (1 << code_bits) - 1; |
|
offset = sub_tables[idx].offset; |
|
table_bits= sub_tables[idx].bits; |
|
/* write header of subtable */ |
|
table[offset] = (short)table_bits; |
|
/* write jump to subtable */ |
|
table[idx + 1]= (short)(offset << 4); |
|
} |
|
|
|
table_bits -= code_bits; |
|
assert( table_bits >= 0 ); |
|
val = (val << 4) | code_bits; |
|
offset += (code << table_bits) + 1; |
|
|
|
for( j = 0; j < (1 << table_bits); j++ ) |
|
{ |
|
assert( table[offset + j] == forbidden_entry ); |
|
table[ offset + j ] = (short)val; |
|
} |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
|
|
int* bsCreateSourceHuffmanTable( const uchar* src, int* dst, |
|
int max_bits, int first_bits ) |
|
{ |
|
int i, val_idx, code = 0; |
|
int* table = dst; |
|
*dst++ = first_bits; |
|
for( i = 1, val_idx = max_bits; i <= max_bits; i++ ) |
|
{ |
|
int code_count = src[i - 1]; |
|
dst[0] = code_count; |
|
code <<= 1; |
|
for( int k = 0; k < code_count; k++ ) |
|
{ |
|
dst[k + 1] = (src[val_idx + k] << huff_val_shift)|(code + k); |
|
} |
|
code += code_count; |
|
dst += code_count + 1; |
|
val_idx += code_count; |
|
} |
|
dst[0] = -1; |
|
return table; |
|
} |
|
|
|
|
|
/////////////////////////// WBaseStream ///////////////////////////////// |
|
|
|
// WBaseStream - base class for output streams |
|
WBaseStream::WBaseStream() |
|
{ |
|
m_start = m_end = m_current = 0; |
|
m_file = 0; |
|
m_block_size = BS_DEF_BLOCK_SIZE; |
|
m_is_opened = false; |
|
} |
|
|
|
|
|
WBaseStream::~WBaseStream() |
|
{ |
|
Close(); // Close files |
|
Release(); // free buffers |
|
} |
|
|
|
|
|
bool WBaseStream::IsOpened() |
|
{ |
|
return m_is_opened; |
|
} |
|
|
|
|
|
void WBaseStream::Allocate() |
|
{ |
|
if( !m_start ) |
|
m_start = new uchar[m_block_size]; |
|
|
|
m_end = m_start + m_block_size; |
|
m_current = m_start; |
|
} |
|
|
|
|
|
void WBaseStream::WriteBlock() |
|
{ |
|
int size = (int)(m_current - m_start); |
|
assert( m_file != 0 ); |
|
|
|
//fseek( m_file, m_block_pos, SEEK_SET ); |
|
fwrite( m_start, 1, size, m_file ); |
|
m_current = m_start; |
|
|
|
/*if( written < size ) throw RBS_THROW_EOS;*/ |
|
|
|
m_block_pos += size; |
|
} |
|
|
|
|
|
bool WBaseStream::Open( const char* filename ) |
|
{ |
|
Close(); |
|
Allocate(); |
|
|
|
m_file = fopen( filename, "wb" ); |
|
|
|
if( m_file ) |
|
{ |
|
m_is_opened = true; |
|
m_block_pos = 0; |
|
m_current = m_start; |
|
} |
|
return m_file != 0; |
|
} |
|
|
|
|
|
void WBaseStream::Close() |
|
{ |
|
if( m_file ) |
|
{ |
|
WriteBlock(); |
|
fclose( m_file ); |
|
m_file = 0; |
|
} |
|
m_is_opened = false; |
|
} |
|
|
|
|
|
void WBaseStream::Release() |
|
{ |
|
if( m_start ) |
|
{ |
|
delete[] m_start; |
|
} |
|
m_start = m_end = m_current = 0; |
|
} |
|
|
|
|
|
void WBaseStream::SetBlockSize( int block_size ) |
|
{ |
|
assert( block_size > 0 && (block_size & (block_size-1)) == 0 ); |
|
|
|
if( m_start && block_size == m_block_size ) return; |
|
Release(); |
|
m_block_size = block_size; |
|
Allocate(); |
|
} |
|
|
|
|
|
int WBaseStream::GetPos() |
|
{ |
|
assert( IsOpened() ); |
|
return m_block_pos + (int)(m_current - m_start); |
|
} |
|
|
|
|
|
///////////////////////////// WLByteStream /////////////////////////////////// |
|
|
|
WLByteStream::~WLByteStream() |
|
{ |
|
} |
|
|
|
void WLByteStream::PutByte( int val ) |
|
{ |
|
*m_current++ = (uchar)val; |
|
if( m_current >= m_end ) |
|
WriteBlock(); |
|
} |
|
|
|
|
|
void WLByteStream::PutBytes( const void* buffer, int count ) |
|
{ |
|
uchar* data = (uchar*)buffer; |
|
|
|
assert( data && m_current && count >= 0 ); |
|
|
|
while( count ) |
|
{ |
|
int l = (int)(m_end - m_current); |
|
|
|
if( l > count ) |
|
l = count; |
|
|
|
if( l > 0 ) |
|
{ |
|
memcpy( m_current, data, l ); |
|
m_current += l; |
|
data += l; |
|
count -= l; |
|
} |
|
if( m_current == m_end ) |
|
WriteBlock(); |
|
} |
|
} |
|
|
|
|
|
void WLByteStream::PutWord( int val ) |
|
{ |
|
uchar *current = m_current; |
|
|
|
if( current+1 < m_end ) |
|
{ |
|
current[0] = (uchar)val; |
|
current[1] = (uchar)(val >> 8); |
|
m_current = current + 2; |
|
if( m_current == m_end ) |
|
WriteBlock(); |
|
} |
|
else |
|
{ |
|
PutByte(val); |
|
PutByte(val >> 8); |
|
} |
|
} |
|
|
|
|
|
void WLByteStream::PutDWord( int val ) |
|
{ |
|
uchar *current = m_current; |
|
|
|
if( current+3 < m_end ) |
|
{ |
|
current[0] = (uchar)val; |
|
current[1] = (uchar)(val >> 8); |
|
current[2] = (uchar)(val >> 16); |
|
current[3] = (uchar)(val >> 24); |
|
m_current = current + 4; |
|
if( m_current == m_end ) |
|
WriteBlock(); |
|
} |
|
else |
|
{ |
|
PutByte(val); |
|
PutByte(val >> 8); |
|
PutByte(val >> 16); |
|
PutByte(val >> 24); |
|
} |
|
} |
|
|
|
|
|
///////////////////////////// WMByteStream /////////////////////////////////// |
|
|
|
WMByteStream::~WMByteStream() |
|
{ |
|
} |
|
|
|
|
|
void WMByteStream::PutWord( int val ) |
|
{ |
|
uchar *current = m_current; |
|
|
|
if( current+1 < m_end ) |
|
{ |
|
current[0] = (uchar)(val >> 8); |
|
current[1] = (uchar)val; |
|
m_current = current + 2; |
|
if( m_current == m_end ) |
|
WriteBlock(); |
|
} |
|
else |
|
{ |
|
PutByte(val >> 8); |
|
PutByte(val); |
|
} |
|
} |
|
|
|
|
|
void WMByteStream::PutDWord( int val ) |
|
{ |
|
uchar *current = m_current; |
|
|
|
if( current+3 < m_end ) |
|
{ |
|
current[0] = (uchar)(val >> 24); |
|
current[1] = (uchar)(val >> 16); |
|
current[2] = (uchar)(val >> 8); |
|
current[3] = (uchar)val; |
|
m_current = current + 4; |
|
if( m_current == m_end ) |
|
WriteBlock(); |
|
} |
|
else |
|
{ |
|
PutByte(val >> 24); |
|
PutByte(val >> 16); |
|
PutByte(val >> 8); |
|
PutByte(val); |
|
} |
|
} |
|
|
|
|
|
|
|
///////////////////////////// WMBitStream /////////////////////////////////// |
|
|
|
WMBitStream::WMBitStream() |
|
{ |
|
m_pad_val = 0; |
|
ResetBuffer(); |
|
} |
|
|
|
|
|
WMBitStream::~WMBitStream() |
|
{ |
|
} |
|
|
|
|
|
bool WMBitStream::Open( const char* filename ) |
|
{ |
|
ResetBuffer(); |
|
return WBaseStream::Open( filename ); |
|
} |
|
|
|
|
|
void WMBitStream::ResetBuffer() |
|
{ |
|
m_val = 0; |
|
m_bit_idx = 32; |
|
m_current = m_start; |
|
} |
|
|
|
void WMBitStream::Flush() |
|
{ |
|
if( m_bit_idx < 32 ) |
|
{ |
|
Put( m_pad_val, m_bit_idx & 7 ); |
|
*((ulong*&)m_current)++ = m_val; |
|
} |
|
} |
|
|
|
|
|
void WMBitStream::Close() |
|
{ |
|
if( m_is_opened ) |
|
{ |
|
Flush(); |
|
WBaseStream::Close(); |
|
} |
|
} |
|
|
|
|
|
void WMBitStream::WriteBlock() |
|
{ |
|
if( !bsIsBigEndian() ) |
|
bsBSwapBlock( m_start, m_current ); |
|
WBaseStream::WriteBlock(); |
|
} |
|
|
|
|
|
int WMBitStream::GetPos() |
|
{ |
|
return WBaseStream::GetPos() + ((32 - m_bit_idx) >> 3); |
|
} |
|
|
|
|
|
void WMBitStream::Put( int val, int bits ) |
|
{ |
|
int bit_idx = m_bit_idx - bits; |
|
ulong curval = m_val; |
|
|
|
assert( 0 <= bits && bits < 32 ); |
|
|
|
val &= bs_bit_mask[bits]; |
|
|
|
if( bit_idx >= 0 ) |
|
{ |
|
curval |= val << bit_idx; |
|
} |
|
else |
|
{ |
|
*((ulong*&)m_current)++ = curval | ((unsigned)val >> -bit_idx); |
|
if( m_current >= m_end ) |
|
{ |
|
WriteBlock(); |
|
} |
|
bit_idx += 32; |
|
curval = val << bit_idx; |
|
} |
|
|
|
m_val = curval; |
|
m_bit_idx = bit_idx; |
|
} |
|
|
|
|
|
void WMBitStream::PutHuff( int val, const ulong* table ) |
|
{ |
|
int min_val = (int)table[0]; |
|
val -= min_val; |
|
|
|
assert( (unsigned)val < table[1] ); |
|
|
|
ulong code = table[val + 2]; |
|
assert( code != 0 ); |
|
|
|
Put( code >> 8, code & 255 ); |
|
} |
|
|
|
|
|
bool bsCreateEncodeHuffmanTable( const int* src, ulong* table, int max_size ) |
|
{ |
|
int i, k; |
|
int min_val = INT_MAX, max_val = INT_MIN; |
|
int size; |
|
|
|
/* calc min and max values in the table */ |
|
for( i = 1, k = 1; src[k] >= 0; i++ ) |
|
{ |
|
int code_count = src[k++]; |
|
|
|
for( code_count += k; k < code_count; k++ ) |
|
{ |
|
int val = src[k] >> huff_val_shift; |
|
if( val < min_val ) |
|
min_val = val; |
|
if( val > max_val ) |
|
max_val = val; |
|
} |
|
} |
|
|
|
size = max_val - min_val + 3; |
|
|
|
if( size > max_size ) |
|
{ |
|
assert(0); |
|
return false; |
|
} |
|
|
|
memset( table, 0, size*sizeof(table[0])); |
|
|
|
table[0] = min_val; |
|
table[1] = size - 2; |
|
|
|
for( i = 1, k = 1; src[k] >= 0; i++ ) |
|
{ |
|
int code_count = src[k++]; |
|
|
|
for( code_count += k; k < code_count; k++ ) |
|
{ |
|
int val = src[k] >> huff_val_shift; |
|
int code = src[k] & huff_code_mask; |
|
|
|
table[val - min_val + 2] = (code << 8) | i; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
|