mirror of
https://github.com/whoahq/whoa.git
synced 2026-02-01 00:02:45 +03:00
feat: introduce MPQ decompression utilities including PKWARE, ADPCM, and Huffman algorithms
This commit is contained in:
parent
a3d69ff2e7
commit
c82c9da821
@ -1,5 +1,7 @@
|
||||
file(GLOB PRIVATE_SOURCES
|
||||
"*.cpp"
|
||||
"mpq/*.cpp"
|
||||
"mpq/*.c"
|
||||
)
|
||||
|
||||
if(WHOA_SYSTEM_MAC)
|
||||
@ -19,6 +21,7 @@ add_library(util STATIC
|
||||
target_include_directories(util
|
||||
PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_SOURCE_DIR}/src/util/mpq
|
||||
${ZLIB_INCLUDE_DIRS}
|
||||
${BZIP2_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#include "util/Mpq.hpp"
|
||||
#include <bzlib.h>
|
||||
#include <zlib.h>
|
||||
#include "util/mpq/Decompress.hpp"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
@ -18,9 +17,6 @@ namespace {
|
||||
constexpr uint32_t MPQ_FILE_ENCRYPTED = 0x00010000;
|
||||
constexpr uint32_t MPQ_FILE_SINGLE_UNIT = 0x01000000;
|
||||
|
||||
constexpr uint8_t MPQ_COMP_ZLIB = 0x02;
|
||||
constexpr uint8_t MPQ_COMP_BZIP2 = 0x08;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct MpqUserDataHeader {
|
||||
uint32_t id;
|
||||
@ -146,62 +142,6 @@ namespace {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DecompressZlib(const uint8_t* in, size_t inSize, uint8_t* out, size_t outSize) {
|
||||
uLongf destLen = static_cast<uLongf>(outSize);
|
||||
int result = uncompress(out, &destLen, in, static_cast<uLongf>(inSize));
|
||||
return result == Z_OK && destLen == outSize;
|
||||
}
|
||||
|
||||
bool DecompressBzip2(const uint8_t* in, size_t inSize, uint8_t* out, size_t outSize) {
|
||||
unsigned int destLen = static_cast<unsigned int>(outSize);
|
||||
int result = BZ2_bzBuffToBuffDecompress(
|
||||
reinterpret_cast<char*>(out),
|
||||
&destLen,
|
||||
const_cast<char*>(reinterpret_cast<const char*>(in)),
|
||||
static_cast<unsigned int>(inSize),
|
||||
0,
|
||||
0
|
||||
);
|
||||
return result == BZ_OK && destLen == outSize;
|
||||
}
|
||||
|
||||
bool DecompressBlock(const uint8_t* in, size_t inSize, uint8_t* out, size_t outSize) {
|
||||
if (inSize == outSize) {
|
||||
std::memcpy(out, in, outSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inSize == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t type = in[0];
|
||||
const uint8_t* payload = in + 1;
|
||||
size_t payloadSize = inSize - 1;
|
||||
|
||||
if (type == 0) {
|
||||
if (payloadSize != outSize) {
|
||||
return false;
|
||||
}
|
||||
std::memcpy(out, payload, outSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((type & (type - 1)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == MPQ_COMP_ZLIB) {
|
||||
return DecompressZlib(payload, payloadSize, out, outSize);
|
||||
}
|
||||
|
||||
if (type == MPQ_COMP_BZIP2) {
|
||||
return DecompressBzip2(payload, payloadSize, out, outSize);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct MpqArchive {
|
||||
std::ifstream stream;
|
||||
uint64_t baseOffset = 0;
|
||||
@ -345,7 +285,7 @@ namespace {
|
||||
}
|
||||
|
||||
if (block->flags & MPQ_FILE_COMPRESSED) {
|
||||
if (!DecompressBlock(raw.data(), raw.size(), buffer.data(), buffer.size())) {
|
||||
if (!MpqCompression::DecompressBlock(raw.data(), raw.size(), buffer.data(), buffer.size())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@ -390,7 +330,7 @@ namespace {
|
||||
}
|
||||
|
||||
uint8_t* outPtr = buffer.data() + i * sectorSize;
|
||||
if (!DecompressBlock(raw.data(), raw.size(), outPtr, outSize)) {
|
||||
if (!MpqCompression::DecompressBlock(raw.data(), raw.size(), outPtr, outSize)) {
|
||||
if (raw.size() == outSize) {
|
||||
std::memcpy(outPtr, raw.data(), outSize);
|
||||
} else {
|
||||
|
||||
247
src/util/mpq/Decompress.cpp
Normal file
247
src/util/mpq/Decompress.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
#include "util/mpq/Decompress.hpp"
|
||||
|
||||
#include <bzlib.h>
|
||||
#include <zlib.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include "adpcm.h"
|
||||
#include "huff.h"
|
||||
#include "pklib.h"
|
||||
#include "sparse.h"
|
||||
|
||||
namespace MpqCompression {
|
||||
namespace {
|
||||
constexpr uint8_t MPQ_COMP_HUFFMANN = 0x01;
|
||||
constexpr uint8_t MPQ_COMP_ZLIB = 0x02;
|
||||
constexpr uint8_t MPQ_COMP_PKWARE = 0x08;
|
||||
constexpr uint8_t MPQ_COMP_BZIP2 = 0x10;
|
||||
constexpr uint8_t MPQ_COMP_SPARSE = 0x20;
|
||||
constexpr uint8_t MPQ_COMP_ADPCM_MONO = 0x40;
|
||||
constexpr uint8_t MPQ_COMP_ADPCM_STEREO = 0x80;
|
||||
constexpr uint8_t MPQ_COMP_LZMA = 0x12;
|
||||
|
||||
struct MpqDataInfo {
|
||||
unsigned char* in;
|
||||
unsigned char* inEnd;
|
||||
unsigned char* out;
|
||||
unsigned char* outEnd;
|
||||
};
|
||||
|
||||
unsigned int ReadInputData(char* buf, unsigned int* size, void* param) {
|
||||
MpqDataInfo* info = static_cast<MpqDataInfo*>(param);
|
||||
unsigned int maxAvail = static_cast<unsigned int>(info->inEnd - info->in);
|
||||
unsigned int toRead = *size;
|
||||
if (toRead > maxAvail) {
|
||||
toRead = maxAvail;
|
||||
}
|
||||
std::memcpy(buf, info->in, toRead);
|
||||
info->in += toRead;
|
||||
return toRead;
|
||||
}
|
||||
|
||||
void WriteOutputData(char* buf, unsigned int* size, void* param) {
|
||||
MpqDataInfo* info = static_cast<MpqDataInfo*>(param);
|
||||
unsigned int maxWrite = static_cast<unsigned int>(info->outEnd - info->out);
|
||||
unsigned int toWrite = *size;
|
||||
if (toWrite > maxWrite) {
|
||||
toWrite = maxWrite;
|
||||
}
|
||||
std::memcpy(info->out, buf, toWrite);
|
||||
info->out += toWrite;
|
||||
}
|
||||
|
||||
int DecompressZlib(void* out, int* outSize, void* in, int inSize) {
|
||||
z_stream z = {};
|
||||
z.next_in = reinterpret_cast<Bytef*>(in);
|
||||
z.avail_in = static_cast<uInt>(inSize);
|
||||
z.total_in = inSize;
|
||||
z.next_out = reinterpret_cast<Bytef*>(out);
|
||||
z.avail_out = static_cast<uInt>(*outSize);
|
||||
z.total_out = 0;
|
||||
z.zalloc = nullptr;
|
||||
z.zfree = nullptr;
|
||||
|
||||
int result = inflateInit(&z);
|
||||
if (result == Z_OK) {
|
||||
result = inflate(&z, Z_FINISH);
|
||||
*outSize = static_cast<int>(z.total_out);
|
||||
inflateEnd(&z);
|
||||
}
|
||||
|
||||
return result >= Z_OK;
|
||||
}
|
||||
|
||||
int DecompressBzip2(void* out, int* outSize, void* in, int inSize) {
|
||||
bz_stream strm = {};
|
||||
strm.next_in = reinterpret_cast<char*>(in);
|
||||
strm.avail_in = inSize;
|
||||
strm.next_out = reinterpret_cast<char*>(out);
|
||||
strm.avail_out = *outSize;
|
||||
strm.bzalloc = nullptr;
|
||||
strm.bzfree = nullptr;
|
||||
strm.opaque = nullptr;
|
||||
|
||||
int result = BZ2_bzDecompressInit(&strm, 0, 0);
|
||||
if (result == BZ_OK) {
|
||||
result = BZ2_bzDecompress(&strm);
|
||||
*outSize = strm.total_out_lo32;
|
||||
BZ2_bzDecompressEnd(&strm);
|
||||
}
|
||||
|
||||
return result >= BZ_OK;
|
||||
}
|
||||
|
||||
int DecompressPKLIB(void* out, int* outSize, void* in, int inSize) {
|
||||
std::vector<char> work(EXP_BUFFER_SIZE);
|
||||
std::memset(work.data(), 0, work.size());
|
||||
|
||||
MpqDataInfo info = {
|
||||
static_cast<unsigned char*>(in),
|
||||
static_cast<unsigned char*>(in) + inSize,
|
||||
static_cast<unsigned char*>(out),
|
||||
static_cast<unsigned char*>(out) + *outSize
|
||||
};
|
||||
|
||||
unsigned int result = explode(ReadInputData, WriteOutputData, work.data(), &info);
|
||||
*outSize = static_cast<int>(info.out - static_cast<unsigned char*>(out));
|
||||
return result == CMP_NO_ERROR ? 1 : 0;
|
||||
}
|
||||
|
||||
int DecompressHuff(void* out, int* outSize, void* in, int inSize) {
|
||||
THuffmannTree tree(false);
|
||||
TInputStream stream(in, static_cast<size_t>(inSize));
|
||||
unsigned int result = tree.Decompress(out, static_cast<unsigned int>(*outSize), &stream);
|
||||
*outSize = static_cast<int>(result);
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
int DecompressAdpcmMono(void* out, int* outSize, void* in, int inSize) {
|
||||
int result = DecompressADPCM(out, *outSize, in, inSize, 1);
|
||||
*outSize = result;
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
int DecompressAdpcmStereo(void* out, int* outSize, void* in, int inSize) {
|
||||
int result = DecompressADPCM(out, *outSize, in, inSize, 2);
|
||||
*outSize = result;
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
int DecompressSparseWrapper(void* out, int* outSize, void* in, int inSize) {
|
||||
return DecompressSparse(out, outSize, in, inSize);
|
||||
}
|
||||
|
||||
struct DecompressEntry {
|
||||
uint8_t mask;
|
||||
int (*fn)(void* out, int* outSize, void* in, int inSize);
|
||||
};
|
||||
|
||||
constexpr DecompressEntry kDecompressTable[] = {
|
||||
{MPQ_COMP_BZIP2, DecompressBzip2},
|
||||
{MPQ_COMP_PKWARE, DecompressPKLIB},
|
||||
{MPQ_COMP_ZLIB, DecompressZlib},
|
||||
{MPQ_COMP_HUFFMANN, DecompressHuff},
|
||||
{MPQ_COMP_ADPCM_STEREO, DecompressAdpcmStereo},
|
||||
{MPQ_COMP_ADPCM_MONO, DecompressAdpcmMono},
|
||||
{MPQ_COMP_SPARSE, DecompressSparseWrapper}
|
||||
};
|
||||
|
||||
constexpr uint8_t kKnownMask =
|
||||
MPQ_COMP_HUFFMANN |
|
||||
MPQ_COMP_ZLIB |
|
||||
MPQ_COMP_PKWARE |
|
||||
MPQ_COMP_BZIP2 |
|
||||
MPQ_COMP_SPARSE |
|
||||
MPQ_COMP_ADPCM_MONO |
|
||||
MPQ_COMP_ADPCM_STEREO;
|
||||
}
|
||||
|
||||
bool DecompressBlock(const uint8_t* in, size_t inSize, uint8_t* out, size_t outSize) {
|
||||
if (inSize == outSize) {
|
||||
std::memcpy(out, in, outSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inSize < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inSize > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outSize > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t type = in[0];
|
||||
const uint8_t* payload = in + 1;
|
||||
size_t payloadSize = inSize - 1;
|
||||
|
||||
if (type == 0) {
|
||||
if (payloadSize != outSize) {
|
||||
return false;
|
||||
}
|
||||
std::memcpy(out, payload, outSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type == MPQ_COMP_LZMA) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((type & ~kKnownMask) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int steps = 0;
|
||||
for (const auto& entry : kDecompressTable) {
|
||||
if (type & entry.mask) {
|
||||
++steps;
|
||||
}
|
||||
}
|
||||
|
||||
if (steps == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> work;
|
||||
uint8_t* workBuf = nullptr;
|
||||
if (steps > 1) {
|
||||
work.resize(outSize);
|
||||
workBuf = work.data();
|
||||
}
|
||||
|
||||
const uint8_t* currentInput = payload;
|
||||
size_t currentSize = payloadSize;
|
||||
int remaining = steps - 1;
|
||||
|
||||
for (const auto& entry : kDecompressTable) {
|
||||
if ((type & entry.mask) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t* output = (remaining & 1) ? workBuf : out;
|
||||
int outputSize = static_cast<int>(outSize);
|
||||
int inputSize = static_cast<int>(currentSize);
|
||||
|
||||
if (!entry.fn(output, &outputSize, const_cast<uint8_t*>(currentInput), inputSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outputSize <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
currentInput = output;
|
||||
currentSize = static_cast<size_t>(outputSize);
|
||||
--remaining;
|
||||
}
|
||||
|
||||
return currentSize == outSize;
|
||||
}
|
||||
}
|
||||
8
src/util/mpq/Decompress.hpp
Normal file
8
src/util/mpq/Decompress.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace MpqCompression {
|
||||
bool DecompressBlock(const uint8_t* in, size_t inSize, uint8_t* out, size_t outSize);
|
||||
}
|
||||
539
src/util/mpq/adpcm.cpp
Normal file
539
src/util/mpq/adpcm.cpp
Normal file
@ -0,0 +1,539 @@
|
||||
/*****************************************************************************/
|
||||
/* adpcm.cpp Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* This module contains implementation of adpcm decompression method used by */
|
||||
/* Storm.dll to decompress WAVE files. Thanks to Tom Amigo for releasing */
|
||||
/* his sources. */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */
|
||||
/* 20.05.03 2.00 Lad Added compression */
|
||||
/* 19.11.03 2.01 Dan Big endian handling */
|
||||
/* 10.01.13 3.00 Lad Refactored, beautified, documented :-) */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "adpcm.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tables necessary dor decompression
|
||||
|
||||
static const int NextStepTable[] =
|
||||
{
|
||||
-1, 0, -1, 4, -1, 2, -1, 6,
|
||||
-1, 1, -1, 5, -1, 3, -1, 7,
|
||||
-1, 1, -1, 5, -1, 3, -1, 7,
|
||||
-1, 2, -1, 4, -1, 6, -1, 8
|
||||
};
|
||||
|
||||
static const int StepSizeTable[] =
|
||||
{
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
16, 17, 19, 21, 23, 25, 28, 31,
|
||||
34, 37, 41, 45, 50, 55, 60, 66,
|
||||
73, 80, 88, 97, 107, 118, 130, 143,
|
||||
157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658,
|
||||
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
||||
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
||||
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
||||
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
||||
32767
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper class for writing output ADPCM data
|
||||
|
||||
class TADPCMStream
|
||||
{
|
||||
public:
|
||||
|
||||
TADPCMStream(void * pvBuffer, size_t cbBuffer)
|
||||
{
|
||||
pbBufferEnd = (unsigned char *)pvBuffer + cbBuffer;
|
||||
pbBuffer = (unsigned char *)pvBuffer;
|
||||
}
|
||||
|
||||
bool ReadByteSample(unsigned char & ByteSample)
|
||||
{
|
||||
// Check if there is enough space in the buffer
|
||||
if(pbBuffer >= pbBufferEnd)
|
||||
return false;
|
||||
|
||||
ByteSample = *pbBuffer++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteByteSample(unsigned char ByteSample)
|
||||
{
|
||||
// Check if there is enough space in the buffer
|
||||
if(pbBuffer >= pbBufferEnd)
|
||||
return false;
|
||||
|
||||
*pbBuffer++ = ByteSample;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadWordSample(short & OneSample)
|
||||
{
|
||||
// Check if we have enough space in the output buffer
|
||||
if((size_t)(pbBufferEnd - pbBuffer) < sizeof(short))
|
||||
return false;
|
||||
|
||||
// Write the sample
|
||||
OneSample = pbBuffer[0] + (((short)pbBuffer[1]) << 0x08);
|
||||
pbBuffer += sizeof(short);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteWordSample(short OneSample)
|
||||
{
|
||||
// Check if we have enough space in the output buffer
|
||||
if((size_t)(pbBufferEnd - pbBuffer) < sizeof(short))
|
||||
return false;
|
||||
|
||||
// Write the sample
|
||||
*pbBuffer++ = (unsigned char)(OneSample & 0xFF);
|
||||
*pbBuffer++ = (unsigned char)(OneSample >> 0x08);
|
||||
return true;
|
||||
}
|
||||
|
||||
int LengthProcessed(void * pvOutBuffer)
|
||||
{
|
||||
return (int)((unsigned char *)pbBuffer - (unsigned char *)pvOutBuffer);
|
||||
}
|
||||
|
||||
unsigned char * pbBufferEnd;
|
||||
unsigned char * pbBuffer;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Local functions
|
||||
|
||||
static inline short GetNextStepIndex(int StepIndex, unsigned int EncodedSample)
|
||||
{
|
||||
// Get the next step index
|
||||
StepIndex = StepIndex + NextStepTable[EncodedSample & 0x1F];
|
||||
|
||||
// Don't make the step index overflow
|
||||
if(StepIndex < 0)
|
||||
StepIndex = 0;
|
||||
else if(StepIndex > 88)
|
||||
StepIndex = 88;
|
||||
|
||||
return (short)StepIndex;
|
||||
}
|
||||
|
||||
static inline int UpdatePredictedSample(int PredictedSample, int EncodedSample, int Difference, int BitMask = 0x40)
|
||||
{
|
||||
// Is the sign bit set?
|
||||
if(EncodedSample & BitMask)
|
||||
{
|
||||
PredictedSample -= Difference;
|
||||
if(PredictedSample <= -32768)
|
||||
PredictedSample = -32768;
|
||||
}
|
||||
else
|
||||
{
|
||||
PredictedSample += Difference;
|
||||
if(PredictedSample >= 32767)
|
||||
PredictedSample = 32767;
|
||||
}
|
||||
|
||||
return PredictedSample;
|
||||
}
|
||||
|
||||
static inline int DecodeSample(int PredictedSample, int EncodedSample, int StepSize, int Difference)
|
||||
{
|
||||
if(EncodedSample & 0x01)
|
||||
Difference += (StepSize >> 0);
|
||||
|
||||
if(EncodedSample & 0x02)
|
||||
Difference += (StepSize >> 1);
|
||||
|
||||
if(EncodedSample & 0x04)
|
||||
Difference += (StepSize >> 2);
|
||||
|
||||
if(EncodedSample & 0x08)
|
||||
Difference += (StepSize >> 3);
|
||||
|
||||
if(EncodedSample & 0x10)
|
||||
Difference += (StepSize >> 4);
|
||||
|
||||
if(EncodedSample & 0x20)
|
||||
Difference += (StepSize >> 5);
|
||||
|
||||
return UpdatePredictedSample(PredictedSample, EncodedSample, Difference);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Compression routine
|
||||
|
||||
int CompressADPCM(void * pvOutBuffer, int cbOutBuffer, void * pvInBuffer, int cbInBuffer, int ChannelCount, int CompressionLevel)
|
||||
{
|
||||
TADPCMStream os(pvOutBuffer, cbOutBuffer); // The output stream
|
||||
TADPCMStream is(pvInBuffer, cbInBuffer); // The input stream
|
||||
unsigned char BitShift = (unsigned char)(CompressionLevel - 1);
|
||||
short PredictedSamples[MAX_ADPCM_CHANNEL_COUNT];// Predicted samples for each channel
|
||||
short StepIndexes[MAX_ADPCM_CHANNEL_COUNT]; // Step indexes for each channel
|
||||
short InputSample; // Input sample for the current channel
|
||||
int TotalStepSize;
|
||||
int ChannelIndex;
|
||||
int AbsDifference;
|
||||
int Difference;
|
||||
int MaxBitMask;
|
||||
int StepSize;
|
||||
|
||||
// First byte in the output stream contains zero. The second one contains the compression level
|
||||
os.WriteByteSample(0);
|
||||
if(!os.WriteByteSample(BitShift))
|
||||
return 2;
|
||||
|
||||
// Set the initial step index for each channel
|
||||
PredictedSamples[0] = PredictedSamples[1] = 0;
|
||||
StepIndexes[0] = StepIndexes[1] = INITIAL_ADPCM_STEP_INDEX;
|
||||
|
||||
// Next, InitialSample value for each channel follows
|
||||
for(int i = 0; i < ChannelCount; i++)
|
||||
{
|
||||
// Get the initial sample from the input stream
|
||||
if(!is.ReadWordSample(InputSample))
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
|
||||
// Store the initial sample to our sample array
|
||||
PredictedSamples[i] = InputSample;
|
||||
|
||||
// Also store the loaded sample to the output stream
|
||||
if(!os.WriteWordSample(InputSample))
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
}
|
||||
|
||||
// Get the initial index
|
||||
ChannelIndex = ChannelCount - 1;
|
||||
|
||||
// Now keep reading the input data as long as there is something in the input buffer
|
||||
while(is.ReadWordSample(InputSample))
|
||||
{
|
||||
int EncodedSample = 0;
|
||||
|
||||
// If we have two channels, we need to flip the channel index
|
||||
ChannelIndex = (ChannelIndex + 1) % ChannelCount;
|
||||
|
||||
// Get the difference from the previous sample.
|
||||
// If the difference is negative, set the sign bit to the encoded sample
|
||||
AbsDifference = InputSample - PredictedSamples[ChannelIndex];
|
||||
if(AbsDifference < 0)
|
||||
{
|
||||
AbsDifference = -AbsDifference;
|
||||
EncodedSample |= 0x40;
|
||||
}
|
||||
|
||||
// If the difference is too low (higher that difference treshold),
|
||||
// write a step index modifier marker
|
||||
StepSize = StepSizeTable[StepIndexes[ChannelIndex]];
|
||||
if(AbsDifference < (StepSize >> CompressionLevel))
|
||||
{
|
||||
if(StepIndexes[ChannelIndex] != 0)
|
||||
StepIndexes[ChannelIndex]--;
|
||||
|
||||
os.WriteByteSample(0x80);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the difference is too high, write marker that
|
||||
// indicates increase in step size
|
||||
while(AbsDifference > (StepSize << 1))
|
||||
{
|
||||
if(StepIndexes[ChannelIndex] >= 0x58)
|
||||
break;
|
||||
|
||||
// Modify the step index
|
||||
StepIndexes[ChannelIndex] += 8;
|
||||
if(StepIndexes[ChannelIndex] > 0x58)
|
||||
StepIndexes[ChannelIndex] = 0x58;
|
||||
|
||||
// Write the "modify step index" marker
|
||||
StepSize = StepSizeTable[StepIndexes[ChannelIndex]];
|
||||
os.WriteByteSample(0x81);
|
||||
}
|
||||
|
||||
// Get the limit bit value
|
||||
MaxBitMask = (1 << (BitShift - 1));
|
||||
MaxBitMask = (MaxBitMask > 0x20) ? 0x20 : MaxBitMask;
|
||||
Difference = StepSize >> BitShift;
|
||||
TotalStepSize = 0;
|
||||
|
||||
for(int BitVal = 0x01; BitVal <= MaxBitMask; BitVal <<= 1)
|
||||
{
|
||||
if((TotalStepSize + StepSize) <= AbsDifference)
|
||||
{
|
||||
TotalStepSize += StepSize;
|
||||
EncodedSample |= BitVal;
|
||||
}
|
||||
StepSize >>= 1;
|
||||
}
|
||||
|
||||
PredictedSamples[ChannelIndex] = (short)UpdatePredictedSample(PredictedSamples[ChannelIndex],
|
||||
EncodedSample,
|
||||
Difference + TotalStepSize);
|
||||
// Write the encoded sample to the output stream
|
||||
if(!os.WriteByteSample((unsigned char)EncodedSample))
|
||||
break;
|
||||
|
||||
// Calculates the step index to use for the next encode
|
||||
StepIndexes[ChannelIndex] = GetNextStepIndex(StepIndexes[ChannelIndex], EncodedSample);
|
||||
}
|
||||
}
|
||||
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Decompression routine
|
||||
|
||||
int DecompressADPCM(void * pvOutBuffer, int cbOutBuffer, void * pvInBuffer, int cbInBuffer, int ChannelCount)
|
||||
{
|
||||
TADPCMStream os(pvOutBuffer, cbOutBuffer); // Output stream
|
||||
TADPCMStream is(pvInBuffer, cbInBuffer); // Input stream
|
||||
unsigned char EncodedSample;
|
||||
unsigned char BitShift;
|
||||
short PredictedSamples[MAX_ADPCM_CHANNEL_COUNT]; // Predicted sample for each channel
|
||||
short StepIndexes[MAX_ADPCM_CHANNEL_COUNT]; // Predicted step index for each channel
|
||||
int ChannelIndex; // Current channel index
|
||||
|
||||
// Initialize the StepIndex for each channel
|
||||
PredictedSamples[0] = PredictedSamples[1] = 0;
|
||||
StepIndexes[0] = StepIndexes[1] = INITIAL_ADPCM_STEP_INDEX;
|
||||
|
||||
// The first byte is always zero, the second one contains bit shift (compression level - 1)
|
||||
is.ReadByteSample(BitShift);
|
||||
is.ReadByteSample(BitShift);
|
||||
|
||||
// Next, InitialSample value for each channel follows
|
||||
for(int i = 0; i < ChannelCount; i++)
|
||||
{
|
||||
// Get the initial sample from the input stream
|
||||
short InitialSample;
|
||||
|
||||
// Attempt to read the initial sample
|
||||
if(!is.ReadWordSample(InitialSample))
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
|
||||
// Store the initial sample to our sample array
|
||||
PredictedSamples[i] = InitialSample;
|
||||
|
||||
// Also store the loaded sample to the output stream
|
||||
if(!os.WriteWordSample(InitialSample))
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
}
|
||||
|
||||
// Get the initial index
|
||||
ChannelIndex = ChannelCount - 1;
|
||||
|
||||
// Keep reading as long as there is something in the input buffer
|
||||
while(is.ReadByteSample(EncodedSample))
|
||||
{
|
||||
// If we have two channels, we need to flip the channel index
|
||||
ChannelIndex = (ChannelIndex + 1) % ChannelCount;
|
||||
|
||||
if(EncodedSample == 0x80)
|
||||
{
|
||||
if(StepIndexes[ChannelIndex] != 0)
|
||||
StepIndexes[ChannelIndex]--;
|
||||
|
||||
if(!os.WriteWordSample(PredictedSamples[ChannelIndex]))
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
}
|
||||
else if(EncodedSample == 0x81)
|
||||
{
|
||||
// Modify the step index
|
||||
StepIndexes[ChannelIndex] += 8;
|
||||
if(StepIndexes[ChannelIndex] > 0x58)
|
||||
StepIndexes[ChannelIndex] = 0x58;
|
||||
|
||||
// Next pass, keep going on the same channel
|
||||
ChannelIndex = (ChannelIndex + 1) % ChannelCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
int StepIndex = StepIndexes[ChannelIndex];
|
||||
int StepSize = StepSizeTable[StepIndex];
|
||||
|
||||
// Encode one sample
|
||||
PredictedSamples[ChannelIndex] = (short)DecodeSample(PredictedSamples[ChannelIndex],
|
||||
EncodedSample,
|
||||
StepSize,
|
||||
StepSize >> BitShift);
|
||||
|
||||
// Write the decoded sample to the output stream
|
||||
if(!os.WriteWordSample(PredictedSamples[ChannelIndex]))
|
||||
break;
|
||||
|
||||
// Calculates the step index to use for the next encode
|
||||
StepIndexes[ChannelIndex] = GetNextStepIndex(StepIndex, EncodedSample);
|
||||
}
|
||||
}
|
||||
|
||||
// Return total bytes written since beginning of the output buffer
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ADPCM decompression present in Starcraft I BETA
|
||||
|
||||
typedef struct _ADPCM_DATA
|
||||
{
|
||||
const unsigned int * pValues;
|
||||
int BitCount;
|
||||
int field_8;
|
||||
int field_C;
|
||||
int field_10;
|
||||
|
||||
} ADPCM_DATA, *PADPCM_DATA;
|
||||
|
||||
static const unsigned int adpcm_values_2[] = {0x33, 0x66};
|
||||
static const unsigned int adpcm_values_3[] = {0x3A, 0x3A, 0x50, 0x70};
|
||||
static const unsigned int adpcm_values_4[] = {0x3A, 0x3A, 0x3A, 0x3A, 0x4D, 0x66, 0x80, 0x9A};
|
||||
static const unsigned int adpcm_values_6[] =
|
||||
{
|
||||
0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A,
|
||||
0x46, 0x53, 0x60, 0x6D, 0x7A, 0x86, 0x93, 0xA0, 0xAD, 0xBA, 0xC6, 0xD3, 0xE0, 0xED, 0xFA, 0x106
|
||||
};
|
||||
|
||||
static const unsigned int * InitAdpcmData(PADPCM_DATA pData, unsigned char BitCount)
|
||||
{
|
||||
switch(BitCount)
|
||||
{
|
||||
case 2:
|
||||
pData->pValues = adpcm_values_2;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
pData->pValues = adpcm_values_3;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
pData->pValues = adpcm_values_4;
|
||||
break;
|
||||
|
||||
default:
|
||||
pData->pValues = NULL;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
pData->pValues = adpcm_values_6;
|
||||
break;
|
||||
}
|
||||
|
||||
pData->BitCount = BitCount;
|
||||
pData->field_C = 0x20000;
|
||||
pData->field_8 = 1 << BitCount;
|
||||
pData->field_10 = (1 << BitCount) / 2;
|
||||
return pData->pValues;
|
||||
}
|
||||
|
||||
int DecompressADPCM_SC1B(void * pvOutBuffer, int cbOutBuffer, void * pvInBuffer, int cbInBuffer, int ChannelCount)
|
||||
{
|
||||
TADPCMStream os(pvOutBuffer, cbOutBuffer); // Output stream
|
||||
TADPCMStream is(pvInBuffer, cbInBuffer); // Input stream
|
||||
ADPCM_DATA AdpcmData;
|
||||
int LowBitValues[MAX_ADPCM_CHANNEL_COUNT];
|
||||
int UpperBits[MAX_ADPCM_CHANNEL_COUNT];
|
||||
int BitMasks[MAX_ADPCM_CHANNEL_COUNT];
|
||||
int PredictedSamples[MAX_ADPCM_CHANNEL_COUNT];
|
||||
int ChannelIndex;
|
||||
int ChannelIndexMax;
|
||||
int OutputSample;
|
||||
unsigned char BitCount;
|
||||
unsigned char EncodedSample;
|
||||
short InputValue16;
|
||||
int reg_eax;
|
||||
int Difference;
|
||||
|
||||
// The first byte contains number of bits
|
||||
if(!is.ReadByteSample(BitCount))
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
if(!InitAdpcmData(&AdpcmData, BitCount))
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
assert(AdpcmData.pValues != NULL);
|
||||
|
||||
// Init bit values
|
||||
for(int i = 0; i < ChannelCount; i++)
|
||||
{
|
||||
unsigned char OneByte;
|
||||
|
||||
if(!is.ReadByteSample(OneByte))
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
LowBitValues[i] = OneByte & 0x01;
|
||||
UpperBits[i] = OneByte >> 1;
|
||||
}
|
||||
|
||||
//
|
||||
for(int i = 0; i < ChannelCount; i++)
|
||||
{
|
||||
if(!is.ReadWordSample(InputValue16))
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
BitMasks[i] = InputValue16 << AdpcmData.BitCount;
|
||||
}
|
||||
|
||||
// Next, InitialSample value for each channel follows
|
||||
for(int i = 0; i < ChannelCount; i++)
|
||||
{
|
||||
if(!is.ReadWordSample(InputValue16))
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
|
||||
PredictedSamples[i] = InputValue16;
|
||||
os.WriteWordSample(InputValue16);
|
||||
}
|
||||
|
||||
// Get the initial index
|
||||
ChannelIndexMax = ChannelCount - 1;
|
||||
ChannelIndex = 0;
|
||||
|
||||
// Keep reading as long as there is something in the input buffer
|
||||
while(is.ReadByteSample(EncodedSample))
|
||||
{
|
||||
reg_eax = ((PredictedSamples[ChannelIndex] * 3) << 3) - PredictedSamples[ChannelIndex];
|
||||
PredictedSamples[ChannelIndex] = ((reg_eax * 10) + 0x80) >> 8;
|
||||
|
||||
Difference = (((EncodedSample >> 1) + 1) * BitMasks[ChannelIndex] + AdpcmData.field_10) >> AdpcmData.BitCount;
|
||||
|
||||
PredictedSamples[ChannelIndex] = UpdatePredictedSample(PredictedSamples[ChannelIndex], EncodedSample, Difference, 0x01);
|
||||
|
||||
BitMasks[ChannelIndex] = (AdpcmData.pValues[EncodedSample >> 1] * BitMasks[ChannelIndex] + 0x80) >> 6;
|
||||
if(BitMasks[ChannelIndex] < AdpcmData.field_8)
|
||||
BitMasks[ChannelIndex] = AdpcmData.field_8;
|
||||
|
||||
if(BitMasks[ChannelIndex] > AdpcmData.field_C)
|
||||
BitMasks[ChannelIndex] = AdpcmData.field_C;
|
||||
|
||||
reg_eax = (cbInBuffer - is.LengthProcessed(pvInBuffer)) >> ChannelIndexMax;
|
||||
OutputSample = PredictedSamples[ChannelIndex];
|
||||
if(reg_eax < UpperBits[ChannelIndex])
|
||||
{
|
||||
if(LowBitValues[ChannelIndex])
|
||||
{
|
||||
OutputSample += (UpperBits[ChannelIndex] - reg_eax);
|
||||
if(OutputSample > 32767)
|
||||
OutputSample = 32767;
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputSample += (reg_eax - UpperBits[ChannelIndex]);
|
||||
if(OutputSample < -32768)
|
||||
OutputSample = -32768;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the word sample and swap channel
|
||||
os.WriteWordSample((short)(OutputSample));
|
||||
ChannelIndex = (ChannelIndex + 1) % ChannelCount;
|
||||
}
|
||||
|
||||
return os.LengthProcessed(pvOutBuffer);
|
||||
}
|
||||
|
||||
27
src/util/mpq/adpcm.h
Normal file
27
src/util/mpq/adpcm.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*****************************************************************************/
|
||||
/* adpcm.h Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Header file for adpcm decompress functions */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 31.03.03 1.00 Lad The first version of adpcm.h */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __ADPCM_H__
|
||||
#define __ADPCM_H__
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define MAX_ADPCM_CHANNEL_COUNT 2
|
||||
#define INITIAL_ADPCM_STEP_INDEX 0x2C
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public functions
|
||||
|
||||
int CompressADPCM (void * pvOutBuffer, int dwOutLength, void * pvInBuffer, int dwInLength, int ChannelCount, int nCmpType);
|
||||
int DecompressADPCM (void * pvOutBuffer, int dwOutLength, void * pvInBuffer, int dwInLength, int ChannelCount);
|
||||
int DecompressADPCM_SC1B(void * pvOutBuffer, int cbOutBuffer, void * pvInBuffer, int cbInBuffer, int ChannelCount);
|
||||
|
||||
#endif // __ADPCM_H__
|
||||
521
src/util/mpq/explode.c
Normal file
521
src/util/mpq/explode.c
Normal file
@ -0,0 +1,521 @@
|
||||
/*****************************************************************************/
|
||||
/* explode.c Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Implode function of PKWARE Data Compression library */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */
|
||||
/* 08.04.03 1.01 Lad Renamed to explode.c to be compatible with pklib */
|
||||
/* 02.05.03 1.01 Lad Stress test done */
|
||||
/* 22.04.10 1.01 Lad Documented */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pklib.h"
|
||||
|
||||
#define PKDCL_OK 0
|
||||
#define PKDCL_STREAM_END 1 // All data from the input stream is read
|
||||
#define PKDCL_NEED_DICT 2 // Need more data (dictionary)
|
||||
#define PKDCL_CONTINUE 10 // Internal flag, not returned to user
|
||||
#define PKDCL_GET_INPUT 11 // Internal flag, not returned to user
|
||||
|
||||
char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n"
|
||||
"Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n"
|
||||
"Patent No. 5,051,745\r\n"
|
||||
"PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n"
|
||||
"Version 1.11\r\n";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tables
|
||||
|
||||
const unsigned char DistBits[0x40] =
|
||||
{
|
||||
0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
|
||||
};
|
||||
|
||||
const unsigned char DistCode[0x40] =
|
||||
{
|
||||
0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A,
|
||||
0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C,
|
||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||
0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00
|
||||
};
|
||||
|
||||
const unsigned char ExLenBits[0x10] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
|
||||
};
|
||||
|
||||
const unsigned short LenBase[0x10] =
|
||||
{
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||
0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106
|
||||
};
|
||||
|
||||
const unsigned char LenBits[0x10] =
|
||||
{
|
||||
0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07
|
||||
};
|
||||
|
||||
const unsigned char LenCode[0x10] =
|
||||
{
|
||||
0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00
|
||||
};
|
||||
|
||||
const unsigned char ChBitsAsc[0x100] =
|
||||
{
|
||||
0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08,
|
||||
0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B,
|
||||
0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06,
|
||||
0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08,
|
||||
0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05,
|
||||
0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D,
|
||||
0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
|
||||
};
|
||||
|
||||
const unsigned short ChCodeAsc[0x100] =
|
||||
{
|
||||
0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0,
|
||||
0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0,
|
||||
0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360,
|
||||
0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60,
|
||||
0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8,
|
||||
0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098,
|
||||
0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C,
|
||||
0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710,
|
||||
0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8,
|
||||
0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E,
|
||||
0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8,
|
||||
0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088,
|
||||
0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A,
|
||||
0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D,
|
||||
0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078,
|
||||
0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0,
|
||||
0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040,
|
||||
0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380,
|
||||
0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180,
|
||||
0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280,
|
||||
0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080,
|
||||
0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300,
|
||||
0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0,
|
||||
0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320,
|
||||
0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220,
|
||||
0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0,
|
||||
0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0,
|
||||
0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340,
|
||||
0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900,
|
||||
0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600,
|
||||
0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200,
|
||||
0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Local functions
|
||||
|
||||
static void GenDecodeTabs(
|
||||
unsigned char * positions, // [out] Table of positions
|
||||
const unsigned char * start_indexes, // [in] Table of start indexes
|
||||
const unsigned char * length_bits, // [in] Table of lengths. Each length is stored as number of bits
|
||||
size_t elements) // [in] Number of elements in start_indexes and length_bits
|
||||
{
|
||||
unsigned int index;
|
||||
unsigned int length;
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < elements; i++)
|
||||
{
|
||||
length = 1 << length_bits[i]; // Get the length in bytes
|
||||
|
||||
for(index = start_indexes[i]; index < 0x100; index += length)
|
||||
{
|
||||
positions[index] = (unsigned char)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GenAscTabs(TDcmpStruct * pWork)
|
||||
{
|
||||
const unsigned short * pChCodeAsc = &ChCodeAsc[0xFF];
|
||||
unsigned int acc, add;
|
||||
unsigned short count;
|
||||
|
||||
for(count = 0x00FF; pChCodeAsc >= ChCodeAsc; pChCodeAsc--, count--)
|
||||
{
|
||||
unsigned char * pChBitsAsc = pWork->ChBitsAsc + count;
|
||||
unsigned char bits_asc = *pChBitsAsc;
|
||||
|
||||
if(bits_asc <= 8)
|
||||
{
|
||||
add = (1 << bits_asc);
|
||||
acc = *pChCodeAsc;
|
||||
|
||||
do
|
||||
{
|
||||
pWork->offs2C34[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
}
|
||||
while(acc < 0x100);
|
||||
}
|
||||
else if((acc = (*pChCodeAsc & 0xFF)) != 0)
|
||||
{
|
||||
pWork->offs2C34[acc] = 0xFF;
|
||||
|
||||
if(*pChCodeAsc & 0x3F)
|
||||
{
|
||||
bits_asc -= 4;
|
||||
*pChBitsAsc = bits_asc;
|
||||
|
||||
add = (1 << bits_asc);
|
||||
acc = *pChCodeAsc >> 4;
|
||||
do
|
||||
{
|
||||
pWork->offs2D34[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
}
|
||||
while(acc < 0x100);
|
||||
}
|
||||
else
|
||||
{
|
||||
bits_asc -= 6;
|
||||
*pChBitsAsc = bits_asc;
|
||||
|
||||
add = (1 << bits_asc);
|
||||
acc = *pChCodeAsc >> 6;
|
||||
do
|
||||
{
|
||||
pWork->offs2E34[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
}
|
||||
while(acc < 0x80);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bits_asc -= 8;
|
||||
*pChBitsAsc = bits_asc;
|
||||
|
||||
add = (1 << bits_asc);
|
||||
acc = *pChCodeAsc >> 8;
|
||||
do
|
||||
{
|
||||
pWork->offs2EB4[acc] = (unsigned char)count;
|
||||
acc += add;
|
||||
}
|
||||
while(acc < 0x100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Removes given number of bits in the bit buffer. New bits are reloaded from
|
||||
// the input buffer, if needed.
|
||||
// Returns: PKDCL_OK: Operation was successful
|
||||
// PKDCL_STREAM_END: There are no more bits in the input buffer
|
||||
|
||||
static int WasteBits(TDcmpStruct * pWork, unsigned int nBits)
|
||||
{
|
||||
// If number of bits required is less than number of (bits in the buffer) ?
|
||||
if(nBits <= pWork->extra_bits)
|
||||
{
|
||||
pWork->extra_bits -= nBits;
|
||||
pWork->bit_buff >>= nBits;
|
||||
return PKDCL_OK;
|
||||
}
|
||||
|
||||
// Load input buffer if necessary
|
||||
pWork->bit_buff >>= pWork->extra_bits;
|
||||
if(pWork->in_pos == pWork->in_bytes)
|
||||
{
|
||||
pWork->in_pos = sizeof(pWork->in_buff);
|
||||
if((pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param)) == 0)
|
||||
return PKDCL_STREAM_END;
|
||||
pWork->in_pos = 0;
|
||||
}
|
||||
|
||||
// Update bit buffer
|
||||
pWork->bit_buff |= (pWork->in_buff[pWork->in_pos++] << 8);
|
||||
pWork->bit_buff >>= (nBits - pWork->extra_bits);
|
||||
pWork->extra_bits = (pWork->extra_bits - nBits) + 8;
|
||||
return PKDCL_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Decodes next literal from the input (compressed) data.
|
||||
// Returns : 0x000: One byte 0x00
|
||||
// 0x001: One byte 0x01
|
||||
// ...
|
||||
// 0x0FF: One byte 0xFF
|
||||
// 0x100: Repetition, length of 0x02 bytes
|
||||
// 0x101: Repetition, length of 0x03 bytes
|
||||
// ...
|
||||
// 0x304: Repetition, length of 0x206 bytes
|
||||
// 0x305: End of stream
|
||||
// 0x306: Error
|
||||
|
||||
static unsigned int DecodeLit(TDcmpStruct * pWork)
|
||||
{
|
||||
unsigned int extra_length_bits; // Number of bits of extra literal length
|
||||
unsigned int length_code; // Length code
|
||||
unsigned int value;
|
||||
|
||||
// Test the current bit in byte buffer. If is not set, simply return the next 8 bits.
|
||||
if(pWork->bit_buff & 1)
|
||||
{
|
||||
// Remove one bit from the input data
|
||||
if(WasteBits(pWork, 1))
|
||||
return 0x306;
|
||||
|
||||
// The next 8 bits hold the index to the length code table
|
||||
length_code = pWork->LengthCodes[pWork->bit_buff & 0xFF];
|
||||
|
||||
// Remove the apropriate number of bits
|
||||
if(WasteBits(pWork, pWork->LenBits[length_code]))
|
||||
return 0x306;
|
||||
|
||||
// Are there some extra bits for the obtained length code ?
|
||||
if((extra_length_bits = pWork->ExLenBits[length_code]) != 0)
|
||||
{
|
||||
unsigned int extra_length = pWork->bit_buff & ((1 << extra_length_bits) - 1);
|
||||
|
||||
if(WasteBits(pWork, extra_length_bits))
|
||||
{
|
||||
if((length_code + extra_length) != 0x10E)
|
||||
return 0x306;
|
||||
}
|
||||
length_code = pWork->LenBase[length_code] + extra_length;
|
||||
}
|
||||
|
||||
// In order to distinguish uncompressed byte from repetition length,
|
||||
// we have to add 0x100 to the length.
|
||||
return length_code + 0x100;
|
||||
}
|
||||
|
||||
// Remove one bit from the input data
|
||||
if(WasteBits(pWork, 1))
|
||||
return 0x306;
|
||||
|
||||
// If the binary compression type, read 8 bits and return them as one byte.
|
||||
if(pWork->ctype == CMP_BINARY)
|
||||
{
|
||||
unsigned int uncompressed_byte = pWork->bit_buff & 0xFF;
|
||||
|
||||
if(WasteBits(pWork, 8))
|
||||
return 0x306;
|
||||
return uncompressed_byte;
|
||||
}
|
||||
|
||||
// When ASCII compression ...
|
||||
if(pWork->bit_buff & 0xFF)
|
||||
{
|
||||
value = pWork->offs2C34[pWork->bit_buff & 0xFF];
|
||||
|
||||
if(value == 0xFF)
|
||||
{
|
||||
if(pWork->bit_buff & 0x3F)
|
||||
{
|
||||
if(WasteBits(pWork, 4))
|
||||
return 0x306;
|
||||
|
||||
value = pWork->offs2D34[pWork->bit_buff & 0xFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(WasteBits(pWork, 6))
|
||||
return 0x306;
|
||||
|
||||
value = pWork->offs2E34[pWork->bit_buff & 0x7F];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(WasteBits(pWork, 8))
|
||||
return 0x306;
|
||||
|
||||
value = pWork->offs2EB4[pWork->bit_buff & 0xFF];
|
||||
}
|
||||
|
||||
return WasteBits(pWork, pWork->ChBitsAsc[value]) ? 0x306 : value;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Decodes the distance of the repetition, backwards relative to the
|
||||
// current output buffer position
|
||||
|
||||
static unsigned int DecodeDist(TDcmpStruct * pWork, unsigned int rep_length)
|
||||
{
|
||||
unsigned int dist_pos_code; // Distance position code
|
||||
unsigned int dist_pos_bits; // Number of bits of distance position
|
||||
unsigned int distance; // Distance position
|
||||
|
||||
// Next 2-8 bits in the input buffer is the distance position code
|
||||
dist_pos_code = pWork->DistPosCodes[pWork->bit_buff & 0xFF];
|
||||
dist_pos_bits = pWork->DistBits[dist_pos_code];
|
||||
if(WasteBits(pWork, dist_pos_bits))
|
||||
return 0;
|
||||
|
||||
if(rep_length == 2)
|
||||
{
|
||||
// If the repetition is only 2 bytes length,
|
||||
// then take 2 bits from the stream in order to get the distance
|
||||
distance = (dist_pos_code << 2) | (pWork->bit_buff & 0x03);
|
||||
if(WasteBits(pWork, 2))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the repetition is more than 2 bytes length,
|
||||
// then take "dsize_bits" bits in order to get the distance
|
||||
distance = (dist_pos_code << pWork->dsize_bits) | (pWork->bit_buff & pWork->dsize_mask);
|
||||
if(WasteBits(pWork, pWork->dsize_bits))
|
||||
return 0;
|
||||
}
|
||||
return distance + 1;
|
||||
}
|
||||
|
||||
static unsigned int Expand(TDcmpStruct * pWork)
|
||||
{
|
||||
unsigned int next_literal; // Literal decoded from the compressed data
|
||||
unsigned int result; // Value to be returned
|
||||
unsigned int copyBytes; // Number of bytes to copy to the output buffer
|
||||
|
||||
pWork->outputPos = 0x1000; // Initialize output buffer position
|
||||
|
||||
// Decode the next literal from the input data.
|
||||
// The returned literal can either be an uncompressed byte (next_literal < 0x100)
|
||||
// or an encoded length of the repeating byte sequence that
|
||||
// is to be copied to the current buffer position
|
||||
while((result = next_literal = DecodeLit(pWork)) < 0x305)
|
||||
{
|
||||
// If the literal is greater than 0x100, it holds length
|
||||
// of repeating byte sequence
|
||||
// literal of 0x100 means repeating sequence of 0x2 bytes
|
||||
// literal of 0x101 means repeating sequence of 0x3 bytes
|
||||
// ...
|
||||
// literal of 0x305 means repeating sequence of 0x207 bytes
|
||||
if(next_literal >= 0x100)
|
||||
{
|
||||
unsigned char * source;
|
||||
unsigned char * target;
|
||||
unsigned int rep_length; // Length of the repetition, in bytes
|
||||
unsigned int minus_dist; // Backward distance to the repetition, relative to the current buffer position
|
||||
|
||||
// Get the length of the repeating sequence.
|
||||
// Note that the repeating block may overlap the current output position,
|
||||
// for example if there was a sequence of equal bytes
|
||||
rep_length = next_literal - 0xFE;
|
||||
|
||||
// Get backward distance to the repetition
|
||||
if((minus_dist = DecodeDist(pWork, rep_length)) == 0)
|
||||
{
|
||||
result = 0x306;
|
||||
break;
|
||||
}
|
||||
|
||||
// Target and source pointer
|
||||
target = &pWork->out_buff[pWork->outputPos];
|
||||
source = target - minus_dist;
|
||||
|
||||
// Update buffer output position
|
||||
pWork->outputPos += rep_length;
|
||||
|
||||
// Copy the repeating sequence
|
||||
while(rep_length-- > 0)
|
||||
*target++ = *source++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pWork->out_buff[pWork->outputPos++] = (unsigned char)next_literal;
|
||||
}
|
||||
|
||||
// Flush the output buffer, if number of extracted bytes has reached the end
|
||||
if(pWork->outputPos >= 0x2000)
|
||||
{
|
||||
// Copy decompressed data into user buffer
|
||||
copyBytes = 0x1000;
|
||||
pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param);
|
||||
|
||||
// Now copy the decompressed data to the first half of the buffer.
|
||||
// This is needed because the decompression might reuse them as repetitions.
|
||||
// Note that if the output buffer overflowed previously, the extra decompressed bytes
|
||||
// are stored in "out_buff_overflow", and they will now be
|
||||
// within decompressed part of the output buffer.
|
||||
memmove(pWork->out_buff, &pWork->out_buff[0x1000], pWork->outputPos - 0x1000);
|
||||
pWork->outputPos -= 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush any remaining decompressed bytes
|
||||
copyBytes = pWork->outputPos - 0x1000;
|
||||
pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Main exploding function.
|
||||
|
||||
unsigned int PKEXPORT explode(
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param),
|
||||
char *work_buf,
|
||||
void *param)
|
||||
{
|
||||
TDcmpStruct * pWork = (TDcmpStruct *)work_buf;
|
||||
|
||||
// Initialize work struct and load compressed data
|
||||
pWork->read_buf = read_buf;
|
||||
pWork->write_buf = write_buf;
|
||||
pWork->param = param;
|
||||
pWork->in_pos = sizeof(pWork->in_buff);
|
||||
pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param);
|
||||
if(pWork->in_bytes <= 4)
|
||||
return CMP_BAD_DATA;
|
||||
|
||||
pWork->ctype = pWork->in_buff[0]; // Get the compression type (CMP_BINARY or CMP_ASCII)
|
||||
pWork->dsize_bits = pWork->in_buff[1]; // Get the dictionary size
|
||||
pWork->bit_buff = pWork->in_buff[2]; // Initialize 16-bit bit buffer
|
||||
pWork->extra_bits = 0; // Extra (over 8) bits
|
||||
pWork->in_pos = 3; // Position in input buffer
|
||||
|
||||
// Test for the valid dictionary size
|
||||
if(4 > pWork->dsize_bits || pWork->dsize_bits > 6)
|
||||
return CMP_INVALID_DICTSIZE;
|
||||
|
||||
pWork->dsize_mask = 0xFFFF >> (0x10 - pWork->dsize_bits); // Shifted by 'sar' instruction
|
||||
|
||||
if(pWork->ctype != CMP_BINARY)
|
||||
{
|
||||
if(pWork->ctype != CMP_ASCII)
|
||||
return CMP_INVALID_MODE;
|
||||
|
||||
memcpy(pWork->ChBitsAsc, ChBitsAsc, sizeof(pWork->ChBitsAsc));
|
||||
GenAscTabs(pWork);
|
||||
}
|
||||
|
||||
memcpy(pWork->LenBits, LenBits, sizeof(pWork->LenBits));
|
||||
GenDecodeTabs(pWork->LengthCodes, LenCode, LenBits, sizeof(LenBits));
|
||||
memcpy(pWork->ExLenBits, ExLenBits, sizeof(pWork->ExLenBits));
|
||||
memcpy(pWork->LenBase, LenBase, sizeof(pWork->LenBase));
|
||||
memcpy(pWork->DistBits, DistBits, sizeof(pWork->DistBits));
|
||||
GenDecodeTabs(pWork->DistPosCodes, DistCode, DistBits, sizeof(DistBits));
|
||||
if(Expand(pWork) != 0x306)
|
||||
return CMP_NO_ERROR;
|
||||
|
||||
return CMP_ABORT;
|
||||
}
|
||||
895
src/util/mpq/huff.cpp
Normal file
895
src/util/mpq/huff.cpp
Normal file
@ -0,0 +1,895 @@
|
||||
/*****************************************************************************/
|
||||
/* huffman.cpp Copyright (c) Ladislav Zezula 1998-2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* This module contains Huffmann (de)compression methods */
|
||||
/* */
|
||||
/* Authors : Ladislav Zezula (ladik@zezula.net) */
|
||||
/* ShadowFlare (BlakFlare@hotmail.com) */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* xx.xx.xx 1.00 Lad The first version of dcmp.cpp */
|
||||
/* 03.05.03 1.00 Lad Added compression methods */
|
||||
/* 19.11.03 1.01 Dan Big endian handling */
|
||||
/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */
|
||||
/* 09.01.13 3.00 Lad Refactored, beautified, documented :-) */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "huff.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Table of byte-to-weight values
|
||||
|
||||
// Table for (de)compression. Every compression type has 258 entries
|
||||
static unsigned char ByteToWeight_00[] =
|
||||
{
|
||||
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
// Data for compression type 0x01
|
||||
static unsigned char ByteToWeight_01[] =
|
||||
{
|
||||
0x54, 0x16, 0x16, 0x0D, 0x0C, 0x08, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x04, 0x04, 0x03, 0x05,
|
||||
0x0E, 0x0B, 0x14, 0x13, 0x13, 0x09, 0x0B, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02,
|
||||
0x0D, 0x07, 0x09, 0x06, 0x06, 0x04, 0x03, 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
|
||||
0x09, 0x06, 0x04, 0x04, 0x04, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04,
|
||||
0x08, 0x03, 0x04, 0x07, 0x09, 0x05, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02,
|
||||
0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02,
|
||||
0x06, 0x0A, 0x08, 0x08, 0x06, 0x07, 0x04, 0x03, 0x04, 0x04, 0x02, 0x02, 0x04, 0x02, 0x03, 0x03,
|
||||
0x04, 0x03, 0x07, 0x07, 0x09, 0x06, 0x04, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x0A, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x03, 0x05, 0x02, 0x03,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0x04, 0x07, 0x09, 0x08, 0x0C, 0x02,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03,
|
||||
0x04, 0x01, 0x02, 0x04, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
|
||||
0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x4B,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
// Data for compression type 0x02
|
||||
static unsigned char ByteToWeight_02[] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00, 0x23, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x06, 0x0E, 0x10, 0x04,
|
||||
0x06, 0x08, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01,
|
||||
0x01, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x03, 0x02,
|
||||
0x03, 0x01, 0x03, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01,
|
||||
0x01, 0x29, 0x07, 0x16, 0x12, 0x40, 0x0A, 0x0A, 0x11, 0x25, 0x01, 0x03, 0x17, 0x10, 0x26, 0x2A,
|
||||
0x10, 0x01, 0x23, 0x23, 0x2F, 0x10, 0x06, 0x07, 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
// Data for compression type 0x03
|
||||
static unsigned char ByteToWeight_03[] =
|
||||
{
|
||||
0xFF, 0x0B, 0x07, 0x05, 0x0B, 0x02, 0x02, 0x02, 0x06, 0x02, 0x02, 0x01, 0x04, 0x02, 0x01, 0x03,
|
||||
0x09, 0x01, 0x01, 0x01, 0x03, 0x04, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
|
||||
0x05, 0x01, 0x01, 0x01, 0x0D, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
|
||||
0x0A, 0x04, 0x02, 0x01, 0x06, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01,
|
||||
0x05, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03,
|
||||
0x01, 0x03, 0x01, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x03, 0x05, 0x01, 0x03, 0x01, 0x03, 0x03,
|
||||
0x02, 0x01, 0x04, 0x03, 0x0A, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x02, 0x01, 0x0A, 0x02, 0x05, 0x01, 0x01, 0x02, 0x07, 0x02, 0x17, 0x01, 0x05, 0x01, 0x01,
|
||||
0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x06, 0x02, 0x01, 0x04, 0x05, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
// Data for compression type 0x04
|
||||
static unsigned char ByteToWeight_04[] =
|
||||
{
|
||||
0xFF, 0xFB, 0x98, 0x9A, 0x84, 0x85, 0x63, 0x64, 0x3E, 0x3E, 0x22, 0x22, 0x13, 0x13, 0x18, 0x17,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
// Data for compression type 0x05
|
||||
static unsigned char ByteToWeight_05[] =
|
||||
{
|
||||
0xFF, 0xF1, 0x9D, 0x9E, 0x9A, 0x9B, 0x9A, 0x97, 0x93, 0x93, 0x8C, 0x8E, 0x86, 0x88, 0x80, 0x82,
|
||||
0x7C, 0x7C, 0x72, 0x73, 0x69, 0x6B, 0x5F, 0x60, 0x55, 0x56, 0x4A, 0x4B, 0x40, 0x41, 0x37, 0x37,
|
||||
0x2F, 0x2F, 0x27, 0x27, 0x21, 0x21, 0x1B, 0x1C, 0x17, 0x17, 0x13, 0x13, 0x10, 0x10, 0x0D, 0x0D,
|
||||
0x0B, 0x0B, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x05, 0x05, 0x04, 0x04, 0x04, 0x19, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
// Data for compression type 0x06
|
||||
static unsigned char ByteToWeight_06[] =
|
||||
{
|
||||
0xC3, 0xCB, 0xF5, 0x41, 0xFF, 0x7B, 0xF7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xBF, 0xCC, 0xF2, 0x40, 0xFD, 0x7C, 0xF7, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7A, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
// Data for compression type 0x07
|
||||
static unsigned char ByteToWeight_07[] =
|
||||
{
|
||||
0xC3, 0xD9, 0xEF, 0x3D, 0xF9, 0x7C, 0xE9, 0x1E, 0xFD, 0xAB, 0xF1, 0x2C, 0xFC, 0x5B, 0xFE, 0x17,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xBD, 0xD9, 0xEC, 0x3D, 0xF5, 0x7D, 0xE8, 0x1D, 0xFB, 0xAE, 0xF0, 0x2C, 0xFB, 0x5C, 0xFF, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x70, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
// Data for compression type 0x08
|
||||
static unsigned char ByteToWeight_08[] =
|
||||
{
|
||||
0xBA, 0xC5, 0xDA, 0x33, 0xE3, 0x6D, 0xD8, 0x18, 0xE5, 0x94, 0xDA, 0x23, 0xDF, 0x4A, 0xD1, 0x10,
|
||||
0xEE, 0xAF, 0xE4, 0x2C, 0xEA, 0x5A, 0xDE, 0x15, 0xF4, 0x87, 0xE9, 0x21, 0xF6, 0x43, 0xFC, 0x12,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xB0, 0xC7, 0xD8, 0x33, 0xE3, 0x6B, 0xD6, 0x18, 0xE7, 0x95, 0xD8, 0x23, 0xDB, 0x49, 0xD0, 0x11,
|
||||
0xE9, 0xB2, 0xE2, 0x2B, 0xE8, 0x5C, 0xDD, 0x15, 0xF1, 0x87, 0xE7, 0x20, 0xF7, 0x44, 0xFF, 0x13,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x5F, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
static unsigned char * WeightTables[0x09] =
|
||||
{
|
||||
ByteToWeight_00,
|
||||
ByteToWeight_01,
|
||||
ByteToWeight_02,
|
||||
ByteToWeight_03,
|
||||
ByteToWeight_04,
|
||||
ByteToWeight_05,
|
||||
ByteToWeight_06,
|
||||
ByteToWeight_07,
|
||||
ByteToWeight_08
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Debug/diagnostics
|
||||
|
||||
#ifdef _DEBUG
|
||||
void DumpHuffmannTree(THTreeItem * pItem)
|
||||
{
|
||||
THTreeItem * pChildLo; // Item with the lower weight
|
||||
THTreeItem * pChildHi; // Item with the higher weight
|
||||
|
||||
// Get the lower-weight branch
|
||||
pChildLo = pItem->pChildLo;
|
||||
if(pChildLo != NULL)
|
||||
{
|
||||
// Get the higher-weight branch
|
||||
pChildHi = pChildLo->pPrev;
|
||||
|
||||
// Parse the lower-weight branch
|
||||
DumpHuffmannTree(pChildHi);
|
||||
DumpHuffmannTree(pChildLo);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// TInputStream functions
|
||||
|
||||
TInputStream::TInputStream(void * pvInBuffer, size_t cbInBuffer)
|
||||
{
|
||||
pbInBufferEnd = (unsigned char *)pvInBuffer + cbInBuffer;
|
||||
pbInBuffer = (unsigned char *)pvInBuffer;
|
||||
BitBuffer = 0;
|
||||
BitCount = 0;
|
||||
}
|
||||
|
||||
// Gets one bit from input stream
|
||||
unsigned int TInputStream::Get1Bit()
|
||||
{
|
||||
unsigned int OneBit = 0;
|
||||
|
||||
// Ensure that the input stream is reloaded, if there are no bits left
|
||||
if(BitCount == 0)
|
||||
{
|
||||
// Refill the bit buffer
|
||||
BitBuffer = *pbInBuffer++;
|
||||
BitCount = 8;
|
||||
}
|
||||
|
||||
// Copy the bit from bit buffer to the variable
|
||||
OneBit = (BitBuffer & 0x01);
|
||||
BitBuffer >>= 1;
|
||||
BitCount--;
|
||||
|
||||
return OneBit;
|
||||
}
|
||||
|
||||
// Gets the whole byte from the input stream.
|
||||
unsigned int TInputStream::Get8Bits()
|
||||
{
|
||||
unsigned int dwReloadByte = 0;
|
||||
unsigned int dwOneByte = 0;
|
||||
|
||||
// If there is not enough bits to get the value,
|
||||
// we have to add 8 more bits from the input buffer
|
||||
if(BitCount < 8)
|
||||
{
|
||||
dwReloadByte = *pbInBuffer++;
|
||||
BitBuffer |= dwReloadByte << BitCount;
|
||||
BitCount += 8;
|
||||
}
|
||||
|
||||
// Return the lowest 8 its
|
||||
dwOneByte = (BitBuffer & 0xFF);
|
||||
BitBuffer >>= 8;
|
||||
BitCount -= 8;
|
||||
return dwOneByte;
|
||||
}
|
||||
|
||||
// Gets 7 bits from the stream. DOES NOT remove the bits from input stream
|
||||
bool TInputStream::Peek7Bits(unsigned int & Value)
|
||||
{
|
||||
unsigned int Value8Bits = 0;
|
||||
|
||||
// If there is not enough bits to get the value,
|
||||
// we have to add 8 more bits from the input buffer
|
||||
if(BitCount < 7)
|
||||
{
|
||||
// Load additional 8 bits. Be careful if we have no more data
|
||||
if(pbInBuffer >= pbInBufferEnd)
|
||||
return false;
|
||||
Value8Bits = *pbInBuffer++;
|
||||
|
||||
// Add these 8 bits to the bit buffer
|
||||
BitBuffer |= Value8Bits << BitCount;
|
||||
BitCount += 8;
|
||||
}
|
||||
|
||||
// Return 7 bits of data. DO NOT remove them from the input stream
|
||||
Value = (BitBuffer & 0x7F);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TInputStream::SkipBits(unsigned int dwBitsToSkip)
|
||||
{
|
||||
unsigned int dwReloadByte = 0;
|
||||
|
||||
// If there is not enough bits in the buffer,
|
||||
// we have to add 8 more bits from the input buffer
|
||||
if(BitCount < dwBitsToSkip)
|
||||
{
|
||||
dwReloadByte = *pbInBuffer++;
|
||||
BitBuffer |= dwReloadByte << BitCount;
|
||||
BitCount += 8;
|
||||
}
|
||||
|
||||
// Skip the remaining bits
|
||||
BitBuffer >>= dwBitsToSkip;
|
||||
BitCount -= dwBitsToSkip;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// TOutputStream functions
|
||||
|
||||
TOutputStream::TOutputStream(void * pvOutBuffer, size_t cbOutLength)
|
||||
{
|
||||
pbOutBufferEnd = (unsigned char *)pvOutBuffer + cbOutLength;
|
||||
pbOutBuffer = (unsigned char *)pvOutBuffer;
|
||||
BitBuffer = 0;
|
||||
BitCount = 0;
|
||||
}
|
||||
|
||||
void TOutputStream::PutBits(unsigned int dwValue, unsigned int nBitCount)
|
||||
{
|
||||
BitBuffer |= (dwValue << BitCount);
|
||||
BitCount += nBitCount;
|
||||
|
||||
// Flush completed bytes
|
||||
while(BitCount >= 8)
|
||||
{
|
||||
if(pbOutBuffer < pbOutBufferEnd)
|
||||
*pbOutBuffer++ = (unsigned char)BitBuffer;
|
||||
|
||||
BitBuffer >>= 8;
|
||||
BitCount -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void TOutputStream::Flush()
|
||||
{
|
||||
while(BitCount != 0)
|
||||
{
|
||||
if(pbOutBuffer < pbOutBufferEnd)
|
||||
*pbOutBuffer++ = (unsigned char)BitBuffer;
|
||||
|
||||
BitBuffer >>= 8;
|
||||
BitCount -= ((BitCount > 8) ? 8 : BitCount);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Methods of the THTreeItem struct
|
||||
|
||||
void THTreeItem::RemoveItem()
|
||||
{
|
||||
if(pNext != NULL)
|
||||
{
|
||||
pPrev->pNext = pNext;
|
||||
pNext->pPrev = pPrev;
|
||||
pNext = pPrev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// THuffmannTree class functions
|
||||
|
||||
THuffmannTree::THuffmannTree(bool bCompression)
|
||||
{
|
||||
pFirst = pLast = LIST_HEAD();
|
||||
MinValidValue = 1;
|
||||
ItemsUsed = 0;
|
||||
bIsCmp0 = 0;
|
||||
|
||||
memset(ItemsByByte, 0, sizeof(ItemsByByte));
|
||||
|
||||
// If we are going to decompress data, we need to invalidate all item links
|
||||
// We do so by zeroing their ValidValue, so it becomes lower MinValidValue
|
||||
if(bCompression == false)
|
||||
{
|
||||
memset(QuickLinks, 0, sizeof(QuickLinks));
|
||||
}
|
||||
}
|
||||
|
||||
THuffmannTree::~THuffmannTree()
|
||||
{
|
||||
// Our Huffmann tree does not use any memory allocations,
|
||||
// so we don't need to do eny code in the destructor
|
||||
}
|
||||
|
||||
void THuffmannTree::LinkTwoItems(THTreeItem * pItem1, THTreeItem * pItem2)
|
||||
{
|
||||
pItem2->pNext = pItem1->pNext;
|
||||
pItem2->pPrev = pItem1->pNext->pPrev;
|
||||
pItem1->pNext->pPrev = pItem2;
|
||||
pItem1->pNext = pItem2;
|
||||
}
|
||||
|
||||
// Inserts item into the tree (?)
|
||||
void THuffmannTree::InsertItem(THTreeItem * pNewItem, TInsertPoint InsertPoint, THTreeItem * pInsertPoint)
|
||||
{
|
||||
// Remove the item from the tree
|
||||
pNewItem->RemoveItem();
|
||||
|
||||
if(pInsertPoint == NULL)
|
||||
pInsertPoint = LIST_HEAD();
|
||||
|
||||
switch(InsertPoint)
|
||||
{
|
||||
case InsertAfter:
|
||||
LinkTwoItems(pInsertPoint, pNewItem);
|
||||
return;
|
||||
|
||||
case InsertBefore:
|
||||
pNewItem->pNext = pInsertPoint; // Set next item (or pointer to pointer to first item)
|
||||
pNewItem->pPrev = pInsertPoint->pPrev; // Set prev item (or last item in the tree)
|
||||
pInsertPoint->pPrev->pNext = pNewItem;
|
||||
pInsertPoint->pPrev = pNewItem; // Set the next/last item
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
THTreeItem * THuffmannTree::FindHigherOrEqualItem(THTreeItem * pItem, unsigned int Weight)
|
||||
{
|
||||
// Parse all existing items
|
||||
if(pItem != NULL)
|
||||
{
|
||||
while(pItem != LIST_HEAD())
|
||||
{
|
||||
if(pItem->Weight >= Weight)
|
||||
return pItem;
|
||||
|
||||
pItem = pItem->pPrev;
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, we just get the first item
|
||||
return LIST_HEAD();
|
||||
}
|
||||
|
||||
THTreeItem * THuffmannTree::CreateNewItem(unsigned int DecompressedValue, unsigned int Weight, TInsertPoint InsertPoint)
|
||||
{
|
||||
THTreeItem * pNewItem = NULL;
|
||||
|
||||
// Don't let the item buffer run out of space
|
||||
if(ItemsUsed < HUFF_ITEM_COUNT)
|
||||
{
|
||||
// Allocate new item from the item pool
|
||||
pNewItem = &ItemBuffer[ItemsUsed++];
|
||||
|
||||
// Insert this item to the top of the tree
|
||||
InsertItem(pNewItem, InsertPoint, NULL);
|
||||
|
||||
// Fill the rest of the item
|
||||
pNewItem->DecompressedValue = DecompressedValue;
|
||||
pNewItem->Weight = Weight;
|
||||
pNewItem->pParent = NULL;
|
||||
pNewItem->pChildLo = NULL;
|
||||
}
|
||||
|
||||
return pNewItem;
|
||||
}
|
||||
|
||||
unsigned int THuffmannTree::FixupItemPosByWeight(THTreeItem * pNewItem, unsigned int MaxWeight)
|
||||
{
|
||||
THTreeItem * pHigherItem;
|
||||
|
||||
if(pNewItem->Weight < MaxWeight)
|
||||
{
|
||||
// Find an item that has higher weight than this one
|
||||
pHigherItem = FindHigherOrEqualItem(pLast, pNewItem->Weight);
|
||||
|
||||
// Remove the item and put it to the new position
|
||||
pNewItem->RemoveItem();
|
||||
LinkTwoItems(pHigherItem, pNewItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxWeight = pNewItem->Weight;
|
||||
}
|
||||
|
||||
// Return the (updated) maximum weight
|
||||
return MaxWeight;
|
||||
}
|
||||
|
||||
// Builds Huffman tree. Called with the first 8 bits loaded from input stream
|
||||
bool THuffmannTree::BuildTree(unsigned int CompressionType)
|
||||
{
|
||||
THTreeItem * pNewItem;
|
||||
THTreeItem * pChildLo;
|
||||
THTreeItem * pChildHi;
|
||||
unsigned char * WeightTable;
|
||||
unsigned int MaxWeight; // [ESP+10] - The greatest character found in table
|
||||
|
||||
// Clear all pointers in HTree item array
|
||||
memset(ItemsByByte, 0, sizeof(ItemsByByte));
|
||||
MaxWeight = 0;
|
||||
|
||||
// Ensure that the compression type is in range
|
||||
if((CompressionType & 0x0F) > 0x08)
|
||||
return false;
|
||||
WeightTable = WeightTables[CompressionType & 0x0F];
|
||||
|
||||
// Build the linear list of entries that is sorted by byte weight
|
||||
for(unsigned int i = 0; i < 0x100; i++)
|
||||
{
|
||||
// Skip all the bytes which are zero.
|
||||
if(WeightTable[i] != 0)
|
||||
{
|
||||
// Create new tree item
|
||||
ItemsByByte[i] = pNewItem = CreateNewItem(i, WeightTable[i], InsertAfter);
|
||||
|
||||
// We need to put the item to the right place in the list
|
||||
MaxWeight = FixupItemPosByWeight(pNewItem, MaxWeight);
|
||||
}
|
||||
}
|
||||
|
||||
// Insert termination entries at the end of the list
|
||||
ItemsByByte[0x100] = CreateNewItem(0x100, 1, InsertBefore);
|
||||
ItemsByByte[0x101] = CreateNewItem(0x101, 1, InsertBefore);
|
||||
|
||||
// Now we need to build the tree. We start at the last entry
|
||||
// and go backwards to the first one
|
||||
pChildLo = pLast;
|
||||
|
||||
// Work as long as both children are valid
|
||||
// pChildHi is child with higher weight, pChildLo is the one with lower weight
|
||||
while(pChildLo != LIST_HEAD())
|
||||
{
|
||||
// Also get and verify the higher-weight child
|
||||
pChildHi = pChildLo->pPrev;
|
||||
if(pChildHi == LIST_HEAD())
|
||||
break;
|
||||
|
||||
// Create new parent item for the children
|
||||
pNewItem = CreateNewItem(0, pChildHi->Weight + pChildLo->Weight, InsertAfter);
|
||||
if(pNewItem == NULL)
|
||||
return false;
|
||||
|
||||
// Link both child items to their new parent
|
||||
pChildLo->pParent = pNewItem;
|
||||
pChildHi->pParent = pNewItem;
|
||||
pNewItem->pChildLo = pChildLo;
|
||||
|
||||
// Fixup the item's position by its weight
|
||||
MaxWeight = FixupItemPosByWeight(pNewItem, MaxWeight);
|
||||
|
||||
// Get the previous lower-weight child
|
||||
pChildLo = pChildHi->pPrev;
|
||||
}
|
||||
|
||||
// Initialize the MinValidValue to 1, which invalidates all quick-link items
|
||||
MinValidValue = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
void THuffmannTree::IncWeightsAndRebalance(THTreeItem * pItem)
|
||||
{
|
||||
THTreeItem * pHigherItem; // A previous item with greater or equal weight
|
||||
THTreeItem * pChildHi; // The higher-weight child
|
||||
THTreeItem * pChildLo; // The lower-weight child
|
||||
THTreeItem * pParent;
|
||||
|
||||
// Climb up the tree and increment weight of each tree item
|
||||
for(; pItem != NULL; pItem = pItem->pParent)
|
||||
{
|
||||
// Increment the item's weight
|
||||
pItem->Weight++;
|
||||
|
||||
// Find a previous item with equal or greater weight, which is not equal to this item
|
||||
pHigherItem = FindHigherOrEqualItem(pItem->pPrev, pItem->Weight);
|
||||
pChildHi = pHigherItem->pNext;
|
||||
|
||||
// If the item is not equal to the tree item, we need to rebalance the tree
|
||||
if(pChildHi != pItem)
|
||||
{
|
||||
// Move the previous item to the RIGHT from the given item
|
||||
pChildHi->RemoveItem();
|
||||
LinkTwoItems(pItem, pChildHi);
|
||||
|
||||
// Move the given item AFTER the greater-weight tree item
|
||||
pItem->RemoveItem();
|
||||
LinkTwoItems(pHigherItem, pItem);
|
||||
|
||||
// We need to maintain the tree so that pChildHi->Weight is >= pChildLo->Weight.
|
||||
// Rebalance the tree accordingly.
|
||||
pChildLo = pChildHi->pParent->pChildLo;
|
||||
pParent = pItem->pParent;
|
||||
if(pParent->pChildLo == pItem)
|
||||
pParent->pChildLo = pChildHi;
|
||||
if(pChildLo == pChildHi)
|
||||
pChildHi->pParent->pChildLo = pItem;
|
||||
pParent = pItem->pParent;
|
||||
pItem->pParent = pChildHi->pParent;
|
||||
pChildHi->pParent = pParent;
|
||||
|
||||
// Increment the global valid value. This invalidates all quick-link items.
|
||||
MinValidValue++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool THuffmannTree::InsertNewBranchAndRebalance(unsigned int Value1, unsigned int Value2)
|
||||
{
|
||||
THTreeItem * pLastItem = pLast;
|
||||
THTreeItem * pChildHi;
|
||||
THTreeItem * pChildLo;
|
||||
|
||||
// Create higher-weight child
|
||||
pChildHi = CreateNewItem(Value1, pLastItem->Weight, InsertBefore);
|
||||
if(pChildHi != NULL)
|
||||
{
|
||||
pChildHi->pParent = pLastItem;
|
||||
ItemsByByte[Value1] = pChildHi;
|
||||
|
||||
// Create lower-weight child
|
||||
pChildLo = CreateNewItem(Value2, 0, InsertBefore);
|
||||
if(pChildLo != NULL)
|
||||
{
|
||||
pChildLo->pParent = pLastItem;
|
||||
pLastItem->pChildLo = pChildLo;
|
||||
ItemsByByte[Value2] = pChildLo;
|
||||
|
||||
IncWeightsAndRebalance(pChildLo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// No more space in the tree buffer
|
||||
return false;
|
||||
}
|
||||
|
||||
void THuffmannTree::EncodeOneByte(TOutputStream * os, THTreeItem * pItem)
|
||||
{
|
||||
THTreeItem * pParent = pItem->pParent;
|
||||
unsigned int BitBuffer = 0;
|
||||
unsigned int BitCount = 0;
|
||||
|
||||
// Put 1's as long as there is parent
|
||||
while(pParent != NULL)
|
||||
{
|
||||
// Fill the bit buffer
|
||||
BitBuffer = (BitBuffer << 1) | ((pParent->pChildLo != pItem) ? 1 : 0);
|
||||
BitCount++;
|
||||
|
||||
// Move to the parent
|
||||
pItem = pParent;
|
||||
pParent = pParent->pParent;
|
||||
}
|
||||
|
||||
// Write the bits to the output stream
|
||||
os->PutBits(BitBuffer, BitCount);
|
||||
}
|
||||
|
||||
unsigned int THuffmannTree::DecodeOneByte(TInputStream * is)
|
||||
{
|
||||
THTreeItem * pItemLink = NULL;
|
||||
THTreeItem * pItem;
|
||||
unsigned int ItemLinkIndex;
|
||||
unsigned int BitCount = 0;
|
||||
bool bHasItemLinkIndex;
|
||||
|
||||
// Try to retrieve quick link index
|
||||
bHasItemLinkIndex = is->Peek7Bits(ItemLinkIndex);
|
||||
|
||||
// Is the quick-link item valid?
|
||||
if(bHasItemLinkIndex && QuickLinks[ItemLinkIndex].ValidValue > MinValidValue)
|
||||
{
|
||||
// If that item needs less than 7 bits, we can get decompressed value directly
|
||||
if(QuickLinks[ItemLinkIndex].ValidBits <= 7)
|
||||
{
|
||||
is->SkipBits(QuickLinks[ItemLinkIndex].ValidBits);
|
||||
return QuickLinks[ItemLinkIndex].DecompressedValue;
|
||||
}
|
||||
|
||||
// Otherwise we cannot get decompressed value directly
|
||||
// but we can skip 7 levels of tree parsing
|
||||
pItem = QuickLinks[ItemLinkIndex].pItem;
|
||||
is->SkipBits(7);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just a sanity check
|
||||
if(pFirst == LIST_HEAD())
|
||||
return 0x1FF;
|
||||
|
||||
// We don't have the quick-link item, we need to parse the tree from its root
|
||||
pItem = pFirst;
|
||||
}
|
||||
|
||||
// Step down the tree until we find a terminal item
|
||||
while(pItem->pChildLo != NULL)
|
||||
{
|
||||
// If the next bit in the compressed stream is set, we get the higher-weight
|
||||
// child. Otherwise, get the lower-weight child.
|
||||
pItem = is->Get1Bit() ? pItem->pChildLo->pPrev : pItem->pChildLo;
|
||||
BitCount++;
|
||||
|
||||
// If the number of loaded bits reached 7,
|
||||
// remember the current item for storing into quick-link item array
|
||||
if(BitCount == 7)
|
||||
pItemLink = pItem;
|
||||
}
|
||||
|
||||
// If we didn't get the item from the quick-link array,
|
||||
// set the entry in it
|
||||
if(bHasItemLinkIndex && QuickLinks[ItemLinkIndex].ValidValue < MinValidValue)
|
||||
{
|
||||
// If the current compressed byte was more than 7 bits,
|
||||
// set a quick-link item with pointer to tree item
|
||||
if(BitCount > 7)
|
||||
{
|
||||
QuickLinks[ItemLinkIndex].ValidValue = MinValidValue;
|
||||
QuickLinks[ItemLinkIndex].ValidBits = BitCount;
|
||||
QuickLinks[ItemLinkIndex].pItem = pItemLink;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Limit the quick-decompress item to lower amount of bits
|
||||
// Coverity fix 84457: (x >> 32) has undefined behavior
|
||||
ItemLinkIndex = (BitCount != 0) ? ItemLinkIndex & (0xFFFFFFFF >> (32 - BitCount)) : 0;
|
||||
while(ItemLinkIndex < LINK_ITEM_COUNT)
|
||||
{
|
||||
// Fill the quick-decompress item
|
||||
QuickLinks[ItemLinkIndex].ValidValue = MinValidValue;
|
||||
QuickLinks[ItemLinkIndex].ValidBits = BitCount;
|
||||
QuickLinks[ItemLinkIndex].DecompressedValue = pItem->DecompressedValue;
|
||||
|
||||
// Increment the index
|
||||
ItemLinkIndex += (1 << BitCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the decompressed value from the found item
|
||||
return pItem->DecompressedValue;
|
||||
}
|
||||
|
||||
unsigned int THuffmannTree::Compress(TOutputStream * os, void * pvInBuffer, int cbInBuffer, int CompressionType)
|
||||
{
|
||||
unsigned char * pbInBufferEnd = (unsigned char *)pvInBuffer + cbInBuffer;
|
||||
unsigned char * pbInBuffer = (unsigned char *)pvInBuffer;
|
||||
unsigned char * pbOutBuff = os->pbOutBuffer;
|
||||
unsigned char InputByte;
|
||||
|
||||
if(!BuildTree(CompressionType))
|
||||
return 0;
|
||||
bIsCmp0 = (CompressionType == 0);
|
||||
|
||||
// Store the compression type into output buffer
|
||||
os->PutBits(CompressionType, 8);
|
||||
|
||||
// Process the entire input buffer
|
||||
while(pbInBuffer < pbInBufferEnd)
|
||||
{
|
||||
// Get the (next) byte from the input buffer
|
||||
InputByte = *pbInBuffer++;
|
||||
|
||||
// Do we have an item for such input value?
|
||||
if(ItemsByByte[InputByte] == NULL)
|
||||
{
|
||||
// Encode the relationship
|
||||
EncodeOneByte(os, ItemsByByte[0x101]);
|
||||
|
||||
// Store the loaded byte into output stream
|
||||
os->PutBits(InputByte, 8);
|
||||
|
||||
if(!InsertNewBranchAndRebalance(pLast->DecompressedValue, InputByte))
|
||||
return 0;
|
||||
|
||||
if(bIsCmp0)
|
||||
{
|
||||
IncWeightsAndRebalance(ItemsByByte[InputByte]);
|
||||
continue;
|
||||
}
|
||||
|
||||
IncWeightsAndRebalance(ItemsByByte[InputByte]);
|
||||
}
|
||||
else
|
||||
{
|
||||
EncodeOneByte(os, ItemsByByte[InputByte]);
|
||||
}
|
||||
|
||||
if(bIsCmp0)
|
||||
{
|
||||
IncWeightsAndRebalance(ItemsByByte[InputByte]);
|
||||
}
|
||||
}
|
||||
|
||||
// Put the termination mark to the compressed stream
|
||||
EncodeOneByte(os, ItemsByByte[0x100]);
|
||||
|
||||
// Flush the remaining bits
|
||||
os->Flush();
|
||||
return (unsigned int)(os->pbOutBuffer - pbOutBuff);
|
||||
}
|
||||
|
||||
// Decompression using Huffman tree (1500E450)
|
||||
unsigned int THuffmannTree::Decompress(void * pvOutBuffer, unsigned int cbOutLength, TInputStream * is)
|
||||
{
|
||||
unsigned char * pbOutBufferEnd = (unsigned char *)pvOutBuffer + cbOutLength;
|
||||
unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer;
|
||||
unsigned int DecompressedValue = 0;
|
||||
unsigned int CompressionType = 0;
|
||||
|
||||
// Test the output length. Must not be NULL.
|
||||
if(cbOutLength == 0)
|
||||
return 0;
|
||||
|
||||
// Get the compression type from the input stream
|
||||
CompressionType = is->Get8Bits();
|
||||
bIsCmp0 = (CompressionType == 0) ? 1 : 0;
|
||||
|
||||
// Build the Huffman tree
|
||||
if(!BuildTree(CompressionType))
|
||||
return 0;
|
||||
|
||||
// Process the entire input buffer until end of the stream
|
||||
while((DecompressedValue = DecodeOneByte(is)) != 0x100)
|
||||
{
|
||||
// Did an error occur?
|
||||
if(DecompressedValue == 0x1FF) // An error occurred
|
||||
return 0;
|
||||
|
||||
// Huffman tree needs to be modified
|
||||
if(DecompressedValue == 0x101)
|
||||
{
|
||||
// The decompressed byte is stored in the next 8 bits
|
||||
DecompressedValue = is->Get8Bits();
|
||||
|
||||
if(!InsertNewBranchAndRebalance(pLast->DecompressedValue, DecompressedValue))
|
||||
return 0;
|
||||
|
||||
if(bIsCmp0 == 0)
|
||||
IncWeightsAndRebalance(ItemsByByte[DecompressedValue]);
|
||||
}
|
||||
|
||||
// Store the byte to the output stream
|
||||
if(pbOutBuffer >= pbOutBufferEnd)
|
||||
break;
|
||||
*pbOutBuffer++ = (unsigned char)DecompressedValue;
|
||||
|
||||
if(bIsCmp0)
|
||||
{
|
||||
IncWeightsAndRebalance(ItemsByByte[DecompressedValue]);
|
||||
}
|
||||
}
|
||||
|
||||
return (unsigned int)(pbOutBuffer - (unsigned char *)pvOutBuffer);
|
||||
}
|
||||
|
||||
143
src/util/mpq/huff.h
Normal file
143
src/util/mpq/huff.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*****************************************************************************/
|
||||
/* huffman.h Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Description : */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* xx.xx.xx 1.00 Lad The first version of huffman.h */
|
||||
/* 03.05.03 2.00 Lad Added compression */
|
||||
/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __HUFFMAN_H__
|
||||
#define __HUFFMAN_H__
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define HUFF_ITEM_COUNT 0x203 // Number of items in the item pool
|
||||
#define LINK_ITEM_COUNT 0x80 // Maximum number of quick-link items
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Structures and classes
|
||||
|
||||
// Input stream for Huffmann decompression
|
||||
class TInputStream
|
||||
{
|
||||
public:
|
||||
|
||||
TInputStream(void * pvInBuffer, size_t cbInBuffer);
|
||||
unsigned int Get1Bit();
|
||||
unsigned int Get8Bits();
|
||||
bool Peek7Bits(unsigned int & Value);
|
||||
void SkipBits(unsigned int BitCount);
|
||||
|
||||
unsigned char * pbInBufferEnd; // End position in the the input buffer
|
||||
unsigned char * pbInBuffer; // Current position in the the input buffer
|
||||
unsigned int BitBuffer; // Input bit buffer
|
||||
unsigned int BitCount; // Number of bits remaining in 'dwBitBuff'
|
||||
};
|
||||
|
||||
|
||||
// Output stream for Huffmann compression
|
||||
class TOutputStream
|
||||
{
|
||||
public:
|
||||
|
||||
TOutputStream(void * pvOutBuffer, size_t cbOutLength);
|
||||
void PutBits(unsigned int dwValue, unsigned int nBitCount);
|
||||
void Flush();
|
||||
|
||||
unsigned char * pbOutBufferEnd; // End position in the output buffer
|
||||
unsigned char * pbOutBuffer; // Current position in the output buffer
|
||||
unsigned int BitBuffer; // Bit buffer
|
||||
unsigned int BitCount; // Number of bits in the bit buffer
|
||||
};
|
||||
|
||||
// A virtual tree item that represents the head of the item list
|
||||
#define LIST_HEAD() ((THTreeItem *)(&pFirst))
|
||||
|
||||
enum TInsertPoint
|
||||
{
|
||||
InsertAfter = 1,
|
||||
InsertBefore = 2
|
||||
};
|
||||
|
||||
// Huffmann tree item
|
||||
struct THTreeItem
|
||||
{
|
||||
THTreeItem() { pPrev = pNext = NULL; DecompressedValue = 0; Weight = 0; pParent = pChildLo = NULL; }
|
||||
// ~THTreeItem() { RemoveItem(); }
|
||||
|
||||
void RemoveItem();
|
||||
// void RemoveEntry();
|
||||
|
||||
THTreeItem * pNext; // Pointer to lower-weight tree item
|
||||
THTreeItem * pPrev; // Pointer to higher-weight item
|
||||
unsigned int DecompressedValue; // 08 - Decompressed byte value (also index in the array)
|
||||
unsigned int Weight; // 0C - Weight
|
||||
THTreeItem * pParent; // 10 - Pointer to parent item (NULL if none)
|
||||
THTreeItem * pChildLo; // 14 - Pointer to the child with lower-weight child ("left child")
|
||||
};
|
||||
|
||||
|
||||
// Structure used for quick navigating in the huffmann tree.
|
||||
// Allows skipping up to 7 bits in the compressed stream, thus
|
||||
// decompressing a bit faster. Sometimes it can even get the decompressed
|
||||
// byte directly.
|
||||
struct TQuickLink
|
||||
{
|
||||
unsigned int ValidValue; // If greater than THuffmannTree::MinValidValue, the entry is valid
|
||||
unsigned int ValidBits; // Number of bits that are valid for this item link
|
||||
union
|
||||
{
|
||||
THTreeItem * pItem; // Pointer to the item within the Huffmann tree
|
||||
unsigned int DecompressedValue; // Value for direct decompression
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Structure for Huffman tree (Size 0x3674 bytes). Because I'm not expert
|
||||
// for the decompression, I do not know actually if the class is really a Hufmann
|
||||
// tree. If someone knows the decompression details, please let me know
|
||||
class THuffmannTree
|
||||
{
|
||||
public:
|
||||
|
||||
THuffmannTree(bool bCompression);
|
||||
~THuffmannTree();
|
||||
|
||||
void LinkTwoItems(THTreeItem * pItem1, THTreeItem * pItem2);
|
||||
void InsertItem(THTreeItem * item, TInsertPoint InsertPoint, THTreeItem * item2);
|
||||
|
||||
THTreeItem * FindHigherOrEqualItem(THTreeItem * pItem, unsigned int Weight);
|
||||
THTreeItem * CreateNewItem(unsigned int DecompressedValue, unsigned int Weight, TInsertPoint InsertPoint);
|
||||
|
||||
unsigned int FixupItemPosByWeight(THTreeItem * pItem, unsigned int MaxWeight);
|
||||
bool BuildTree(unsigned int CompressionType);
|
||||
|
||||
void IncWeightsAndRebalance(THTreeItem * pItem);
|
||||
bool InsertNewBranchAndRebalance(unsigned int Value1, unsigned int Value2);
|
||||
|
||||
void EncodeOneByte(TOutputStream * os, THTreeItem * pItem);
|
||||
unsigned int DecodeOneByte(TInputStream * is);
|
||||
|
||||
unsigned int Compress(TOutputStream * os, void * pvInBuffer, int cbInBuffer, int nCmpType);
|
||||
unsigned int Decompress(void * pvOutBuffer, unsigned int cbOutLength, TInputStream * is);
|
||||
|
||||
THTreeItem ItemBuffer[HUFF_ITEM_COUNT]; // Buffer for tree items. No memory allocation is needed
|
||||
unsigned int ItemsUsed; // Number of tree items used from ItemBuffer
|
||||
|
||||
// Head of the linear item list
|
||||
THTreeItem * pFirst; // Pointer to the highest weight item
|
||||
THTreeItem * pLast; // Pointer to the lowest weight item
|
||||
|
||||
THTreeItem * ItemsByByte[0x102]; // Array of item pointers, one for each possible byte value
|
||||
TQuickLink QuickLinks[LINK_ITEM_COUNT]; // Array of quick-link items
|
||||
|
||||
unsigned int MinValidValue; // A minimum value of TQDecompress::ValidValue to be considered valid
|
||||
unsigned int bIsCmp0; // 1 if compression type 0
|
||||
};
|
||||
|
||||
#endif // __HUFFMAN_H__
|
||||
160
src/util/mpq/pklib.h
Normal file
160
src/util/mpq/pklib.h
Normal file
@ -0,0 +1,160 @@
|
||||
/*****************************************************************************/
|
||||
/* pklib.h Copyright (c) Ladislav Zezula 2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Header file for PKWARE Data Compression Library */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 31.03.03 1.00 Lad Created */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __PKLIB_H__
|
||||
#define __PKLIB_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define CMP_BINARY 0 // Binary compression
|
||||
#define CMP_ASCII 1 // Ascii compression
|
||||
|
||||
#define CMP_NO_ERROR 0
|
||||
#define CMP_INVALID_DICTSIZE 1
|
||||
#define CMP_INVALID_MODE 2
|
||||
#define CMP_BAD_DATA 3
|
||||
#define CMP_ABORT 4
|
||||
|
||||
#define CMP_IMPLODE_DICT_SIZE1 1024 // Dictionary size of 1024
|
||||
#define CMP_IMPLODE_DICT_SIZE2 2048 // Dictionary size of 2048
|
||||
#define CMP_IMPLODE_DICT_SIZE3 4096 // Dictionary size of 4096
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Define calling convention
|
||||
|
||||
#ifndef PKEXPORT
|
||||
#ifdef WIN32
|
||||
#define PKEXPORT __cdecl // Use for normal __cdecl calling
|
||||
#else
|
||||
#define PKEXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Internal structures
|
||||
|
||||
// Compression structure
|
||||
typedef struct
|
||||
{
|
||||
unsigned int distance; // 0000: Backward distance of the currently found repetition, decreased by 1
|
||||
unsigned int out_bytes; // 0004: # bytes available in out_buff
|
||||
unsigned int out_bits; // 0008: # of bits available in the last out byte
|
||||
unsigned int dsize_bits; // 000C: Number of bits needed for dictionary size. 4 = 0x400, 5 = 0x800, 6 = 0x1000
|
||||
unsigned int dsize_mask; // 0010: Bit mask for dictionary. 0x0F = 0x400, 0x1F = 0x800, 0x3F = 0x1000
|
||||
unsigned int ctype; // 0014: Compression type (CMP_ASCII or CMP_BINARY)
|
||||
unsigned int dsize_bytes; // 0018: Dictionary size in bytes
|
||||
unsigned char dist_bits[0x40]; // 001C: Distance bits
|
||||
unsigned char dist_codes[0x40]; // 005C: Distance codes
|
||||
unsigned char nChBits[0x306]; // 009C: Table of literal bit lengths to be put to the output stream
|
||||
unsigned short nChCodes[0x306]; // 03A2: Table of literal codes to be put to the output stream
|
||||
unsigned short offs09AE; // 09AE:
|
||||
|
||||
void * param; // 09B0: User parameter
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // 9B4
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param); // 9B8
|
||||
|
||||
unsigned short offs09BC[0x204]; // 09BC:
|
||||
unsigned long offs0DC4; // 0DC4:
|
||||
unsigned short phash_to_index[0x900]; // 0DC8: Array of indexes (one for each PAIR_HASH) to the "pair_hash_offsets" table
|
||||
unsigned short phash_to_index_end; // 1FC8: End marker for "phash_to_index" table
|
||||
char out_buff[0x802]; // 1FCA: Compressed data
|
||||
unsigned char work_buff[0x2204]; // 27CC: Work buffer
|
||||
// + DICT_OFFSET => Dictionary
|
||||
// + UNCMP_OFFSET => Uncompressed data
|
||||
unsigned short phash_offs[0x2204]; // 49D0: Table of offsets for each PAIR_HASH
|
||||
} TCmpStruct;
|
||||
|
||||
#define CMP_BUFFER_SIZE sizeof(TCmpStruct) // Size of compression structure.
|
||||
// Defined as 36312 in pkware header file
|
||||
|
||||
|
||||
// Decompression structure
|
||||
typedef struct
|
||||
{
|
||||
unsigned long offs0000; // 0000
|
||||
unsigned long ctype; // 0004: Compression type (CMP_BINARY or CMP_ASCII)
|
||||
unsigned long outputPos; // 0008: Position in output buffer
|
||||
unsigned long dsize_bits; // 000C: Dict size (4, 5, 6 for 0x400, 0x800, 0x1000)
|
||||
unsigned long dsize_mask; // 0010: Dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000)
|
||||
unsigned long bit_buff; // 0014: 16-bit buffer for processing input data
|
||||
unsigned long extra_bits; // 0018: Number of extra (above 8) bits in bit buffer
|
||||
unsigned int in_pos; // 001C: Position in in_buff
|
||||
unsigned long in_bytes; // 0020: Number of bytes in input buffer
|
||||
void * param; // 0024: Custom parameter
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // Pointer to function that reads data from the input stream
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param);// Pointer to function that writes data to the output stream
|
||||
|
||||
unsigned char out_buff[0x2204]; // 0030: Output circle buffer.
|
||||
// 0x0000 - 0x0FFF: Previous uncompressed data, kept for repetitions
|
||||
// 0x1000 - 0x1FFF: Currently decompressed data
|
||||
// 0x2000 - 0x2203: Reserve space for the longest possible repetition
|
||||
unsigned char in_buff[0x800]; // 2234: Buffer for data to be decompressed
|
||||
unsigned char DistPosCodes[0x100]; // 2A34: Table of distance position codes
|
||||
unsigned char LengthCodes[0x100]; // 2B34: Table of length codes
|
||||
unsigned char offs2C34[0x100]; // 2C34: Buffer for
|
||||
unsigned char offs2D34[0x100]; // 2D34: Buffer for
|
||||
unsigned char offs2E34[0x80]; // 2E34: Buffer for
|
||||
unsigned char offs2EB4[0x100]; // 2EB4: Buffer for
|
||||
unsigned char ChBitsAsc[0x100]; // 2FB4: Buffer for
|
||||
unsigned char DistBits[0x40]; // 30B4: Numbers of bytes to skip copied block length
|
||||
unsigned char LenBits[0x10]; // 30F4: Numbers of bits for skip copied block length
|
||||
unsigned char ExLenBits[0x10]; // 3104: Number of valid bits for copied block
|
||||
unsigned short LenBase[0x10]; // 3114: Buffer for
|
||||
} TDcmpStruct;
|
||||
|
||||
#define EXP_BUFFER_SIZE sizeof(TDcmpStruct) // Size of decompression structure
|
||||
// Defined as 12596 in pkware headers
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tables (in explode.c)
|
||||
|
||||
extern const unsigned char DistBits[0x40];
|
||||
extern const unsigned char DistCode[0x40];
|
||||
extern const unsigned char ExLenBits[0x10];
|
||||
extern const unsigned short LenBase[0x10];
|
||||
extern const unsigned char LenBits[0x10];
|
||||
extern const unsigned char LenCode[0x10];
|
||||
extern const unsigned char ChBitsAsc[0x100];
|
||||
extern const unsigned short ChCodeAsc[0x100];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public functions
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned int PKEXPORT implode(
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param),
|
||||
char *work_buf,
|
||||
void *param,
|
||||
unsigned int *type,
|
||||
unsigned int *dsize);
|
||||
|
||||
|
||||
unsigned int PKEXPORT explode(
|
||||
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
|
||||
void (*write_buf)(char *buf, unsigned int *size, void *param),
|
||||
char *work_buf,
|
||||
void *param);
|
||||
|
||||
// The original name "crc32" was changed to "crc32_pklib" due
|
||||
// to compatibility with zlib
|
||||
unsigned long PKEXPORT crc32_pklib(char *buffer, unsigned int *size, unsigned long *old_crc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // End of 'extern "C"' declaration
|
||||
#endif
|
||||
|
||||
#endif // __PKLIB_H__
|
||||
282
src/util/mpq/sparse.cpp
Normal file
282
src/util/mpq/sparse.cpp
Normal file
@ -0,0 +1,282 @@
|
||||
/*****************************************************************************/
|
||||
/* huffman.cpp Copyright (c) Ladislav Zezula 1998-2003 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* This module contains Huffmann (de)compression methods */
|
||||
/* */
|
||||
/* Authors : Ladislav Zezula (ladik.zezula.net) */
|
||||
/* ShadowFlare (BlakFlare@hotmail.com) */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* xx.xx.xx 1.00 Lad The first version of dcmp.cpp */
|
||||
/* 03.05.03 1.00 Lad Added compression methods */
|
||||
/* 19.11.03 1.01 Dan Big endian handling */
|
||||
/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sparse.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public functions
|
||||
|
||||
void CompressSparse(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
|
||||
{
|
||||
unsigned char * pbOutBufferEnd = (unsigned char *)pvOutBuffer + *pcbOutBuffer;
|
||||
unsigned char * pbInBufferEnd = (unsigned char *)pvInBuffer + cbInBuffer;
|
||||
unsigned char * pbLastNonZero = (unsigned char *)pvInBuffer;
|
||||
unsigned char * pbOutBuffer0 = (unsigned char *)pvOutBuffer;
|
||||
unsigned char * pbInBuffPtr = (unsigned char *)pvInBuffer;
|
||||
unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer;
|
||||
unsigned char * pbInBuffer = (unsigned char *)pvInBuffer;
|
||||
size_t NumberOfNonZeros;
|
||||
size_t NumberOfZeros;
|
||||
|
||||
// There must be at least 4 bytes of free space in the output buffer now
|
||||
if((pbInBuffer + 4) >= pbInBufferEnd)
|
||||
return;
|
||||
|
||||
// Put the original data length (in little endian)
|
||||
*pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x18);
|
||||
*pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x10);
|
||||
*pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x08);
|
||||
*pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x00);
|
||||
|
||||
// If there is at least 3 bytes in the input buffer, do this loop
|
||||
while(pbInBuffer < (pbInBufferEnd - 3))
|
||||
{
|
||||
// Reset the zero count and frontal pointer
|
||||
pbLastNonZero = pbInBuffer;
|
||||
pbInBuffPtr = pbInBuffer;
|
||||
NumberOfZeros = 0;
|
||||
|
||||
if(pbInBuffPtr < pbInBufferEnd)
|
||||
{
|
||||
do
|
||||
{
|
||||
// Count number of zeros
|
||||
if(*pbInBuffPtr == 0)
|
||||
{
|
||||
NumberOfZeros++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Were there at least 3 zeros before? If yes, we need to flush the data
|
||||
if(NumberOfZeros >= 3)
|
||||
break;
|
||||
pbLastNonZero = pbInBuffPtr + 1;
|
||||
NumberOfZeros = 0;
|
||||
}
|
||||
}
|
||||
while(++pbInBuffPtr < pbInBufferEnd);
|
||||
}
|
||||
|
||||
// Get number of nonzeros that we found so far and flush them
|
||||
NumberOfNonZeros = pbLastNonZero - pbInBuffer;
|
||||
if(NumberOfNonZeros != 0)
|
||||
{
|
||||
// Process blocks that are longer than 0x81 nonzero bytes
|
||||
while(NumberOfNonZeros > 0x81)
|
||||
{
|
||||
// Verify if we still have enough space in output buffer
|
||||
if((pbOutBuffer + 0x81) >= pbOutBufferEnd)
|
||||
return;
|
||||
|
||||
// Put marker that means "0x80 of nonzeros"
|
||||
*pbOutBuffer++ = 0xFF;
|
||||
memcpy(pbOutBuffer, pbInBuffer, 0x80);
|
||||
|
||||
// Adjust counter of nonzeros and both pointers
|
||||
NumberOfNonZeros -= 0x80;
|
||||
pbOutBuffer += 0x80;
|
||||
pbInBuffer += 0x80;
|
||||
}
|
||||
|
||||
// BUGBUG: The following code will be triggered if the NumberOfNonZeros
|
||||
// was 0x81 before. It will copy just one byte. This seems like a bug to me,
|
||||
// but since I want StormLib to be exact like Blizzard code is, I will keep
|
||||
// it that way here
|
||||
if(NumberOfNonZeros > 0x80)
|
||||
{
|
||||
// Verify if we still have enough space in output buffer
|
||||
if((pbOutBuffer + 2) >= pbOutBufferEnd)
|
||||
return;
|
||||
|
||||
// Put marker that means "1 nonzero byte"
|
||||
*pbOutBuffer++ = 0x80;
|
||||
memcpy(pbOutBuffer, pbInBuffer, 1);
|
||||
|
||||
// Adjust counter of nonzeros and both pointers
|
||||
NumberOfNonZeros--;
|
||||
pbOutBuffer++;
|
||||
pbInBuffer++;
|
||||
}
|
||||
|
||||
// If there is 1 nonzero or more, put the block
|
||||
if(NumberOfNonZeros >= 0x01)
|
||||
{
|
||||
// Verify if we still have enough space in output buffer
|
||||
if((pbOutBuffer + NumberOfNonZeros + 1) >= pbOutBufferEnd)
|
||||
return;
|
||||
|
||||
// Put marker that means "Several nonzero bytes"
|
||||
*pbOutBuffer++ = (unsigned char)(0x80 | (NumberOfNonZeros - 1));
|
||||
memcpy(pbOutBuffer, pbInBuffer, NumberOfNonZeros);
|
||||
|
||||
// Adjust pointers
|
||||
pbOutBuffer += NumberOfNonZeros;
|
||||
pbInBuffer += NumberOfNonZeros;
|
||||
}
|
||||
}
|
||||
|
||||
// Now flush all zero bytes
|
||||
while(NumberOfZeros > 0x85)
|
||||
{
|
||||
// Do we have at least 2 bytes in the output buffer ?
|
||||
if((pbOutBuffer + 1) >= pbOutBufferEnd)
|
||||
return;
|
||||
|
||||
// Put marker that means "0x82 zeros"
|
||||
*pbOutBuffer++ = 0x7F;
|
||||
|
||||
// Adjust zero counter and input pointer
|
||||
NumberOfZeros -= 0x82;
|
||||
pbInBuffer += 0x82;
|
||||
}
|
||||
|
||||
// If we got more than 0x82 zeros, flush 3 of them now
|
||||
if(NumberOfZeros > 0x82)
|
||||
{
|
||||
// Do we have at least 2 bytes in the output buffer ?
|
||||
if((pbOutBuffer + 1) >= pbOutBufferEnd)
|
||||
return;
|
||||
|
||||
// Put marker that means "0x03 zeros"
|
||||
*pbOutBuffer++ = 0;
|
||||
|
||||
// Adjust zero counter and input pointer
|
||||
NumberOfZeros -= 0x03;
|
||||
pbInBuffer += 0x03;
|
||||
}
|
||||
|
||||
// Is there at least three zeros ?
|
||||
if(NumberOfZeros >= 3)
|
||||
{
|
||||
// Do we have at least 2 bytes in the output buffer ?
|
||||
if((pbOutBuffer + 1) >= pbOutBufferEnd)
|
||||
return;
|
||||
|
||||
// Put marker that means "Several zeros"
|
||||
*pbOutBuffer++ = (unsigned char)(NumberOfZeros - 3);
|
||||
|
||||
// Adjust pointer
|
||||
pbInBuffer += NumberOfZeros;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush last three bytes
|
||||
if(pbInBuffer < pbInBufferEnd)
|
||||
{
|
||||
pbInBuffPtr = pbInBuffer;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(*pbInBuffPtr++ != 0)
|
||||
{
|
||||
// Get number of bytes remaining
|
||||
NumberOfNonZeros = (pbInBufferEnd - pbInBuffer);
|
||||
|
||||
// Not enough space in the output buffer ==> exit
|
||||
if((pbOutBuffer + NumberOfNonZeros + 1) >= pbOutBufferEnd)
|
||||
return;
|
||||
|
||||
// Terminate with a marker that means "0x80 of nonzeros"
|
||||
*pbOutBuffer++ = 0xFF;
|
||||
memcpy(pbOutBuffer, pbInBuffer, NumberOfNonZeros);
|
||||
|
||||
// Adjust pointer
|
||||
pbOutBuffer += NumberOfNonZeros;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Is there are more chars in the input buffer
|
||||
if(pbInBuffPtr < pbInBufferEnd)
|
||||
continue;
|
||||
|
||||
// If the compression will not compress it by even 1 byte, do nothing
|
||||
if((pbOutBuffer + 1) >= pbOutBufferEnd)
|
||||
return;
|
||||
|
||||
// Terminate with a chunk that means "0x82 of zeros"
|
||||
*pbOutBuffer++ = 0x7F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Out the length of the output buffer
|
||||
*pcbOutBuffer = (int)(pbOutBuffer - pbOutBuffer0);
|
||||
}
|
||||
|
||||
int DecompressSparse(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
|
||||
{
|
||||
unsigned char * pbInBufferEnd = (unsigned char *)pvInBuffer + cbInBuffer;
|
||||
unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer;
|
||||
unsigned char * pbInBuffer = (unsigned char *)pvInBuffer;
|
||||
unsigned int cbChunkSize;
|
||||
unsigned int cbOutBuffer = 0;
|
||||
unsigned int OneByte;
|
||||
|
||||
// Don't decompress anything that is shorter than 5 bytes
|
||||
if(cbInBuffer < 5)
|
||||
return 0;
|
||||
|
||||
// Get the 32-bits from the input stream
|
||||
OneByte = *pbInBuffer++;
|
||||
cbOutBuffer |= (OneByte << 0x18);
|
||||
OneByte = *pbInBuffer++;
|
||||
cbOutBuffer |= (OneByte << 0x10);
|
||||
OneByte = *pbInBuffer++;
|
||||
cbOutBuffer |= (OneByte << 0x08);
|
||||
OneByte = *pbInBuffer++;
|
||||
cbOutBuffer |= (OneByte << 0x00);
|
||||
|
||||
// Verify the size of the stream against the output buffer size
|
||||
if(cbOutBuffer > (unsigned int)*pcbOutBuffer)
|
||||
return 0;
|
||||
|
||||
// Put the output size to the buffer
|
||||
*pcbOutBuffer = cbOutBuffer;
|
||||
|
||||
// Process the input buffer
|
||||
while(pbInBuffer < pbInBufferEnd)
|
||||
{
|
||||
// Get (next) byte from the stream
|
||||
OneByte = *pbInBuffer++;
|
||||
|
||||
// If highest bit, it means that that normal data follow
|
||||
if(OneByte & 0x80)
|
||||
{
|
||||
cbChunkSize = (OneByte & 0x7F) + 1;
|
||||
cbChunkSize = (cbChunkSize < cbOutBuffer) ? cbChunkSize : cbOutBuffer;
|
||||
memcpy(pbOutBuffer, pbInBuffer, cbChunkSize);
|
||||
pbInBuffer += cbChunkSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
cbChunkSize = (OneByte & 0x7F) + 3;
|
||||
cbChunkSize = (cbChunkSize < cbOutBuffer) ? cbChunkSize : cbOutBuffer;
|
||||
memset(pbOutBuffer, 0, cbChunkSize);
|
||||
}
|
||||
|
||||
// Increment output buffer pointer
|
||||
pbOutBuffer += cbChunkSize;
|
||||
cbOutBuffer -= cbChunkSize;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
17
src/util/mpq/sparse.h
Normal file
17
src/util/mpq/sparse.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*****************************************************************************/
|
||||
/* sparse.h Copyright (c) Ladislav Zezula 2010 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* implementation of Sparse compression, used in Starcraft II */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Date Ver Who Comment */
|
||||
/* -------- ---- --- ------- */
|
||||
/* 05.03.10 1.00 Lad The first version of sparse.h */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __SPARSE_H__
|
||||
#define __SPARSE_H__
|
||||
|
||||
void CompressSparse(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer);
|
||||
int DecompressSparse(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer);
|
||||
|
||||
#endif // __SPARSE_H__
|
||||
Loading…
Reference in New Issue
Block a user