From e701009d4a2ada3d967646f5512b3a122f3c9eb4 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 21 Oct 2021 00:55:00 +0200 Subject: [PATCH] Enable ADPCM and Huffman compression This allows for huge savings in the size of dubbing packs, from 397MB to down to just 134MB --- 3rdParty/StormLib/src/SCompression.cpp | 17 +- 3rdParty/StormLib/src/StormCommon.h | 2 +- 3rdParty/StormLib/src/adpcm/adpcm.cpp | 401 ++++++++++++ 3rdParty/StormLib/src/adpcm/adpcm.h | 26 + 3rdParty/StormLib/src/huffman/huff.cpp | 873 +++++++++++++++++++++++++ 3rdParty/StormLib/src/huffman/huff.h | 143 ++++ CMakeLists.txt | 2 + 7 files changed, 1453 insertions(+), 11 deletions(-) create mode 100644 3rdParty/StormLib/src/adpcm/adpcm.cpp create mode 100644 3rdParty/StormLib/src/adpcm/adpcm.h create mode 100644 3rdParty/StormLib/src/huffman/huff.cpp create mode 100644 3rdParty/StormLib/src/huffman/huff.h diff --git a/3rdParty/StormLib/src/SCompression.cpp b/3rdParty/StormLib/src/SCompression.cpp index 63486afdb..f21c19717 100644 --- a/3rdParty/StormLib/src/SCompression.cpp +++ b/3rdParty/StormLib/src/SCompression.cpp @@ -63,7 +63,6 @@ typedef struct } TDecompressTable; -#ifdef FULL /*****************************************************************************/ /* */ /* Support for Huffman compression (0x01) */ @@ -88,6 +87,7 @@ int Decompress_huff(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, i return (*pcbOutBuffer == 0) ? 0 : 1; } +#ifdef FULL /******************************************************************************/ /* */ /* Support for ZLIB compression (0x02) */ @@ -603,6 +603,8 @@ int Decompress_SPARSE(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, return DecompressSparse(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer); } +#endif // FULL + /******************************************************************************/ /* */ /* Support for ADPCM mono compression (0x40) */ @@ -670,7 +672,6 @@ static int Decompress_ADPCM_stereo(void * pvOutBuffer, int * pcbOutBuffer, void *pcbOutBuffer = DecompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 2); return 1; } -#endif // FULL /*****************************************************************************/ /* */ @@ -763,9 +764,11 @@ static TCompressTable cmp_table[] = { #ifdef FULL {MPQ_COMPRESSION_SPARSE, Compress_SPARSE}, // Sparse compression +#endif // FULL {MPQ_COMPRESSION_ADPCM_MONO, Compress_ADPCM_mono}, // IMA ADPCM mono compression {MPQ_COMPRESSION_ADPCM_STEREO, Compress_ADPCM_stereo}, // IMA ADPCM stereo compression {MPQ_COMPRESSION_HUFFMANN, Compress_huff}, // Huffmann compression +#ifdef FULL {MPQ_COMPRESSION_ZLIB, Compress_ZLIB}, // Compression with the "zlib" library #endif // FULL {MPQ_COMPRESSION_PKWARE, Compress_PKLIB}, // Compression with Pkware DCL @@ -921,9 +924,11 @@ static TDecompressTable dcmp_table[] = {MPQ_COMPRESSION_PKWARE, Decompress_PKLIB}, // Decompression with Pkware Data Compression Library #ifdef FULL {MPQ_COMPRESSION_ZLIB, Decompress_ZLIB}, // Decompression with the "zlib" library +#endif // FULL {MPQ_COMPRESSION_HUFFMANN, Decompress_huff}, // Huffmann decompression {MPQ_COMPRESSION_ADPCM_STEREO, Decompress_ADPCM_stereo}, // IMA ADPCM stereo decompression {MPQ_COMPRESSION_ADPCM_MONO, Decompress_ADPCM_mono}, // IMA ADPCM mono decompression +#ifdef FULL {MPQ_COMPRESSION_SPARSE, Decompress_SPARSE} // Sparse decompression #endif // FULL }; @@ -1124,21 +1129,13 @@ int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInB // case (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_HUFFMANN): -#ifdef FULL pfnDecompress1 = Decompress_huff; pfnDecompress2 = Decompress_ADPCM_mono; -#else - assert(0); -#endif // FULL break; case (MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN): -#ifdef FULL pfnDecompress1 = Decompress_huff; pfnDecompress2 = Decompress_ADPCM_stereo; -#else - assert(0); -#endif // FULL break; default: diff --git a/3rdParty/StormLib/src/StormCommon.h b/3rdParty/StormLib/src/StormCommon.h index c1e7340b0..33bfbaf50 100644 --- a/3rdParty/StormLib/src/StormCommon.h +++ b/3rdParty/StormLib/src/StormCommon.h @@ -20,13 +20,13 @@ // Include functions from Pkware Data Compression Library #include "../../PKWare/pkware.h" -#ifdef FULL // Include functions from Huffmann compression #include "huffman/huff.h" // Include functions from IMA ADPCM compression #include "adpcm/adpcm.h" +#ifdef FULL // Include functions from SPARSE compression #include "sparse/sparse.h" diff --git a/3rdParty/StormLib/src/adpcm/adpcm.cpp b/3rdParty/StormLib/src/adpcm/adpcm.cpp new file mode 100644 index 000000000..e551bda4d --- /dev/null +++ b/3rdParty/StormLib/src/adpcm/adpcm.cpp @@ -0,0 +1,401 @@ +/*****************************************************************************/ +/* 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 + +#include "adpcm.h" + +//----------------------------------------------------------------------------- +// Tables necessary dor decompression + +static 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 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 * pvBuffer) + { + return pbBuffer - (unsigned char *)pvBuffer; + } + + 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) +{ + // Is the sign bit set? + if(EncodedSample & 0x40) + { + 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; + +// _tprintf(_T("== CMPR Started ==============\n")); + + // 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); + } + } + +// _tprintf(_T("== CMPR Ended ================\n")); + 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; + +// _tprintf(_T("== DCMP Started ==============\n")); + + // The first byte is always zero, the second one contains bit shift (compression level - 1) + is.ReadByteSample(BitShift); + is.ReadByteSample(BitShift); +// _tprintf(_T("DCMP: BitShift = %u\n"), (unsigned int)(unsigned char)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); + +// _tprintf(_T("DCMP: Loaded InitialSample[%u]: %04X\n"), i, (unsigned int)(unsigned short)InitialSample); + + // 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)) + { +// _tprintf(_T("DCMP: Loaded Encoded Sample: %02X\n"), (unsigned int)(unsigned char)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]--; + +// _tprintf(_T("DCMP: Writing Decoded Sample: %04lX\n"), (unsigned int)(unsigned short)PredictedSamples[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; + +// _tprintf(_T("DCMP: New value of StepIndex: %04lX\n"), (unsigned int)(unsigned short)StepIndexes[ChannelIndex]); + + // 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); + +// _tprintf(_T("DCMP: Writing decoded sample: %04X\n"), (unsigned int)(unsigned short)PredictedSamples[ChannelIndex]); + + // 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); +// _tprintf(_T("DCMP: New step index: %04X\n"), (unsigned int)(unsigned short)StepIndexes[ChannelIndex]); + } + } + +// _tprintf(_T("DCMP: Total length written: %u\n"), (unsigned int)os.LengthProcessed(pvOutBuffer)); +// _tprintf(_T("== DCMP Ended ================\n")); + + // Return total bytes written since beginning of the output buffer + return os.LengthProcessed(pvOutBuffer); +} diff --git a/3rdParty/StormLib/src/adpcm/adpcm.h b/3rdParty/StormLib/src/adpcm/adpcm.h new file mode 100644 index 000000000..b1bf36143 --- /dev/null +++ b/3rdParty/StormLib/src/adpcm/adpcm.h @@ -0,0 +1,26 @@ +/*****************************************************************************/ +/* 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 nCmpType, int ChannelCount); +int DecompressADPCM(void * pvOutBuffer, int dwOutLength, void * pvInBuffer, int dwInLength, int ChannelCount); + +#endif // __ADPCM_H__ diff --git a/3rdParty/StormLib/src/huffman/huff.cpp b/3rdParty/StormLib/src/huffman/huff.cpp new file mode 100644 index 000000000..9de5acb51 --- /dev/null +++ b/3rdParty/StormLib/src/huffman/huff.cpp @@ -0,0 +1,873 @@ +/*****************************************************************************/ +/* 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 +#include + +#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 7 bits from the stream. DOES NOT remove the bits from input stream +unsigned int TInputStream::Peek7Bits() +{ + unsigned int dwReloadByte = 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) + { + dwReloadByte = *pbInBuffer++; + BitBuffer |= dwReloadByte << BitCount; + BitCount += 8; + } + + // Return the first available 7 bits. DO NOT remove them from the input stream + return (BitBuffer & 0x7F); +} + +// 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; +} + +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; + + // 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); + + // 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++; + } + } +} + +void 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); + pChildHi->pParent = pLastItem; + ItemsByByte[Value1] = pChildHi; + + // Create lower-weight child + pChildLo = CreateNewItem(Value2, 0, InsertBefore); + pChildLo->pParent = pLastItem; + pLastItem->pChildLo = pChildLo; + ItemsByByte[Value2] = pChildLo; + + IncWeightsAndRebalance(pChildLo); +} + +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; + + // Check for the end of the input stream + if(is->pbInBuffer >= is->pbInBufferEnd && is->BitCount < 7) + return 0x1FF; + + // Get the eventual quick-link index + ItemLinkIndex = is->Peek7Bits(); + + // Is the quick-link item valid? + if(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(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); + + InsertNewBranchAndRebalance(pLast->DecompressedValue, InputByte); + + 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(); + + InsertNewBranchAndRebalance(pLast->DecompressedValue, DecompressedValue); + + if(bIsCmp0 == 0) + IncWeightsAndRebalance(ItemsByByte[DecompressedValue]); + } + + // A byte successfully decoded - store it in the output stream + *pbOutBuffer++ = (unsigned char)DecompressedValue; + if(pbOutBuffer >= pbOutBufferEnd) + break; + + if(bIsCmp0) + { + IncWeightsAndRebalance(ItemsByByte[DecompressedValue]); + } + } + + return (unsigned int)(pbOutBuffer - (unsigned char *)pvOutBuffer); +} + diff --git a/3rdParty/StormLib/src/huffman/huff.h b/3rdParty/StormLib/src/huffman/huff.h new file mode 100644 index 000000000..89993fdef --- /dev/null +++ b/3rdParty/StormLib/src/huffman/huff.h @@ -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 Peek7Bits(); + unsigned int Get8Bits(); + 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); + void 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__ diff --git a/CMakeLists.txt b/CMakeLists.txt index a35c9cd7b..64906fab4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,6 +324,8 @@ endif() add_subdirectory(3rdParty/simpleini) add_library(StormLib STATIC + 3rdParty/StormLib/src/huffman/huff.cpp + 3rdParty/StormLib/src/adpcm/adpcm.cpp 3rdParty/StormLib/src/FileStream.cpp 3rdParty/StormLib/src/SBaseCommon.cpp 3rdParty/StormLib/src/SBaseFileTable.cpp