ScummVM API documentation
bitstream.h
1/* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22// Based on xoreos' BitStream implementation
23
24#ifndef COMMON_BITSTREAM_H
25#define COMMON_BITSTREAM_H
26
27#include "common/scummsys.h"
28#include "common/textconsole.h"
29#include "common/stream.h"
30#include "common/types.h"
31#include "common/util.h"
32
33namespace Common {
34
54template<class STREAM, typename CONTAINER, int valueBits, bool isLE, bool MSB2LSB>
56private:
57 STREAM *_stream;
58 DisposeAfterUse::Flag _disposeAfterUse;
59
60 CONTAINER _bitContainer;
61 uint8 _bitsLeft;
62 uint32 _size;
63 uint32 _pos;
64
66 FORCEINLINE uint32 readData() {
67 if (isLE) {
68 if (valueBits == 8)
69 return _stream->readByte();
70 if (valueBits == 16)
71 return _stream->readUint16LE();
72 if (valueBits == 32)
73 return _stream->readUint32LE();
74 } else {
75 if (valueBits == 8)
76 return _stream->readByte();
77 if (valueBits == 16)
78 return _stream->readUint16BE();
79 if (valueBits == 32)
80 return _stream->readUint32BE();
81 }
82
83 assert(false);
84 return 0;
85 }
86
88 FORCEINLINE void fillContainer(size_t min) {
89 while (_bitsLeft < min) {
90
91 CONTAINER data;
92 if (_pos + _bitsLeft + valueBits <= _size) {
93 data = readData();
94 } else {
95 // Peeking data out of bounds is well-defined and returns 0 bits.
96 // This is for convenience when using speed-up techniques reading
97 // more bits than actually available. Call eos() to check if data
98 // was actually read out of bounds. Peeking out of bounds does not
99 // set the eos flag.
100 data = 0;
101 }
102
103 // Move the data value to the right position in the bit container
104 if (MSB2LSB)
105 _bitContainer |= data << ((sizeof(_bitContainer) * 8) - valueBits - _bitsLeft);
106 else
107 _bitContainer |= data << _bitsLeft;
108
109 _bitsLeft += valueBits;
110 }
111}
112
114 FORCEINLINE static uint32 getNBits(CONTAINER value, size_t n) {
115 if (n == 0)
116 return 0;
117
118 const size_t toShift = (sizeof(value) * 8) - n;
119
120 if (MSB2LSB)
121 return value >> toShift;
122 else
123 return (value << toShift) >> toShift;
124 }
125
127 FORCEINLINE void skipBits(size_t n) {
128 assert(n <= _bitsLeft);
129
130 // Shift to the next bit
131 if (MSB2LSB)
132 _bitContainer <<= n;
133 else
134 _bitContainer >>= n;
135
136 _bitsLeft -= n;
137 _pos += n;
138 }
139
140public:
142 BitStreamImpl(STREAM *stream, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::NO) :
143 _stream(stream), _disposeAfterUse(disposeAfterUse), _bitContainer(0), _bitsLeft(0), _pos(0) {
144
145 if ((valueBits != 8) && (valueBits != 16) && (valueBits != 32))
146 error("BitStreamImpl: Invalid memory layout %d, %d, %d", valueBits, int(isLE), int(MSB2LSB));
147
148 _size = (_stream->size() & ~((uint32) ((valueBits >> 3) - 1))) * 8;
149 }
150
152 BitStreamImpl(STREAM &stream) :
153 _stream(&stream), _disposeAfterUse(DisposeAfterUse::NO), _bitContainer(0), _bitsLeft(0), _pos(0) {
154
155 if ((valueBits != 8) && (valueBits != 16) && (valueBits != 32))
156 error("BitStreamImpl: Invalid memory layout %d, %d, %d", valueBits, int(isLE), int(MSB2LSB));
157
158 _size = (_stream->size() & ~((uint32) ((valueBits >> 3) - 1))) * 8;
159 }
160
162 if (_disposeAfterUse == DisposeAfterUse::YES)
163 delete _stream;
164 }
165
167 uint peekBit() {
168 fillContainer(1);
169
170 return getNBits(_bitContainer, 1);
171 }
172
174 uint getBit() {
175 const uint b = peekBit();
176
177 skipBits(1);
178
179 return b;
180 }
181
187 template<int n>
188 uint32 peekBits() {
189 if (n > 32)
190 error("BitStreamImpl::peekBits(): Too many bits requested to be peeked");
191
192 fillContainer(n);
193 return getNBits(_bitContainer, n);
194 }
195
206 template<int n>
207 uint32 getBits() {
208 if (n > 32)
209 error("BitStreamImpl::getBits(): Too many bits requested to be read");
210
211 const uint32 b = peekBits<n>();
212
213 skipBits(n);
214
215 return b;
216 }
217
223 uint32 peekBits(size_t n) {
224 if (n > 32)
225 error("BitStreamImpl::peekBits(): Too many bits requested to be peeked");
226
227 fillContainer(n);
228 return getNBits(_bitContainer, n);
229 }
230
241 uint32 getBits(size_t n) {
242 if (n > 32)
243 error("BitStreamImpl::getBits(): Too many bits requested to be read");
244
245 const uint32 b = peekBits(n);
246
247 skipBits(n);
248
249 return b;
250 }
251
263 void addBit(uint32 &x, uint32 n) {
264 if (n >= 32)
265 error("BitStreamImpl::addBit(): Too many bits requested to be read");
266
267 if (MSB2LSB)
268 x = (x << 1) | getBit();
269 else
270 x = (x & ~(1 << n)) | (getBit() << n);
271 }
272
274 void rewind() {
275 _stream->seek(0);
276
277 _bitContainer = 0;
278 _bitsLeft = 0;
279 _pos = 0;
280 }
281
283 void skip(uint32 n) {
284 if (n >= _bitsLeft) {
285 n -= _bitsLeft;
286 skipBits(_bitsLeft);
287 }
288
289 while (n > 32) {
290 fillContainer(32);
291 skipBits(32);
292 n -= 32;
293 }
294
295 fillContainer(n);
296 skipBits(n);
297 }
298
300 void align() {
301 uint32 bitsAfterBoundary = _pos % valueBits;
302 if (bitsAfterBoundary) {
303 skip(valueBits - bitsAfterBoundary);
304 }
305 }
306
308 uint32 pos() const {
309 return _pos;
310 }
311
313 uint32 size() const {
314 return _size;
315 }
316
317 bool eos() const {
318 return _stream->eos() || (_pos >= _size);
319 }
320
321 static bool isMSB2LSB() {
322 return MSB2LSB;
323 }
324};
325
326
327
340private:
341 const byte * const _ptrOrig;
342 const byte *_ptr;
343 const uint32 _size;
344 uint32 _pos;
345 DisposeAfterUse::Flag _disposeMemory;
346 bool _eos;
348public:
349 BitStreamMemoryStream(const byte *dataPtr, uint32 dataSize, DisposeAfterUse::Flag disposeMemory = DisposeAfterUse::NO) :
350 _ptrOrig(dataPtr),
351 _ptr(dataPtr),
352 _size(dataSize),
353 _pos(0),
354 _disposeMemory(disposeMemory),
355 _eos(false) {}
356
358 if (_disposeMemory)
359 free(const_cast<byte *>(_ptrOrig));
360 }
361
362 bool eos() const {
363 return _eos;
364 }
365
366 bool err() const {
367 return false;
368 }
369
370 uint32 pos() const {
371 return _pos;
372 }
373
374 uint32 size() const {
375 return _size;
376 }
377
378 bool seek(uint32 offset) {
379 assert(offset <= _size);
380
381 _eos = false;
382 _pos = offset;
383 _ptr = _ptrOrig + _pos;
384 return true;
385 }
386
387 byte readByte() {
388 if (_pos >= _size) {
389 _eos = true;
390 return 0;
391 }
392
393 _pos++;
394 return *_ptr++;
395 }
396
397 uint16 readUint16LE() {
398 if (_pos + 2 > _size) {
399 _eos = true;
400 if (_pos < _size) {
401 _pos++;
402 return *_ptr++;
403 } else {
404 return 0;
405 }
406 }
407
408 uint16 val = READ_LE_UINT16(_ptr);
409
410 _pos += 2;
411 _ptr += 2;
412
413 return val;
414 }
415
416 uint16 readUint16BE() {
417 if (_pos + 2 > _size) {
418 _eos = true;
419 if (_pos < _size) {
420 _pos++;
421 return (*_ptr++) << 8;
422 } else {
423 return 0;
424 }
425 }
426
427 uint16 val = READ_LE_UINT16(_ptr);
428
429 _pos += 2;
430 _ptr += 2;
431
432 return val;
433 }
434
435 uint32 readUint32LE() {
436 if (_pos + 4 > _size) {
437 uint32 val = readByte();
438 val |= (uint32)readByte() << 8;
439 val |= (uint32)readByte() << 16;
440 val |= (uint32)readByte() << 24;
441
442 return val;
443 }
444
445 uint32 val = READ_LE_UINT32(_ptr);
446
447 _pos += 4;
448 _ptr += 4;
449
450 return val;
451 }
452
453 uint32 readUint32BE() {
454 if (_pos + 4 > _size) {
455 uint32 val = (uint32)readByte() << 24;
456 val |= (uint32)readByte() << 16;
457 val |= (uint32)readByte() << 8;
458 val |= (uint32)readByte();
459
460 return val;
461 }
462
463 uint32 val = READ_BE_UINT32(_ptr);
464
465 _pos += 4;
466 _ptr += 4;
467
468 return val;
469 }
470
471};
472
482
491
500
501
502
507
516
525
530} // End of namespace Common
531
532#endif // COMMON_BITSTREAM_H
Definition: bitstream.h:55
void skip(uint32 n)
Definition: bitstream.h:283
uint32 pos() const
Definition: bitstream.h:308
uint peekBit()
Definition: bitstream.h:167
BitStreamImpl(STREAM *stream, DisposeAfterUse::Flag disposeAfterUse=DisposeAfterUse::NO)
Definition: bitstream.h:142
BitStreamImpl(STREAM &stream)
Definition: bitstream.h:152
uint32 size() const
Definition: bitstream.h:313
uint32 getBits()
Definition: bitstream.h:207
uint32 getBits(size_t n)
Definition: bitstream.h:241
uint32 peekBits(size_t n)
Definition: bitstream.h:223
void rewind()
Definition: bitstream.h:274
void align()
Definition: bitstream.h:300
void addBit(uint32 &x, uint32 n)
Definition: bitstream.h:263
uint32 peekBits()
Definition: bitstream.h:188
uint getBit()
Definition: bitstream.h:174
Definition: bitstream.h:339
BitStreamMemoryStream(const byte *dataPtr, uint32 dataSize, DisposeAfterUse::Flag disposeMemory=DisposeAfterUse::NO)
Definition: bitstream.h:349
BitStreamImpl< SeekableReadStream, uint64, 8, false, true > BitStream8MSB
Definition: bitstream.h:479
BitStreamImpl< BitStreamMemoryStream, uint64, 32, true, true > BitStreamMemory32LEMSB
Definition: bitstream.h:518
BitStreamImpl< SeekableReadStream, uint64, 16, false, false > BitStream16BELSB
Definition: bitstream.h:490
BitStreamImpl< SeekableReadStream, uint64, 16, true, true > BitStream16LEMSB
Definition: bitstream.h:484
BitStreamImpl< SeekableReadStream, uint64, 16, true, false > BitStream16LELSB
Definition: bitstream.h:486
BitStreamImpl< SeekableReadStream, uint64, 32, false, false > BitStream32BELSB
Definition: bitstream.h:499
BitStreamImpl< SeekableReadStream, uint64, 16, false, true > BitStream16BEMSB
Definition: bitstream.h:488
BitStreamImpl< BitStreamMemoryStream, uint64, 8, false, true > BitStreamMemory8MSB
Definition: bitstream.h:504
BitStreamImpl< SeekableReadStream, uint64, 32, true, false > BitStream32LELSB
Definition: bitstream.h:495
BitStreamImpl< BitStreamMemoryStream, uint64, 32, false, false > BitStreamMemory32BELSB
Definition: bitstream.h:524
BitStreamImpl< BitStreamMemoryStream, uint64, 32, true, false > BitStreamMemory32LELSB
Definition: bitstream.h:520
BitStreamImpl< SeekableReadStream, uint64, 8, false, false > BitStream8LSB
Definition: bitstream.h:481
BitStreamImpl< BitStreamMemoryStream, uint64, 8, false, false > BitStreamMemory8LSB
Definition: bitstream.h:506
BitStreamImpl< BitStreamMemoryStream, uint64, 16, false, true > BitStreamMemory16BEMSB
Definition: bitstream.h:513
BitStreamImpl< SeekableReadStream, uint64, 32, true, true > BitStream32LEMSB
Definition: bitstream.h:493
BitStreamImpl< BitStreamMemoryStream, uint64, 16, true, false > BitStreamMemory16LELSB
Definition: bitstream.h:511
BitStreamImpl< BitStreamMemoryStream, uint64, 32, false, true > BitStreamMemory32BEMSB
Definition: bitstream.h:522
BitStreamImpl< BitStreamMemoryStream, uint64, 16, true, true > BitStreamMemory16LEMSB
Definition: bitstream.h:509
BitStreamImpl< BitStreamMemoryStream, uint64, 16, false, false > BitStreamMemory16BELSB
Definition: bitstream.h:515
BitStreamImpl< SeekableReadStream, uint64, 32, false, true > BitStream32BEMSB
Definition: bitstream.h:497
void NORETURN_PRE error(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
Definition: algorithm.h:29