/* Copyright (C) 2002-2003 Victor Luchits This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // huff.c #include "qcommon.h" //#define HUFF_DEBUG typedef struct huffNode_s { unsigned pos, count; struct huffNode_s *children[2]; } huffNode_t; typedef struct huffTab_s { unsigned len; unsigned bits; } huffTab_t; typedef struct huffTree_s { huffNode_t *headNode; huffTab_t lookupTable[256]; } huffTree_t; static huffTree_t huffTree; static unsigned huffCounts[256] = { 66067,11275, 7275, 2794,13169, 2863, 2503, 1476 , 985, 1473, 1003, 3366, 3305, 3119, 1496, 529 , 6183, 1280, 1591, 1226, 1318, 1194, 1200, 1147 , 1184, 1228, 1160, 1180, 1160, 450, 1363, 687 , 1756, 292, 1142, 400, 253, 276, 656, 247 , 546, 376, 372, 540, 314, 529, 616, 879 , 531, 650, 614, 611, 440, 483, 381, 751 , 457, 372, 273, 251, 362, 224, 357, 367 , 5078, 384, 473, 327, 577, 251, 256, 261 , 294, 237, 241, 230, 275, 268, 211, 271 , 345, 350, 326, 230, 247, 207, 311, 261 , 262, 232, 262, 192, 300, 234, 394, 386 , 330, 854, 372, 946, 702, 790, 343, 492 , 732, 627, 233, 266, 539, 581, 2371, 2634 , 554, 235, 723, 1229, 2289, 468, 409, 536 , 251, 268, 183, 204, 222, 204, 200, 194 , 2992, 287, 1072, 208, 702, 311, 1312, 424 , 382, 228, 220, 231, 338, 190, 255, 544 , 333, 188, 234, 408, 221, 256, 211, 541 , 310, 383, 277, 602, 636, 242, 249, 781 , 496, 328, 310, 216, 272, 180, 202, 690 , 275, 206, 348, 235, 238, 208, 280, 311 , 231, 270, 427, 275, 214, 190, 202, 298 , 366, 244, 274, 444, 262, 269, 344, 452 , 1210, 701, 306, 182, 1139, 205, 357, 300 , 353, 188, 347, 225, 307, 239, 509, 365 , 569, 241, 216, 250, 288, 245, 191, 186 , 809, 178, 227, 244, 540, 598, 396, 328 , 802, 850, 498, 467, 405, 373, 363, 404 , 431, 368, 392, 392, 551, 345, 310, 374 , 486, 455, 399, 490, 594, 673, 683, 611 , 909, 804, 893, 1246, 3032, 3928, 5402,32286 }; #ifdef HUFF_DEBUG unsigned debugHuffCounts[256]; /* ============= Huff_ResetCounts ============= */ static void Huff_ResetCounts( void ) { memset ( debugHuffCounts, 0, sizeof(debugHuffCounts) ); } /* ============= Huff_AddCounts ============= */ void Huff_AddCounts( unsigned char *data, unsigned len ) { int i; for( i = 0; i < len; i++ ) debugHuffCounts[data[i]]++; } /* ============= Huff_DumpCounts_f ============= */ void Huff_DumpCounts_f( void ) { int i, j; Com_Printf( " %5i", debugHuffCounts[0] ); for( j = 1; j < 8; j++ ) Com_Printf ( ",%5i", debugHuffCounts[j] ); Com_Printf ( "\n" ); for( i = 8; i < 256; i += 8 ) { for( j = 0; j < 8; j++ ) Com_Printf ( ",%5i", debugHuffCounts[i+j] ); Com_Printf ( "\n" ); } Huff_ResetCounts (); } #endif /* ============= Huff_BuildTable ============= */ static void Huff_BuildTable( huffNode_t *node, huffTab_t *table, unsigned len, unsigned bits ) { if( !node ) Com_Error ( ERR_FATAL, "Huff_BuildTable: no node" ); if( node->children[0] ) { if( !node->children[1] ) Com_Error( ERR_FATAL, "Huff_BuildTable: bad node" ); if( len >= 32 ) Com_Error( ERR_FATAL, "Huff_BuildTable: bad len" ); bits <<= 1; Huff_BuildTable( node->children[0], table, len + 1, bits ); Huff_BuildTable( node->children[1], table, len + 1, bits | 1 ); return; } table[node->pos].len = len; table[node->pos].bits = bits; } /* ============= Huff_BuildTree ============= */ static void Huff_BuildTree( huffTree_t *tree, unsigned *counts ) { int i, j; unsigned best[2], bestval[2]; huffNode_t *nodes[256], *headNode; headNode = ( huffNode_t * )Mem_ZoneMalloc( sizeof( huffNode_t ) * (256 + 255) ); for( i = 0; i < 256; i++ ) { nodes[i] = headNode++; nodes[i]->count = counts[i]; nodes[i]->pos = ( unsigned )i; } for( i = 0; i < 255; i++ ) { best[0] = best[1] = 0; bestval[0] = bestval[1] = 99999999; for ( j = 0; j < 256; j++ ) { if( !nodes[j] ) continue; if ( nodes[j]->count < bestval[0] ) { best[1] = best[0]; bestval[1] = bestval[0]; best[0] = j + 1; bestval[0] = nodes[j]->count; } else if ( nodes[j]->count < bestval[1] ) { best[1] = j + 1; bestval[1] = nodes[j]->count; } } if( !best[0] ) Com_Error( ERR_FATAL, "Huff_BuildTree: no node 0: %i", bestval[0] ); if( !best[1] ) Com_Error( ERR_FATAL, "Huff_BuildTree: no node 1: %i", bestval[1] ); headNode->children[0] = nodes[best[1]-1]; headNode->children[1] = nodes[best[0]-1]; headNode->count = headNode->children[0]->count + headNode->children[1]->count; headNode->pos = 0xff; nodes[best[0]-1] = headNode++; nodes[best[1]-1] = NULL; } tree->headNode = --headNode; memset( tree->lookupTable, 0, sizeof( tree->lookupTable ) ); Huff_BuildTable( tree->headNode, tree->lookupTable, 0, 0 ); } /* ============= Huff_Decode ============= */ static unsigned Huff_Decode( huffTree_t *tree, unsigned char *in, unsigned inSize, unsigned char *out, unsigned maxOutSize ) { huffNode_t *node; unsigned bits, tbits; unsigned outSize; if( !inSize ) return 0; if( *in == 0xff ) { memcpy( out, in + 1, inSize - 1 ); return inSize - 1; } outSize = 0; tbits = ((inSize - 1) << 3) - *in++; for( bits = 0; bits < tbits; ) { node = tree->headNode; do { if( in[bits >> 3] & (1 << (bits & 7)) ) node = node->children[1]; else node = node->children[0]; bits++; } while( node->children[0] ); if( outSize == maxOutSize ) Com_Error ( ERR_DROP, "Huff_Decode: outlen == maxOutSize" ); *out++ = node->pos; outSize++; } return outSize; } /* ============= Huff_Encode ============= */ static unsigned Huff_Encode( huffTree_t *tree, unsigned char *in, unsigned inSize, unsigned char *out, unsigned maxOutSize ) { unsigned i, j; unsigned bits, pos, len, bitsPos; unsigned outSize; if( !inSize ) return 0; bitsPos = 0; for( i = 0; i < inSize; i++, bitsPos += len ) { bits = tree->lookupTable[in[i]].bits; len = tree->lookupTable[in[i]].len; pos = bitsPos + len - 1; if( (pos>>3) >= maxOutSize ) return maxOutSize + 1; for( j = 0; j < len; j++, pos--, bits >>= 1 ) { if( bits & 1 ) out[(pos>>3)+1] |= (1 << (pos & 7)); else out[(pos>>3)+1] &= ~(1 << (pos & 7)); } } outSize = (bitsPos + 7) / 8 + 1; if( outSize >= inSize + 1 ) { if( inSize + 1 > maxOutSize ) return inSize + 1; *out = 0xff; memcpy( out + 1, in, inSize ); return inSize + 1; } else if( outSize > maxOutSize ) { return outSize; } else { *out = ((outSize - 1) << 3) - bitsPos; } return outSize; } /* ============= Huff_DecodeStatic ============= */ unsigned Huff_DecodeStatic( unsigned char *in, unsigned inSize, unsigned char *out, unsigned maxOutSize ) { return Huff_Decode( &huffTree, in, inSize, out, maxOutSize ); } /* ============= Huff_EncodeStatic ============= */ unsigned Huff_EncodeStatic( unsigned char *in, unsigned inSize, unsigned char *out, unsigned maxOutSize ) { return Huff_Encode( &huffTree, in, inSize, out, maxOutSize ); } /* ============= Huff_Init ============= */ void Huff_Init( void ) { #ifdef HUFF_DEBUG Cmd_AddCommand( "dumpcounts", Huff_DumpCounts_f ); #endif Huff_BuildTree( &huffTree, huffCounts ); #ifdef HUFF_DEBUG Huff_ResetCounts (); #endif }