-
Notifications
You must be signed in to change notification settings - Fork 8
/
decompress.c
109 lines (90 loc) · 1.78 KB
/
decompress.c
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
#include <stdio.h>
#include <assert.h>
const int ROOT = (254*2);
const int LUT_TAG = 0x100;
int main(int argc, char *argv[])
{
FILE *fp;
int src, dst, i;
char signature[4];
long unpacked_size;
int bit;
char out_filename[64];
char *suffix;
unsigned short leaf;
unsigned short lut[255*2];
int cdata_length;
unsigned char cdata[64000];
unsigned char value;
unsigned char data[64000];
if (argc != 2)
{
printf("Syntax: %s <HUFF file>", argv[0]);
return 1;
}
fp = fopen(argv[1], "rb");
/* must be HUFF */
fread(signature, 4, 1, fp);
if (strncmp(signature, "HUFF", 4) != 0)
{
printf("Tried to expand a file that isn't HUFF!\n");
return 1;
}
/* number of bytes when unpacked */
fread(&unpacked_size, 4, 1, fp);
/* read the huffman lookup tree */
fread(&lut, 255*2*2, 1, fp);
assert(ftell(fp) == 0x404);
cdata_length = fread(cdata, 1, sizeof(cdata), fp);
fclose(fp);
memset(data, 0xcc, sizeof(data));
printf("packed size %d\n", cdata_length);
printf("unpacked size %d\n", unpacked_size);
src = 0;
dst = 0;
leaf = ROOT;
bit = 1;
value = cdata[src++];
while (dst < unpacked_size)
{
unsigned short dx;
if ((value & bit) == 0)
{
/* left */
assert(leaf <= 255*2);
dx = lut[leaf];
}
else
{
/* right */
assert((leaf+1) <= 255*2);
dx = lut[leaf + 1];
}
bit = bit << 1;
if (bit == 0x100)
{
/* overflow, read another byte */
bit = 1;
value = cdata[src++];
}
if (dx >= LUT_TAG)
{
dx = dx - LUT_TAG;
leaf = dx * 2;
}
else
{
/* decompressed a byte */
data[dst++] = (dx & 0xff);
leaf = ROOT;
}
}
assert(dst == unpacked_size);
strcpy(out_filename, argv[1]);
suffix = strchr(out_filename, '.');
*suffix = '\0';
fp = fopen(out_filename, "wb");
fwrite(data, 1, dst, fp);
fclose(fp);
return 0;
}