source: branches/port5/ptpan/PT_huffman.cxx

Last change on this file was 5908, checked in by westram, 16 years ago
  • source files with identical names are really a pain when using valgrind
File size: 7.6 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <PT_server.h>
6#include <PT_server_prototypes.h>
7#include "ptpan.h"
8#include "pt_prototypes.h"
9
10/* /// "BuildHuffmanCodeRec()" */
11void BuildHuffmanCodeRec(struct HuffCode *hcbase, 
12                         struct HuffCodeInternal *hc,
13                         ULONG len, ULONG rootidx,
14                         ULONG codelen, ULONG code)
15{
16  ULONG idx;
17  idx = hc[rootidx].hc_Left;
18  if(idx < len) // left is leaf?
19  {
20    hcbase[hc[idx].hc_ID].hc_CodeLength = codelen;
21    hcbase[hc[idx].hc_ID].hc_Codec = code;
22  } else {
23    BuildHuffmanCodeRec(hcbase, hc, len, idx, codelen + 1, code << 1);
24  }
25  code ^= 1;
26  idx = hc[rootidx].hc_Right;
27  if(idx < len) // right is leaf?
28  {
29    hcbase[hc[idx].hc_ID].hc_CodeLength = codelen;
30    hcbase[hc[idx].hc_ID].hc_Codec = code;
31  } else {
32    BuildHuffmanCodeRec(hcbase, hc, len, idx, codelen + 1, code << 1);
33  }
34}
35/* \\\ */
36
37/* /// "BuildHuffmanCode()" */
38BOOL BuildHuffmanCode(struct HuffCode *hcbase, ULONG len, LONG threshold)
39{
40  ULONG cnt;
41  ULONG w;
42  ULONG min0idx, min0val;
43  ULONG min1idx, min1val;
44  struct HuffCodeInternal *hc;
45  ULONG newlen;
46  ULONG xtrlen;
47  ULONG rootidx;
48  ULONG total = 0;
49  BOOL take;
50
51  /* generate huffman tree. I know this is not the fastest
52     routine as it doesn't sort the array prior to building
53     the tree, but as we are speaking of very small trees
54     this should not be a problem */
55
56  /* calculate total weight */
57  newlen = 0;
58  for(cnt = 0; cnt < len; cnt++)
59  {
60    if((w = hcbase[cnt].hc_Weight))
61    {
62      if(((LONG) w) >= threshold) /* check, if we've got a threshold and need to skip it */
63      {
64        newlen++;
65        total += w;
66      }
67    }
68  }
69  if(!newlen)
70  {
71    return(FALSE);
72  }
73  hc = (struct HuffCodeInternal *) calloc(newlen << 1, sizeof(struct HuffCodeInternal));
74  if(!hc)
75  {
76    printf("ARGHGHH! No temporary memory for huffman tree!\n");
77    return(FALSE);
78  }
79  rootidx = xtrlen = 0;
80  for(cnt = 0; cnt < len; cnt++)
81  {
82    if((w = hcbase[cnt].hc_Weight))
83    {
84      hc[xtrlen].hc_Weight = w;
85      take = TRUE;
86      if(threshold)
87      {
88        if(threshold < 0) /* automatic threshold calculation */
89        {
90        if(w*3 <= (total / newlen)) /* make less popular codes uniformly */
91        {
92        hc[xtrlen].hc_Weight = 1; /* reduce weight, but keep it */
93        }
94        }
95        else if(w < (ULONG) threshold) /* hard threshold -- don't generate code for this weight */
96        {
97          take = FALSE;
98        }
99      }
100      if(take)
101      {
102        hc[xtrlen++].hc_ID = cnt;
103      }
104    }
105  }
106  do
107  {
108    /* now choose the two items with the smallest weight != 0 */
109    min0idx = min0val = 0xffffffff;
110    min1idx = min1val = 0xffffffff;
111    for(cnt = 0; cnt < xtrlen; cnt++)
112    {
113      w = hc[cnt].hc_Weight;
114      if(w)
115      {
116        if(w < min0val)
117        {
118          min1val = min0val;
119          min1idx = min0idx;
120          min0val = w;
121          min0idx = cnt;
122        } 
123        else if(w < min1val)
124        {
125          min1val = w;
126          min1idx = cnt;
127        }
128      }
129    }
130    if(min1idx == 0xffffffff)
131    {
132      break;
133    }
134    /* merge these nodes */
135    hc[xtrlen].hc_Weight = min0val + min1val;
136    hc[xtrlen].hc_Left = min0idx;
137    hc[xtrlen].hc_Right = min1idx;
138    hc[min0idx].hc_Weight = 0;
139    hc[min1idx].hc_Weight = 0;
140    rootidx = xtrlen++;
141  } while(TRUE);
142
143  //printf("Codespace: %ld, codes generated: %ld\n", len, newlen);
144  /* now generate codes */
145  BuildHuffmanCodeRec(hcbase, hc, newlen, rootidx, 1, 0);
146
147  /* generate average code length for debugging */
148#if 0
149  {
150    float clen = 0;
151    for(cnt = 0; cnt < len; cnt++)
152    {
153      clen += hcbase[cnt].hc_Weight * hcbase[cnt].hc_CodeLength;
154    }
155    printf("Average code length: %f\n", clen / ((float) total));
156  }
157#endif
158  free(hc);
159  return(TRUE);
160}
161/* \\\ */
162
163/* /// "WriteHuffmanTree()" */
164void WriteHuffmanTree(struct HuffCode *hc, ULONG size, FILE *fh)
165{
166  ULONG cnt;
167
168  fwrite(&size, sizeof(size), 1, fh);
169  for(cnt = 0; cnt < size; cnt++)
170  {
171    if(hc[cnt].hc_CodeLength)
172    {
173      fwrite(&cnt, sizeof(cnt), 1, fh);
174      fwrite(&hc[cnt].hc_CodeLength, sizeof(hc[cnt].hc_CodeLength), 1, fh);
175      fwrite(&hc[cnt].hc_Codec, sizeof(hc[cnt].hc_Codec), 1, fh);
176    }
177  }
178  cnt = ~0UL;
179  fwrite(&cnt, sizeof(cnt), 1, fh);
180}
181/* \\\ */
182
183/* /// "ReadHuffmanTree()" */
184struct HuffTree * ReadHuffmanTree(FILE *fh)
185{
186  struct HuffTree *ht;
187  struct HuffTree *root;
188  ULONG maxid;
189  ULONG cnt;
190  UWORD codelen;
191  ULONG codec;
192  UWORD depth;
193  UWORD leafbit;
194
195  root = (struct HuffTree *) calloc(sizeof(struct HuffTree), 1);
196  if(!root)
197  {
198    return(NULL); /* out of memory */
199  }
200  /* read length first (not used) */
201  fread(&maxid, sizeof(maxid), 1, fh);
202  do
203  {
204    fread(&cnt, sizeof(cnt), 1, fh);
205    if(cnt == ~0UL)
206    {
207      break;
208    }
209
210    fread(&codelen, sizeof(codelen), 1, fh);
211    fread(&codec, sizeof(codec), 1, fh);
212
213    /* build leaf from the root going down */
214    ht = root;
215    depth = 0;
216    while(depth++ < codelen)
217    {
218      leafbit = (codec >> (codelen - depth)) & 1;
219      if(!ht->ht_Child[leafbit])
220      {
221        if(!(ht->ht_Child[leafbit] = (struct HuffTree *) calloc(sizeof(struct HuffTree), 1)))
222        {
223        return(NULL); /* out of memory */
224        }
225      }
226      ht = ht->ht_Child[leafbit];
227    }
228    /* got to the leaf */
229    ht->ht_ID = cnt;
230    /* these are not really needed, but codelength is used to check if this is a leaf */
231    ht->ht_Codec = codec;
232    ht->ht_CodeLength = codelen;
233    if(ht->ht_Child[0] || ht->ht_Child[1]) /* debugging purposes */
234    {
235      printf("Huffman tree does not comply to the fano condition (%ld: %08lx, %d)!\n", 
236         cnt, codec, codelen);
237    }
238  } while(TRUE);
239  return(root);
240}
241/* \\\ */
242
243/* /// "BuildHuffmanTreeFromTable()" */
244struct HuffTree * BuildHuffmanTreeFromTable(struct HuffCode *hc, ULONG maxid)
245{
246  struct HuffTree *ht;
247  struct HuffTree *root;
248  ULONG cnt;
249  UWORD codelen;
250  ULONG codec;
251  UWORD depth;
252  UWORD leafbit;
253
254  root = (struct HuffTree *) calloc(sizeof(struct HuffTree), 1);
255  if(!root)
256  {
257    return(NULL); /* out of memory */
258  }
259
260  for(cnt = 0; cnt < maxid; cnt++)
261  {
262    if((codelen = hc[cnt].hc_CodeLength))
263    {
264      codec = hc[cnt].hc_Codec;
265     
266      /* build leaf from the root going down */
267      ht = root;
268      depth = 0;
269      while(depth++ < codelen)
270      {
271        leafbit = (codec >> (codelen - depth)) & 1;
272        if(!ht->ht_Child[leafbit])
273        {
274        if(!(ht->ht_Child[leafbit] = (struct HuffTree *) calloc(sizeof(struct HuffTree), 1)))
275        {
276        return(NULL); /* out of memory */
277        }
278        }
279        ht = ht->ht_Child[leafbit];
280      }
281      /* got to the leaf */
282      ht->ht_ID = cnt;
283      /* these are not really needed, but codelength is used to check if this is a leaf */
284      ht->ht_Codec = codec;
285      ht->ht_CodeLength = codelen;
286      if(ht->ht_Child[0] || ht->ht_Child[1]) /* debugging purposes */
287      {
288        printf("Huffman tree does not comply to the fano condition (%ld: %08lx, %d)!\n", 
289        cnt, codec, codelen);
290      }
291    }
292  }
293  return(root);
294}
295/* \\\ */
296
297/* /// "FreeHuffmanTree()" */
298void FreeHuffmanTree(struct HuffTree *root)
299{
300  if(!root)
301  {
302    return;
303  }
304  FreeHuffmanTree(root->ht_Child[0]);
305  FreeHuffmanTree(root->ht_Child[1]);
306  free(root);
307}
308/* \\\ */
309
310/* /// "FindHuffTreeID()" */
311struct HuffTree * FindHuffTreeID(struct HuffTree *ht, UBYTE *adr, ULONG bitpos)
312{
313  adr += bitpos >> 3;
314  bitpos &= 7;
315  while(!ht->ht_CodeLength)
316  {
317    ht = ht->ht_Child[(*adr >> (7 - bitpos)) & 1];
318    if(++bitpos > 7)
319    {
320      adr++;
321      bitpos = 0;
322    }   
323  }
324  return(ht);
325}
326/* \\\ */
Note: See TracBrowser for help on using the repository browser.