forked from alexfru/dflat20
-
Notifications
You must be signed in to change notification settings - Fork 2
/
huffc.c
118 lines (99 loc) · 2.65 KB
/
huffc.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
110
111
112
113
114
115
116
117
118
/* ------------------- huffc.c -------------------- */
#include "dflat.h"
#include "htree.h"
extern struct htree *ht;
extern int root;
extern int treect;
static int lastchar = '\n';
static void compress(FILE *, int, int);
static void outbit(FILE *fo, int bit);
static int fgetcx(FILE *fi)
{
int c;
/* ------- bypass comments ------- */
if ((c = fgetc(fi)) == ';' && lastchar == '\n')
do {
while (c != '\n' && c != EOF)
c = fgetc(fi);
} while (c == ';');
lastchar = c;
return c;
}
int main(int argc, char *argv[])
{
FILE *fi, *fo;
int c;
BYTECOUNTER bytectr = 0;
if (argc < 3) {
printf("\nusage: huffc infile outfile");
exit(1);
}
if ((fi = fopen(argv[1], "rb")) == NULL) {
printf("\nCannot open %s", argv[1]);
exit(1);
}
if ((fo = fopen(argv[2], "wb")) == NULL) {
printf("\nCannot open %s", argv[2]);
fclose(fi);
exit(1);
}
ht = calloc(256, sizeof(struct htree));
/* - read the input file and count character frequency - */
while ((c = fgetcx(fi)) != EOF) {
c &= 255;
ht[c].cnt++;
bytectr++;
}
/* ---- build the huffman tree ---- */
buildtree();
/* --- write the byte count to the output file --- */
fwrite(&bytectr, sizeof bytectr, 1, fo);
/* --- write the tree count to the output file --- */
fwrite(&treect, sizeof treect, 1, fo);
/* --- write the root offset to the output file --- */
fwrite(&root, sizeof root, 1, fo);
/* -- write the tree to the output file -- */
for (c = 256; c < treect; c++) {
int lf = ht[c].left;
int rt = ht[c].right;
fwrite(&lf, sizeof lf, 1, fo);
fwrite(&rt, sizeof rt, 1, fo);
}
/* ------ compress the file ------ */
fseek(fi, 0L, 0);
while ((c = fgetcx(fi)) != EOF)
compress(fo, (c & 255), 0);
outbit(fo, -1);
fclose(fi);
fclose(fo);
free(ht);
return 0;
}
/* ---- compress a character value into a bit stream ---- */
static void compress(FILE *fo, int h, int child)
{
if (ht[h].parent != -1)
compress(fo, ht[h].parent, h);
if (child) {
if (child == ht[h].right)
outbit(fo, 0);
else if (child == ht[h].left)
outbit(fo, 1);
}
}
static char out8;
static int ct8;
/* -- collect and write bits to the compressed output file -- */
static void outbit(FILE *fo, int bit)
{
if (ct8 == 8 || bit == -1) {
while (ct8 < 8) {
out8 <<= 1;
ct8++;
}
fputc(out8, fo);
ct8 = 0;
}
out8 = (out8 << 1) | bit;
ct8++;
}