File: readhuff.c

package info (click to toggle)
nomarch 1.4-4
  • links: PTS
  • area: main
  • in suites: bullseye, sid
  • size: 136 kB
  • sloc: ansic: 912; makefile: 70; sh: 23
file content (150 lines) | stat: -rw-r--r-- 3,077 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/* nomarch 1.0 - extract old `.arc' archives.
 * Copyright (C) 2001 Russell Marks. See main.c for license details.
 *
 * readhuff.c - read RLE+Huffman-compressed files (the CP/M `SQ' scheme).
 */

/* I was originally going to adapt some old GPL'd Huffman code,
 * but it turns out the format pretty much forces an array-based
 * implementation. Not that I mind that :-), it just makes it
 * a bit unusual. So this is from scratch (though it wasn't too hard).
 */

#include <stdio.h>
#include <stdlib.h>
#include "readrle.h"

#include "readhuff.h"


struct huff_node_tag
  {
  /* data is stored as a negative `pointer' */
  int kids[2];
  };

#define READ_WORD(x) (x)=rawinput(),(x)|=(rawinput()<<8)
#define VALUE_CONV(x) ((x)^0xffff)

#define HUFF_EOF	256


static int bitbox,bitsleft;

static unsigned char *data_in_point,*data_in_max;
static unsigned char *data_out_point,*data_out_max;


static int rawinput(void)
{
if(data_in_point<data_in_max)
  return(*data_in_point++);
return(-1);
}

static void rawoutput(int byte)
{
if(data_out_point<data_out_max)
  *data_out_point++=byte;
}


static void bit_init(void)
{
bitbox=0; bitsleft=0;
}

static int bit_input(void)
{
if(bitsleft==0)
  {
  bitbox=rawinput();
  if(bitbox==-1) return(-1);
  bitsleft=8;
  }

bitsleft--;
return((bitbox&(1<<(7-bitsleft)))?1:0);
}


unsigned char *convert_huff(unsigned char *data_in,
                            unsigned long in_len,
                            unsigned long orig_len)
{
unsigned char *data_out;
struct huff_node_tag *nodearr;
int nodes,f,b;

if((data_out=malloc(orig_len))==NULL)
  fprintf(stderr,"nomarch: out of memory!\n"),exit(1);

data_in_point=data_in; data_in_max=data_in+in_len;
data_out_point=data_out; data_out_max=data_out+orig_len;

READ_WORD(nodes);

if(!nodes)
  {
  free(data_out);
  return(NULL);
  }

if((nodearr=malloc(sizeof(struct huff_node_tag)*nodes))==NULL)
  fprintf(stderr,"nomarch: out of memory!\n"),exit(1);

/* apparently the tree can be empty (zero-length file?), so
 * there's a preset entry which is required. In the context of
 * .arc I'm sure this is cruft which we don't actually need,
 * but just in case...
 */
nodearr[0].kids[0]=nodearr[0].kids[1]=VALUE_CONV(HUFF_EOF);

for(f=0;f<nodes;f++)
  {
  READ_WORD(nodearr[f].kids[0]);
  READ_WORD(nodearr[f].kids[1]);
  }

/* after the table, we get the codes to interpret; this is
 * a bitstream, with EOF marked by the code HUFF_EOF.
 */
bit_init();
outputrle(-1,NULL);

do
  {
  f=0;
  while((f&0x8000)==0)
    {
    if(f>=nodes)
      {
      /* must be corrupt */
      free(nodearr);
      free(data_out);
      return(NULL);
      }

    /* it seems we can't rely on getting the EOF code (even though we
     * do >95% of the time!), so check for `real' EOF too.
     * (worth checking in case of corrupt file too, I guess.)
     */
    if((b=bit_input())==-1)
      {
      f=VALUE_CONV(HUFF_EOF);
      break;
      }
    
    f=nodearr[f].kids[b];
    }
  
  f=VALUE_CONV(f);
  if(f!=HUFF_EOF)
    outputrle(f,rawoutput);
  }
while(f!=HUFF_EOF);

free(nodearr);

return(data_out);
}