mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-26 03:37:53 +00:00
c91a07229a
Our warning() and error() functions always add an exclamation mark to the end of the message anyway. svn-id: r52791
202 lines
4.8 KiB
C++
202 lines
4.8 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 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.
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
/***************************************************************************
|
|
** decomp.c
|
|
**
|
|
** Routines that deal with AGI version 3 specific features.
|
|
** The original LZW code is from DJJ, October 1989, p.86.
|
|
** It has been modified to handle AGI compression.
|
|
**
|
|
** (c) 1997 Lance Ewing
|
|
***************************************************************************/
|
|
|
|
#include "agi/agi.h"
|
|
#include "agi/lzw.h"
|
|
|
|
namespace Agi {
|
|
|
|
|
|
class LZWDecoder {
|
|
private:
|
|
|
|
enum {
|
|
MAXBITS = 12,
|
|
TABLE_SIZE = 18041, // strange number
|
|
START_BITS = 9
|
|
};
|
|
|
|
int32 BITS, MAX_VALUE, MAX_CODE;
|
|
uint32 *prefixCode;
|
|
uint8 *appendCharacter;
|
|
uint8 *decodeStack;
|
|
int32 inputBitCount; // Number of bits in input bit buffer
|
|
uint32 inputBitBuffer;
|
|
|
|
public:
|
|
LZWDecoder();
|
|
~LZWDecoder();
|
|
|
|
void lzwExpand(uint8 *in, uint8 *out, int32 len);
|
|
|
|
private:
|
|
int setBits(int32 value);
|
|
uint8 *decodeString(uint8 *buffer, uint32 code);
|
|
uint32 inputCode(uint8 **input);
|
|
};
|
|
|
|
LZWDecoder::LZWDecoder() {
|
|
decodeStack = (uint8 *)calloc(1, 8192);
|
|
prefixCode = (uint32 *)malloc(TABLE_SIZE * sizeof(uint32));
|
|
appendCharacter = (uint8 *)malloc(TABLE_SIZE * sizeof(uint8));
|
|
inputBitCount = 0; // Number of bits in input bit buffer
|
|
inputBitBuffer = 0L;
|
|
}
|
|
|
|
LZWDecoder::~LZWDecoder() {
|
|
free(decodeStack);
|
|
free(prefixCode);
|
|
free(appendCharacter);
|
|
}
|
|
|
|
/**
|
|
* Adjust the number of bits used to store codes to the value passed in.
|
|
*/
|
|
int LZWDecoder::setBits(int32 value) {
|
|
if (value == MAXBITS)
|
|
return true;
|
|
|
|
BITS = value;
|
|
MAX_VALUE = (1 << BITS) - 1;
|
|
MAX_CODE = MAX_VALUE - 1;
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Return the string that the code taken from the input buffer
|
|
* represents. The string is returned as a stack, i.e. the characters are
|
|
* in reverse order.
|
|
*/
|
|
uint8 *LZWDecoder::decodeString(uint8 *buffer, uint32 code) {
|
|
uint32 i;
|
|
|
|
for (i = 0; code > 255;) {
|
|
*buffer++ = appendCharacter[code];
|
|
code = prefixCode[code];
|
|
if (i++ >= 4000) {
|
|
error("lzw: error in code expansion");
|
|
}
|
|
}
|
|
*buffer = code;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
/**
|
|
* Return the next code from the input buffer.
|
|
*/
|
|
uint32 LZWDecoder::inputCode(uint8 **input) {
|
|
uint32 r;
|
|
|
|
while (inputBitCount <= 24) {
|
|
inputBitBuffer |= (uint32) * (*input)++ << inputBitCount;
|
|
inputBitCount += 8;
|
|
}
|
|
r = (inputBitBuffer & 0x7FFF) % (1 << BITS);
|
|
inputBitBuffer >>= BITS;
|
|
inputBitCount -= BITS;
|
|
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* Uncompress the data contained in the input buffer and store
|
|
* the result in the output buffer. The fileLength parameter says how
|
|
* many bytes to uncompress. The compression itself is a form of LZW that
|
|
* adjusts the number of bits that it represents its codes in as it fills
|
|
* up the available codes. Two codes have special meaning:
|
|
*
|
|
* code 256 = start over
|
|
* code 257 = end of data
|
|
*/
|
|
void LZWDecoder::lzwExpand(uint8 *in, uint8 *out, int32 len) {
|
|
int32 c, lzwnext, lzwnew, lzwold;
|
|
uint8 *s, *end;
|
|
|
|
LZWDecoder d;
|
|
|
|
setBits(START_BITS); // Starts at 9-bits
|
|
lzwnext = 257; // Next available code to define
|
|
|
|
end = (uint8 *)(out + (uint32)len);
|
|
|
|
lzwold = inputCode(&in); // Read in the first code
|
|
c = lzwold;
|
|
lzwnew = inputCode(&in);
|
|
|
|
while ((out < end) && (lzwnew != 0x101)) {
|
|
if (lzwnew == 0x100) {
|
|
// Code to "start over"
|
|
lzwnext = 258;
|
|
setBits(START_BITS);
|
|
lzwold = inputCode(&in);
|
|
c = lzwold;
|
|
*out++ = (char)c;
|
|
lzwnew = inputCode(&in);
|
|
} else {
|
|
if (lzwnew >= lzwnext) {
|
|
// Handles special LZW scenario
|
|
*decodeStack = c;
|
|
s = decodeString(decodeStack + 1, lzwold);
|
|
} else
|
|
s = decodeString(decodeStack, lzwnew);
|
|
|
|
// Reverse order of decoded string and
|
|
// store in out buffer
|
|
c = *s;
|
|
while (s >= decodeStack)
|
|
*out++ = *s--;
|
|
|
|
if (lzwnext > MAX_CODE)
|
|
setBits(BITS + 1);
|
|
|
|
prefixCode[lzwnext] = lzwold;
|
|
appendCharacter[lzwnext] = c;
|
|
lzwnext++;
|
|
lzwold = lzwnew;
|
|
|
|
lzwnew = inputCode(&in);
|
|
}
|
|
}
|
|
}
|
|
|
|
void lzwExpand(uint8 *in, uint8 *out, int32 len) {
|
|
LZWDecoder d;
|
|
d.lzwExpand(in, out, len);
|
|
}
|
|
|
|
} // End of namespace Agi
|