Initial commit
This commit is contained in:
238
engines/dgds/decompress.cpp
Normal file
238
engines/dgds/decompress.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/util.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "dgds/decompress.h"
|
||||
|
||||
namespace Dgds {
|
||||
|
||||
uint32 RleDecompressor::decompress(byte *dest, uint32 sz, Common::SeekableReadStream &input) {
|
||||
uint32 left = sz;
|
||||
|
||||
uint32 lenR = 0, lenW = 0;
|
||||
while (left > 0 && !input.eos()) {
|
||||
lenR = input.readByte();
|
||||
|
||||
if (lenR == 128) {
|
||||
lenW = 0;
|
||||
} else if (lenR <= 127) {
|
||||
lenW = MIN(lenR, left);
|
||||
for (uint32 j = 0; j < lenW; j++) {
|
||||
*dest++ = input.readByte();
|
||||
}
|
||||
for (; lenR > lenW; lenR--) {
|
||||
input.readByte();
|
||||
}
|
||||
} else {
|
||||
lenW = MIN(lenR & 0x7F, left);
|
||||
byte val = input.readByte();
|
||||
memset(dest, val, lenW);
|
||||
dest += lenW;
|
||||
}
|
||||
|
||||
left -= lenW;
|
||||
}
|
||||
|
||||
return sz - left;
|
||||
}
|
||||
|
||||
LzwDecompressor::LzwDecompressor() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void LzwDecompressor::reset() {
|
||||
memset(&_codeTable, 0, sizeof(_codeTable));
|
||||
|
||||
for (uint32 code = 0; code < 256; code++) {
|
||||
_codeTable[code].len = 1;
|
||||
_codeTable[code].str[0] = code;
|
||||
}
|
||||
|
||||
_tableSize = 0x101;
|
||||
_tableMax = 0x200;
|
||||
_tableFull = false;
|
||||
|
||||
_codeSize = 9;
|
||||
_codeLen = 0;
|
||||
|
||||
_cacheBits = 0;
|
||||
_bitsData = 0;
|
||||
_bitsSize = 0;
|
||||
}
|
||||
|
||||
uint32 LzwDecompressor::decompress(byte *dest, uint32 sz, Common::SeekableReadStream &input) {
|
||||
_bitsData = 0;
|
||||
_bitsSize = 0;
|
||||
|
||||
reset();
|
||||
|
||||
uint32 idx;
|
||||
idx = 0;
|
||||
_cacheBits = 0;
|
||||
|
||||
do {
|
||||
uint32 code;
|
||||
|
||||
code = getCode(_codeSize, input);
|
||||
if (code == 0xFFFFFFFF) break;
|
||||
|
||||
_cacheBits += _codeSize;
|
||||
if (_cacheBits >= _codeSize * 8) {
|
||||
_cacheBits -= _codeSize * 8;
|
||||
}
|
||||
|
||||
if (code == 0x100) {
|
||||
if (_cacheBits > 0)
|
||||
getCode(_codeSize * 8 - _cacheBits, input);
|
||||
reset();
|
||||
} else {
|
||||
if (code >= _tableSize && !_tableFull) {
|
||||
_codeCur[_codeLen++] = _codeCur[0];
|
||||
|
||||
for (uint32 i = 0; i < _codeLen; i++) {
|
||||
if (idx >= sz)
|
||||
break;
|
||||
dest[idx++] = _codeCur[i];
|
||||
}
|
||||
} else {
|
||||
for (uint32 i = 0; i < _codeTable[code].len; i++) {
|
||||
if (idx >= sz)
|
||||
break;
|
||||
dest[idx++] = _codeTable[code].str[i];
|
||||
}
|
||||
|
||||
_codeCur[_codeLen++] = _codeTable[code].str[0];
|
||||
}
|
||||
|
||||
if (_codeLen >= 2) {
|
||||
if (!_tableFull) {
|
||||
uint32 i;
|
||||
|
||||
if (_tableSize == _tableMax && _codeSize == 12) {
|
||||
_tableFull = true;
|
||||
i = _tableSize;
|
||||
} else {
|
||||
i = _tableSize++;
|
||||
_cacheBits = 0;
|
||||
}
|
||||
|
||||
if (_tableSize == _tableMax && _codeSize < 12) {
|
||||
_codeSize++;
|
||||
_tableMax <<= 1;
|
||||
}
|
||||
|
||||
for (uint32 j = 0; j < _codeLen; j++) {
|
||||
_codeTable[i].str[j] = _codeCur[j];
|
||||
_codeTable[i].len++;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < _codeTable[code].len; i++)
|
||||
_codeCur[i] = _codeTable[code].str[i];
|
||||
|
||||
_codeLen = _codeTable[code].len;
|
||||
}
|
||||
}
|
||||
} while (idx < sz);
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
uint32 LzwDecompressor::getCode(uint32 totalBits, Common::SeekableReadStream &input) {
|
||||
const byte bitMasks[9] = {
|
||||
0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF
|
||||
};
|
||||
|
||||
uint32 numBits = totalBits;
|
||||
uint32 useBits = numBits;
|
||||
uint32 result = 0;
|
||||
|
||||
while (numBits > 0) {
|
||||
if (input.pos() >= input.size())
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
if (_bitsSize == 0) {
|
||||
_bitsSize = 8;
|
||||
_bitsData = input.readByte();
|
||||
}
|
||||
|
||||
useBits = numBits;
|
||||
if (useBits > 8)
|
||||
useBits = 8;
|
||||
if (useBits > _bitsSize)
|
||||
useBits = _bitsSize;
|
||||
|
||||
result |= (_bitsData & bitMasks[useBits]) << (totalBits - numBits);
|
||||
|
||||
numBits -= useBits;
|
||||
_bitsSize -= useBits;
|
||||
_bitsData >>= useBits;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Decompressor::Decompressor() {
|
||||
}
|
||||
|
||||
Decompressor::~Decompressor() {
|
||||
}
|
||||
|
||||
byte *Decompressor::decompress(Common::SeekableReadStream *input, int size, uint32 &uncompressedSize) {
|
||||
byte compression = input->readByte();
|
||||
uncompressedSize = input->readUint32LE();
|
||||
byte *data = new byte[uncompressedSize];
|
||||
|
||||
uint32 result = 0;
|
||||
uint32 expectedSize = size;
|
||||
switch (compression) {
|
||||
case 0x00:
|
||||
result = input->read(data, size);
|
||||
break;
|
||||
case 0x01:
|
||||
result = _rleDecompressor.decompress(data, uncompressedSize, *input);
|
||||
expectedSize = uncompressedSize;
|
||||
break;
|
||||
case 0x02:
|
||||
result = _lzwDecompressor.decompress(data, uncompressedSize, *input);
|
||||
expectedSize = uncompressedSize;
|
||||
break;
|
||||
default:
|
||||
input->skip(size);
|
||||
result = size;
|
||||
warning("Unknown chunk compression: 0x%x", compression);
|
||||
break;
|
||||
}
|
||||
|
||||
if (result != expectedSize) {
|
||||
warning("Loading resource with compression type %d - expected %d bytes, got %d",
|
||||
compression, expectedSize, result);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
} // End of namespace Dgds
|
||||
|
||||
Reference in New Issue
Block a user