512 lines
12 KiB
C
512 lines
12 KiB
C
//*@@@+++@@@@******************************************************************
|
|
//
|
|
// Copyright © Microsoft Corp.
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// • Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
// • Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
//*@@@---@@@@******************************************************************
|
|
|
|
#include "strcodec.h"
|
|
|
|
#ifdef MEM_TRACE
|
|
#define TRACE_MALLOC 1
|
|
#define TRACE_NEW 0
|
|
#define TRACE_HEAP 0
|
|
#include "memtrace.h"
|
|
#endif
|
|
|
|
// Huffman lookup tables
|
|
static const short g4HuffLookupTable[40] = {
|
|
19,19,19,19,27,27,27,27,10,10,10,10,10,10,10,10,
|
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
|
0,0,0,0,0,0,0,0 };
|
|
|
|
static const short g5HuffLookupTable[2][42] = {{
|
|
28,28,36,36,19,19,19,19,10,10,10,10,10,10,10,10,
|
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
|
0,0,0,0,0,0,0,0,0,0 },
|
|
{
|
|
11,11,11,11,19,19,19,19,27,27,27,27,35,35,35,35,
|
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
|
0,0,0,0,0,0,0,0,0,0 }};
|
|
|
|
static const short g6HuffLookupTable[4][44] = {{
|
|
13,29,44,44,19,19,19,19,34,34,34,34,34,34,34,34,
|
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
|
0,0,0,0,0,0,0,0,0,0,0,0 },
|
|
{
|
|
12,12,28,28,43,43,43,43,2,2,2,2,2,2,2,2,
|
|
18,18,18,18,18,18,18,18,34,34,34,34,34,34,34,34,
|
|
0,0,0,0,0,0,0,0,0,0,0,0 },
|
|
{
|
|
4,4,12,12,43,43,43,43,18,18,18,18,18,18,18,18,
|
|
26,26,26,26,26,26,26,26,34,34,34,34,34,34,34,34,
|
|
0,0,0,0,0,0,0,0,0,0,0,0 },
|
|
{
|
|
5,13,36,36,43,43,43,43,18,18,18,18,18,18,18,18,
|
|
25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
|
|
0,0,0,0,0,0,0,0,0,0,0,0 }};
|
|
|
|
static const short g7HuffLookupTable[2][46] = {{
|
|
45,53,36,36,27,27,27,27,2,2,2,2,2,2,2,2,
|
|
10,10,10,10,10,10,10,10,18,18,18,18,18,18,18,18,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
|
|
{
|
|
-32736,37,28,28,19,19,19,19,10,10,10,10,10,10,10,10,
|
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
|
5,6,0,0,0,0,0,0,0,0,0,0,0,0 }};
|
|
|
|
static const short g8HuffLookupTable[2][48] = {{
|
|
53,21,28,28,11,11,11,11,43,43,43,43,59,59,59,59,
|
|
2,2,2,2,2,2,2,2,34,34,34,34,34,34,34,34,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
|
|
{
|
|
52,52,20,20,3,3,3,3,11,11,11,11,27,27,27,27,
|
|
35,35,35,35,43,43,43,43,58,58,58,58,58,58,58,58,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }};
|
|
|
|
static const short g9HuffLookupTable[2][50] = {{
|
|
13,29,37,61,20,20,68,68,3,3,3,3,51,51,51,51,
|
|
41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0 },
|
|
{
|
|
-32736,53,28,28,11,11,11,11,19,19,19,19,43,43,43,43,
|
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
|
-32734,4,7,8,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0 }};
|
|
|
|
static const short g12HuffLookupTable[5][56] = {{
|
|
-32736,5,76,76,37,53,69,85,43,43,43,43,91,91,91,91,
|
|
57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
|
|
-32734,1,2,3,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0 },
|
|
{
|
|
-32736,85,13,53,4,4,36,36,43,43,43,43,67,67,67,67,
|
|
75,75,75,75,91,91,91,91,58,58,58,58,58,58,58,58,
|
|
2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0 },
|
|
{
|
|
-32736,37,92,92,11,11,11,11,43,43,43,43,59,59,59,59,
|
|
67,67,67,67,75,75,75,75,2,2,2,2,2,2,2,2,
|
|
-32734,-32732,2,3,6,10,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0 },
|
|
{
|
|
-32736,29,37,69,3,3,3,3,43,43,43,43,59,59,59,59,
|
|
75,75,75,75,91,91,91,91,10,10,10,10,10,10,10,10,
|
|
-32734,10,2,6,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0 },
|
|
{
|
|
-32736,93,28,28,60,60,76,76,3,3,3,3,43,43,43,43,
|
|
9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
|
|
-32734,-32732,-32730,2,4,8,6,10,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0 }};
|
|
|
|
/**********************************************************************
|
|
Allocation and dellocation
|
|
**********************************************************************/
|
|
Void Clean (CAdaptiveHuffman *pAdHuff)
|
|
{
|
|
if (pAdHuff == NULL)
|
|
return;
|
|
free (pAdHuff);
|
|
}
|
|
|
|
CAdaptiveHuffman *Allocate (Int iNSymbols, CODINGMODE cm)
|
|
{
|
|
CAdaptiveHuffman *pAdHuff = (CAdaptiveHuffman *) malloc (sizeof (CAdaptiveHuffman));
|
|
|
|
UNREFERENCED_PARAMETER(cm);
|
|
|
|
if (pAdHuff == NULL)
|
|
return NULL;
|
|
if (iNSymbols > 255 || iNSymbols <= 0)
|
|
goto ErrorExit;
|
|
|
|
memset (pAdHuff, 0, sizeof (CAdaptiveHuffman));
|
|
pAdHuff->m_iNSymbols = iNSymbols;
|
|
|
|
pAdHuff->m_pDelta = NULL;
|
|
pAdHuff->m_iDiscriminant = pAdHuff->m_iUpperBound = pAdHuff->m_iLowerBound = 0;
|
|
|
|
return pAdHuff;
|
|
|
|
ErrorExit:
|
|
Clean (pAdHuff);
|
|
return NULL;
|
|
}
|
|
|
|
/**********************************************************************
|
|
Adapt Huffman table
|
|
**********************************************************************/
|
|
// Alphabet size = 4
|
|
static const Int g_Index4Table[] = {
|
|
1,2,3,3
|
|
};
|
|
static const Int g4CodeTable[] = {
|
|
4,
|
|
1, 1,
|
|
1, 2,
|
|
0, 3,
|
|
1, 3
|
|
};
|
|
|
|
// Alphabet size = 5
|
|
static const Int g_Index5Table[] = {
|
|
1,2,3,4,4,
|
|
1,3,3,3,3
|
|
};
|
|
static const Int g5CodeTable[] = {
|
|
5,
|
|
1, 1,
|
|
1, 2,
|
|
1, 3,
|
|
0, 4,
|
|
1, 4,
|
|
|
|
5,
|
|
1, 1,
|
|
0, 3,
|
|
1, 3,
|
|
2, 3,
|
|
3, 3,
|
|
};
|
|
static const Int g5DeltaTable[] = { 0,-1,0,1,1 };
|
|
|
|
// Alphabet size = 6
|
|
static const Int g_Index6Table[] = {
|
|
1,5,3,5,2,4,
|
|
2,4,2,4,2,3,
|
|
4,4,2,2,2,3,
|
|
5,5,2,1,4,3,
|
|
};
|
|
static const Int g6CodeTable[] = {
|
|
6,
|
|
1, 1,
|
|
0, 5,
|
|
1, 3,
|
|
1, 5,
|
|
1, 2,
|
|
1, 4,
|
|
|
|
6,
|
|
1, 2,
|
|
0, 4,
|
|
2, 2,
|
|
1, 4,
|
|
3, 2,
|
|
1, 3,
|
|
|
|
6,
|
|
0, 4,
|
|
1, 4,
|
|
1, 2,
|
|
2, 2,
|
|
3, 2,
|
|
1, 3,
|
|
|
|
6,
|
|
0, 5,
|
|
1, 5,
|
|
1, 2,
|
|
1, 1,
|
|
1, 4,
|
|
1, 3
|
|
};
|
|
static const Int g6DeltaTable[] = {
|
|
-1, 1, 1, 1, 0, 1,
|
|
-2, 0, 0, 2, 0, 0,
|
|
-1,-1, 0, 1,-2, 0
|
|
};
|
|
|
|
// Alphabet size = 7
|
|
static const Int g_Index7Table[] = { 2,2,2,3,4,5,5,
|
|
1,2,3,4,5,6,6 };
|
|
static const Int g7CodeTable[] = {
|
|
7,
|
|
1, 2,
|
|
2, 2,
|
|
3, 2,
|
|
1, 3,
|
|
1, 4,
|
|
0, 5,
|
|
1, 5,
|
|
|
|
7,
|
|
1, 1,
|
|
1, 2,
|
|
1, 3,
|
|
1, 4,
|
|
1, 5,
|
|
0, 6,
|
|
1, 6
|
|
};
|
|
static const Int g7DeltaTable[] = { 1,0,-1,-1,-1,-1,-1 };
|
|
|
|
// Alphabet size = 8
|
|
static const Int g_Index8Table[] = { 2,3,5,4,2,3,5,3,
|
|
3,3,4,3,3,3,4,2};
|
|
static const Int g8CodeTable[] = {
|
|
8,
|
|
2, 2,
|
|
1, 3,
|
|
1, 5,
|
|
1, 4,
|
|
3, 2,
|
|
2, 3,
|
|
0, 5,
|
|
3, 3,
|
|
|
|
8,
|
|
1, 3,
|
|
2, 3,
|
|
1, 4,
|
|
3, 3,
|
|
4, 3,
|
|
5, 3,
|
|
0, 4,
|
|
3, 2
|
|
};
|
|
static const Int g8DeltaTable[] = { -1,0,1,1,-1,0,1,1 };
|
|
|
|
static const Int g_Index9Table[] = {
|
|
3,5,4,5,5,1,3,5,4,
|
|
1,3,3,4,6,3,5,7,7,
|
|
};
|
|
static const Int g9CodeTable[] = {
|
|
9,
|
|
2, 3,
|
|
0, 5,
|
|
2, 4,
|
|
1, 5,
|
|
2, 5,
|
|
1, 1,
|
|
3, 3,
|
|
3, 5,
|
|
3, 4,
|
|
|
|
9,
|
|
1, 1,
|
|
1, 3,
|
|
2, 3,
|
|
1, 4,
|
|
1, 6,
|
|
3, 3,
|
|
1, 5,
|
|
0, 7,
|
|
1, 7,
|
|
};
|
|
static const Int g9DeltaTable[] = { 2,2,1,1,-1,-2,-2,-2,-3 };
|
|
|
|
// Alphabet size = 12
|
|
static const Int g_Index12Table[] = { // index12 is the most critical symbol
|
|
5,6,7,7,5,3,5,1,5,4,5,3,
|
|
4,5,6,6,4,3,5,2,3,3,5,3,
|
|
2,3,7,7,5,3,7,3,3,3,7,4,
|
|
3,2,7,5,5,3,7,3,5,3,6,3,
|
|
3,1,7,4,7,3,8,4,7,4,8,5,
|
|
};
|
|
static const Int g12CodeTable[] = {
|
|
12,
|
|
1, 5,
|
|
1, 6,
|
|
0, 7,
|
|
1, 7,
|
|
4, 5,
|
|
2, 3,
|
|
5, 5,
|
|
1, 1,
|
|
6, 5,
|
|
1, 4,
|
|
7, 5,
|
|
3, 3,
|
|
|
|
12,
|
|
2, 4,
|
|
2, 5,
|
|
0, 6,
|
|
1, 6,
|
|
3, 4,
|
|
2, 3,
|
|
3, 5,
|
|
3, 2,
|
|
3, 3,
|
|
4, 3,
|
|
1, 5,
|
|
5, 3,
|
|
|
|
12,
|
|
3, 2,
|
|
1, 3,
|
|
0, 7,
|
|
1, 7,
|
|
1, 5,
|
|
2, 3,
|
|
2, 7,
|
|
3, 3,
|
|
4, 3,
|
|
5, 3,
|
|
3, 7,
|
|
1, 4,
|
|
|
|
12,
|
|
1, 3,
|
|
3, 2,
|
|
0, 7,
|
|
1, 5,
|
|
2, 5,
|
|
2, 3,
|
|
1, 7,
|
|
3, 3,
|
|
3, 5,
|
|
4, 3,
|
|
1, 6,
|
|
5, 3,
|
|
|
|
12,
|
|
2, 3,
|
|
1, 1,
|
|
1, 7,
|
|
1, 4,
|
|
2, 7,
|
|
3, 3,
|
|
0, 8,
|
|
2, 4,
|
|
3, 7,
|
|
3, 4,
|
|
1, 8,
|
|
1, 5
|
|
};
|
|
static const Int g12DeltaTable[] = {
|
|
1, 1, 1, 1, 1, 0, 0,-1, 2, 1, 0, 0,
|
|
2, 2,-1,-1,-1, 0,-2,-1, 0, 0,-2,-1,
|
|
-1, 1, 0, 2, 0, 0, 0, 0,-2, 0, 1, 1,
|
|
0, 1, 0, 1,-2, 0,-1,-1,-2,-1,-2,-2
|
|
};
|
|
|
|
/**********************************************************************
|
|
Adapt fixed length codes based on discriminant
|
|
**********************************************************************/
|
|
static const Int THRESHOLD = 8;
|
|
static const Int MEMORY = 8;
|
|
|
|
Void AdaptDiscriminant (CAdaptiveHuffman *pAdHuff)
|
|
{
|
|
Int iSym = pAdHuff->m_iNSymbols, t, dL, dH;
|
|
const Int *pCodes, *pDelta = NULL;
|
|
Bool bChange = FALSE;
|
|
static const Int gMaxTables[] = { 0,0,0,0, 1,2, 4,2, 2,2, 0,0,5 };
|
|
static const Int gSecondDisc[]= { 0,0,0,0, 0,0, 1,0, 0,0, 0,0,1 };
|
|
|
|
if (!pAdHuff->m_bInitialize) {
|
|
pAdHuff->m_bInitialize = 1;
|
|
pAdHuff->m_iDiscriminant = pAdHuff->m_iDiscriminant1 = 0;
|
|
pAdHuff->m_iTableIndex = gSecondDisc[iSym];//(gMaxTables[iSym] - 1) >> 1;
|
|
}
|
|
|
|
dL = dH = pAdHuff->m_iDiscriminant;
|
|
if (gSecondDisc[iSym]) {
|
|
dH = pAdHuff->m_iDiscriminant1;
|
|
}
|
|
|
|
if (dL < pAdHuff->m_iLowerBound) {
|
|
pAdHuff->m_iTableIndex--;
|
|
bChange = TRUE;
|
|
}
|
|
else if (dH > pAdHuff->m_iUpperBound) {
|
|
pAdHuff->m_iTableIndex++;
|
|
bChange = TRUE;
|
|
}
|
|
if (bChange) {
|
|
/** if initialization is fixed, we can exit on !bChange **/
|
|
pAdHuff->m_iDiscriminant = 0;
|
|
pAdHuff->m_iDiscriminant1 = 0;
|
|
}
|
|
{
|
|
if (pAdHuff->m_iDiscriminant < -THRESHOLD * MEMORY)
|
|
pAdHuff->m_iDiscriminant = -THRESHOLD * MEMORY;
|
|
else if (pAdHuff->m_iDiscriminant > THRESHOLD * MEMORY)
|
|
pAdHuff->m_iDiscriminant = THRESHOLD * MEMORY;
|
|
|
|
if (pAdHuff->m_iDiscriminant1 < -THRESHOLD * MEMORY)
|
|
pAdHuff->m_iDiscriminant1 = -THRESHOLD * MEMORY;
|
|
else if (pAdHuff->m_iDiscriminant1 > THRESHOLD * MEMORY)
|
|
pAdHuff->m_iDiscriminant1 = THRESHOLD * MEMORY;
|
|
}
|
|
|
|
t = pAdHuff->m_iTableIndex;
|
|
assert (t >= 0);
|
|
assert (t < gMaxTables[iSym]);
|
|
|
|
//pAdHuff->m_iDiscriminant >>= 1;
|
|
pAdHuff->m_iLowerBound = (t == 0) ? (-1 << 31) : -THRESHOLD;
|
|
pAdHuff->m_iUpperBound = (t == gMaxTables[iSym] - 1) ? (1 << 30) : THRESHOLD;
|
|
|
|
switch (iSym) {
|
|
case 4:
|
|
pCodes = g4CodeTable;
|
|
pAdHuff->m_hufDecTable = (short *) g4HuffLookupTable;
|
|
break;
|
|
case 5:
|
|
pCodes = g5CodeTable + (iSym * 2 + 1) * t;
|
|
pDelta = g5DeltaTable;
|
|
pAdHuff->m_hufDecTable = g5HuffLookupTable[t];
|
|
break;
|
|
case 6:
|
|
pCodes = g6CodeTable + (iSym * 2 + 1) * t;
|
|
pAdHuff->m_pDelta1 = g6DeltaTable + iSym * (t - (t + 1 == gMaxTables[iSym]));
|
|
pDelta = g6DeltaTable + (t - 1 + (t == 0)) * iSym;
|
|
pAdHuff->m_hufDecTable = g6HuffLookupTable[t];
|
|
break;
|
|
case 7:
|
|
pCodes = g7CodeTable + (iSym * 2 + 1) * t;
|
|
pDelta = g7DeltaTable;
|
|
pAdHuff->m_hufDecTable = g7HuffLookupTable[t];
|
|
break;
|
|
case 8:
|
|
//printf ("%d ", t);
|
|
pCodes = g8CodeTable;// + (iSym * 2 + 1) * t;
|
|
//pDelta = g8DeltaTable;
|
|
pAdHuff->m_hufDecTable = g8HuffLookupTable[0];
|
|
break;
|
|
case 9:
|
|
pCodes = g9CodeTable + (iSym * 2 + 1) * t;
|
|
pDelta = g9DeltaTable;
|
|
pAdHuff->m_hufDecTable = g9HuffLookupTable[t];
|
|
break;
|
|
case 12:
|
|
pCodes = g12CodeTable + (iSym * 2 + 1) * t;
|
|
pAdHuff->m_pDelta1 = g12DeltaTable + iSym * (t - (t + 1 == gMaxTables[iSym]));
|
|
pDelta = g12DeltaTable + (t - 1 + (t == 0)) * iSym;
|
|
pAdHuff->m_hufDecTable = g12HuffLookupTable[t];
|
|
break;
|
|
default:
|
|
assert (0); // undefined fixed length table
|
|
return;
|
|
}
|
|
|
|
pAdHuff->m_pTable = pCodes;
|
|
pAdHuff->m_pDelta = pDelta;
|
|
}
|
|
|