//*@@@+++@@@@****************************************************************** // // 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; }