diff options
author | Eugene Sandulenko | 2011-10-20 09:27:26 -0700 |
---|---|---|
committer | Eugene Sandulenko | 2011-10-20 09:27:26 -0700 |
commit | f5e4d63a77ab83cc50bb0fa1ec4761bc4454688a (patch) | |
tree | 94a06380dc7fa7870f2de3c73c70abcac8c129b8 | |
parent | 1736345906af095c863a62ded2638ce92c2a0704 (diff) | |
parent | c9a59235b202d96aae2f295af7404d1b22e60bcf (diff) | |
download | scummvm-rg350-f5e4d63a77ab83cc50bb0fa1ec4761bc4454688a.tar.gz scummvm-rg350-f5e4d63a77ab83cc50bb0fa1ec4761bc4454688a.tar.bz2 scummvm-rg350-f5e4d63a77ab83cc50bb0fa1ec4761bc4454688a.zip |
Merge pull request #80 from DrMcCoy/newbitstream
COMMON: Rewrite Common::BitStream as a template
-rw-r--r-- | common/bitstream.cpp | 217 | ||||
-rw-r--r-- | common/bitstream.h | 361 | ||||
-rw-r--r-- | common/module.mk | 1 | ||||
-rw-r--r-- | video/bink_decoder.cpp | 20 | ||||
-rw-r--r-- | video/smk_decoder.cpp | 142 |
5 files changed, 290 insertions, 451 deletions
diff --git a/common/bitstream.cpp b/common/bitstream.cpp deleted file mode 100644 index b41ad237e0..0000000000 --- a/common/bitstream.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -// Based on eos' BitStream implementation - -#include "common/bitstream.h" -#include "common/memstream.h" -#include "common/stream.h" -#include "common/textconsole.h" -#include "common/util.h" - -namespace Common { - -BitStream::BitStream() { -} - -BitStream::~BitStream() { -} - -void BitStream::skip(uint32 n) { - while (n-- > 0) - getBit(); -} - - -BitStreamBE::BitStreamBE(SeekableReadStream &stream, uint32 bitCount) : _value(0), _inValue(0) { - if ((bitCount % 8) != 0) - error("Big-endian bit stream size has to be divisible by 8"); - - // Read the number of bytes of the stream - - uint32 byteSize = bitCount / 8; - byte *data = (byte *)malloc(byteSize); - - if (stream.read(data, byteSize) != byteSize) { - free(data); - error("Bad BitStreamBE size"); - } - - _stream = new MemoryReadStream(data, byteSize, DisposeAfterUse::YES); -} - -BitStreamBE::BitStreamBE(const byte *data, uint32 bitCount) : _value(0), _inValue(0) { - if ((bitCount % 8) != 0) - error("Big-endian bit stream size has to be divisible by 8"); - - // Copy the number of bytes from the data array - - uint32 byteSize = bitCount / 8; - byte *dataN = (byte *)malloc(byteSize); - - memcpy(dataN, data, byteSize); - - _stream = new MemoryReadStream(dataN, byteSize, DisposeAfterUse::YES); -} - -BitStreamBE::~BitStreamBE() { - delete _stream; -} - -uint32 BitStreamBE::getBit() { - if (_inValue == 0) { - // Need to get new byte - - if (_stream->eos()) - error("End of bit stream reached"); - - _value = _stream->readByte(); - } - - // Get the current bit - int b = ((_value & 0x80) == 0) ? 0 : 1; - - // Shift to the next bit - _value <<= 1; - - // Increase the position within the current byte - _inValue = (_inValue + 1) % 8; - - return b; -} - -uint32 BitStreamBE::getBits(uint32 n) { - if (n > 32) - error("Too many bits requested to be read"); - - // Read the number of bits - uint32 v = 0; - while (n-- > 0) - v = (v << 1) | getBit(); - - return v; -} - -void BitStreamBE::addBit(uint32 &x, uint32 n) { - x = (x << 1) | getBit(); -} - -uint32 BitStreamBE::pos() const { - if (_stream->pos() == 0) - return 0; - - uint32 p = (_inValue == 0) ? _stream->pos() : (_stream->pos() - 1); - return p * 8 + _inValue; -} - -uint32 BitStreamBE::size() const { - return _stream->size() * 8; -} - - -BitStream32LE::BitStream32LE(SeekableReadStream &stream, uint32 bitCount) : _value(0), _inValue(0) { - if ((bitCount % 32) != 0) - error("32bit little-endian bit stream size has to be divisible by 32"); - - // Read the number of bytes of the stream - - uint32 byteSize = bitCount / 8; - byte *data = (byte *)malloc(byteSize); - - if (stream.read(data, byteSize) != byteSize) { - free(data); - error("Bad BitStream32LE size"); - } - - _stream = new MemoryReadStream(data, byteSize, DisposeAfterUse::YES); -} - -BitStream32LE::BitStream32LE(const byte *data, uint32 bitCount) : _value(0), _inValue(0) { - if ((bitCount % 32) != 0) - error("32bit little-endian bit stream size has to be divisible by 32"); - - // Copy the number of bytes from the data array - - uint32 byteSize = bitCount / 8; - byte *dataN = (byte *)malloc(byteSize); - - memcpy(dataN, data, byteSize); - - _stream = new MemoryReadStream(dataN, byteSize, DisposeAfterUse::YES); -} - -BitStream32LE::~BitStream32LE() { - delete _stream; -} - -uint32 BitStream32LE::getBit() { - if (_inValue == 0) { - // Need to get new 32bit value - - if (_stream->eos()) - error("End of bit stream reached"); - - _value = _stream->readUint32LE(); - } - - // Get the current bit - int b = ((_value & 1) == 0) ? 0 : 1; - - // Shift to the next bit - _value >>= 1; - - // Increase the position within the current byte - _inValue = (_inValue + 1) % 32; - - return b; -} - -uint32 BitStream32LE::getBits(uint32 n) { - if (n > 32) - error("Too many bits requested to be read"); - - // Read the number of bits - uint32 v = 0; - for (uint32 i = 0; i < n; i++) - v = (v >> 1) | (((uint32) getBit()) << 31); - - v >>= (32 - n); - return v; -} - -void BitStream32LE::addBit(uint32 &x, uint32 n) { - x = (x & ~(1 << n)) | (getBit() << n); -} - -uint32 BitStream32LE::pos() const { - if (_stream->pos() == 0) - return 0; - - uint32 p = ((_inValue == 0) ? _stream->pos() : (_stream->pos() - 1)) & 0xFFFFFFFC; - return p * 8 + _inValue; -} - -uint32 BitStream32LE::size() const { - return _stream->size() * 8; -} - -} // End of namespace Common diff --git a/common/bitstream.h b/common/bitstream.h index 7be0dccf45..34063dbfe1 100644 --- a/common/bitstream.h +++ b/common/bitstream.h @@ -26,148 +26,269 @@ #define COMMON_BITSTREAM_H #include "common/scummsys.h" +#include "common/textconsole.h" +#include "common/stream.h" namespace Common { -class SeekableReadStream; - -/** - * A bit stream, giving access to data one bit at a time. - * - * Used in engines: - * - scumm - */ +/** A bit stream. */ class BitStream { public: - BitStream(); - virtual ~BitStream(); + virtual ~BitStream() { + } - /** Read a bit from the bitstream. */ - virtual uint32 getBit() = 0; + /** Return the stream position in bits. */ + virtual uint32 pos() const = 0; - /** Read a number of bits, creating a multi-bit value. */ - virtual uint32 getBits(uint32 n) = 0; + /** Return the stream size in bits. */ + virtual uint32 size() const = 0; - /** Add more bits, creating a multi-bit value in stages. */ - virtual void addBit(uint32 &x, uint32 n) = 0; + /** Has the end of the stream been reached? */ + virtual bool eos() const = 0; - /** Skip a number of bits. */ - void skip(uint32 n); + /** Rewind the bit stream back to the start. */ + virtual void rewind() = 0; - /** Get the current position, in bits. */ - virtual uint32 pos() const = 0; - /** Return the number of bits in the stream. */ - virtual uint32 size() const = 0; -}; + /** Skip the specified amount of bits. */ + virtual void skip(uint32 n) = 0; -/** - * A big-endian bit stream. - * - * The input data is read one byte at a time. Their bits are handed out - * in the order of MSB to LSB. When all 8 bits of a byte have been consumed, - * another input data byte is read. - */ -class BitStreamBE : public BitStream { -public: - /** - * Create a big endian bit stream. - * - * Reads and copies bitCount bits from the provided stream. - * Ownership of the stream is not transferred. - */ - BitStreamBE(SeekableReadStream &stream, uint32 bitCount); - - /** - * Create a big endian bit stream. - * - * Reads and copies bitCount bits from the provided data. - * Ownership of the data is not transferred. - */ - BitStreamBE(const byte *data, uint32 bitCount); - - ~BitStreamBE(); - - uint32 getBit(); - - /** - * Read a number of bits, creating a multi-bit value. - * - * The bits are read one at a time, in the order MSB to LSB and - * or'd together to create a multi-bit value. - */ - uint32 getBits(uint32 n); - - /** - * Add more bits, creating a multi-bit value in stages. - * - * Shifts in n new bits into the value x, in the order of MSB to LSB. - */ - void addBit(uint32 &x, uint32 n); - - uint32 pos() const; - uint32 size() const; + /** Read a bit from the bit stream. */ + virtual uint32 getBit() = 0; -private: - SeekableReadStream *_stream; + /** Read a multi-bit value from the bit stream. */ + virtual uint32 getBits(uint8 n) = 0; + + /** Read a bit from the bit stream, without changing the stream's position. */ + virtual uint32 peekBit() = 0; + + /** Read a multi-bit value from the bit stream, without changing the stream's position. */ + virtual uint32 peekBits(uint8 n) = 0; + + /** Add a bit to the value x, making it an n-bit value. */ + virtual void addBit(uint32 &x, uint32 n) = 0; - byte _value; ///< Current byte. - uint8 _inValue; ///< Position within the current byte. +protected: + BitStream() { + } }; /** - * A little-endian bit stream, reading 32bit values at a time. + * A template implementing a bit stream for different data memory layouts. + * + * Such a bit stream reads valueBits-wide values from the data stream and + * gives * access to their bits, one at a time. * - * The input data is read one little-endian uint32 at a time. Their bits are - * handed out in the order of LSB to MSB. When all 8 bits of a byte have been - * consumed, another little-endian input data uint32 is read. + * For example, a bit stream with the layout parameters 32, true, false + * for valueBits, isLE and isMSB2LSB, reads 32bit little-endian values + * from the data stream and hands out the bits in the order of LSB to MSB. */ -class BitStream32LE : public BitStream { -public: - /** - * Create a little-endian bit stream. - * - * Reads and copies bitCount bits from the provided stream. - * Ownership of the stream is not transferred. - */ - BitStream32LE(SeekableReadStream &stream, uint32 bitCount); - - /** - * Create a little-endian bit stream. - * - * Reads and copies bitCount bits from the provided data. - * Ownership of the data is not transferred. - */ - BitStream32LE(const byte *data, uint32 bitCount); - - ~BitStream32LE(); - - uint32 getBit(); - - /** - * Read a number of bits, creating a multi-bit value. - * - * The bits are read one at a time, in the order LSB to MSB and - * or'd together to create a multi-bit value. - */ - uint32 getBits(uint32 n); - - /** - * Add more bits, creating a multi-bit value in stages. - * - * Shifts in n new bits into the value x, in the order of LSB to MSB. - */ - void addBit(uint32 &x, uint32 n); - - uint32 pos() const; - uint32 size() const; - +template<int valueBits, bool isLE, bool isMSB2LSB> +class BitStreamImpl : public BitStream { private: - SeekableReadStream *_stream; + SeekableReadStream *_stream; ///< The input stream. + bool _disposeAfterUse; ///< Should we delete the stream on destruction? + + uint32 _value; ///< Current value. + uint8 _inValue; ///< Position within the current value. + + /** Read a data value. */ + inline uint32 readData() { + if (isLE) { + if (valueBits == 8) + return _stream->readByte(); + if (valueBits == 16) + return _stream->readUint16LE(); + if (valueBits == 32) + return _stream->readUint32LE(); + } else { + if (valueBits == 8) + return _stream->readByte(); + if (valueBits == 16) + return _stream->readUint16BE(); + if (valueBits == 32) + return _stream->readUint32BE(); + } + + assert(false); + return 0; + } + + /** Read the next data value. */ + inline void readValue() { + if ((size() - pos()) < valueBits) + error("BitStreamImpl::readValue(): End of bit stream reached"); + + _value = readData(); + if (_stream->err() || _stream->eos()) + error("BitStreamImpl::readValue(): Read error"); + + // If we're reading the bits MSB first, we need to shift the value to that position + if (isMSB2LSB) + _value <<= 32 - valueBits; + } - uint32 _value; ///< Current 32bit value. - uint8 _inValue; ///< Position within the current 32bit value. +public: + /** Create a bit stream using this input data stream and optionally delete it on destruction. */ + BitStreamImpl(SeekableReadStream *stream, bool disposeAfterUse = false) : + _stream(stream), _disposeAfterUse(disposeAfterUse), _value(0), _inValue(0) { + + if ((valueBits != 8) && (valueBits != 16) && (valueBits != 32)) + error("BitStreamImpl: Invalid memory layout %d, %d, %d", valueBits, isLE, isMSB2LSB); + } + + /** Create a bit stream using this input data stream. */ + BitStreamImpl(SeekableReadStream &stream) : + _stream(&stream), _disposeAfterUse(false), _value(0), _inValue(0) { + + if ((valueBits != 8) && (valueBits != 16) && (valueBits != 32)) + error("BitStreamImpl: Invalid memory layout %d, %d, %d", valueBits, isLE, isMSB2LSB); + } + + ~BitStreamImpl() { + if (_disposeAfterUse) + delete _stream; + } + + /** Read a bit from the bit stream. */ + uint32 getBit() { + // Check if we need the next value + if (_inValue == 0) + readValue(); + + // Get the current bit + int b = 0; + if (isMSB2LSB) + b = ((_value & 0x80000000) == 0) ? 0 : 1; + else + b = ((_value & 1) == 0) ? 0 : 1; + + // Shift to the next bit + if (isMSB2LSB) + _value <<= 1; + else + _value >>= 1; + + // Increase the position within the current value + _inValue = (_inValue + 1) % valueBits; + + return b; + } + + /** Read a multi-bit value from the bit stream. */ + uint32 getBits(uint8 n) { + if (n > 32) + error("BitStreamImpl::getBits(): Too many bits requested to be read"); + + // Read the number of bits + uint32 v = 0; + + if (isMSB2LSB) { + while (n-- > 0) + v = (v << 1) | getBit(); + } else { + for (uint32 i = 0; i < n; i++) + v = (v >> 1) | (((uint32) getBit()) << 31); + + v >>= (32 - n); + } + + return v; + } + + uint32 peekBit() { + uint32 value = _value; + uint8 inValue = _inValue; + uint32 curPos = _stream->pos(); + + uint32 v = getBit(); + + _stream->seek(curPos); + _inValue = inValue; + _value = value; + + return v; + } + + uint32 peekBits(uint8 n) { + uint32 value = _value; + uint8 inValue = _inValue; + uint32 curPos = _stream->pos(); + + uint32 v = getBits(n); + + _stream->seek(curPos); + _inValue = inValue; + _value = value; + + return v; + } + + /** Add a bit to the value x, making it an n-bit value. */ + void addBit(uint32 &x, uint32 n) { + if (isMSB2LSB) + x = (x << 1) | getBit(); + else + x = (x & ~(1 << n)) | (getBit() << n); + } + + /** Rewind the bit stream back to the start. */ + void rewind() { + _stream->seek(0); + + _value = 0; + _inValue = 0; + } + + /** Skip the specified amount of bits. */ + void skip(uint32 n) { + while (n-- > 0) + getBit(); + } + + /** Return the stream position in bits. */ + uint32 pos() const { + if (_stream->pos() == 0) + return 0; + + uint32 p = (_inValue == 0) ? _stream->pos() : ((_stream->pos() - 1) & ~((uint32) ((valueBits >> 3) - 1))); + return p * 8 + _inValue; + } + + /** Return the stream size in bits. */ + uint32 size() const { + return (_stream->size() & ~((uint32) ((valueBits >> 3) - 1))) * 8; + } + + bool eos() const { + return _stream->eos() || (pos() >= size()); + } }; +// typedefs for various memory layouts. + +/** 8-bit data, MSB to LSB. */ +typedef BitStreamImpl<8, false, true > BitStream8MSB; +/** 8-bit data, LSB to MSB. */ +typedef BitStreamImpl<8, false, false> BitStream8LSB; + +/** 16-bit little-endian data, MSB to LSB. */ +typedef BitStreamImpl<16, true , true > BitStream16LEMSB; +/** 16-bit little-endian data, LSB to MSB. */ +typedef BitStreamImpl<16, true , false> BitStream16LELSB; +/** 16-bit big-endian data, MSB to LSB. */ +typedef BitStreamImpl<16, false, true > BitStream16BEMSB; +/** 16-bit big-endian data, LSB to MSB. */ +typedef BitStreamImpl<16, false, false> BitStream16BELSB; + +/** 32-bit little-endian data, MSB to LSB. */ +typedef BitStreamImpl<32, true , true > BitStream32LEMSB; +/** 32-bit little-endian data, LSB to MSB. */ +typedef BitStreamImpl<32, true , false> BitStream32LELSB; +/** 32-bit big-endian data, MSB to LSB. */ +typedef BitStreamImpl<32, false, true > BitStream32BEMSB; +/** 32-bit big-endian data, LSB to MSB. */ +typedef BitStreamImpl<32, false, false> BitStream32BELSB; + } // End of namespace Common #endif // COMMON_BITSTREAM_H diff --git a/common/module.mk b/common/module.mk index b55c11637a..7434df7052 100644 --- a/common/module.mk +++ b/common/module.mk @@ -38,7 +38,6 @@ MODULE_OBJS := \ ifdef USE_BINK MODULE_OBJS += \ - bitstream.o \ cosinetables.o \ dct.o \ fft.o \ diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp index a08c93522b..46ac8ac386 100644 --- a/video/bink_decoder.cpp +++ b/video/bink_decoder.cpp @@ -30,6 +30,7 @@ #include "common/textconsole.h" #include "common/math.h" #include "common/stream.h" +#include "common/substream.h" #include "common/file.h" #include "common/str.h" #include "common/bitstream.h" @@ -199,28 +200,37 @@ const Graphics::Surface *BinkDecoder::decodeNextFrame() { error("Audio packet too big for the frame"); if (audioPacketLength >= 4) { + uint32 audioPacketStart = _bink->pos(); + uint32 audioPacketEnd = _bink->pos() + audioPacketLength; + if (i == _audioTrack) { // Only play one audio track // Number of samples in bytes audio.sampleCount = _bink->readUint32LE() / (2 * audio.channels); - audio.bits = new Common::BitStream32LE(*_bink, (audioPacketLength - 4) * 8); + audio.bits = + new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, + audioPacketStart + 4, audioPacketEnd), true); audioPacket(audio); delete audio.bits; audio.bits = 0; + } - } else - // Skip the rest - _bink->skip(audioPacketLength); + _bink->seek(audioPacketEnd); frameSize -= audioPacketLength; } } - frame.bits = new Common::BitStream32LE(*_bink, frameSize * 8); + uint32 videoPacketStart = _bink->pos(); + uint32 videoPacketEnd = _bink->pos() + frameSize; + + frame.bits = + new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, + videoPacketStart, videoPacketEnd), true); videoPacket(frame); diff --git a/video/smk_decoder.cpp b/video/smk_decoder.cpp index dce80eda2c..e0e771f04b 100644 --- a/video/smk_decoder.cpp +++ b/video/smk_decoder.cpp @@ -29,6 +29,8 @@ #include "common/endian.h" #include "common/util.h" #include "common/stream.h" +#include "common/memstream.h" +#include "common/bitstream.h" #include "common/system.h" #include "common/textconsole.h" @@ -46,85 +48,15 @@ enum SmkBlockTypes { }; /* - * class BitStream - * Little-endian bit stream provider. - */ - -class BitStream { -public: - BitStream(byte *buf, uint32 length) - : _buf(buf), _end(buf+length), _bitCount(8) { - _curByte = *_buf++; - } - - bool getBit(); - byte getBits8(); - - byte peek8() const; - void skip(int n); - -private: - byte *_buf; - byte *_end; - byte _curByte; - byte _bitCount; -}; - -bool BitStream::getBit() { - if (_bitCount == 0) { - assert(_buf < _end); - _curByte = *_buf++; - _bitCount = 8; - } - - bool v = _curByte & 1; - - _curByte >>= 1; - --_bitCount; - - return v; -} - -byte BitStream::getBits8() { - assert(_buf < _end); - - byte v = (*_buf << _bitCount) | _curByte; - _curByte = *_buf++ >> (8 - _bitCount); - - return v; -} - -byte BitStream::peek8() const { - if (_buf == _end) - return _curByte; - - assert(_buf < _end); - return (*_buf << _bitCount) | _curByte; -} - -void BitStream::skip(int n) { - assert(n <= 8); - _curByte >>= n; - - if (_bitCount >= n) { - _bitCount -= n; - } else { - assert(_buf < _end); - _bitCount = _bitCount + 8 - n; - _curByte = *_buf++ >> (8 - _bitCount); - } -} - -/* * class SmallHuffmanTree * A Huffman-tree to hold 8-bit values. */ class SmallHuffmanTree { public: - SmallHuffmanTree(BitStream &bs); + SmallHuffmanTree(Common::BitStream &bs); - uint16 getCode(BitStream &bs); + uint16 getCode(Common::BitStream &bs); private: enum { SMK_NODE = 0x8000 @@ -138,10 +70,10 @@ private: uint16 _prefixtree[256]; byte _prefixlength[256]; - BitStream &_bs; + Common::BitStream &_bs; }; -SmallHuffmanTree::SmallHuffmanTree(BitStream &bs) +SmallHuffmanTree::SmallHuffmanTree(Common::BitStream &bs) : _treeSize(0), _bs(bs) { uint32 bit = _bs.getBit(); assert(bit); @@ -157,7 +89,7 @@ SmallHuffmanTree::SmallHuffmanTree(BitStream &bs) uint16 SmallHuffmanTree::decodeTree(uint32 prefix, int length) { if (!_bs.getBit()) { // Leaf - _tree[_treeSize] = _bs.getBits8(); + _tree[_treeSize] = _bs.getBits(8); if (length <= 8) { for (int i = 0; i < 256; i += (1 << length)) { @@ -186,8 +118,8 @@ uint16 SmallHuffmanTree::decodeTree(uint32 prefix, int length) { return r1+r2+1; } -uint16 SmallHuffmanTree::getCode(BitStream &bs) { - byte peek = bs.peek8(); +uint16 SmallHuffmanTree::getCode(Common::BitStream &bs) { + byte peek = bs.peekBits(8); uint16 *p = &_tree[_prefixtree[peek]]; bs.skip(_prefixlength[peek]); @@ -207,11 +139,11 @@ uint16 SmallHuffmanTree::getCode(BitStream &bs) { class BigHuffmanTree { public: - BigHuffmanTree(BitStream &bs, int allocSize); + BigHuffmanTree(Common::BitStream &bs, int allocSize); ~BigHuffmanTree(); void reset(); - uint32 getCode(BitStream &bs); + uint32 getCode(Common::BitStream &bs); private: enum { SMK_NODE = 0x80000000 @@ -227,13 +159,13 @@ private: byte _prefixlength[256]; /* Used during construction */ - BitStream &_bs; + Common::BitStream &_bs; uint32 _markers[3]; SmallHuffmanTree *_loBytes; SmallHuffmanTree *_hiBytes; }; -BigHuffmanTree::BigHuffmanTree(BitStream &bs, int allocSize) +BigHuffmanTree::BigHuffmanTree(Common::BitStream &bs, int allocSize) : _bs(bs) { uint32 bit = _bs.getBit(); if (!bit) { @@ -249,12 +181,9 @@ BigHuffmanTree::BigHuffmanTree(BitStream &bs, int allocSize) _loBytes = new SmallHuffmanTree(_bs); _hiBytes = new SmallHuffmanTree(_bs); - _markers[0] = _bs.getBits8(); - _markers[0] |= (_bs.getBits8() << 8); - _markers[1] = _bs.getBits8(); - _markers[1] |= (_bs.getBits8() << 8); - _markers[2] = _bs.getBits8(); - _markers[2] |= (_bs.getBits8() << 8); + _markers[0] = _bs.getBits(16); + _markers[1] = _bs.getBits(16); + _markers[2] = _bs.getBits(16); _last[0] = _last[1] = _last[2] = 0xffffffff; @@ -328,8 +257,8 @@ uint32 BigHuffmanTree::decodeTree(uint32 prefix, int length) { return r1+r2+1; } -uint32 BigHuffmanTree::getCode(BitStream &bs) { - byte peek = bs.peek8(); +uint32 BigHuffmanTree::getCode(Common::BitStream &bs) { + byte peek = bs.peekBits(8); uint32 *p = &_tree[_prefixtree[peek]]; bs.skip(_prefixlength[peek]); @@ -459,18 +388,16 @@ bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { for (i = 0; i < _frameCount; ++i) _frameTypes[i] = _fileStream->readByte(); - byte *huffmanTrees = new byte[_header.treesSize]; + byte *huffmanTrees = (byte *) malloc(_header.treesSize); _fileStream->read(huffmanTrees, _header.treesSize); - BitStream bs(huffmanTrees, _header.treesSize); + Common::BitStream8LSB bs(new Common::MemoryReadStream(huffmanTrees, _header.treesSize, DisposeAfterUse::YES), true); _MMapTree = new BigHuffmanTree(bs, _header.mMapSize); _MClrTree = new BigHuffmanTree(bs, _header.mClrSize); _FullTree = new BigHuffmanTree(bs, _header.fullSize); _TypeTree = new BigHuffmanTree(bs, _header.typeSize); - delete[] huffmanTrees; - _surface = new Graphics::Surface(); // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled) @@ -556,10 +483,13 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { uint32 frameDataSize = frameSize - (_fileStream->pos() - startPos); - _frameData = (byte *)malloc(frameDataSize); + _frameData = (byte *)malloc(frameDataSize + 1); + // Padding to keep the BigHuffmanTrees from reading past the data end + _frameData[frameDataSize] = 0x00; + _fileStream->read(_frameData, frameDataSize); - BitStream bs(_frameData, frameDataSize); + Common::BitStream8LSB bs(new Common::MemoryReadStream(_frameData, frameDataSize + 1, DisposeAfterUse::YES), true); _MMapTree->reset(); _MClrTree->reset(); @@ -701,8 +631,6 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { _fileStream->seek(startPos + frameSize); - free(_frameData); - if (_curFrame == 0) _startTime = g_system->getMillis(); @@ -712,7 +640,9 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) { if (_header.audioInfo[track].hasAudio && chunkSize > 0 && track == 0) { // If it's track 0, play the audio data - byte *soundBuffer = (byte *)malloc(chunkSize); + byte *soundBuffer = (byte *)malloc(chunkSize + 1); + // Padding to keep the SmallHuffmanTrees from reading past the data end + soundBuffer[chunkSize] = 0x00; _fileStream->read(soundBuffer, chunkSize); @@ -722,7 +652,7 @@ void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpac return; } else if (_header.audioInfo[track].compression == kCompressionDPCM) { // Compressed audio (Huffman DPCM encoded) - queueCompressedBuffer(soundBuffer, chunkSize, unpackedSize, track); + queueCompressedBuffer(soundBuffer, chunkSize + 1, unpackedSize, track); free(soundBuffer); } else { // Uncompressed audio (PCM) @@ -752,7 +682,7 @@ void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpac void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize, int streamNum) { - BitStream audioBS(buffer, bufferSize); + Common::BitStream8LSB audioBS(new Common::MemoryReadStream(buffer, bufferSize), true); bool dataPresent = audioBS.getBit(); if (!dataPresent) @@ -779,20 +709,16 @@ void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize, if (isStereo) { if (is16Bits) { - byte hi = audioBS.getBits8(); - byte lo = audioBS.getBits8(); - bases[1] = (int16) ((hi << 8) | lo); + bases[1] = FROM_BE_16(audioBS.getBits(16)); } else { - bases[1] = audioBS.getBits8(); + bases[1] = audioBS.getBits(8); } } if (is16Bits) { - byte hi = audioBS.getBits8(); - byte lo = audioBS.getBits8(); - bases[0] = (int16) ((hi << 8) | lo); + bases[0] = FROM_BE_16(audioBS.getBits(16)); } else { - bases[0] = audioBS.getBits8(); + bases[0] = audioBS.getBits(8); } // The bases are the first samples, too |