1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
5//  By downloading, copying, installing or using the software you agree to this license.
6//  If you do not agree to this license, do not download, install,
7//  copy or use the software.
8//
9//
10//                        Intel License Agreement
11//                For Open Source Computer Vision Library
12//
13// Copyright (C) 2000, Intel Corporation, all rights reserved.
14// Third party copyrights are property of their respective owners.
15//
16// Redistribution and use in source and binary forms, with or without modification,
17// are permitted provided that the following conditions are met:
18//
19//   * Redistribution's of source code must retain the above copyright notice,
20//     this list of conditions and the following disclaimer.
21//
22//   * Redistribution's in binary form must reproduce the above copyright notice,
23//     this list of conditions and the following disclaimer in the documentation
24//     and/or other materials provided with the distribution.
25//
26//   * The name of Intel Corporation may not be used to endorse or promote products
27//     derived from this software without specific prior written permission.
28//
29// This software is provided by the copyright holders and contributors "as is" and
30// any express or implied warranties, including, but not limited to, the implied
31// warranties of merchantability and fitness for a particular purpose are disclaimed.
32// In no event shall the Intel Corporation or contributors be liable for any direct,
33// indirect, incidental, special, exemplary, or consequential damages
34// (including, but not limited to, procurement of substitute goods or services;
35// loss of use, data, or profits; or business interruption) however caused
36// and on any theory of liability, whether in contract, strict liability,
37// or tort (including negligence or otherwise) arising in any way out of
38// the use of this software, even if advised of the possibility of such damage.
39//
40//M*/
41
42#include "_highgui.h"
43#include "bitstrm.h"
44
45#define  BS_DEF_BLOCK_SIZE   (1<<15)
46
47const ulong bs_bit_mask[] = {
48    0,
49    0x00000001, 0x00000003, 0x00000007, 0x0000000F,
50    0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
51    0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
52    0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
53    0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
54    0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
55    0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
56    0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
57};
58
59void bsBSwapBlock( uchar *start, uchar *end )
60{
61    ulong* data = (ulong*)start;
62    int i, size = (int)(end - start+3)/4;
63
64    for( i = 0; i < size; i++ )
65    {
66        ulong temp = data[i];
67        temp = BSWAP( temp );
68        data[i] = temp;
69    }
70}
71
72bool  bsIsBigEndian( void )
73{
74    return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0;
75}
76
77/////////////////////////  RBaseStream ////////////////////////////
78
79bool  RBaseStream::IsOpened()
80{
81    return m_is_opened;
82}
83
84void  RBaseStream::Allocate()
85{
86    if( !m_start )
87    {
88        m_start = new uchar[m_block_size + m_unGetsize];
89        m_start+= m_unGetsize;
90    }
91    m_end = m_start + m_block_size;
92    m_current = m_end;
93}
94
95
96RBaseStream::RBaseStream()
97{
98    m_start = m_end = m_current = 0;
99    m_file = 0;
100    m_block_size = BS_DEF_BLOCK_SIZE;
101    m_unGetsize = 4; // 32 bits
102    m_is_opened = false;
103    m_jmp_set = false;
104}
105
106
107RBaseStream::~RBaseStream()
108{
109    Close();    // Close files
110    Release();  // free  buffers
111}
112
113
114void  RBaseStream::ReadBlock()
115{
116    size_t readed;
117    assert( m_file != 0 );
118
119    // copy unget buffer
120    if( m_start )
121    {
122        memcpy( m_start - m_unGetsize, m_end - m_unGetsize, m_unGetsize );
123    }
124
125    SetPos( GetPos() ); // normalize position
126
127    fseek( m_file, m_block_pos, SEEK_SET );
128    readed = fread( m_start, 1, m_block_size, m_file );
129    m_end = m_start + readed;
130    m_current   -= m_block_size;
131    m_block_pos += m_block_size;
132
133    if( readed == 0 || m_current >= m_end )
134    {
135        if( m_jmp_set )
136            longjmp( m_jmp_buf, RBS_THROW_EOS );
137    }
138}
139
140
141bool  RBaseStream::Open( const char* filename )
142{
143    Close();
144    Allocate();
145
146    m_file = fopen( filename, "rb" );
147
148    if( m_file )
149    {
150        m_is_opened = true;
151        SetPos(0);
152    }
153    return m_file != 0;
154}
155
156void  RBaseStream::Close()
157{
158    if( m_file )
159    {
160        fclose( m_file );
161        m_file = 0;
162    }
163    m_is_opened = false;
164}
165
166
167void  RBaseStream::Release()
168{
169    if( m_start )
170    {
171        delete[] (m_start - m_unGetsize);
172    }
173    m_start = m_end = m_current = 0;
174}
175
176
177void  RBaseStream::SetBlockSize( int block_size, int unGetsize )
178{
179    assert( unGetsize >= 0 && block_size > 0 &&
180           (block_size & (block_size-1)) == 0 );
181
182    if( m_start && block_size == m_block_size && unGetsize == m_unGetsize ) return;
183    Release();
184    m_block_size = block_size;
185    m_unGetsize = unGetsize;
186    Allocate();
187}
188
189
190void  RBaseStream::SetPos( int pos )
191{
192    int offset = pos & (m_block_size - 1);
193    int block_pos = pos - offset;
194
195    assert( IsOpened() && pos >= 0 );
196
197    if( m_current < m_end && block_pos == m_block_pos - m_block_size )
198    {
199        m_current = m_start + offset;
200    }
201    else
202    {
203        m_block_pos = block_pos;
204        m_current = m_start + m_block_size + offset;
205    }
206}
207
208
209int  RBaseStream::GetPos()
210{
211    assert( IsOpened() );
212    return m_block_pos - m_block_size + (int)(m_current - m_start);
213}
214
215void  RBaseStream::Skip( int bytes )
216{
217    assert( bytes >= 0 );
218    m_current += bytes;
219}
220
221jmp_buf& RBaseStream::JmpBuf()
222{
223    m_jmp_set = true;
224    return m_jmp_buf;
225}
226
227/////////////////////////  RLByteStream ////////////////////////////
228
229RLByteStream::~RLByteStream()
230{
231}
232
233int  RLByteStream::GetByte()
234{
235    uchar *current = m_current;
236    int   val;
237
238    if( current >= m_end )
239    {
240        ReadBlock();
241        current = m_current;
242    }
243
244    val = *((uchar*)current);
245    m_current = current + 1;
246    return val;
247}
248
249
250void  RLByteStream::GetBytes( void* buffer, int count, int* readed )
251{
252    uchar*  data = (uchar*)buffer;
253    assert( count >= 0 );
254
255    if( readed) *readed = 0;
256
257    while( count > 0 )
258    {
259        int l;
260
261        for(;;)
262        {
263            l = (int)(m_end - m_current);
264            if( l > count ) l = count;
265            if( l > 0 ) break;
266            ReadBlock();
267        }
268        memcpy( data, m_current, l );
269        m_current += l;
270        data += l;
271        count -= l;
272        if( readed ) *readed += l;
273    }
274}
275
276
277////////////  RLByteStream & RMByteStream <Get[d]word>s ////////////////
278
279RMByteStream::~RMByteStream()
280{
281}
282
283
284int  RLByteStream::GetWord()
285{
286    uchar *current = m_current;
287    int   val;
288
289    if( current+1 < m_end )
290    {
291        val = current[0] + (current[1] << 8);
292        m_current = current + 2;
293    }
294    else
295    {
296        val = GetByte();
297        val|= GetByte() << 8;
298    }
299    return val;
300}
301
302
303int  RLByteStream::GetDWord()
304{
305    uchar *current = m_current;
306    int   val;
307
308    if( current+3 < m_end )
309    {
310        val = current[0] + (current[1] << 8) +
311              (current[2] << 16) + (current[3] << 24);
312        m_current = current + 4;
313    }
314    else
315    {
316        val = GetByte();
317        val |= GetByte() << 8;
318        val |= GetByte() << 16;
319        val |= GetByte() << 24;
320    }
321    return val;
322}
323
324
325int  RMByteStream::GetWord()
326{
327    uchar *current = m_current;
328    int   val;
329
330    if( current+1 < m_end )
331    {
332        val = (current[0] << 8) + current[1];
333        m_current = current + 2;
334    }
335    else
336    {
337        val = GetByte() << 8;
338        val|= GetByte();
339    }
340    return val;
341}
342
343
344int  RMByteStream::GetDWord()
345{
346    uchar *current = m_current;
347    int   val;
348
349    if( current+3 < m_end )
350    {
351        val = (current[0] << 24) + (current[1] << 16) +
352              (current[2] << 8) + current[3];
353        m_current = current + 4;
354    }
355    else
356    {
357        val = GetByte() << 24;
358        val |= GetByte() << 16;
359        val |= GetByte() << 8;
360        val |= GetByte();
361    }
362    return val;
363}
364
365
366/////////////////////////  RLBitStream ////////////////////////////
367
368RLBitStream::~RLBitStream()
369{
370}
371
372
373void  RLBitStream::ReadBlock()
374{
375    RBaseStream::ReadBlock();
376    if( bsIsBigEndian() )
377        bsBSwapBlock( m_start, m_end );
378}
379
380
381void  RLBitStream::SetPos( int pos )
382{
383    RBaseStream::SetPos(pos);
384    int offset = (int)(m_current - m_end);
385    m_current = m_end + (offset & -4);
386    m_bit_idx = (offset&3)*8;
387}
388
389
390int  RLBitStream::GetPos()
391{
392    return RBaseStream::GetPos() + (m_bit_idx >> 3);
393}
394
395
396int  RLBitStream::Get( int bits )
397{
398    int    bit_idx     = m_bit_idx;
399    int    new_bit_idx = bit_idx + bits;
400    int    mask    = new_bit_idx >= 32 ? -1 : 0;
401    ulong* current = (ulong*)m_current;
402
403    assert( (unsigned)bits < 32 );
404
405    if( (m_current = (uchar*)(current - mask)) >= m_end )
406    {
407        ReadBlock();
408        current = ((ulong*)m_current) + mask;
409    }
410    m_bit_idx = new_bit_idx & 31;
411    return ((current[0] >> bit_idx) |
412           ((current[1] <<-bit_idx) & mask)) & bs_bit_mask[bits];
413}
414
415int  RLBitStream::Show( int bits )
416{
417    int    bit_idx = m_bit_idx;
418    int    new_bit_idx = bit_idx + bits;
419    int    mask    = new_bit_idx >= 32 ? -1 : 0;
420    ulong* current = (ulong*)m_current;
421
422    assert( (unsigned)bits < 32 );
423
424    if( (uchar*)(current - mask) >= m_end )
425    {
426        ReadBlock();
427        current = ((ulong*)m_current) + mask;
428        m_current = (uchar*)current;
429    }
430    return ((current[0] >> bit_idx) |
431           ((current[1] <<-bit_idx) & mask)) & bs_bit_mask[bits];
432}
433
434
435void  RLBitStream::Move( int shift )
436{
437    int new_bit_idx = m_bit_idx + shift;
438    m_current += (new_bit_idx >> 5) << 2;
439    m_bit_idx  = new_bit_idx & 31;
440}
441
442
443int  RLBitStream::GetHuff( const short* table )
444{
445    int  val;
446    int  code_bits;
447
448    for(;;)
449    {
450        int table_bits = table[0];
451        val = table[Show(table_bits) + 2];
452        code_bits = val & 15;
453        val >>= 4;
454
455        if( code_bits != 0 ) break;
456        table += val*2;
457        Move( table_bits );
458    }
459
460    Move( code_bits );
461    if( val == RBS_HUFF_FORB )
462    {
463        if( m_jmp_set )
464            longjmp( m_jmp_buf, RBS_THROW_FORB );
465    }
466
467    return val;
468}
469
470void  RLBitStream::Skip( int bytes )
471{
472    Move( bytes*8 );
473}
474
475/////////////////////////  RMBitStream ////////////////////////////
476
477
478RMBitStream::~RMBitStream()
479{
480}
481
482
483void  RMBitStream::ReadBlock()
484{
485    RBaseStream::ReadBlock();
486    if( !bsIsBigEndian() )
487        bsBSwapBlock( m_start, m_end );
488}
489
490
491void  RMBitStream::SetPos( int pos )
492{
493    RBaseStream::SetPos(pos);
494    int offset = (int)(m_current - m_end);
495    m_current = m_end + ((offset - 1) & -4);
496    m_bit_idx = (32 - (offset&3)*8) & 31;
497}
498
499
500int  RMBitStream::GetPos()
501{
502    return RBaseStream::GetPos() + ((32 - m_bit_idx) >> 3);
503}
504
505
506int  RMBitStream::Get( int bits )
507{
508    int    bit_idx = m_bit_idx - bits;
509    int    mask    = bit_idx >> 31;
510    ulong* current = ((ulong*)m_current) - mask;
511
512    assert( (unsigned)bits < 32 );
513
514    if( (m_current = (uchar*)current) >= m_end )
515    {
516        ReadBlock();
517        current = (ulong*)m_current;
518    }
519    m_bit_idx = bit_idx &= 31;
520    return (((current[-1] << -bit_idx) & mask)|
521             (current[0] >> bit_idx)) & bs_bit_mask[bits];
522}
523
524
525int  RMBitStream::Show( int bits )
526{
527    int    bit_idx = m_bit_idx - bits;
528    int    mask    = bit_idx >> 31;
529    ulong* current = ((ulong*)m_current) - mask;
530
531    assert( (unsigned)bits < 32 );
532
533    if( ((uchar*)current) >= m_end )
534    {
535        m_current = (uchar*)current;
536        ReadBlock();
537        current = (ulong*)m_current;
538        m_current -= 4;
539    }
540    return (((current[-1]<<-bit_idx) & mask)|
541             (current[0] >> bit_idx)) & bs_bit_mask[bits];
542}
543
544
545int  RMBitStream::GetHuff( const short* table )
546{
547    int  val;
548    int  code_bits;
549
550    for(;;)
551    {
552        int table_bits = table[0];
553        val = table[Show(table_bits) + 1];
554        code_bits = val & 15;
555        val >>= 4;
556
557        if( code_bits != 0 ) break;
558        table += val;
559        Move( table_bits );
560    }
561
562    Move( code_bits );
563    if( val == RBS_HUFF_FORB )
564    {
565        if( m_jmp_set )
566            longjmp( m_jmp_buf, RBS_THROW_FORB );
567    }
568
569    return val;
570}
571
572
573void  RMBitStream::Move( int shift )
574{
575    int new_bit_idx = m_bit_idx - shift;
576    m_current -= (new_bit_idx >> 5)<<2;
577    m_bit_idx  = new_bit_idx & 31;
578}
579
580
581void  RMBitStream::Skip( int bytes )
582{
583    Move( bytes*8 );
584}
585
586
587static const int huff_val_shift = 20, huff_code_mask = (1 << huff_val_shift) - 1;
588
589bool bsCreateDecodeHuffmanTable( const int* src, short* table, int max_size )
590{
591    const int forbidden_entry = (RBS_HUFF_FORB << 4)|1;
592    int       first_bits = src[0];
593    struct
594    {
595        int bits;
596        int offset;
597    }
598    sub_tables[1 << 11];
599    int  size = (1 << first_bits) + 1;
600    int  i, k;
601
602    /* calc bit depths of sub tables */
603    memset( sub_tables, 0, ((size_t)1 << first_bits)*sizeof(sub_tables[0]) );
604    for( i = 1, k = 1; src[k] >= 0; i++ )
605    {
606        int code_count = src[k++];
607        int sb = i - first_bits;
608
609        if( sb <= 0 )
610            k += code_count;
611        else
612            for( code_count += k; k < code_count; k++ )
613            {
614                int  code = src[k] & huff_code_mask;
615                sub_tables[code >> sb].bits = sb;
616            }
617    }
618
619    /* calc offsets of sub tables and whole size of table */
620    for( i = 0; i < (1 << first_bits); i++ )
621    {
622        int b = sub_tables[i].bits;
623        if( b > 0 )
624        {
625            b = 1 << b;
626            sub_tables[i].offset = size;
627            size += b + 1;
628        }
629    }
630
631    if( size > max_size )
632    {
633        assert(0);
634        return false;
635    }
636
637    /* fill first table and subtables with forbidden values */
638    for( i = 0; i < size; i++ )
639    {
640        table[i] = (short)forbidden_entry;
641    }
642
643    /* write header of first table */
644    table[0] = (short)first_bits;
645
646    /* fill first table and sub tables */
647    for( i = 1, k = 1; src[k] >= 0; i++ )
648    {
649        int code_count = src[k++];
650        for( code_count += k; k < code_count; k++ )
651        {
652            int  table_bits= first_bits;
653            int  code_bits = i;
654            int  code = src[k] & huff_code_mask;
655            int  val  = src[k] >>huff_val_shift;
656            int  j, offset = 0;
657
658            if( code_bits > table_bits )
659            {
660                int idx = code >> (code_bits -= table_bits);
661                code &= (1 << code_bits) - 1;
662                offset   = sub_tables[idx].offset;
663                table_bits= sub_tables[idx].bits;
664                /* write header of subtable */
665                table[offset]  = (short)table_bits;
666                /* write jump to subtable */
667                table[idx + 1]= (short)(offset << 4);
668            }
669
670            table_bits -= code_bits;
671            assert( table_bits >= 0 );
672            val = (val << 4) | code_bits;
673            offset += (code << table_bits) + 1;
674
675            for( j = 0; j < (1 << table_bits); j++ )
676            {
677                assert( table[offset + j] == forbidden_entry );
678                table[ offset + j ] = (short)val;
679            }
680        }
681    }
682    return true;
683}
684
685
686int*  bsCreateSourceHuffmanTable( const uchar* src, int* dst,
687                                  int max_bits, int first_bits )
688{
689    int   i, val_idx, code = 0;
690    int*  table = dst;
691    *dst++ = first_bits;
692    for( i = 1, val_idx = max_bits; i <= max_bits; i++ )
693    {
694        int code_count = src[i - 1];
695        dst[0] = code_count;
696        code <<= 1;
697        for( int k = 0; k < code_count; k++ )
698        {
699            dst[k + 1] = (src[val_idx + k] << huff_val_shift)|(code + k);
700        }
701        code += code_count;
702        dst += code_count + 1;
703        val_idx += code_count;
704    }
705    dst[0] = -1;
706    return  table;
707}
708
709
710/////////////////////////// WBaseStream /////////////////////////////////
711
712// WBaseStream - base class for output streams
713WBaseStream::WBaseStream()
714{
715    m_start = m_end = m_current = 0;
716    m_file = 0;
717    m_block_size = BS_DEF_BLOCK_SIZE;
718    m_is_opened = false;
719}
720
721
722WBaseStream::~WBaseStream()
723{
724    Close();    // Close files
725    Release();  // free  buffers
726}
727
728
729bool  WBaseStream::IsOpened()
730{
731    return m_is_opened;
732}
733
734
735void  WBaseStream::Allocate()
736{
737    if( !m_start )
738        m_start = new uchar[m_block_size];
739
740    m_end = m_start + m_block_size;
741    m_current = m_start;
742}
743
744
745void  WBaseStream::WriteBlock()
746{
747    int size = (int)(m_current - m_start);
748    assert( m_file != 0 );
749
750    //fseek( m_file, m_block_pos, SEEK_SET );
751    fwrite( m_start, 1, size, m_file );
752    m_current = m_start;
753
754    /*if( written < size ) throw RBS_THROW_EOS;*/
755
756    m_block_pos += size;
757}
758
759
760bool  WBaseStream::Open( const char* filename )
761{
762    Close();
763    Allocate();
764
765    m_file = fopen( filename, "wb" );
766
767    if( m_file )
768    {
769        m_is_opened = true;
770        m_block_pos = 0;
771        m_current = m_start;
772    }
773    return m_file != 0;
774}
775
776
777void  WBaseStream::Close()
778{
779    if( m_file )
780    {
781        WriteBlock();
782        fclose( m_file );
783        m_file = 0;
784    }
785    m_is_opened = false;
786}
787
788
789void  WBaseStream::Release()
790{
791    if( m_start )
792    {
793        delete[] m_start;
794    }
795    m_start = m_end = m_current = 0;
796}
797
798
799void  WBaseStream::SetBlockSize( int block_size )
800{
801    assert( block_size > 0 && (block_size & (block_size-1)) == 0 );
802
803    if( m_start && block_size == m_block_size ) return;
804    Release();
805    m_block_size = block_size;
806    Allocate();
807}
808
809
810int  WBaseStream::GetPos()
811{
812    assert( IsOpened() );
813    return m_block_pos + (int)(m_current - m_start);
814}
815
816
817///////////////////////////// WLByteStream ///////////////////////////////////
818
819WLByteStream::~WLByteStream()
820{
821}
822
823void WLByteStream::PutByte( int val )
824{
825    *m_current++ = (uchar)val;
826    if( m_current >= m_end )
827        WriteBlock();
828}
829
830
831void WLByteStream::PutBytes( const void* buffer, int count )
832{
833    uchar* data = (uchar*)buffer;
834
835    assert( data && m_current && count >= 0 );
836
837    while( count )
838    {
839        int l = (int)(m_end - m_current);
840
841        if( l > count )
842            l = count;
843
844        if( l > 0 )
845        {
846            memcpy( m_current, data, l );
847            m_current += l;
848            data += l;
849            count -= l;
850        }
851        if( m_current == m_end )
852            WriteBlock();
853    }
854}
855
856
857void WLByteStream::PutWord( int val )
858{
859    uchar *current = m_current;
860
861    if( current+1 < m_end )
862    {
863        current[0] = (uchar)val;
864        current[1] = (uchar)(val >> 8);
865        m_current = current + 2;
866        if( m_current == m_end )
867            WriteBlock();
868    }
869    else
870    {
871        PutByte(val);
872        PutByte(val >> 8);
873    }
874}
875
876
877void WLByteStream::PutDWord( int val )
878{
879    uchar *current = m_current;
880
881    if( current+3 < m_end )
882    {
883        current[0] = (uchar)val;
884        current[1] = (uchar)(val >> 8);
885        current[2] = (uchar)(val >> 16);
886        current[3] = (uchar)(val >> 24);
887        m_current = current + 4;
888        if( m_current == m_end )
889            WriteBlock();
890    }
891    else
892    {
893        PutByte(val);
894        PutByte(val >> 8);
895        PutByte(val >> 16);
896        PutByte(val >> 24);
897    }
898}
899
900
901///////////////////////////// WMByteStream ///////////////////////////////////
902
903WMByteStream::~WMByteStream()
904{
905}
906
907
908void WMByteStream::PutWord( int val )
909{
910    uchar *current = m_current;
911
912    if( current+1 < m_end )
913    {
914        current[0] = (uchar)(val >> 8);
915        current[1] = (uchar)val;
916        m_current = current + 2;
917        if( m_current == m_end )
918            WriteBlock();
919    }
920    else
921    {
922        PutByte(val >> 8);
923        PutByte(val);
924    }
925}
926
927
928void WMByteStream::PutDWord( int val )
929{
930    uchar *current = m_current;
931
932    if( current+3 < m_end )
933    {
934        current[0] = (uchar)(val >> 24);
935        current[1] = (uchar)(val >> 16);
936        current[2] = (uchar)(val >> 8);
937        current[3] = (uchar)val;
938        m_current = current + 4;
939        if( m_current == m_end )
940            WriteBlock();
941    }
942    else
943    {
944        PutByte(val >> 24);
945        PutByte(val >> 16);
946        PutByte(val >> 8);
947        PutByte(val);
948    }
949}
950
951
952
953///////////////////////////// WMBitStream ///////////////////////////////////
954
955WMBitStream::WMBitStream()
956{
957    m_pad_val = 0;
958    ResetBuffer();
959}
960
961
962WMBitStream::~WMBitStream()
963{
964}
965
966
967bool  WMBitStream::Open( const char* filename )
968{
969    ResetBuffer();
970    return WBaseStream::Open( filename );
971}
972
973
974void  WMBitStream::ResetBuffer()
975{
976    m_val = 0;
977    m_bit_idx = 32;
978    m_current = m_start;
979}
980
981void  WMBitStream::Flush()
982{
983    if( m_bit_idx < 32 )
984    {
985        Put( m_pad_val, m_bit_idx & 7 );
986        *((ulong*&)m_current)++ = m_val;
987    }
988}
989
990
991void  WMBitStream::Close()
992{
993    if( m_is_opened )
994    {
995        Flush();
996        WBaseStream::Close();
997    }
998}
999
1000
1001void  WMBitStream::WriteBlock()
1002{
1003    if( !bsIsBigEndian() )
1004        bsBSwapBlock( m_start, m_current );
1005    WBaseStream::WriteBlock();
1006}
1007
1008
1009int  WMBitStream::GetPos()
1010{
1011    return WBaseStream::GetPos() + ((32 - m_bit_idx) >> 3);
1012}
1013
1014
1015void  WMBitStream::Put( int val, int bits )
1016{
1017    int  bit_idx = m_bit_idx - bits;
1018    ulong  curval = m_val;
1019
1020    assert( 0 <= bits && bits < 32 );
1021
1022    val &= bs_bit_mask[bits];
1023
1024    if( bit_idx >= 0 )
1025    {
1026        curval |= val << bit_idx;
1027    }
1028    else
1029    {
1030        *((ulong*&)m_current)++ = curval | ((unsigned)val >> -bit_idx);
1031        if( m_current >= m_end )
1032        {
1033            WriteBlock();
1034        }
1035        bit_idx += 32;
1036        curval = val << bit_idx;
1037    }
1038
1039    m_val = curval;
1040    m_bit_idx = bit_idx;
1041}
1042
1043
1044void  WMBitStream::PutHuff( int val, const ulong* table )
1045{
1046    int min_val = (int)table[0];
1047    val -= min_val;
1048
1049    assert( (unsigned)val < table[1] );
1050
1051    ulong code = table[val + 2];
1052    assert( code != 0 );
1053
1054    Put( code >> 8, code & 255 );
1055}
1056
1057
1058bool bsCreateEncodeHuffmanTable( const int* src, ulong* table, int max_size )
1059{
1060    int  i, k;
1061    int  min_val = INT_MAX, max_val = INT_MIN;
1062    int  size;
1063
1064    /* calc min and max values in the table */
1065    for( i = 1, k = 1; src[k] >= 0; i++ )
1066    {
1067        int code_count = src[k++];
1068
1069        for( code_count += k; k < code_count; k++ )
1070        {
1071            int  val = src[k] >> huff_val_shift;
1072            if( val < min_val )
1073                min_val = val;
1074            if( val > max_val )
1075                max_val = val;
1076        }
1077    }
1078
1079    size = max_val - min_val + 3;
1080
1081    if( size > max_size )
1082    {
1083        assert(0);
1084        return false;
1085    }
1086
1087    memset( table, 0, size*sizeof(table[0]));
1088
1089    table[0] = min_val;
1090    table[1] = size - 2;
1091
1092    for( i = 1, k = 1; src[k] >= 0; i++ )
1093    {
1094        int code_count = src[k++];
1095
1096        for( code_count += k; k < code_count; k++ )
1097        {
1098            int  val = src[k] >> huff_val_shift;
1099            int  code = src[k] & huff_code_mask;
1100
1101            table[val - min_val + 2] = (code << 8) | i;
1102        }
1103    }
1104    return true;
1105}
1106
1107