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//                           License Agreement
11//                For Open Source Computer Vision Library
12//
13// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15// Third party copyrights are property of their respective owners.
16//
17// Redistribution and use in source and binary forms, with or without modification,
18// are permitted provided that the following conditions are met:
19//
20//   * Redistribution's of source code must retain the above copyright notice,
21//     this list of conditions and the following disclaimer.
22//
23//   * Redistribution's in binary form must reproduce the above copyright notice,
24//     this list of conditions and the following disclaimer in the documentation
25//     and/or other materials provided with the distribution.
26//
27//   * The name of the copyright holders may not be used to endorse or promote products
28//     derived from this software without specific prior written permission.
29//
30// This software is provided by the copyright holders and contributors "as is" and
31// any express or implied warranties, including, but not limited to, the implied
32// warranties of merchantability and fitness for a particular purpose are disclaimed.
33// In no event shall the Intel Corporation or contributors be liable for any direct,
34// indirect, incidental, special, exemplary, or consequential damages
35// (including, but not limited to, procurement of substitute goods or services;
36// loss of use, data, or profits; or business interruption) however caused
37// and on any theory of liability, whether in contract, strict liability,
38// or tort (including negligence or otherwise) arising in any way out of
39// the use of this software, even if advised of the possibility of such damage.
40//
41//M*/
42
43#include "precomp.hpp"
44#include "bitstrm.hpp"
45
46namespace cv
47{
48
49const int BS_DEF_BLOCK_SIZE = 1<<15;
50
51bool  bsIsBigEndian( void )
52{
53    return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0;
54}
55
56/////////////////////////  RBaseStream ////////////////////////////
57
58bool  RBaseStream::isOpened()
59{
60    return m_is_opened;
61}
62
63void  RBaseStream::allocate()
64{
65    if( !m_allocated )
66    {
67        m_start = new uchar[m_block_size];
68        m_end = m_start + m_block_size;
69        m_current = m_end;
70        m_allocated = true;
71    }
72}
73
74
75RBaseStream::RBaseStream()
76{
77    m_start = m_end = m_current = 0;
78    m_file = 0;
79    m_block_size = BS_DEF_BLOCK_SIZE;
80    m_is_opened = false;
81    m_allocated = false;
82}
83
84
85RBaseStream::~RBaseStream()
86{
87    close();    // Close files
88    release();  // free  buffers
89}
90
91
92void  RBaseStream::readBlock()
93{
94    setPos( getPos() ); // normalize position
95
96    if( m_file == 0 )
97    {
98        if( m_block_pos == 0 && m_current < m_end )
99            return;
100        throw RBS_THROW_EOS;
101    }
102
103    fseek( m_file, m_block_pos, SEEK_SET );
104    size_t readed = fread( m_start, 1, m_block_size, m_file );
105    m_end = m_start + readed;
106    m_current = m_start;
107
108    if( readed == 0 || m_current >= m_end )
109        throw RBS_THROW_EOS;
110}
111
112
113bool  RBaseStream::open( const String& filename )
114{
115    close();
116    allocate();
117
118    m_file = fopen( filename.c_str(), "rb" );
119    if( m_file )
120    {
121        m_is_opened = true;
122        setPos(0);
123        readBlock();
124    }
125    return m_file != 0;
126}
127
128bool  RBaseStream::open( const Mat& buf )
129{
130    close();
131    if( buf.empty() )
132        return false;
133    CV_Assert(buf.isContinuous());
134    m_start = buf.data;
135    m_end = m_start + buf.cols*buf.rows*buf.elemSize();
136    m_allocated = false;
137    m_is_opened = true;
138    setPos(0);
139
140    return true;
141}
142
143void  RBaseStream::close()
144{
145    if( m_file )
146    {
147        fclose( m_file );
148        m_file = 0;
149    }
150    m_is_opened = false;
151    if( !m_allocated )
152        m_start = m_end = m_current = 0;
153}
154
155
156void  RBaseStream::release()
157{
158    if( m_allocated )
159        delete[] m_start;
160    m_start = m_end = m_current = 0;
161    m_allocated = false;
162}
163
164
165void  RBaseStream::setPos( int pos )
166{
167    assert( isOpened() && pos >= 0 );
168
169    if( !m_file )
170    {
171        m_current = m_start + pos;
172        m_block_pos = 0;
173        return;
174    }
175
176    int offset = pos % m_block_size;
177    m_block_pos = pos - offset;
178    m_current = m_start + offset;
179}
180
181
182int  RBaseStream::getPos()
183{
184    assert( isOpened() );
185    return m_block_pos + (int)(m_current - m_start);
186}
187
188void  RBaseStream::skip( int bytes )
189{
190    assert( bytes >= 0 );
191    m_current += bytes;
192}
193
194/////////////////////////  RLByteStream ////////////////////////////
195
196RLByteStream::~RLByteStream()
197{
198}
199
200int  RLByteStream::getByte()
201{
202    uchar *current = m_current;
203    int   val;
204
205    if( current >= m_end )
206    {
207        readBlock();
208        current = m_current;
209    }
210
211    val = *((uchar*)current);
212    m_current = current + 1;
213    return val;
214}
215
216
217int RLByteStream::getBytes( void* buffer, int count )
218{
219    uchar*  data = (uchar*)buffer;
220    int readed = 0;
221    assert( count >= 0 );
222
223    while( count > 0 )
224    {
225        int l;
226
227        for(;;)
228        {
229            l = (int)(m_end - m_current);
230            if( l > count ) l = count;
231            if( l > 0 ) break;
232            readBlock();
233        }
234        memcpy( data, m_current, l );
235        m_current += l;
236        data += l;
237        count -= l;
238        readed += l;
239    }
240    return readed;
241}
242
243
244////////////  RLByteStream & RMByteStream <Get[d]word>s ////////////////
245
246RMByteStream::~RMByteStream()
247{
248}
249
250
251int  RLByteStream::getWord()
252{
253    uchar *current = m_current;
254    int   val;
255
256    if( current+1 < m_end )
257    {
258        val = current[0] + (current[1] << 8);
259        m_current = current + 2;
260    }
261    else
262    {
263        val = getByte();
264        val|= getByte() << 8;
265    }
266    return val;
267}
268
269
270int  RLByteStream::getDWord()
271{
272    uchar *current = m_current;
273    int   val;
274
275    if( current+3 < m_end )
276    {
277        val = current[0] + (current[1] << 8) +
278              (current[2] << 16) + (current[3] << 24);
279        m_current = current + 4;
280    }
281    else
282    {
283        val = getByte();
284        val |= getByte() << 8;
285        val |= getByte() << 16;
286        val |= getByte() << 24;
287    }
288    return val;
289}
290
291
292int  RMByteStream::getWord()
293{
294    uchar *current = m_current;
295    int   val;
296
297    if( current+1 < m_end )
298    {
299        val = (current[0] << 8) + current[1];
300        m_current = current + 2;
301    }
302    else
303    {
304        val = getByte() << 8;
305        val|= getByte();
306    }
307    return val;
308}
309
310
311int  RMByteStream::getDWord()
312{
313    uchar *current = m_current;
314    int   val;
315
316    if( current+3 < m_end )
317    {
318        val = (current[0] << 24) + (current[1] << 16) +
319              (current[2] << 8) + current[3];
320        m_current = current + 4;
321    }
322    else
323    {
324        val = getByte() << 24;
325        val |= getByte() << 16;
326        val |= getByte() << 8;
327        val |= getByte();
328    }
329    return val;
330}
331
332/////////////////////////// WBaseStream /////////////////////////////////
333
334// WBaseStream - base class for output streams
335WBaseStream::WBaseStream()
336{
337    m_start = m_end = m_current = 0;
338    m_file = 0;
339    m_block_size = BS_DEF_BLOCK_SIZE;
340    m_is_opened = false;
341    m_buf = 0;
342}
343
344
345WBaseStream::~WBaseStream()
346{
347    close();
348    release();
349}
350
351
352bool  WBaseStream::isOpened()
353{
354    return m_is_opened;
355}
356
357
358void  WBaseStream::allocate()
359{
360    if( !m_start )
361        m_start = new uchar[m_block_size];
362
363    m_end = m_start + m_block_size;
364    m_current = m_start;
365}
366
367
368void  WBaseStream::writeBlock()
369{
370    int size = (int)(m_current - m_start);
371
372    assert( isOpened() );
373    if( size == 0 )
374        return;
375
376    if( m_buf )
377    {
378        size_t sz = m_buf->size();
379        m_buf->resize( sz + size );
380        memcpy( &(*m_buf)[sz], m_start, size );
381    }
382    else
383    {
384        fwrite( m_start, 1, size, m_file );
385    }
386    m_current = m_start;
387    m_block_pos += size;
388}
389
390
391bool  WBaseStream::open( const String& filename )
392{
393    close();
394    allocate();
395
396    m_file = fopen( filename.c_str(), "wb" );
397    if( m_file )
398    {
399        m_is_opened = true;
400        m_block_pos = 0;
401        m_current = m_start;
402    }
403    return m_file != 0;
404}
405
406bool  WBaseStream::open( std::vector<uchar>& buf )
407{
408    close();
409    allocate();
410
411    m_buf = &buf;
412    m_is_opened = true;
413    m_block_pos = 0;
414    m_current = m_start;
415
416    return true;
417}
418
419void  WBaseStream::close()
420{
421    if( m_is_opened )
422        writeBlock();
423    if( m_file )
424    {
425        fclose( m_file );
426        m_file = 0;
427    }
428    m_buf = 0;
429    m_is_opened = false;
430}
431
432
433void  WBaseStream::release()
434{
435    if( m_start )
436        delete[] m_start;
437    m_start = m_end = m_current = 0;
438}
439
440
441int  WBaseStream::getPos()
442{
443    assert( isOpened() );
444    return m_block_pos + (int)(m_current - m_start);
445}
446
447
448///////////////////////////// WLByteStream ///////////////////////////////////
449
450WLByteStream::~WLByteStream()
451{
452}
453
454void WLByteStream::putByte( int val )
455{
456    *m_current++ = (uchar)val;
457    if( m_current >= m_end )
458        writeBlock();
459}
460
461
462void WLByteStream::putBytes( const void* buffer, int count )
463{
464    uchar* data = (uchar*)buffer;
465
466    assert( data && m_current && count >= 0 );
467
468    while( count )
469    {
470        int l = (int)(m_end - m_current);
471
472        if( l > count )
473            l = count;
474
475        if( l > 0 )
476        {
477            memcpy( m_current, data, l );
478            m_current += l;
479            data += l;
480            count -= l;
481        }
482        if( m_current == m_end )
483            writeBlock();
484    }
485}
486
487
488void WLByteStream::putWord( int val )
489{
490    uchar *current = m_current;
491
492    if( current+1 < m_end )
493    {
494        current[0] = (uchar)val;
495        current[1] = (uchar)(val >> 8);
496        m_current = current + 2;
497        if( m_current == m_end )
498            writeBlock();
499    }
500    else
501    {
502        putByte(val);
503        putByte(val >> 8);
504    }
505}
506
507
508void WLByteStream::putDWord( int val )
509{
510    uchar *current = m_current;
511
512    if( current+3 < m_end )
513    {
514        current[0] = (uchar)val;
515        current[1] = (uchar)(val >> 8);
516        current[2] = (uchar)(val >> 16);
517        current[3] = (uchar)(val >> 24);
518        m_current = current + 4;
519        if( m_current == m_end )
520            writeBlock();
521    }
522    else
523    {
524        putByte(val);
525        putByte(val >> 8);
526        putByte(val >> 16);
527        putByte(val >> 24);
528    }
529}
530
531
532///////////////////////////// WMByteStream ///////////////////////////////////
533
534WMByteStream::~WMByteStream()
535{
536}
537
538
539void WMByteStream::putWord( int val )
540{
541    uchar *current = m_current;
542
543    if( current+1 < m_end )
544    {
545        current[0] = (uchar)(val >> 8);
546        current[1] = (uchar)val;
547        m_current = current + 2;
548        if( m_current == m_end )
549            writeBlock();
550    }
551    else
552    {
553        putByte(val >> 8);
554        putByte(val);
555    }
556}
557
558
559void WMByteStream::putDWord( int val )
560{
561    uchar *current = m_current;
562
563    if( current+3 < m_end )
564    {
565        current[0] = (uchar)(val >> 24);
566        current[1] = (uchar)(val >> 16);
567        current[2] = (uchar)(val >> 8);
568        current[3] = (uchar)val;
569        m_current = current + 4;
570        if( m_current == m_end )
571            writeBlock();
572    }
573    else
574    {
575        putByte(val >> 24);
576        putByte(val >> 16);
577        putByte(val >> 8);
578        putByte(val);
579    }
580}
581
582}
583