mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-10 03:40:25 +00:00
120 lines
3.1 KiB
C++
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
|