893 lines
36 KiB
C++
893 lines
36 KiB
C++
/*****************************************************************************/
|
|
/* 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 = NULL;
|
|
|
|
// Don't let the item buffer run out of space
|
|
if(ItemsUsed < HUFF_ITEM_COUNT)
|
|
{
|
|
// Allocate new item from the item pool
|
|
pNewItem = &ItemBuffer[ItemsUsed++];
|
|
|
|
// Insert this item to the top of the tree
|
|
InsertItem(pNewItem, InsertPoint, NULL);
|
|
|
|
// Fill the rest of the item
|
|
pNewItem->DecompressedValue = DecompressedValue;
|
|
pNewItem->Weight = Weight;
|
|
pNewItem->pParent = NULL;
|
|
pNewItem->pChildLo = NULL;
|
|
}
|
|
|
|
return pNewItem;
|
|
}
|
|
|
|
unsigned int THuffmannTree::FixupItemPosByWeight(THTreeItem * pNewItem, unsigned int MaxWeight)
|
|
{
|
|
THTreeItem * pHigherItem;
|
|
|
|
if(pNewItem->Weight < MaxWeight)
|
|
{
|
|
// Find an item that has higher weight than this one
|
|
pHigherItem = FindHigherOrEqualItem(pLast, pNewItem->Weight);
|
|
|
|
// Remove the item and put it to the new position
|
|
pNewItem->RemoveItem();
|
|
LinkTwoItems(pHigherItem, pNewItem);
|
|
}
|
|
else
|
|
{
|
|
MaxWeight = pNewItem->Weight;
|
|
}
|
|
|
|
// Return the (updated) maximum weight
|
|
return MaxWeight;
|
|
}
|
|
|
|
// Builds Huffman tree. Called with the first 8 bits loaded from input stream
|
|
bool THuffmannTree::BuildTree(unsigned int CompressionType)
|
|
{
|
|
THTreeItem * pNewItem;
|
|
THTreeItem * pChildLo;
|
|
THTreeItem * pChildHi;
|
|
unsigned char * WeightTable;
|
|
unsigned int MaxWeight; // [ESP+10] - The greatest character found in table
|
|
|
|
// Clear all pointers in HTree item array
|
|
memset(ItemsByByte, 0, sizeof(ItemsByByte));
|
|
MaxWeight = 0;
|
|
|
|
// Ensure that the compression type is in range
|
|
if((CompressionType & 0x0F) > 0x08)
|
|
return false;
|
|
WeightTable = WeightTables[CompressionType & 0x0F];
|
|
|
|
// Build the linear list of entries that is sorted by byte weight
|
|
for(unsigned int i = 0; i < 0x100; i++)
|
|
{
|
|
// Skip all the bytes which are zero.
|
|
if(WeightTable[i] != 0)
|
|
{
|
|
// Create new tree item
|
|
ItemsByByte[i] = pNewItem = CreateNewItem(i, WeightTable[i], InsertAfter);
|
|
|
|
// We need to put the item to the right place in the list
|
|
MaxWeight = FixupItemPosByWeight(pNewItem, MaxWeight);
|
|
}
|
|
}
|
|
|
|
// Insert termination entries at the end of the list
|
|
ItemsByByte[0x100] = CreateNewItem(0x100, 1, InsertBefore);
|
|
ItemsByByte[0x101] = CreateNewItem(0x101, 1, InsertBefore);
|
|
|
|
// Now we need to build the tree. We start at the last entry
|
|
// and go backwards to the first one
|
|
pChildLo = pLast;
|
|
|
|
// Work as long as both children are valid
|
|
// pChildHi is child with higher weight, pChildLo is the one with lower weight
|
|
while(pChildLo != LIST_HEAD())
|
|
{
|
|
// Also get and verify the higher-weight child
|
|
pChildHi = pChildLo->pPrev;
|
|
if(pChildHi == LIST_HEAD())
|
|
break;
|
|
|
|
// Create new parent item for the children
|
|
pNewItem = CreateNewItem(0, pChildHi->Weight + pChildLo->Weight, InsertAfter);
|
|
if(pNewItem == NULL)
|
|
return false;
|
|
|
|
// Link both child items to their new parent
|
|
pChildLo->pParent = pNewItem;
|
|
pChildHi->pParent = pNewItem;
|
|
pNewItem->pChildLo = pChildLo;
|
|
|
|
// Fixup the item's position by its weight
|
|
MaxWeight = FixupItemPosByWeight(pNewItem, MaxWeight);
|
|
|
|
// Get the previous lower-weight child
|
|
pChildLo = pChildHi->pPrev;
|
|
}
|
|
|
|
// Initialize the MinValidValue to 1, which invalidates all quick-link items
|
|
MinValidValue = 1;
|
|
return true;
|
|
}
|
|
|
|
void THuffmannTree::IncWeightsAndRebalance(THTreeItem * pItem)
|
|
{
|
|
THTreeItem * pHigherItem; // A previous item with greater or equal weight
|
|
THTreeItem * pChildHi; // The higher-weight child
|
|
THTreeItem * pChildLo; // The lower-weight child
|
|
THTreeItem * pParent;
|
|
|
|
// Climb up the tree and increment weight of each tree item
|
|
for(; pItem != NULL; pItem = pItem->pParent)
|
|
{
|
|
// Increment the item's weight
|
|
pItem->Weight++;
|
|
|
|
// Find a previous item with equal or greater weight, which is not equal to this item
|
|
pHigherItem = FindHigherOrEqualItem(pItem->pPrev, pItem->Weight);
|
|
pChildHi = pHigherItem->pNext;
|
|
|
|
// If the item is not equal to the tree item, we need to rebalance the tree
|
|
if(pChildHi != pItem)
|
|
{
|
|
// Move the previous item to the RIGHT from the given item
|
|
pChildHi->RemoveItem();
|
|
LinkTwoItems(pItem, pChildHi);
|
|
|
|
// Move the given item AFTER the greater-weight tree item
|
|
pItem->RemoveItem();
|
|
LinkTwoItems(pHigherItem, pItem);
|
|
|
|
// We need to maintain the tree so that pChildHi->Weight is >= pChildLo->Weight.
|
|
// Rebalance the tree accordingly.
|
|
pChildLo = pChildHi->pParent->pChildLo;
|
|
pParent = pItem->pParent;
|
|
if(pParent->pChildLo == pItem)
|
|
pParent->pChildLo = pChildHi;
|
|
if(pChildLo == pChildHi)
|
|
pChildHi->pParent->pChildLo = pItem;
|
|
pParent = pItem->pParent;
|
|
pItem->pParent = pChildHi->pParent;
|
|
pChildHi->pParent = pParent;
|
|
|
|
// Increment the global valid value. This invalidates all quick-link items.
|
|
MinValidValue++;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool THuffmannTree::InsertNewBranchAndRebalance(unsigned int Value1, unsigned int Value2)
|
|
{
|
|
THTreeItem * pLastItem = pLast;
|
|
THTreeItem * pChildHi;
|
|
THTreeItem * pChildLo;
|
|
|
|
// Create higher-weight child
|
|
pChildHi = CreateNewItem(Value1, pLastItem->Weight, InsertBefore);
|
|
if(pChildHi != NULL)
|
|
{
|
|
pChildHi->pParent = pLastItem;
|
|
ItemsByByte[Value1] = pChildHi;
|
|
|
|
// Create lower-weight child
|
|
pChildLo = CreateNewItem(Value2, 0, InsertBefore);
|
|
if(pChildLo != NULL)
|
|
{
|
|
pChildLo->pParent = pLastItem;
|
|
pLastItem->pChildLo = pChildLo;
|
|
ItemsByByte[Value2] = pChildLo;
|
|
|
|
IncWeightsAndRebalance(pChildLo);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// No more space in the tree buffer
|
|
return false;
|
|
}
|
|
|
|
void THuffmannTree::EncodeOneByte(TOutputStream * os, THTreeItem * pItem)
|
|
{
|
|
THTreeItem * pParent = pItem->pParent;
|
|
unsigned int BitBuffer = 0;
|
|
unsigned int BitCount = 0;
|
|
|
|
// Put 1's as long as there is parent
|
|
while(pParent != NULL)
|
|
{
|
|
// Fill the bit buffer
|
|
BitBuffer = (BitBuffer << 1) | ((pParent->pChildLo != pItem) ? 1 : 0);
|
|
BitCount++;
|
|
|
|
// Move to the parent
|
|
pItem = pParent;
|
|
pParent = pParent->pParent;
|
|
}
|
|
|
|
// Write the bits to the output stream
|
|
os->PutBits(BitBuffer, BitCount);
|
|
}
|
|
|
|
unsigned int THuffmannTree::DecodeOneByte(TInputStream * is)
|
|
{
|
|
THTreeItem * pItemLink = NULL;
|
|
THTreeItem * pItem;
|
|
unsigned int ItemLinkIndex;
|
|
unsigned int BitCount = 0;
|
|
|
|
// 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);
|
|
|
|
if(!InsertNewBranchAndRebalance(pLast->DecompressedValue, InputByte))
|
|
return 0;
|
|
|
|
if(bIsCmp0)
|
|
{
|
|
IncWeightsAndRebalance(ItemsByByte[InputByte]);
|
|
continue;
|
|
}
|
|
|
|
IncWeightsAndRebalance(ItemsByByte[InputByte]);
|
|
}
|
|
else
|
|
{
|
|
EncodeOneByte(os, ItemsByByte[InputByte]);
|
|
}
|
|
|
|
if(bIsCmp0)
|
|
{
|
|
IncWeightsAndRebalance(ItemsByByte[InputByte]);
|
|
}
|
|
}
|
|
|
|
// Put the termination mark to the compressed stream
|
|
EncodeOneByte(os, ItemsByByte[0x100]);
|
|
|
|
// Flush the remaining bits
|
|
os->Flush();
|
|
return (unsigned int)(os->pbOutBuffer - pbOutBuff);
|
|
}
|
|
|
|
// Decompression using Huffman tree (1500E450)
|
|
unsigned int THuffmannTree::Decompress(void * pvOutBuffer, unsigned int cbOutLength, TInputStream * is)
|
|
{
|
|
unsigned char * pbOutBufferEnd = (unsigned char *)pvOutBuffer + cbOutLength;
|
|
unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer;
|
|
unsigned int DecompressedValue = 0;
|
|
unsigned int CompressionType = 0;
|
|
|
|
// Test the output length. Must not be NULL.
|
|
if(cbOutLength == 0)
|
|
return 0;
|
|
|
|
// Get the compression type from the input stream
|
|
CompressionType = is->Get8Bits();
|
|
bIsCmp0 = (CompressionType == 0) ? 1 : 0;
|
|
|
|
// Build the Huffman tree
|
|
if(!BuildTree(CompressionType))
|
|
return 0;
|
|
|
|
// Process the entire input buffer until end of the stream
|
|
while((DecompressedValue = DecodeOneByte(is)) != 0x100)
|
|
{
|
|
// Did an error occur?
|
|
if(DecompressedValue == 0x1FF) // An error occurred
|
|
return 0;
|
|
|
|
// Huffman tree needs to be modified
|
|
if(DecompressedValue == 0x101)
|
|
{
|
|
// The decompressed byte is stored in the next 8 bits
|
|
DecompressedValue = is->Get8Bits();
|
|
|
|
if(!InsertNewBranchAndRebalance(pLast->DecompressedValue, DecompressedValue))
|
|
return 0;
|
|
|
|
if(bIsCmp0 == 0)
|
|
IncWeightsAndRebalance(ItemsByByte[DecompressedValue]);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|