Proton/jxrlib/image/sys/adapthuff.c
2020-09-29 14:29:06 -05:00

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;
}