summaryrefslogtreecommitdiff
path: root/3dc/win95/huffman.cpp
diff options
context:
space:
mode:
authorSteven Fuller <relnev@icculus.org>2001-07-01 00:55:22 +0000
committerPatryk Obara <dreamer.tan@gmail.com>2019-08-20 02:09:04 +0200
commit2186d5f3f95cd74a070a490d899291648d58667a (patch)
tree55241a1afa3e1a22e0b6593a8dead0b703800f44 /3dc/win95/huffman.cpp
parent218ca90543758a20ac326e444ca0643174ca7384 (diff)
Initial revision
Diffstat (limited to '3dc/win95/huffman.cpp')
-rw-r--r--3dc/win95/huffman.cpp520
1 files changed, 0 insertions, 520 deletions
diff --git a/3dc/win95/huffman.cpp b/3dc/win95/huffman.cpp
deleted file mode 100644
index b2a0275..0000000
--- a/3dc/win95/huffman.cpp
+++ /dev/null
@@ -1,520 +0,0 @@
-#include "stdio.h"
-#include "stdlib.h"
-#include "string.h"
-#include "malloc.h"
-#include "huffman.hpp"
-
-/* KJL 17:12:25 17/09/98 - Huffman compression/decompression routines */
-
-typedef struct
-{
- int Symbol;
- unsigned int Count;
-} HuffItem;
-
-typedef struct HuffNode // 16-byte node structure
-{
- union
- { // the FIRST four bytes
- struct HuffNode *zero; // points to the "zero" branch or...
- unsigned int value; // holds the value of an end node
- };
-
- union
- { // the SECOND four bytes
- struct HuffNode *one; // points to the "one" branch or...
- struct HuffNode *link; // points to next end node in list
- };
-
- struct HuffNode *parent; // the THIRD four bytes, parent node
-
- union
- { // the FOURTH four bytes
- unsigned int bits; // the bit pattern of this end node
- struct
- {
- unsigned char flag;
- unsigned char curdepth;
- unsigned char maxdepth;
- unsigned char unused;
- };
- };
-
-} HuffNode;
-
-typedef struct
-{
- long wid;
- long bits;
-
-} HuffEncode;
-
-static HuffItem SymbolCensus[257];
-static HuffNode TreeNodes[2*257];
-static int Depths[MAX_DEPTH+1];
-static HuffEncode EncodingTable[257];
-
-#define AllocateMemory malloc
-
-
-/* KJL 17:16:03 17/09/98 - Compression */
-static void PerformSymbolCensus(unsigned char *sourcePtr, int length);
-#ifdef __WATCOMC__
-static int HuffItemsSortSub(const void *cmp1, const void *cmp2);
-#else
-static int __cdecl HuffItemsSortSub(const void *cmp1, const void *cmp2);
-#endif
-static void SortCensusData(void);
-static void BuildHuffmanTree(void);
-static void MakeHuffTreeFromHuffItems(HuffNode *base, HuffItem *source, int count);
-static void MakeCodeLengthsFromHuffTree(int *dest, HuffNode *source, int maxdepth);
-static int HuffDepthsAdjust(int *depth, int maxdepth);
-static void MakeHuffmanEncodeTable(HuffEncode *encodetable, HuffItem *item, int *depths);
-static int HuffEncodeBytes(int *dest, unsigned char *source, int count, HuffEncode *table);
-
-
-extern HuffmanPackage *HuffmanCompression(unsigned char *sourcePtr, int length)
-{
- HuffmanPackage *outpackage;
-
-
- // Step 1: Perform the symbol census
- PerformSymbolCensus(sourcePtr,length);
- // Step 2: Sorting the census data
- SortCensusData();
- // Step 3: Building the Huffman tree
- BuildHuffmanTree();
- // Step 4: Making the code lengths table
- MakeCodeLengthsFromHuffTree(Depths, TreeNodes, MAX_DEPTH);
- // Step 5: Limiting code lengths
- HuffDepthsAdjust(Depths, MAX_DEPTH);
- // Step 6: Making the encoding table
- MakeHuffmanEncodeTable(EncodingTable,&SymbolCensus[256],Depths);
- // Step 7: Encoding data
- outpackage = (HuffmanPackage*)AllocateMemory(sizeof(HuffmanPackage)+length);
- strncpy(outpackage->Identifier,COMPRESSED_RIF_IDENTIFIER,8);
- outpackage->CompressedDataSize = HuffEncodeBytes((int*)(outpackage+1), sourcePtr, length, EncodingTable);
- outpackage->UncompressedDataSize = length;
- for (int n = 0; n < MAX_DEPTH; n++)
- {
- outpackage->CodelengthCount[n] = Depths[n + 1];
- }
- for (n = 0; n < 256; n++)
- {
- outpackage->ByteAssignment[n] = SymbolCensus[n + 1].Symbol;
- }
- return outpackage;
-}
-
-static void PerformSymbolCensus(unsigned char *sourcePtr, int length)
-{
- // init array
- for (int i=0; i<257; i++)
- {
- SymbolCensus[i].Symbol = i;
- SymbolCensus[i].Count = 0;
- }
-
- // count 'em
- do
- {
- SymbolCensus[*sourcePtr++].Count++;
- }
- while (--length);
-}
-
-#ifdef __WATCOMC__
-static int HuffItemsSortSub(const void *cmp1, const void *cmp2)
-#else
-static int __cdecl HuffItemsSortSub(const void *cmp1, const void *cmp2)
-#endif
-{
- if (((HuffItem *)cmp1)->Count > ((HuffItem *)cmp2)->Count)
- return 1;
- if (((HuffItem *)cmp1)->Count < ((HuffItem *)cmp2)->Count)
- return -1;
- return 0;
-}
-static void SortCensusData(void)
-{
- qsort(SymbolCensus, 257, sizeof(HuffItem), HuffItemsSortSub);
-}
-
-static void BuildHuffmanTree(void)
-{
- MakeHuffTreeFromHuffItems(TreeNodes,SymbolCensus,257);
-}
-
-static void MakeHuffTreeFromHuffItems(HuffNode *base, HuffItem *source, int count)
-{
- HuffNode *movdest, *temp;
- int n, upperlim, lowerlim, index;
- unsigned int sum;
-
- if (!count) return;
-
- movdest = base + 1;
- temp = base + count;
- memset(temp, 0, count * sizeof(HuffNode));
- for (n = 0; n < count; n++)
- {
- temp[n].bits = source[n].Count;
- }
- while (upperlim = --count)
- {
- if (temp[0].zero)
- temp[0].zero->parent = temp[0].one->parent = movdest;
- if (temp[1].zero)
- temp[1].zero->parent = temp[1].one->parent = movdest + 1;
- movdest[0] = *temp++;
- movdest[1] = *temp;
- sum = movdest[0].bits + movdest[1].bits;
- lowerlim = 1;
-
- while (lowerlim != upperlim)
- {
- index = (lowerlim + upperlim) >> 1;
- if (sum >= temp[index].bits)
- {
- lowerlim = index + 1;
- }
- else
- {
- upperlim = index;
- }
- }
- index = lowerlim - 1;
- memmove(temp, temp + 1, index * sizeof(HuffNode));
- temp[index].bits = sum;
- temp[index].zero = movdest;
- temp[index].one = movdest + 1;
- movdest += 2;
- }
- base[0] = temp[0];
- if (base[0].zero)
- base[0].zero->parent = base[0].one->parent = base;
-}
-
-static void MakeCodeLengthsFromHuffTree(int *dest, HuffNode *source, int maxdepth)
-{
- int n, depth;
- HuffNode *back;
-
- for (n = 0; n < maxdepth + 1; n++)
- dest[n] = 0;
- depth = 0;
- while (1)
- {
- while (source->one)
- {
- source = source->one;
- depth++;
- }
-
- if (depth > maxdepth) dest[maxdepth]++;
- else dest[depth]++;
-
- do
- {
- back = source;
- source = source->parent;
- if (!depth--)
- return;
- }
- while (back == source->zero);
-
- source = source->zero;
- depth++;
- }
-}
-
-static int HuffDepthsAdjust(int *depth, int maxdepth)
-{
- unsigned int n, m, items, sum, goal, gain, busts;
- unsigned int promotions, excess, hi;
-
- goal = 1 << maxdepth;
- for (n = 0, sum = 0, items = 0; n <= maxdepth; n++)
- {
- items += depth[n];
- sum += (goal >> n) * depth[n];
- }
- if (items > goal)
- return -1; // failure
- for (n = maxdepth - 1; sum > goal; n--)
- {
- if (depth[n])
- {
- gain = (1 << (maxdepth - n)) - 1;
- busts = (sum - goal + gain - 1) / gain;
- busts = depth[n] < busts ? depth[n] : busts;
- depth[n] -= busts;
- depth[maxdepth] += busts;
- sum -= busts * gain;
- }
- }
- excess = goal - sum;
- for (n = 0; excess; n++)
- {
- hi = 1 << (maxdepth - n);
- for (m = n + 1; m <= maxdepth; m++)
- {
- gain = hi - (1 << (maxdepth - m));
- if (excess < gain)
- break;
- if (depth[m])
- {
- promotions = excess / gain;
- promotions = depth[m] > promotions ? promotions : depth[m];
- depth[n] += promotions;
- depth[m] -= promotions;
- excess -= promotions * gain;
- }
- }
- }
- return 0; // success
-}
-
-static void MakeHuffmanEncodeTable(HuffEncode *encodetable, HuffItem *item, int *depths)
-{
- unsigned int d, bitwidth, depthbit, bt, cur;
- int *dep;
-
- dep = depths + 1; // skip depth zero
- bitwidth = 0; // start from small bitwidths
- cur = 0; // current bit pattern
- do
- {
- do
- {
- bitwidth++; // go deeper
- depthbit = 1 << (bitwidth - 1); // keep depth marker
- d = *dep++; // get count here
- }
- while (!d); // until count non-zero
- while (d--)
- { // for all on this level
- encodetable[item->Symbol].wid = bitwidth; // record width
- encodetable[item->Symbol].bits = cur; // record bits
- item--; // count backwards an item
- bt = depthbit; // bt is a temp value
- while (1)
- {
- cur ^= bt; // do an add modulo 1
- if ((cur & bt) || !bt) // break if now a 1
- break; // or out of bits
- bt >>= 1; // do next bit position
- }
- }
- }
- while (cur); // until cur exhausted
-}
-
-static int HuffEncodeBytes(int *dest, unsigned char *source, int count, HuffEncode *table)
-{
- int *start;
- int wid, val, available;
- unsigned int accum, bits;
- unsigned char *sourcelim, *sourceend;
-
- if (!count) return 0;
-
- start = dest;
- sourcelim = sourceend = source + count;
- available = 32;
- if (sourcelim - 32 < sourcelim)
- {
- sourcelim -= 32;
- }
- else
- {
- sourcelim = source;
- }
- if (source < sourcelim)
- {
- do
- {
- goto lpstart;
- do
- {
- accum = (accum >> wid) | (bits << (32 - wid));
-lpstart: val = *source++;
- wid = table[val].wid;
- bits = table[val].bits;
- }
- while ((available -= wid) >= 0);
-
- wid += available;
- if (wid) accum = (accum >> wid) | (bits << (32 - wid));
- *dest++ = accum;
- wid -= available;
- accum = bits << (32 - wid);
- available += 32;
- }
- while (source < sourcelim);
- }
- while (1)
- {
- if (source < sourceend)
- {
- val = *source++;
- }
- else if (source == sourceend)
- {
- val = 0x100; // terminator
- source++;
- }
- else break; // done
-
- wid = table[val].wid;
- bits = table[val].bits;
-
- if ((available -= wid) < 0)
- {
- wid += available;
- if (wid)
- accum = (accum >> wid) | (bits << (32 - wid));
- *dest++ = accum;
- wid -= available;
- accum = bits << (32 - wid);
- available += 32;
- }
- else
- {
- accum = (accum >> wid) | (bits << (32 - wid));
- }
- }
- *dest++ = accum >> available;
- return (dest - start) * 4;
-}
-
-
-
-
-
-
-/* KJL 17:16:24 17/09/98 - Decompression */
-static int DecodeTable[1<<MAX_DEPTH];
-
-static void MakeHuffmanDecodeTable(int *depth, int depthmax, unsigned char *list);
-static int HuffmanDecode(unsigned char *dest, int *source, int *table, int length);
-
-
-extern char *HuffmanDecompress(HuffmanPackage *inpackage)
-{
- unsigned char *uncompressedData = NULL;
- // Step 1: Make the decoding table
- MakeHuffmanDecodeTable(inpackage->CodelengthCount, MAX_DEPTH, inpackage->ByteAssignment);
-
- // Step 2: Decode data
- uncompressedData = (unsigned char*)AllocateMemory(inpackage->UncompressedDataSize+16);
- if (uncompressedData)
- {
- HuffmanDecode(uncompressedData,(int*)(inpackage+1),DecodeTable,inpackage->UncompressedDataSize);
- }
-
- return (char*)uncompressedData;
-}
-
-static void MakeHuffmanDecodeTable(int *depth, int depthmax, unsigned char *list)
-{
- int thisdepth, depthbit, repcount, repspace, lenbits, temp, count;
- int *outp;
- int o = 0;
- unsigned char *p;
- int *outtbl = DecodeTable;
-
- lenbits = 0;
- repcount = 1 << depthmax;
- repspace = 1;
- thisdepth = 0;
- depthbit = 4;
- p = (unsigned char *)list + 255;
- while (1)
- {
- do
- {
- lenbits++;
- depthbit <<= 1;
- repspace <<= 1;
- repcount >>= 1;
- }
- while (!(thisdepth = *depth++));
- do
- {
- if (p < list)
- {
- temp = 0xff;
- }
- else
- {
- temp = lenbits | (*p-- << 8);
- }
- outp = outtbl + (o >> 2);
- count = repcount;
- do
- {
- *outp = temp;
- outp += repspace;
- }
- while (--count);
- temp = depthbit;
- do
- {
- temp >>= 1;
- if (temp & 3) return;
- o ^= temp;
- }
- while (!(o & temp));
- }
- while (--thisdepth);
- }
-}
-
-
-#define EDXMASK ((((1 << (MAX_DEPTH + 1)) - 1) ^ 1) ^ -1)
-
-static int HuffmanDecode(unsigned char *dest, int *source, int *table, int length)
-{
- unsigned char *start;
- int available, reserve, fill, wid;
- unsigned int bits=0, resbits;
- unsigned char *p;
-
- start = dest;
- available = 0;
- reserve = 0;
- wid = 0;
- do
- {
- available += wid;
- fill = 31 - available;
- bits <<= fill;
- if (fill > reserve)
- {
- fill -= reserve;
- available += reserve;
- if (reserve)
- {
- bits = (bits >> reserve) | (resbits << (32 - reserve));
- }
- resbits = *source++;
- reserve = 32;
- }
- bits = (bits >> fill) | (resbits << (32 - fill));
- resbits >>= fill;
- reserve -= fill;
- available = 31;
- goto lpent;
- do
- {
- bits >>= wid;
- *dest++ = p[1];
-lpent: p = (unsigned char *)(((short *)table)+(bits & ~EDXMASK));
- }
- while ((available -= (wid = *p)) >= 0 && (dest-start)!=length);
-
- }
- while (available > -32 && (dest-start)!=length);
- return dest - start;
-}