Browse Source
This allows for huge savings in the size of dubbing packs, from 397MB to down to just 134MBpull/3170/head
7 changed files with 1453 additions and 11 deletions
@ -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 <stddef.h> |
||||
|
||||
#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); |
||||
} |
||||
@ -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__
|
||||
@ -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 <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 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); |
||||
} |
||||
|
||||
@ -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__
|
||||
Loading…
Reference in new issue