scummvm/engines/chamber/decompr.cpp
2023-02-19 23:51:30 +01:00

120 lines
3.1 KiB
C++

/* 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 "chamber/chamber.h"
namespace Chamber {
static struct {
byte codes[256];
byte prefix[256];
byte suffix[256];
byte coddict[256];
byte codlink[256];
byte stackpos;
} DecompCtx;
byte decode_string(byte code, byte prev_n, byte *stack) {
byte n;
while ((n = DecompCtx.coddict[code]) != 0) {
while (n >= prev_n) {
n = DecompCtx.codlink[n];
if (n == 0)
return code;
}
/*if(DecompCtx.stackpos == 255) exit("stack exploded");*/
stack[DecompCtx.stackpos++] = prev_n = n;
code = DecompCtx.prefix[n];
}
return code;
}
uint32 decompress(byte *data, byte *result) {
byte dict_size, more;
uint16 compsize;
uint16 i;
byte code, n, suffix;
byte stack[256];
uint32 decompsize = 0;
do {
dict_size = *data++;
more = *data++;
compsize = *data++;
compsize |= (*data++) << 8;
if (dict_size == 0) {
/* uncompressed block */
decompsize += compsize;
while (compsize--)
*result++ = *data++;
} else {
/* compressed block */
/*
memcpy(DecompCtx.codes + 1, data, dict_size); data += dict_size;
memcpy(DecompCtx.prefix + 1, data, dict_size); data += dict_size;
memcpy(DecompCtx.suffix + 1, data, dict_size); data += dict_size;
*/
for (n = 1, i = 0; i < dict_size; n++, i++) DecompCtx.codes[n] = *data++;
for (n = 1, i = 0; i < dict_size; n++, i++) DecompCtx.prefix[n] = *data++;
for (n = 1, i = 0; i < dict_size; n++, i++) DecompCtx.suffix[n] = *data++;
memset(DecompCtx.coddict, 0, 256);
for (n = 1, i = 0; i < dict_size; n++, i++) {
code = DecompCtx.codes[n];
DecompCtx.codlink[n] = DecompCtx.coddict[code];
DecompCtx.coddict[code] = n;
}
while (compsize-- > 0) {
code = *data++;
if (DecompCtx.coddict[code] == 0) {
/* literal */
*result++ = code;
decompsize += 1;
} else {
/* string */
DecompCtx.stackpos = 0;
n = DecompCtx.coddict[code];
stack[DecompCtx.stackpos++] = n;
for (code = DecompCtx.prefix[n];; code = DecompCtx.suffix[n]) {
suffix = decode_string(code, n, stack);
*result++ = suffix;
decompsize += 1;
if (DecompCtx.stackpos == 0)
break;
n = stack[--DecompCtx.stackpos];
}
}
}
}
} while (more != 0);
return decompsize;
}
} // End of namespace Chamber