Files
Aerofoil/unpacktool/CompactProLZHDecompressor.cpp
2020-05-09 21:05:58 -04:00

130 lines
2.6 KiB
C++

#include "CompactProLZHDecompressor.h"
#include "CSInputBuffer.h"
#include "PrefixCode.h"
CompactProLZHDecompressor::CompactProLZHDecompressor(int blocksize)
: LZSSDecompressor(8192)
, literalcode(nullptr)
, lengthcode(nullptr)
, offsetcode(nullptr)
, blocksize(blocksize)
, blockcount(0)
, blockstart(0)
{
}
CompactProLZHDecompressor::~CompactProLZHDecompressor()
{
delete literalcode;
delete lengthcode;
delete offsetcode;
}
bool CompactProLZHDecompressor::resetLZSSHandle()
{
blockcount = blocksize;
blockstart = 0;
return true;
}
bool CompactProLZHDecompressor::nextLiteralOrOffset(int *offset, int *length, int &result)
{
if (blockcount >= blocksize)
{
if (blockstart)
{
// Don't let your bad implementations leak into your file formats, people!
if (!CSInputSkipToByteBoundary(input))
return false;
if ((CSInputBufferOffset(input) - blockstart) & 1)
{
if (!CSInputSkipBytes(input, 3))
return false;
}
else
{
if (!CSInputSkipBytes(input, 2))
return false;
}
}
delete literalcode;
delete lengthcode;
delete offsetcode;
literalcode = lengthcode = offsetcode = nullptr;
literalcode = allocAndParseCodeOfSize(256);
if (!literalcode)
return false;
lengthcode = allocAndParseCodeOfSize(64);
if (!lengthcode)
return false;
offsetcode = allocAndParseCodeOfSize(128);
if (!offsetcode)
return false;
blockcount = 0;
blockstart = CSInputBufferOffset(input);
}
unsigned int nextBit;
if (!CSInputNextBit(input, nextBit))
return false;
if (nextBit)
{
blockcount += 2;
return CSInputNextSymbolUsingCode(input, literalcode, result);
}
else
{
blockcount += 3;
if (!CSInputNextSymbolUsingCode(input, lengthcode, *length))
return false;
int offsetSym;
if (!CSInputNextSymbolUsingCode(input, offsetcode, offsetSym))
return false;
unsigned int offsetBits;
if (!CSInputNextBitString(input, 6, offsetBits))
return false;
*offset = offsetSym << 6;
*offset |= offsetBits;
result = XADLZSSMatch;
return true;
}
result = XADLZSSEnd;
return true;
}
XADPrefixCode *CompactProLZHDecompressor::allocAndParseCodeOfSize(int size)
{
int numbytes;
if (!CSInputNextByte(input, numbytes))
return nullptr;
if (numbytes * 2 > size)
return nullptr;
std::vector<int> codelengths;
codelengths.resize(size);
for (int i = 0; i < numbytes; i++)
{
int val;
if (!CSInputNextByte(input, val))
return nullptr;
codelengths[2 * i] = val >> 4;
codelengths[2 * i + 1] = val & 0x0f;
}
for (int i = numbytes * 2; i < size; i++) codelengths[i] = 0;
return XADPrefixCode::prefixCodeWithLengths(codelengths.data(), size, 15, true);
}