www.pudn.com > huffman2 > huffman2.c
/* * notez : there's kind of a bug in FastDecode : * if the last code in decodes to more than one char, you might * skip more bits than were written * * this can fuck you up in merge-bit-stream cases * */ /* * notez : you must PackCodeLens BEFORE BuildEncodeTable * in order to set Min & Max CodeLen * if you don't PackCodeLens, call SetMinMaxCodeLen */ /* * * return values for BuildCodeLens : * 1 = all ok * 0 = error * -1 = GotNumSymbols < 2 , don't do Huffman ! * */ /* * * Huffman2 : 7-5-96 * * not a general purpose Huffman utility * does not generate Huffman codes. Codes have same lengths, but * values are ordered thus: * for each code length, values are ordered by alphabetic order * * for general purpose Huffman, use Huffman.c routines * * for deferred-build Huffman (no count transmission, one-pass staticHuff2) * use the old Huffman.c routines * * --- * * Encode BuildTree time is nearly identical to old Huffman * Decode BuildTree time is MUCH shorter! * EncodeC time is identical * DecodeC time is shorter * * --- * * 7-6-95 : * FastDecode ! uses table lookup for multi-symbol-at-a-time operation! * * 7-7-95 * I just peeked the IJG JPEG source & discovered that they use * this method with MaxNumMadeChars = 1 * */ #define DEBUG /* DEBUG toggles some tests which garauntee proper operation, but take some time to do */ #define DO_MEMCLEARS /* DO_MEMCLEARS toggles some unnecessary MemClears probably a good idea to turn it on for debug purposes */ #define PACKCODES_TOPSYM /* if this is on, then in PackCodeLens, the value of the highest non-zero-count symbol is written, and codes are only written up to that symbol ; this helps compression a good deal in most cases */ /* * * Modularized Static Huffman encoding * * Notes: works on a LBitIOInfo structure * this structure must be independently allocated and freed * * Uses the O(n) Huffman algorithm with QuickSort, RadixSort, or NoSort * NOTEZ: RadixSort assumes counts are bounded in the range [0,MaxCharCount] * if AlphaSize > 64 or so, use the RadixSort * * You are responsible for calling * LBitIO_FlushWrite(HI->BII); * yourself. It is no longer done in EncodeCDone * * You must also call * LBitIO_InitRead(HI->BII); * yourself before doing any reads. It is no longer done in DecodeCInit * * 7-4-95 new stuff: * 1. charcounts are now packed as codelengths only (much better packing) * 2. this creates a problem : two chars with different counts but the * same code length are no longer distinguishable by the decoder, * but they were distinguished by the encoder! * 3. result : Huffman2 : uses manual code assignment * * */ #include#include #include #include #include #ifdef DEBUG #include #endif //structs,defines: struct Huff2CodeNode { uword Char; uword Count; struct Huff2CodeNode * Up; struct Huff2CodeNode * Down; /* could use uword indexes instead of pointers */ }; #define HUFF2_CODE_BRANCH 0xFFFF #define FD_MAXCHARSMADE 4 #define FD_MAXCHARSMADE_SUBONE 3 /* see ' !<>! ' marker */ struct Huff2Info { long NumSymbols; struct LBitIOInfo * BII; long MinCodeLen,MaxCodeLen; ulong * CodePrefixByLen; long * NumCodesOfLen; long * CodeLenTable; void * EnDe_codeTable; long EnDe_codeTableLen; /* FastDecode buffer */ long NumCharsWaiting; #if FD_MAXCHARSMADE_SUBONE > 0 uword CharsWaiting[FD_MAXCHARSMADE_SUBONE]; #endif /* BuildCodeLen stuff */ struct Huff2CodeNode * NodeBase; struct Huff2CodeNode ** NodeWork; struct Huff2CodeNode ** MadeNodeWork; struct Huff2CodeNode * CodeNodeHunk; long CodeNodeHunkI; ulong * StackArray; long SortType; void * SortWork; long MaxCharCount; }; #define HUFF2_SORT_NONE 1 // data must be pre-sorted ! #define HUFF2_SORT_RADIX 2 #define HUFF2_SORT_QSORT 3 struct FastDecodeItem { ubyte NumBitsUsed; ubyte NumCharsMade; uword CharsMade[FD_MAXCHARSMADE]; }; //protos: struct Huff2Info * Huff2_Init(long NumSymbols,struct LBitIOInfo * BII,long SortType); void Huff2_CleanUp(struct Huff2Info *HI); void Huff2_GetMaxCharCount(struct Huff2Info *HI,long * CharCounts); void Huff2_ScaleCounts(struct Huff2Info *HI,long * CharCounts,long MaxVal); long Huff2_BuildCodeLens(struct Huff2Info *HI,long *CharCounts); bool Huff2_BuildEncodeTable(struct Huff2Info *HI); bool Huff2_BuildDecodeTable(struct Huff2Info *HI); bool Huff2_BuildFastDecodeTable(struct Huff2Info *HI); void Huff2_EncodeC(struct Huff2Info *HI,uword C); uword Huff2_DecodeC(struct Huff2Info *HI); uword Huff2_FastDecodeC(struct Huff2Info *HI); bool Huff2_FastDecodeArray_Ubyte(struct Huff2Info *HI,ubyte * Array,long ArrayLen); void Huff2_SetMinMaxCodeLen(struct Huff2Info *HI); void Huff2_PackCodeLens(struct Huff2Info *HI); void Huff2_UnPackCodeLens(struct Huff2Info *HI); void Huff2_PackCodeLens_Delta(struct Huff2Info *HI,long * LastCodeLens); void Huff2_UnPackCodeLens_Delta(struct Huff2Info *HI,long * LastCodeLens); //sort protos: bool Huff2RadixSort(struct Huff2CodeNode ** BucketArray, long MaxCharCount,struct Huff2CodeNode ** Array,long ArraySize); void Huff2QuickSort(long Left,long Right); struct Huff2CodeNode ** Huff2QuickSortArray; //global for recursion non-stacking //functions: /* */ struct Huff2Info * Huff2_Init(long NumSymbols,struct LBitIOInfo * BII,long SortType) { struct Huff2Info * HI; if ( (HI = AllocMem(sizeof(struct Huff2Info),MEMF_ANY|MEMF_CLEAR)) == NULL ) return(NULL); HI->NumSymbols = NumSymbols; HI->MaxCharCount = LONG_MAX; HI->BII = BII; HI->SortType = SortType; HI->CodeNodeHunkI = 0; if ( (HI->CodeLenTable = AllocMem(HI->NumSymbols*sizeof(long),MEMF_ANY|MEMF_CLEAR)) == NULL ) { Huff2_CleanUp(HI); return(NULL); } if ( (HI->NumCodesOfLen = AllocMem(32*sizeof(long),MEMF_ANY|MEMF_CLEAR)) == NULL ) { Huff2_CleanUp(HI); return(NULL); } if ( (HI->CodePrefixByLen = AllocMem(32*sizeof(ulong),MEMF_ANY|MEMF_CLEAR)) == NULL ) { Huff2_CleanUp(HI); return(NULL); } return(HI); } /* */ void Huff2_CleanUp(struct Huff2Info * HI) { SmartFree(HI->NodeWork,sizeofpointer*HI->NumSymbols); SmartFree(HI->MadeNodeWork,sizeofpointer*HI->NumSymbols*2); SmartFree(HI->CodeLenTable,HI->NumSymbols*sizeof(long)); SmartFree(HI->NumCodesOfLen,32*sizeof(long)); SmartFree(HI->CodePrefixByLen,32*sizeof(ulong)); SmartFree(HI->CodeNodeHunk,sizeof(struct Huff2CodeNode)*2*HI->NumSymbols); SmartFree(HI->StackArray,2*(HI->NumSymbols)*sizeof(ulong)); SmartFree(HI->EnDe_codeTable,HI->EnDe_codeTableLen); if ( HI->SortType == HUFF2_SORT_RADIX ) { SmartFree(HI->SortWork,sizeofpointer*(HI->MaxCharCount + 1)); } FreeMem(HI,sizeof(struct Huff2Info)); } /* * Compute the codelens into Huff2Info from the CharCounts array * NOTEZ: MadeNodeWork is large enough, but you may have the problem of looping i.e. ( (MadeNodeWorkIn - MadeNodeWorkOut) < NumSymbols ) is just fine, the problem is ( MadeNodeWorkIn < NumSymbols ) isn't true thus all made-array lookups are done: [MadeNodeWorkIn % NumSymbols] 10-15-95 : alloced MadeNodeWork to double length so as to eliminate this. */ /* * * return values : * 1 = all ok * 0 = error * -1 = GotNumSymbols == 1 , don't do Huffman ! * call PackCodeLens * -2 = GotNumSymbols == 0 , don't do Huffman ! * don't call PackCodeLens * */ long Huff2_BuildCodeLens(struct Huff2Info *HI,long *CharCounts) { register struct Huff2CodeNode * CurNode; register struct Huff2CodeNode ** NodeWork; register long i,NumSymbols,GotNumSymbols; /*long swapchar;*/ if ( !HI->CodeNodeHunk || !HI->NodeWork || !HI->MadeNodeWork ) { if ( HI->CodeNodeHunk || HI->NodeWork || HI->MadeNodeWork ) { return(0); } HI->NodeWork = AllocMem(sizeofpointer*HI->NumSymbols,MEMF_ANY); HI->MadeNodeWork = AllocMem(sizeofpointer*2*HI->NumSymbols,MEMF_ANY); HI->CodeNodeHunk = AllocMem(sizeof(struct Huff2CodeNode)*2*HI->NumSymbols,MEMF_ANY); if ( !HI->CodeNodeHunk || !HI->NodeWork || !HI->MadeNodeWork ) { return(0); } } /* reset, if this is an already-used Huff2Info */ if ( HI->NodeBase ) { HI->NodeBase = NULL; HI->CodeNodeHunkI = 0; #ifdef DO_MEMCLEARS MemClearFast((long *)HI->CodeNodeHunk,sizeof(struct Huff2CodeNode)*HI->NumSymbols); MemClearFast((long *)HI->NodeWork,HI->NumSymbols); MemClearFast((long *)HI->MadeNodeWork,HI->NumSymbols); #endif // DO_MEMCLEARS MemClearFast((long *)HI->CodeLenTable,HI->NumSymbols); MemClearFast((long *)HI->NumCodesOfLen,32); HI->MinCodeLen = HI->MaxCodeLen = 0; } NodeWork = HI->NodeWork; NumSymbols = HI->NumSymbols; /* * Read the chars into NodeWork * packing out the NULLs * */ GotNumSymbols=0; for(i=0;i 0 ) { NodeWork[GotNumSymbols] = HI->CodeNodeHunk + HI->CodeNodeHunkI; HI->CodeNodeHunkI++; NodeWork[GotNumSymbols]->Char = i; NodeWork[GotNumSymbols]->Count = CharCounts[i]; NodeWork[GotNumSymbols]->Up = NodeWork[GotNumSymbols]->Down = NULL; GotNumSymbols++; } } /* !!!! you should not do any huffman coding if this ever happens ! */ /* NOTEZ: BuildEncodeTable WILL fail ! */ /* PackCodeLens & UnPackCodeLens will work */ if ( GotNumSymbols < 2 ) { if ( GotNumSymbols == 0 ) { HI->NodeBase = HI->CodeNodeHunk; HI->NodeBase->Char = 0; HI->NodeBase->Count = 1; HI->NodeBase->Up = HI->NodeBase->Down = NULL; return(-2); } else { HI->NodeBase = NodeWork[0]; HI->CodeLenTable[HI->NodeBase->Char] = 1; /* call PackCodeLens anyway, so the decoder knows which char to copy */ return(-1); } } /* * sort NodeWork in order of ascending counts * */ switch(HI->SortType) { case HUFF2_SORT_NONE: break; case HUFF2_SORT_RADIX: if ( ! HI->SortWork ) { if ( HI->MaxCharCount == LONG_MAX ) { return(0); } if ( (HI->SortWork = AllocMem(sizeofpointer*(HI->MaxCharCount + 1),MEMF_ANY)) == NULL ) { return(0); } } if ( ! Huff2RadixSort((struct Huff2CodeNode **)HI->SortWork, HI->MaxCharCount,NodeWork,GotNumSymbols) ) return(0); break; case HUFF2_SORT_QSORT: Huff2QuickSortArray = NodeWork; Huff2QuickSort(0,GotNumSymbols-1); break; default: return(0); break; } /* sort puts lowest value of ->Count first */ /* register the tree-building variables */ { register long MadeNodeWorkIn,MadeNodeWorkOut,NodeWorkOut; register struct Huff2CodeNode ** MadeNodeWork; MadeNodeWork = HI->MadeNodeWork; NodeWorkOut=0; MadeNodeWorkIn = 0; MadeNodeWorkOut = 0; /* * Build the tree while there are more leaf-nodes to go * */ while( NodeWorkOut < (GotNumSymbols-1) ) /* $ 38 % */ { CurNode = HI->CodeNodeHunk + HI->CodeNodeHunkI; HI->CodeNodeHunkI++; CurNode->Char = HUFF2_CODE_BRANCH; #ifdef DEBUG if ( HI->CodeNodeHunkI >= (NumSymbols*2) ) { errputs(" HI->CodeNodeHunkI >= (NumSymbols*2) !"); exit(1); } #endif // DEBUG /* * get the lowest two * if counts are equal, use a madenode before a leafnode * */ if ( MadeNodeWorkOut < MadeNodeWorkIn ) { if ( NodeWork[NodeWorkOut]->Count < MadeNodeWork[MadeNodeWorkOut]->Count ) { CurNode->Down = NodeWork[NodeWorkOut]; NodeWorkOut++; } else { CurNode->Down = MadeNodeWork[MadeNodeWorkOut]; MadeNodeWorkOut++; } if ( MadeNodeWorkOut < MadeNodeWorkIn ) { if ( NodeWork[NodeWorkOut]->Count < MadeNodeWork[MadeNodeWorkOut]->Count ) { CurNode->Up = NodeWork[NodeWorkOut]; NodeWorkOut++; } else { CurNode->Up = MadeNodeWork[MadeNodeWorkOut]; MadeNodeWorkOut++; } } else { CurNode->Up = NodeWork[NodeWorkOut]; NodeWorkOut++; } } else { CurNode->Down = NodeWork[NodeWorkOut]; NodeWorkOut++; CurNode->Up = NodeWork[NodeWorkOut]; NodeWorkOut++; } /* ->Down gets the lower valued count & the lower valued character */ /* make sure lower char is on the Down pointer */ /* notez: this is only needed in encode ! */ /* don't bother swapping the counts, they're not needed anymore */ /* if ( CurNode->Down->Char != HUFF2_CODE_BRANCH && CurNode->Up->Char != HUFF2_CODE_BRANCH ) { if ( CurNode->Down->Char > CurNode->Up->Char ) { swapchar = CurNode->Down->Char; CurNode->Down->Char = CurNode->Up->Char; CurNode->Up->Char = swapchar; } } */ /* * put them into a MadeNode * */ MadeNodeWork[MadeNodeWorkIn] = CurNode; MadeNodeWorkIn++; CurNode->Count = CurNode->Down->Count + CurNode->Up->Count; } /* * we stop the prior loop when there are less than 2 nodework symbols left * if there is only one left, this loops until it is eaten off * */ while ( NodeWorkOut < GotNumSymbols && MadeNodeWorkOut < MadeNodeWorkIn ) { CurNode = HI->CodeNodeHunk + HI->CodeNodeHunkI; HI->CodeNodeHunkI++; CurNode->Char = HUFF2_CODE_BRANCH; #ifdef DEBUG if ( HI->CodeNodeHunkI >= (NumSymbols*2) ) { errputs(" HI->CodeNodeHunkI >= (NumSymbols*2) !"); exit(1); } #endif // DEBUG if ( NodeWork[NodeWorkOut]->Count < MadeNodeWork[MadeNodeWorkOut]->Count ) { CurNode->Down = NodeWork[NodeWorkOut]; NodeWorkOut++; } else { CurNode->Down = MadeNodeWork[MadeNodeWorkOut]; MadeNodeWorkOut++; } if ( MadeNodeWorkOut < MadeNodeWorkIn ) { if ( NodeWorkOut < GotNumSymbols ) { if ( NodeWork[NodeWorkOut]->Count < MadeNodeWork[MadeNodeWorkOut]->Count ) { CurNode->Up = NodeWork[NodeWorkOut]; NodeWorkOut++; } else { CurNode->Up = MadeNodeWork[MadeNodeWorkOut]; MadeNodeWorkOut++; } } else { CurNode->Up = MadeNodeWork[MadeNodeWorkOut]; MadeNodeWorkOut++; } } else { CurNode->Up = NodeWork[NodeWorkOut]; NodeWorkOut++; } MadeNodeWork[MadeNodeWorkIn] = CurNode; MadeNodeWorkIn++; CurNode->Count = CurNode->Down->Count + CurNode->Up->Count; } /* * there may still be extras in MadeNodeWork * */ while ( MadeNodeWorkOut < (MadeNodeWorkIn-1) ) { CurNode = HI->CodeNodeHunk + HI->CodeNodeHunkI; HI->CodeNodeHunkI++; CurNode->Char = HUFF2_CODE_BRANCH; CurNode->Down = MadeNodeWork[MadeNodeWorkOut]; MadeNodeWorkOut++; CurNode->Up = MadeNodeWork[MadeNodeWorkOut]; MadeNodeWorkOut++; #ifdef DEBUG if ( HI->CodeNodeHunkI >= (NumSymbols*2) ) { errputs(" HI->CodeNodeHunkI >= (NumSymbols*2) !"); exit(1); } #endif // DEBUG MadeNodeWork[MadeNodeWorkIn] = CurNode; MadeNodeWorkIn++; CurNode->Count = CurNode->Down->Count + CurNode->Up->Count; } /* * grab the base node out * */ HI->NodeBase = MadeNodeWork[(MadeNodeWorkIn-1)]; if ( HI->NodeBase == NULL ) { return(0); /* debugger catch point */ } } /* end tree-building registered variables */ /* now read out the codelens into an array */ { long * CodeLenTable; long * NumCodesOfLen; register struct Huff2CodeNode * CurNode; register ulong CurCodeLen; register ulong GotC; register ulong * StackArray; register long StackI; if ( ! HI->StackArray ) { if ( (HI->StackArray = AllocMem(2*(HI->NumSymbols)*sizeof(ulong),MEMF_ANY)) == NULL ) return(0); } NumCodesOfLen = HI->NumCodesOfLen; CodeLenTable = HI->CodeLenTable; StackArray = HI->StackArray; StackArray[0] = (ulong) HI->NodeBase; StackArray[1] = 0; StackI = 2; while ( StackI > 0 ) /* $ 15% */ { StackI--; CurCodeLen = StackArray[StackI]; StackI--; CurNode = (struct Huff2CodeNode *) StackArray[StackI]; /* traverse all Up branches w/o Stack bumping remember the Down branches as you go once you reach the end of an Up, go back and get the most recent Down & traverse it */ while ( CurNode ) { GotC = CurNode->Char; if ( GotC == HUFF2_CODE_BRANCH ) { CurCodeLen++; #ifdef DEBUG if ( CurCodeLen > 31 ) { fprintf(stderr,"CodeLen > 31 !"); return(0); } #endif if ( CurNode->Down ) { GotC = CurNode->Down->Char; if ( GotC == HUFF2_CODE_BRANCH ) { StackArray[StackI++] = (ulong) CurNode->Down; StackArray[StackI++] = CurCodeLen; #ifdef DEBUG if ( StackI >= (HI->NumSymbols * 2) ) { errputs("Stack usage higher than expected!"); exit(10); } #endif } else { CodeLenTable[GotC] = CurCodeLen; NumCodesOfLen[CurCodeLen] ++; } } CurNode = CurNode->Up; } else { CodeLenTable[GotC] = CurCodeLen; NumCodesOfLen[CurCodeLen] ++; CurNode = NULL; } } } } /* end codelen-retrieval registered variables */ return(1); } /* * at this point CodeLenTable & NumCodesOfLen are filled out * */ bool Huff2_BuildEncodeTable(struct Huff2Info *HI) { ulong LastCodePrefix; ulong * CodePrefixByLen; ulong * CharToCodeTable; long * CodeLenTable; long * NumCodesOfLen; long NumSymbols; long i; long CurCodeLen; ulong CurCode; NumSymbols = HI->NumSymbols; if ( HI->MaxCodeLen == 0 ) return(0); if ( HI->MaxCodeLen > 30 ) return(0); if ( HI->EnDe_codeTable ) { CharToCodeTable = (ulong *) HI->EnDe_codeTable; MemClear((long *)CharToCodeTable,HI->EnDe_codeTableLen); } else { if ( (CharToCodeTable = AllocMem(NumSymbols*sizeof(ulong),MEMF_ANY|MEMF_CLEAR)) == NULL ) return(0); HI->EnDe_codeTable = (void *) CharToCodeTable; HI->EnDe_codeTableLen = NumSymbols*sizeof(ulong); } CodePrefixByLen = HI->CodePrefixByLen; CodeLenTable = HI->CodeLenTable; NumCodesOfLen = HI->NumCodesOfLen; LastCodePrefix = 0; CodePrefixByLen[HI->MinCodeLen] = 0; for(i=(HI->MinCodeLen);i<(HI->MaxCodeLen);) { LastCodePrefix = (LastCodePrefix + NumCodesOfLen[i]) << 1; i++; CodePrefixByLen[i] = LastCodePrefix; } for(i=0;i 0 ) { CurCode = CodePrefixByLen[CurCodeLen]++; CharToCodeTable[i] = CurCode; } } return(1); } /* * at this point CodeLenTable & NumCodesOfLen are filled out * */ bool Huff2_BuildDecodeTable(struct Huff2Info *HI) { ulong BaseCodeByLen[32]; /* I'm lazy! So sue me! */ ulong LastCodePrefix; ulong * CodePrefixByLen; uword * DecodeTable; long * CodeLenTable; long * NumCodesOfLen; long NumSymbols; long i,CurCodeLen; ulong CurCode,PackedCode; long NumCodesOfLowerLen; NumSymbols = HI->NumSymbols; if ( HI->MaxCodeLen == 0 ) return(0); if ( HI->MaxCodeLen > 30 ) return(0); if ( HI->EnDe_codeTable ) { DecodeTable = (uword *) HI->EnDe_codeTable; MemClear((long *)DecodeTable,HI->EnDe_codeTableLen); } else { HI->EnDe_codeTableLen = 2*NumSymbols*sizeof(uword); if ( (DecodeTable = AllocMem(HI->EnDe_codeTableLen,MEMF_ANY|MEMF_CLEAR)) == NULL ) return(0); HI->EnDe_codeTable = (void *) DecodeTable; } CodePrefixByLen = HI->CodePrefixByLen; CodeLenTable = HI->CodeLenTable; NumCodesOfLen = HI->NumCodesOfLen; LastCodePrefix = 0; NumCodesOfLowerLen = 0; CodePrefixByLen[HI->MinCodeLen] = 0; BaseCodeByLen[HI->MinCodeLen] = 0; for(i=(HI->MinCodeLen);i<(HI->MaxCodeLen);) { LastCodePrefix = (LastCodePrefix + NumCodesOfLen[i]) << 1; NumCodesOfLowerLen += NumCodesOfLen[i]; i++; CodePrefixByLen[i] = LastCodePrefix; BaseCodeByLen[i] = LastCodePrefix - NumCodesOfLowerLen; } for(i=0;i 0 ) { CurCode = CodePrefixByLen[CurCodeLen]++; PackedCode = CurCode - BaseCodeByLen[CurCodeLen]; DecodeTable[PackedCode] = CurCodeLen; DecodeTable[PackedCode+NumSymbols] = i; } } for(i=(HI->MinCodeLen);i<=(HI->MaxCodeLen);i++) { CodePrefixByLen[i] = BaseCodeByLen[i]; } return(1); } /* * The FastDecodeTable is a raw 8 bit table (256 entries) * it is indexed by the next 8 bits of the input bitstream * and the value of the table is : * number of bits used (max of 8) = 3 bits -> 1byte * number of chars made (max of 4) = 2 bits -> 1 byte * values of chars made (max of 4) = 8 bytes * total size = 256*10 = 2560 bytes (not bad!) * ( note that this could be as low as 256*5 = 1280 bytes ) * * note that you must also keep the old decodetable around, * in case the code is longer than 8 bits ( numberofcharsmade == 0 ) * * <> todo: make this routine take the number of bits of the table * as a parameter * */ bool Huff2_BuildFastDecodeTable(struct Huff2Info *HI) { struct FastDecodeItem * FastDecodeTable; uword * DecodeTable; long NumSymbols; long Huff2CodeLen; ulong CurCode,StartCode,Huff2Code,CheckCode,ReadCodeMask,PackedCode; long DecodeTableLen,FastDecodeTableLen; long MinCodeLen,NumBitsUsed; uword GotChar; ulong * CodePrefixByLen; CodePrefixByLen = HI->CodePrefixByLen; NumSymbols = HI->NumSymbols; MinCodeLen = HI->MinCodeLen; if ( HI->MaxCodeLen == 0 ) return(0); if ( HI->MaxCodeLen > 30 ) return(0); DecodeTableLen = 2*NumSymbols*sizeof(uword); FastDecodeTableLen = 256*sizeof(struct FastDecodeItem); if ( HI->EnDe_codeTable ) { DecodeTable = (uword *)HI->EnDe_codeTable; FastDecodeTable = (struct FastDecodeItem *) ( (char *)HI->EnDe_codeTable + DecodeTableLen ); MemClear((long *)DecodeTable,DecodeTableLen); MemClear((long *)FastDecodeTable,FastDecodeTableLen); } else { HI->EnDe_codeTableLen = DecodeTableLen + FastDecodeTableLen; if ( (HI->EnDe_codeTable = AllocMem(HI->EnDe_codeTableLen,MEMF_ANY|MEMF_CLEAR)) == NULL ) return(0); DecodeTable = (uword *)HI->EnDe_codeTable; FastDecodeTable = (struct FastDecodeItem *) ( ((char *)HI->EnDe_codeTable) + DecodeTableLen ); } /* build the old style table */ if ( ! Huff2_BuildDecodeTable(HI) ) return(0); /* now DecodeTable is filled out */ /* step through all the codes & find what chars correspond to them when you find a char for a code, propagate it through all codes which have that as a prefix keep going until NumBitsFree < Huff2CodeLen for all entries */ for(StartCode=0;StartCode<255;StartCode++) { NumBitsUsed = FastDecodeTable[StartCode].NumBitsUsed; while ( (8-NumBitsUsed) >= MinCodeLen && FastDecodeTable[StartCode].NumCharsMade < FD_MAXCHARSMADE ) { CurCode = StartCode ; /* find char that encodes to curcode */ Huff2CodeLen = MinCodeLen; Huff2Code = ( CurCode >> (8 - NumBitsUsed - Huff2CodeLen) ) & ( (1< >= 1; Huff2CodeLen++; if ( ReadCodeMask == 0 ) goto DoneWithCurCode; PackedCode = Huff2Code - CodePrefixByLen[Huff2CodeLen]; } if ( Huff2CodeLen > (8 - NumBitsUsed) ) goto DoneWithCurCode; GotChar = DecodeTable[PackedCode+NumSymbols]; /* step through while Huff2Code is the next code all occurances of Huff2Code will be contiguous */ do { if ( FastDecodeTable[CurCode].NumCharsMade < FD_MAXCHARSMADE ) { FastDecodeTable[CurCode].CharsMade[FastDecodeTable[CurCode].NumCharsMade] = GotChar; FastDecodeTable[CurCode].NumCharsMade++; FastDecodeTable[CurCode].NumBitsUsed = NumBitsUsed + Huff2CodeLen; } CurCode ++; NumBitsUsed = FastDecodeTable[CurCode].NumBitsUsed; if ( Huff2CodeLen > (8-NumBitsUsed) ) break; CheckCode = ( CurCode >> (8 - NumBitsUsed - Huff2CodeLen) ) & ( (1< */ continue; } HI->NumCharsWaiting = 0; return(1); } void Huff2_EncodeC(struct Huff2Info *HI,uword Symbol) { register ulong CurCode; register long CurCodeLen; register struct LBitIOInfo * BII; CurCode = ((ulong *)HI->EnDe_codeTable)[Symbol]; CurCodeLen = HI->CodeLenTable[Symbol]; BII = HI->BII; #ifdef DEBUG if ( CurCodeLen == 0 ) { errputs("Got EncodeC for CodeLen == 0 symbol!"); exit(10); } #endif LBitIO_WriteBits(BII,CurCode,CurCodeLen); } bool Huff2_FastDecodeArray_Ubyte(struct Huff2Info *HI,ubyte * Array,long ArrayLen) { register ulong PeekedCode; register struct FastDecodeItem * FastDecodeTable; long NumCharsMade; uword * CharsMade; long NumSymbols; uword * DecodeTable; ulong * CodePrefixByLen; ulong CurCode,PackedCode; long CurCodeLen; bool bit; ubyte *CurArrayPtr,*ArrayPtrDone; LocalLBitIO_Variables(); LocalLBitIO_GetState(HI->BII); NumSymbols = HI->NumSymbols; FastDecodeTable = (struct FastDecodeItem *) ( ((char *)HI->EnDe_codeTable) + 2*NumSymbols*sizeof(uword) ); DecodeTable = (uword *)HI->EnDe_codeTable; CodePrefixByLen = HI->CodePrefixByLen; CurArrayPtr = Array; ArrayPtrDone = Array + ArrayLen - 4; while ( CurArrayPtr < ArrayPtrDone ) { LocalLBitIO_PeekBits(PeekedCode,8); NumCharsMade = FastDecodeTable[PeekedCode].NumCharsMade; if ( NumCharsMade > 0 ) { CurCodeLen = FastDecodeTable[PeekedCode].NumBitsUsed; LocalLBitIO_SkipBits(CurCodeLen); switch ( NumCharsMade ) { case 1: *CurArrayPtr++ = *(FastDecodeTable[PeekedCode].CharsMade); break; case 2: CharsMade = FastDecodeTable[PeekedCode].CharsMade; *CurArrayPtr++ = *CharsMade++; *CurArrayPtr++ = *CharsMade; break; case 3: CharsMade = FastDecodeTable[PeekedCode].CharsMade; *CurArrayPtr++ = *CharsMade++; *CurArrayPtr++ = *CharsMade++; *CurArrayPtr++ = *CharsMade; break; case 4: CharsMade = FastDecodeTable[PeekedCode].CharsMade; *CurArrayPtr++ = *CharsMade++; *CurArrayPtr++ = *CharsMade++; *CurArrayPtr++ = *CharsMade++; *CurArrayPtr++ = *CharsMade; break; } } else /* use old decode method, can read 9 bits automatically */ { CurCodeLen = 8; CurCode = PeekedCode; LocalLBitIO_SkipBits(8); PackedCode = CurCode - CodePrefixByLen[CurCodeLen]; /* could read another bit here, but who cares? */ while( DecodeTable[PackedCode] != CurCodeLen ) { CurCode += CurCode; LocalLBitIO_ReadBit(bit); CurCode += bit; CurCodeLen++; PackedCode = CurCode - CodePrefixByLen[CurCodeLen]; } *CurArrayPtr++ = DecodeTable[PackedCode+NumSymbols]; } } LocalLBitIO_PutState(HI->BII); /* do normal decode for last 4 to make sure we don't go too far */ ArrayPtrDone += 4; while ( CurArrayPtr < ArrayPtrDone ) { *CurArrayPtr++ = Huff2_DecodeC(HI); } return(1); } uword Huff2_FastDecodeC(struct Huff2Info *HI) { #if FD_MAXCHARSMADE_SUBONE > 0 if ( HI->NumCharsWaiting > 0 ) { HI->NumCharsWaiting--; return(HI->CharsWaiting[HI->NumCharsWaiting]); } #endif // FD_MAXCHARSMADE_SUBONE == 0 /* variables not init-ed if there are chars waiting */ { struct FastDecodeItem * FastDecodeTable; ulong PeekedCode; struct LBitIOInfo * BII; long NumSymbols; NumSymbols = HI->NumSymbols; FastDecodeTable = (struct FastDecodeItem *) ( ((char *)HI->EnDe_codeTable) + 2*NumSymbols*sizeof(uword) ); BII = HI->BII; LBitIO_PeekBits(BII,PeekedCode,8); if ( FastDecodeTable[PeekedCode].NumCharsMade > 0 ) { LBitIO_SkipBits(BII,FastDecodeTable[PeekedCode].NumBitsUsed); #if FD_MAXCHARSMADE_SUBONE > 0 HI->NumCharsWaiting = FastDecodeTable[PeekedCode].NumCharsMade - 1; switch ( HI->NumCharsWaiting ) /* !<>! */ { case 0: break; case 1: HI->CharsWaiting[0] = FastDecodeTable[PeekedCode].CharsMade[1]; break; case 2: HI->CharsWaiting[1] = FastDecodeTable[PeekedCode].CharsMade[1]; HI->CharsWaiting[0] = FastDecodeTable[PeekedCode].CharsMade[2]; break; case 3: HI->CharsWaiting[2] = FastDecodeTable[PeekedCode].CharsMade[1]; HI->CharsWaiting[1] = FastDecodeTable[PeekedCode].CharsMade[2]; HI->CharsWaiting[0] = FastDecodeTable[PeekedCode].CharsMade[3]; break; } #endif // FD_MAXCHARSMADE_SUBONE == 0 return( FastDecodeTable[PeekedCode].CharsMade[0] ); } else /* use old decode method, can read 9 bits automatically */ { uword * DecodeTable; ulong * CodePrefixByLen; ulong CurCode,PackedCode; long CurCodeLen; bool bit; DecodeTable = (uword *)HI->EnDe_codeTable; CodePrefixByLen = HI->CodePrefixByLen; CurCodeLen = 8; CurCode = PeekedCode; LBitIO_SkipBits(BII,8); PackedCode = CurCode - CodePrefixByLen[CurCodeLen]; /* could read another bit here, but who cares? */ while( DecodeTable[PackedCode] != CurCodeLen ) { CurCode += CurCode; LBitIO_ReadBit(BII,bit); CurCode += bit; CurCodeLen++; PackedCode = CurCode - CodePrefixByLen[CurCodeLen]; } #ifdef DEBUG if ( CurCodeLen > HI->MaxCodeLen ) { errputs("Got code longer than MaxCodeLen!"); exit(10); } #endif return(DecodeTable[PackedCode+NumSymbols]); } } /* end variable-space */ } uword Huff2_DecodeC(struct Huff2Info *HI) { uword * DecodeTable; long NumSymbols; ulong * CodePrefixByLen; ulong CurCode,PackedCode; long CurCodeLen; struct LBitIOInfo * BII; bool bit; NumSymbols = HI->NumSymbols; DecodeTable = (uword *) HI->EnDe_codeTable; CodePrefixByLen = HI->CodePrefixByLen; BII = HI->BII; CurCodeLen = HI->MinCodeLen; LBitIO_ReadBits(BII,CurCode,CurCodeLen) PackedCode = CurCode; while( DecodeTable[PackedCode] != CurCodeLen ) { CurCode += CurCode; LBitIO_ReadBit(BII,bit); CurCode += bit; CurCodeLen++; PackedCode = CurCode - CodePrefixByLen[CurCodeLen]; } #ifdef DEBUG if ( CurCodeLen > HI->MaxCodeLen ) { errputs("Got code longer than MaxCodeLen!"); exit(10); } #endif return(DecodeTable[PackedCode+NumSymbols]); } /* * Scale Counts to [0,MaxVal] * (brackets indicate the range is "inclusive") * * a count which was > 0 will not be scaled to 0 * */ void Huff2_ScaleCounts(struct Huff2Info *HI,long * CharCounts,long MaxVal) { long MaxCharCount; long NumSymbols,i; long OutCharCount; NumSymbols = HI->NumSymbols; //get maxcharcount MaxCharCount = 0; for(i=0;i MaxCharCount ) MaxCharCount = CharCounts[i]; } //scale counts if ( MaxCharCount > MaxVal ) { for(i=0;i MaxVal ) OutCharCount = MaxVal; else if ( CharCounts[i] && ! OutCharCount ) OutCharCount = 1; CharCounts[i] = OutCharCount; } } if ( HI->MaxCharCount != MaxVal && HI->SortType == HUFF2_SORT_RADIX && HI->SortWork != NULL ) { FreeMem(HI->SortWork,sizeofpointer*(HI->MaxCharCount+1)); HI->SortWork = NULL; } HI->MaxCharCount = min(MaxCharCount,MaxVal); } /* * Sets ->MaxCharCount in HI * */ void Huff2_GetMaxCharCount(struct Huff2Info *HI,long * CharCounts) { long MaxCharCount; long NumSymbols,i; NumSymbols = HI->NumSymbols; //get maxcharcount MaxCharCount = 0; for(i=0;i MaxCharCount ) MaxCharCount = CharCounts[i]; } if ( HI->MaxCharCount != MaxCharCount && HI->SortType == HUFF2_SORT_RADIX && HI->SortWork != NULL ) { FreeMem(HI->SortWork,sizeofpointer*(HI->MaxCharCount+1)); HI->SortWork = NULL; } HI->MaxCharCount = MaxCharCount; } /* * sets MinCodeLen & MaxCodeLen which must be set * for BuildEncodeTable * */ void Huff2_SetMinMaxCodeLen(struct Huff2Info *HI) { long MinCodeLen,MaxCodeLen; MinCodeLen = 1; while ( HI->NumCodesOfLen[MinCodeLen] == 0 ) MinCodeLen++; MaxCodeLen = 31; while ( HI->NumCodesOfLen[MaxCodeLen] == 0 ) MaxCodeLen--; HI->MaxCodeLen = MaxCodeLen; HI->MinCodeLen = MinCodeLen; } /* * Writes codelens out to the BII * * also sets MinCodeLen & MaxCodeLen which must be set * for BuildEncodeTable * */ void Huff2_PackCodeLens(struct Huff2Info *HI) { long MinCodeLen,MaxCodeLen; long i,j,GotNumSymbols; ubyte RunData[32]; long RunLen; long CurCodeLen; struct LBitIOInfo * BII; BII = HI->BII; #ifdef PACKCODES_TOPSYM GotNumSymbols = HI->NumSymbols; while ( HI->CodeLenTable[GotNumSymbols-1] == 0 ) GotNumSymbols--; if ( (HI->NumSymbols - GotNumSymbols) < 32 ) { LBitIO_WriteBit(BII,0); GotNumSymbols = HI->NumSymbols; } else { LBitIO_WriteBit(BII,1); CurCodeLen = intlog2(HI->NumSymbols); LBitIO_WriteBits(BII,GotNumSymbols,CurCodeLen); } #else GotNumSymbols = HI->NumSymbols; #endif // PACKCODES_TOPSYM MinCodeLen = 1; while ( HI->NumCodesOfLen[MinCodeLen] == 0 ) MinCodeLen++; MaxCodeLen = 31; while ( HI->NumCodesOfLen[MaxCodeLen] == 0 ) MaxCodeLen--; HI->MaxCodeLen = MaxCodeLen; HI->MinCodeLen = MinCodeLen; if ( MaxCodeLen >= 0xF ) { LBitIO_WriteBits(BII,0xF,4); LBitIO_WriteBits(BII,MaxCodeLen-0xF,4); } else { LBitIO_WriteBits(BII,MaxCodeLen,4); } for(i=0;i CodeLenTable[i] == 0 && RunLen < 32 && i 0 ) { LBitIO_WriteBit(BII,0); LBitIO_WriteBits(BII,(RunLen-1),5); } RunLen = 0; while ( ( HI->CodeLenTable[i] != 0 || HI->CodeLenTable[i+1] != 0 ) && RunLen < 32 && i CodeLenTable[i]; RunLen++; i++; } if ( RunLen > 0 ) { LBitIO_WriteBit(BII,1); LBitIO_WriteBits(BII,(RunLen-1),5); for(j=0;j = 0x7 ) { LBitIO_WriteBits(BII,0x7,3); CurCodeLen -= 0x7; } LBitIO_WriteBits(BII,CurCodeLen,3); } } } } /* * reads packed codelens to CodeLenTable * * also sets NumCodesOfLen * */ void Huff2_UnPackCodeLens(struct Huff2Info *HI) { long i,j,GotNumSymbols; long MinCodeLen,MaxCodeLen,CurCodeLen; long RunLen,CurCode; struct LBitIOInfo * BII; bool bit; MemClearMacroFast(HI->CodeLenTable,HI->NumSymbols); MemClearMacroFast(HI->NumCodesOfLen,32); HI->MinCodeLen = HI->MaxCodeLen = 0; BII = HI->BII; #ifdef PACKCODES_TOPSYM LBitIO_ReadBit(BII,bit); if ( bit ) { CurCodeLen = intlog2(HI->NumSymbols); LBitIO_ReadBits(BII,GotNumSymbols,CurCodeLen); } else { GotNumSymbols = HI->NumSymbols; } #else GotNumSymbols = HI->NumSymbols; #endif // PACKCODES_TOPSYM LBitIO_ReadBits(BII,CurCode,4); if ( CurCode == 0xF ) { LBitIO_ReadBits(BII,CurCode,4); MaxCodeLen = CurCode + 0xF; } else { MaxCodeLen = CurCode; } HI->MaxCodeLen = MaxCodeLen; MinCodeLen = MaxCodeLen; for(i=0;i CodeLenTable[i++] = 0; } } else { for(j=0;j CodeLenTable[i++] = CurCodeLen; if ( CurCodeLen > 0 ) HI->NumCodesOfLen[CurCodeLen] ++; if ( CurCodeLen < MinCodeLen && CurCodeLen > 0 ) MinCodeLen = CurCodeLen; } } } HI->MinCodeLen = MinCodeLen; } /* * Writes codelens out to the BII * * compresses differences for an earlier huff build * you must allocate lastcodelens, & set to 0 initially * * also sets MinCodeLen & MaxCodeLen which must be set * for BuildEncodeTable * */ void Huff2_PackCodeLens_Delta(struct Huff2Info *HI,long * LastCodeLens) { long MinCodeLen,MaxCodeLen; long i,j,GotNumSymbols; ubyte RunData[512],RunDataLast[512]; long RunLen; long CurCodeLen; struct LBitIOInfo * BII; BII = HI->BII; #ifdef PACKCODES_TOPSYM GotNumSymbols = HI->NumSymbols; while ( HI->CodeLenTable[GotNumSymbols-1] == 0 ) GotNumSymbols--; if ( (HI->NumSymbols - GotNumSymbols) < 32 ) { LBitIO_WriteBit(BII,0); GotNumSymbols = HI->NumSymbols; } else { LBitIO_WriteBit(BII,1); CurCodeLen = intlog2(HI->NumSymbols); LBitIO_WriteBits(BII,GotNumSymbols,CurCodeLen); } #else GotNumSymbols = HI->NumSymbols; #endif // PACKCODES_TOPSYM MinCodeLen = 1; while ( HI->NumCodesOfLen[MinCodeLen] == 0 ) MinCodeLen++; MaxCodeLen = 31; while ( HI->NumCodesOfLen[MaxCodeLen] == 0 ) MaxCodeLen--; HI->MaxCodeLen = MaxCodeLen; HI->MinCodeLen = MinCodeLen; if ( MaxCodeLen >= 0xF ) { LBitIO_WriteBits(BII,0xF,4); LBitIO_WriteBits(BII,MaxCodeLen-0xF,4); } else { LBitIO_WriteBits(BII,MaxCodeLen,4); } for(i=0;i CodeLenTable[i] - LastCodeLens[i] ) == 0 && i = 0x03 ) { LBitIO_WriteBits(BII,0x03,2); RunLen -= 0x3; if ( RunLen >= 0x07 ) { long Thresh,Bits; LBitIO_WriteBits(BII,0x07,3); RunLen -= 0x7; Thresh = 0xF; Bits = 4; while ( RunLen >= Thresh ) { LBitIO_WriteBits(BII,Thresh,Bits); RunLen -= Thresh; Thresh += Thresh + 1; Bits++; } LBitIO_WriteBits(BII,RunLen,Bits); } else { LBitIO_WriteBits(BII,RunLen,3); } } else { LBitIO_WriteBits(BII,RunLen,2); } if ( i == GotNumSymbols ) break; RunLen = 0; while ( ( ( HI->CodeLenTable[i] - LastCodeLens[i] ) != 0 ) && i CodeLenTable[i]; RunDataLast[RunLen] = LastCodeLens[i]; RunLen++; i++; if ( RunLen == 512 ) return; /* BAD ! */ } if ( RunLen >= 0x03 ) { j = RunLen; LBitIO_WriteBits(BII,0x03,2); RunLen -= 0x3; if ( RunLen >= 0x07 ) { long Thresh,Bits; LBitIO_WriteBits(BII,0x07,3); RunLen -= 0x7; Thresh = 0xF; Bits = 4; while ( RunLen >= Thresh ) { LBitIO_WriteBits(BII,Thresh,Bits); RunLen -= Thresh; Thresh += Thresh + 1; Bits++; } LBitIO_WriteBits(BII,RunLen,Bits); } else { LBitIO_WriteBits(BII,RunLen,3); } RunLen = j; } else { LBitIO_WriteBits(BII,RunLen,2); } if ( RunLen > 0 ) { for(j=0;j = 0x7 ) { LBitIO_WriteBits(BII,0x7,3); CurCodeLen -= 0x7; } LBitIO_WriteBits(BII,CurCodeLen,3); } else { CurCodeLen = RunData[j] - RunDataLast[j]; if ( CurCodeLen < 0 ) { LBitIO_WriteBit(BII,0); CurCodeLen = - (CurCodeLen + 1); } else { LBitIO_WriteBit(BII,1); CurCodeLen--; } while ( CurCodeLen > 0 ) { LBitIO_WriteBit(BII,0); CurCodeLen --; } LBitIO_WriteBit(BII,1); } } } } for(i=0;i NumSymbols;i++) { LastCodeLens[i] = HI->CodeLenTable[i]; } } /* * reads packed codelens to CodeLenTable * * also sets NumCodesOfLen * * <> doesn't decode new style of runlen yet * */ void Huff2_UnPackCodeLens_Delta(struct Huff2Info *HI,long * LastCodeLens) { long i,j,GotNumSymbols; long MinCodeLen,MaxCodeLen,CurCodeLen; long RunLen,CurCode; struct LBitIOInfo * BII; bool bit; long sign; BII = HI->BII; MemClear((long *)HI->NumCodesOfLen,32*sizeof(long)); #ifdef PACKCODES_TOPSYM LBitIO_ReadBit(BII,bit); if ( bit ) { CurCodeLen = intlog2(HI->NumSymbols); LBitIO_ReadBits(BII,GotNumSymbols,CurCodeLen); } else { GotNumSymbols = HI->NumSymbols; } #else GotNumSymbols = HI->NumSymbols; #endif // PACKCODES_TOPSYM LBitIO_ReadBits(BII,CurCode,4); if ( CurCode == 0xF ) { LBitIO_ReadBits(BII,CurCode,4); MaxCodeLen = CurCode + 0xF; } else { MaxCodeLen = CurCode; } HI->MaxCodeLen = MaxCodeLen; MinCodeLen = MaxCodeLen; for(i=0;i CodeLenTable[i] = LastCodeLens[i]; i++; } } else { for(j=0;j 0 ) { LBitIO_ReadBit(BII,bit); if ( bit ) sign = -1; else sign = 1; LBitIO_ReadBit(BII,bit); CurCodeLen = 1; while( bit == 0 ) { CurCodeLen++; LBitIO_ReadBit(BII,bit); } CurCodeLen = CurCodeLen * sign + LastCodeLens[i]; } else { CurCodeLen = 0; LBitIO_ReadBits(BII,CurCode,3); while( CurCode == 0x7 ) { CurCodeLen += 0x7; LBitIO_ReadBits(BII,CurCode,3); } CurCodeLen += CurCode; CurCodeLen = MaxCodeLen - CurCodeLen; } HI->CodeLenTable[i++] = CurCodeLen; if ( CurCodeLen > 0 ) HI->NumCodesOfLen[CurCodeLen] ++; if ( CurCodeLen < MinCodeLen && CurCodeLen > 0 ) MinCodeLen = CurCodeLen; } } } for(i=0;i NumSymbols;i++) { LastCodeLens[i] = HI->CodeLenTable[i]; } HI->MinCodeLen = MinCodeLen; } /* * QuickSort on the NodeWork array * set Huff2QuickSortArray * */ void Huff2QuickSort(long Left,long Right) { if ( (Right - Left) > 1 ) { long i; { long j; long pivot; struct Huff2CodeNode *swapper; register struct Huff2CodeNode ** Array; Array = Huff2QuickSortArray; pivot = Array[Right]->Count; i = Left-1; j = Right; for(;;) { /* could remove i < Right && j > Left checking by putting dummy array slots in [-1] and [GotNumSymbols] w/ Counts 0 and LONG_MAX */ do ++i; while(Array[i]->Count < pivot && i < Right); do --j; while(Array[j]->Count > pivot && j > Left); if (i >= j) break; swapper = Array[i]; Array[i] = Array[j]; Array[j] = swapper; } swapper = Array[i]; Array[i] = Array[Right]; Array[Right] = swapper; } Huff2QuickSort(Left,i-1); Huff2QuickSort(i+1,Right); } else { if ( Right > Left ) { if ( Huff2QuickSortArray[Right]->Count < Huff2QuickSortArray[Left]->Count ) { struct Huff2CodeNode *swapper; swapper = Huff2QuickSortArray[Left]; Huff2QuickSortArray[Left] = Huff2QuickSortArray[Right]; Huff2QuickSortArray[Right] = swapper; } } } } /* * Radix sort on the NodeWork * counts must be bounded by [0,MaxCharCount] * this is much faster than QuickSort for large NumSymbols * * I think NumSymbols as small as 256 is still faster here * Radix = O(256 + 2*NumSymbols) * QuickSort = O(NumSymbols*log2(NumSymbols)) * bigOs are equal for NumSymbols == 64 * * NOTEZ: uses the ->Up in the codenode structure * resets ->Up to NULL when its done * */ bool Huff2RadixSort(struct Huff2CodeNode ** BucketArray, long MaxCharCount,struct Huff2CodeNode ** Array,long ArraySize) { register struct Huff2CodeNode * CurNode; register long i,j; MemClear((long *)BucketArray,sizeofpointer*(MaxCharCount+1)); /* go backwards so that alphabetic order is preserved */ for(i=(ArraySize-1);i>=0;i--) { Array[i]->Up = BucketArray[Array[i]->Count]; BucketArray[Array[i]->Count] = Array[i]; } j=0; for(i=0;i<=MaxCharCount;i++) { CurNode = BucketArray[i]; while(CurNode) /* $ 15% */ { Array[j] = CurNode; CurNode = CurNode->Up; Array[j]->Up = NULL; j++; } } if ( j != ArraySize ) { return(0); } return(1); }