010ef80f94edc3867b6537b09881049b91cbf142
[compress.git] / compress.c
1 /* depend: */
2 /* cflags: */
3 /* linker: */
4
5 #include <assert.h>
6 #include <getopt.h>
7 #include <malloc.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 /* constants */
13
14 #define COMPRESS 1
15 #define DECOMPRESS 2
16
17 #define NB_CHARS 256
18 #define BUFFER_SIZE 4096
19
20 #define DEBUG 4
21 #define INFO 3
22 #define WARNING 2
23 #define ERROR 1
24
25 /* macros */
26
27 #define CEIL(x, y) (((x) + (y) - 1) / (y))
28 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
29 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
30 #define VERBOSE(level, statement...) do { if (level <= verbose) { statement; } } while(0)
31 #define PRINTF(args...) do { fprintf (stdout, args); fflush (stdout); } while (0)
32
33 /* gobal variables */
34
35 char *progname = NULL;
36 int verbose = 2;
37
38 /* help function */
39
40 void usage (int ret)
41 {
42 FILE *fd = ret ? stderr : stdout;
43 fprintf (fd, "usage: %s\n", progname);
44 fprintf (fd, " -h : help message\n");
45 fprintf (fd, " -i <file>: input file\n");
46 fprintf (fd, " -o <file>: output file\n");
47 fprintf (fd, " -v : verbose level (%d)\n", verbose);
48
49 exit (ret);
50 }
51
52 /* create occurence table */
53
54 int *create_table (char *filename)
55 {
56 char buffer[BUFFER_SIZE] = {0};
57 int nbread;
58 int *table = NULL;
59 FILE *fid = NULL;
60
61 VERBOSE (DEBUG, PRINTF ("start creating occurence table\n"));
62
63 /* memory allocation */
64 table = (int *) calloc (NB_CHARS, sizeof (int));
65 if (table == NULL) {
66 VERBOSE (ERROR, printf ("can't allocate memory\n"));
67 return NULL;
68 }
69 VERBOSE (INFO, printf ("memory allocated\n"));
70
71 /* open file */
72 fid = fopen (filename, "rb");
73 if (fid == NULL) {
74 VERBOSE (ERROR, printf ("can't open file '%s'\n", filename));
75 free (table);
76 return NULL;
77 }
78 VERBOSE (INFO, printf ("file '%s' opened\n", filename));
79
80 /* read file */
81 while (!feof (fid)) {
82 nbread = fread (buffer, 1, BUFFER_SIZE, fid);
83 VERBOSE (DEBUG, PRINTF ("nbread: %d\n", nbread));
84 while (nbread--) {
85 table[(int)buffer[nbread]]++;
86 }
87 }
88
89 /* close file */
90 fclose (fid);
91
92 VERBOSE (DEBUG, PRINTF ("end creating occurence table\n"));
93
94 return table;
95 }
96
97 /* print occurence table */
98
99 void print_occ_table (int *table)
100 {
101 int i;
102
103 printf ("Occurence table\n");
104 for (i = 0; i < NB_CHARS; i++) {
105 if (table[i]) {
106 printf ("0x%02x '%c': %d\n", i, ((i < 32) || (i > 127)) ? '.' : i, table[i]);
107 }
108 }
109 }
110
111 /* leaf structure */
112
113 typedef struct _leaf_t
114 {
115 struct _leaf_t *left;
116 struct _leaf_t *right;
117 int occ;
118 char c;
119 } leaf_t;
120
121 /* initialize forest */
122
123 leaf_t **init_forest (int *table)
124 {
125 leaf_t **leafs = NULL;
126 int nb_leafs = 0;
127 int i, l;
128
129 VERBOSE (DEBUG, PRINTF ("start initiliazing forest\n"));
130
131 /* count number of leafs */
132 for (i = 0; i < NB_CHARS; i++) {
133 if (table[i] > 0) {
134 nb_leafs++;
135 }
136 }
137
138 /* allocate memory */
139 leafs = (leaf_t **) calloc (nb_leafs + 1, sizeof (leaf_t *));
140 if (leafs == NULL) {
141 VERBOSE (ERROR, printf ("can't allocate memory\n"));
142 return NULL;
143 }
144
145 /* initialize leafs */
146 for (i = 0, l = 0; i < NB_CHARS; i++) {
147 if (table[i] > 0) {
148 leafs[l] = (leaf_t *) calloc (1, sizeof (leaf_t));
149 if (leafs[l] == NULL) {
150 VERBOSE (ERROR, printf ("can't allocate memory\n"));
151 return NULL;
152 }
153 leafs[l]->occ = table[i];
154 leafs[l]->c = i;
155 l++;
156 }
157 }
158
159 VERBOSE (DEBUG, PRINTF ("end initiliazing forest\n"));
160
161 return leafs;
162 }
163
164 /* create tree */
165
166 leaf_t *create_tree (leaf_t **leafs)
167 {
168 leaf_t *branch = NULL;
169 int nb_leafs = 0;
170 int last = -1;
171 int ante;
172 int i, j;
173
174 VERBOSE (DEBUG, PRINTF ("start creating tree\n"));
175
176 /* count number of leafs */
177 while (leafs[nb_leafs] != NULL) {
178 nb_leafs++;
179 }
180
181 /* create tree */
182 for (j = 0; j < nb_leafs - 1; j++) {
183
184 /* look for leatest occurence */
185 last = -1;
186 for (i = 0; i < nb_leafs; i++) {
187 if (leafs[i] == NULL) {
188 continue;
189 }
190 if ((last == -1) || (leafs[i]->occ < leafs[last]->occ)) {
191 last = i;
192 }
193 }
194
195 /* look for ante leatest occurence */
196 ante = -1;
197 for (i = 0; i < nb_leafs; i++) {
198 if ((i == last) || (leafs[i] == NULL)) {
199 continue;
200 }
201 if ((ante == -1) || (leafs[i]->occ < leafs[ante]->occ)) {
202 ante = i;
203 }
204 }
205
206 /* create branch */
207 if ((last == -1) || (ante == -1)) {
208 VERBOSE (ERROR, printf ("error during tree building\n"));
209 return NULL;
210 }
211 branch = (leaf_t *) calloc (1, sizeof (leaf_t));
212 if (branch == NULL) {
213 VERBOSE (ERROR, printf ("can't allocate memory\n"));
214 return NULL;
215 }
216 branch->left = leafs[last];
217 branch->right = leafs[ante];
218 branch->occ = branch->left->occ + branch->right->occ;
219 leafs[last] = branch;
220 leafs[ante] = NULL;
221 }
222
223 VERBOSE (DEBUG, PRINTF ("end creating tree\n"));
224
225 return (last != -1) ? leafs[last] : NULL;
226 }
227
228 /* free tree */
229
230 void free_tree (leaf_t *root) {
231 if (root) {
232 if (root->left) {
233 free_tree (root->left);
234 }
235 if (root->right) {
236 free_tree (root->right);
237 }
238 free (root);
239 }
240 }
241
242 /* code structure */
243
244 typedef struct {
245 char code[NB_CHARS - 1 + 1];
246 } code_t;
247
248 /* explore tree */
249
250 void explore_tree (code_t *table, leaf_t *root, char *code, int index)
251 {
252 if ((root->left == NULL) && (root->right == NULL)) {
253 strcpy ((char *)(table + (int)(root->c)), code);
254 }
255 else {
256 strcpy (code + index, "1");
257 explore_tree (table, root->left, code, index + 1);
258 strcpy (code + index, "0");
259 explore_tree (table, root->right, code, index + 1);
260 }
261 }
262
263 /* create code table */
264
265 code_t *create_code (leaf_t *root)
266 {
267 code_t *table = NULL;
268 code_t code = {0};
269
270 VERBOSE (DEBUG, PRINTF ("start creating code table\n"));
271
272 /* allocate table */
273 table = (code_t *) calloc (NB_CHARS, sizeof (code_t));
274 if (table == NULL) {
275 VERBOSE (ERROR, printf ("can't allocate memory\n"));
276 return NULL;
277 }
278
279 explore_tree (table, root, (char *)&code, 0);
280
281 VERBOSE (DEBUG, PRINTF ("end creating code table\n"));
282
283 return table;
284 }
285
286 /* print code table */
287
288 void print_code_table (code_t *codes)
289 {
290 char *code;
291 int i;
292
293 printf ("Code table\n");
294 for (i = 0; i < NB_CHARS; i++) {
295 code = (char *)(codes + i);
296 if (strlen (code) == 0) {
297 continue;
298 }
299 printf ("0x%02x '%c': %s\n", i, ((i < 32) || (i > 127)) ? '.' : i, code);
300 }
301 }
302
303 /* encode header and code table */
304
305 char *encode_header_table (code_t *codes, int *occ)
306 {
307 unsigned char buffer[NB_CHARS * (NB_CHARS - 1) / 2 / 8 + NB_CHARS + 6] = {0};
308 char bits[(NB_CHARS - 1) + 8 + 1] = {0};
309 char *code;
310 unsigned char *header = buffer;
311 int i, j, length, mode;
312 int nb = 0;
313 int size = 0;
314
315 VERBOSE (DEBUG, PRINTF ("start encoding header and code table\n"));
316
317 /* mode 1 or 2 */
318 for (i = 0; i < NB_CHARS; i++) {
319 code = (char *)(codes + i);
320 if (strlen (code) > 0) {
321 nb++;
322 size += strlen (code) * occ[i];
323 }
324 }
325 mode = (NB_CHARS < 2 * nb + 1) ? 1 : 2;
326 VERBOSE (DEBUG, PRINTF ("nb chars: %d\n", nb));
327 VERBOSE (DEBUG, PRINTF ("mode: %d\n", mode));
328 VERBOSE (DEBUG, PRINTF ("size: %d\n", size));
329 VERBOSE (DEBUG, PRINTF ("rem: %d\n", size % 256));
330
331 /* header */
332 strcpy ((char *)header, (mode == 1) ? "MZ1 " : "MZ2 ");
333 header += 6;
334
335 /* size */
336 switch (mode) {
337 case 1:
338 for (i = 0; i < NB_CHARS; i++) {
339 code = (char *)(codes + i);
340 *(header++) = (unsigned char) strlen (code);
341 }
342 break;
343 case 2:
344 *(header++) = (unsigned char)(nb - 1);
345 for (i = 0; i < NB_CHARS; i++) {
346 code = (char *)(codes + i);
347 if (strlen (code) > 0) {
348 *(header++) = (unsigned char)i;
349 *(header++) = (unsigned char) strlen (code);
350 }
351 }
352 break;
353 }
354
355 /* bits */
356 for (i = 0; i < NB_CHARS; i++) {
357 code = (char *)(codes + i);
358 if (strlen (code) > 0) {
359 strcat (bits, code);
360 while (strlen (bits) > (8 - 1)) {
361 for (j = 0; j < 8; j++) {
362 *header <<= 1;
363 if (bits[j] == '1') {
364 (*header)++;
365 }
366 }
367 strcpy (bits, bits + 8);
368 header++;
369 }
370 }
371 }
372 if (strlen (bits) > 0) {
373 for (j = 0; j < (int)strlen (bits); j++) {
374 *header <<= 1;
375 if (bits[j] == '1') {
376 (*header)++;
377 }
378 }
379 for (j = (int)strlen (bits); j < 8; j++) {
380 *header <<= 1;
381 }
382 header++;
383 }
384
385 /* length */
386 length = (int)(header - buffer - 6);
387 VERBOSE (DEBUG, PRINTF ("lengh: %d %02x %02x\n", length, length >> 8, length & 0xff));
388 buffer[3] = (unsigned char)(length >> 8);
389 buffer[4] = (unsigned char)(length & 0xff);
390 buffer[5] = (unsigned char)(size % 256);
391
392 /* allocation */
393 header = (unsigned char *) calloc (length + 6, 1);
394 memcpy (header, buffer, length + 6);
395
396 VERBOSE (DEBUG, PRINTF ("end encoding header and code table\n"));
397
398 return (char *)header;
399 }
400
401 /* print header */
402
403 void print_header (char *header)
404 {
405 int length, i;
406
407 length = ((unsigned char)(header[3]) << 8) + (unsigned char)(header[4]);
408 VERBOSE (DEBUG, PRINTF ("lengh: %d\n", length));
409 for (i = 0; i < length + 6; i++) {
410 printf ("%02x", (unsigned char)header[i]);
411 }
412 printf ("\n");
413 }
414
415 /* write crompressed file */
416
417 int write_compress (char *output, char *input, code_t *codes, char *header)
418 {
419 char bufin[BUFFER_SIZE] = {0};
420 char bufout[BUFFER_SIZE] = {0};
421 char bits[(NB_CHARS - 1) + 8 + 1] = {0};
422 FILE *fin, *fout;
423 int length = 0;
424 int i, j, nbread;
425 char *pt;
426
427 VERBOSE (DEBUG, PRINTF ("start writting compressed file\n"));
428
429 /* open input file */
430 fin = fopen (input, "rb");
431 if (fin == NULL) {
432 VERBOSE (ERROR, printf ("can't open file '%s' for reading\n", input));
433 return 1;
434 }
435 VERBOSE (INFO, printf ("file '%s' opened\n", input));
436
437 /* open output file */
438 fout = fopen (output, "wb");
439 if (fin == NULL) {
440 VERBOSE (ERROR, printf ("can't open file '%s' for writing\n", output));
441 return 1;
442 }
443 VERBOSE (INFO, printf ("file '%s' opened\n", output));
444
445 /* write header */
446 length = ((unsigned char)(header[3]) << 8) + (unsigned char)(header[4]);
447 VERBOSE (DEBUG, PRINTF ("lengh: %d\n", length));
448 fwrite (header, 1, length + 6, fout);
449
450 /* write file */
451 pt = bufout;
452 while (!feof (fin)) {
453 nbread = fread (bufin, 1, BUFFER_SIZE, fin);
454 VERBOSE (DEBUG, PRINTF ("nbread: %d\n", nbread));
455 for (i = 0; i < nbread; i++) {
456 strcat (bits, (char *)(codes + bufin[i]));
457 while (strlen (bits) > (8 - 1)) {
458 for (j = 0; j < 8; j++) {
459 *pt <<= 1;
460 if (bits[j] == '1') {
461 (*pt)++;
462 }
463 }
464 strcpy (bits, bits + 8);
465 if (pt - bufout == BUFFER_SIZE - 1) {
466 fwrite (bufout, 1, BUFFER_SIZE, fout);
467 pt = bufout;
468 } else {
469 pt++;
470 }
471 }
472 }
473 }
474 VERBOSE (DEBUG, PRINTF ("lastest bits : %d\n", strlen (bits)));
475 if (strlen (bits) > 0) {
476 for (j = 0; j < (int)strlen (bits); j++) {
477 *pt <<= 1;
478 if (bits[j] == '1') {
479 (*pt)++;
480 }
481 }
482 for (j = (int)strlen (bits); j < 8; j++) {
483 *pt <<= 1;
484 }
485 pt++;
486 }
487 if (pt != bufout) {
488 VERBOSE (DEBUG, PRINTF ("last partial buffer written: %u\n", pt - bufout));
489 fwrite (bufout, 1, pt - bufout, fout);
490 }
491
492 /* closing */
493 fclose (fin);
494 fclose (fout);
495
496 VERBOSE (DEBUG, PRINTF ("end writting compressed file\n"));
497
498 return 0;
499 }
500
501 /* read header */
502
503 code_t *read_header (char *filename) {
504 unsigned char buffer[NB_CHARS * (NB_CHARS - 1) / 2 / 8 + NB_CHARS + 6] = {0};
505 code_t *table = NULL;
506 unsigned char *codes = NULL;
507 unsigned char cur;
508 int lengths[NB_CHARS] = {0};
509 FILE *fid = NULL;
510 int mode = 0;
511 size_t i, j, l, nb, size;
512
513 VERBOSE (DEBUG, PRINTF ("start reading header\n"));
514
515 /* open file */
516 fid = fopen (filename, "rb");
517 if (fid == NULL) {
518 VERBOSE (ERROR, printf ("can't open file '%s'\n", filename));
519 return NULL;
520 }
521 VERBOSE (INFO, printf ("file '%s' opened\n", filename));
522
523 /* read magic number */
524 nb = fread (buffer, 1, 6, fid);
525 VERBOSE (DEBUG, PRINTF ("nb, buffer: %d 0x%02x 0x%02x\n", nb, buffer[0], buffer[1]));
526 if ((nb == 6) && (buffer[0] == 'M') && (buffer[1] == 'Z')) {
527 mode = (buffer[2] == '1') ? 1 : (buffer[2] == '2') ? 2 : 0;
528 size = ((unsigned char)(buffer[3]) << 8) + (unsigned char)(buffer[4]);
529 VERBOSE (DEBUG, PRINTF ("mode, size: %d %d\n", mode, size));
530 if (size > NB_CHARS * (NB_CHARS - 1) / 2 / 8 + NB_CHARS) {
531 mode = 0;
532 } else {
533 nb = fread (buffer, 1, size, fid);
534 VERBOSE (DEBUG, PRINTF ("nb read: %d\n", nb));
535 if (nb != size) {
536 mode = 0;
537 }
538 }
539 }
540 fclose (fid);
541 if (mode == 0) {
542 VERBOSE (ERROR, printf ("incorrect file\n"));
543 return NULL;
544 }
545
546 /* analyse header */
547 codes = (unsigned char *)buffer;
548 switch (mode) {
549 case 1:
550 for (i = 0; i < NB_CHARS; i++) {
551 lengths[i] = *(codes++);
552 }
553 break;
554 case 2:
555 nb = *(codes++) + 1;
556 VERBOSE (DEBUG, PRINTF ("nb codes: %d\n", nb));
557 for (i = 0; i < nb; i++) {
558 j = *(codes++);
559 lengths[j] = *(codes++);
560 }
561 break;
562 }
563 VERBOSE (DEBUG, for (i = 0; i < NB_CHARS; i++) if (lengths[i]) PRINTF ("%d: %d\n", i, lengths[i]));
564
565 /* check lengths */
566 for (i = 0, l = 0; i < NB_CHARS; i++) {
567 l += lengths[i];
568 }
569 if (((mode == 1) && (size - 256 != (l + 7) / 8)) ||
570 ((mode == 2) && (size - 2 * nb - 1 != (l + 7) / 8))) {
571 VERBOSE (ERROR, printf ("incorrect code table length\n"));
572 return NULL;
573 }
574
575 /* allocate table */
576 table = (code_t *) calloc (NB_CHARS, sizeof (code_t));
577 if (table == NULL) {
578 VERBOSE (ERROR, printf ("can't allocate memory\n"));
579 return NULL;
580 }
581
582 /* decode code */
583 cur = *(codes++);
584 l = 8;
585 for (i = 0; i < NB_CHARS; i++) {
586 if (lengths[i] == 0) {
587 continue;
588 }
589 while (lengths[i]--) {
590 strcat ((char *)(table + i), ((cur & 0x80) == 0) ? "0" : "1");
591 l--;
592 cur <<= 1;
593 if (l == 0) {
594 cur = *(codes++);
595 l = 8;
596 }
597 }
598 }
599
600 VERBOSE (DEBUG, PRINTF ("end reading header\n"));
601
602 return table;
603 }
604
605 /* write decompressed file */
606
607 int write_decompress (char *output, char *input, code_t *codes)
608 {
609 char bufin[BUFFER_SIZE] = {0};
610 char bufout[BUFFER_SIZE] = {0};
611 unsigned char buffer[MAX(NB_CHARS * (NB_CHARS - 1) / 2 / 8 + NB_CHARS + 6, BUFFER_SIZE)] = {0};
612 char bits[(NB_CHARS - 1) + 1] = {0};
613 FILE *fin, *fout;
614 int i, j, k, nb, size, rem;
615 int is_found;
616 int l = 0;
617 char *pt;
618
619 VERBOSE (DEBUG, PRINTF ("start writing decompressed file\n"));
620
621 /* open file for reading */
622 fin = fopen (input, "rb");
623 if (fin == NULL) {
624 VERBOSE (ERROR, printf ("can't open file '%s' for reading\n", input));
625 return 1;
626 }
627 VERBOSE (INFO, printf ("file '%s' opened\n", input));
628
629 /* read magic number */
630 nb = fread (buffer, 1, 6, fin);
631 if (nb != 6) {
632 VERBOSE (ERROR, printf ("can't read file\n"));
633 fclose (fin);
634 return 1;
635 }
636 size = ((unsigned char)(buffer[3]) << 8) + (unsigned char)(buffer[4]);
637 VERBOSE (DEBUG, printf ("table size: %d\n", size));
638 rem = buffer[5];
639 VERBOSE (DEBUG, printf ("remainder: %d\n", rem));
640 nb = fread (buffer, 1, size, fin);
641 if (nb != size) {
642 VERBOSE (ERROR, printf ("can't read file\n"));
643 fclose (fin);
644 return 1;
645 }
646
647 /* open file for writing */
648 fout = fopen (output, "wb");
649 if (fout == NULL) {
650 VERBOSE (ERROR, printf ("can't open file '%s' for writing\n", output));
651 return 2;
652 }
653 VERBOSE (INFO, printf ("file '%s' opened\n", output));
654
655 /* write file */
656 pt = bufout;
657 while (!feof (fin)) {
658 nb = fread (bufin, 1, BUFFER_SIZE, fin);
659 VERBOSE (DEBUG, PRINTF ("nbread: %d\n", nb));
660 for (i = 0; i < nb; i++) {
661 for (j = 0; j < 8; j++) {
662 strcat (bits, ((bufin[i] & 0x80) == 0) ? "0" : "1");
663 bufin[i] <<= 1;
664 l++;
665 VERBOSE (DEBUG, PRINTF ("bits: %d - %s\n", strlen (bits), bits));
666
667 /* look for correct code */
668 is_found = 0;
669 for (k = 0; (k < NB_CHARS) && (!is_found); k++) {
670 if (strcmp ((char *)(codes + k), bits) == 0) {
671 is_found = 1;
672 VERBOSE (DEBUG, PRINTF ("found: %d\n", k));
673 *pt= k;
674 bits[0] = 0;
675 if (pt - bufout == BUFFER_SIZE - 1) {
676 VERBOSE (DEBUG, PRINTF ("nb buffer out: %u\n", (pt - bufout)));
677 fwrite (bufout, 1, BUFFER_SIZE, fout);
678 pt = bufout;
679 } else {
680 pt++;
681 }
682 }
683 }
684 if ((i == nb - 1) && (l % 256 == rem) && (feof (fin))) {
685 VERBOSE (DEBUG, PRINTF ("break\n"));
686 break;
687 }
688 }
689 }
690 }
691 if (pt != bufout) {
692 VERBOSE (DEBUG, PRINTF ("nb buffer out: %u\n", (pt - bufout)));
693 fwrite (bufout, 1, pt - bufout, fout);
694 }
695
696 /* close files */
697 fclose (fin);
698 fclose (fout);
699
700 VERBOSE (DEBUG, PRINTF ("end writing decompressed file\n"));
701
702 return 0;
703 }
704
705 /* main function */
706
707 int main (int argc, char *argv[])
708 {
709 char *input = NULL;
710 char *output = NULL;
711 int *table = NULL;
712 leaf_t **leafs = NULL;
713 leaf_t *root = NULL;
714 code_t *codes = NULL;
715 char *header = NULL;
716 int mode = COMPRESS;
717 int rc = 1;
718
719 progname = argv[0];
720
721 int c;
722 VERBOSE (DEBUG, PRINTF ("start processing arguments\n"));
723 while ((c = getopt(argc, argv, "cdhi:o:v:")) != EOF) {
724 VERBOSE (DEBUG, PRINTF ("option: %c\n", c));
725 switch (c) {
726 case 'c':
727 mode = COMPRESS;
728 break;
729 case 'd':
730 mode = DECOMPRESS;
731 break;
732 case 'i':
733 input = optarg;
734 VERBOSE (DEBUG, PRINTF ("input: %s\n", input));
735 break;
736 case 'o':
737 output = optarg;
738 VERBOSE (DEBUG, PRINTF ("output: %s\n", output));
739 break;
740 case 'v':
741 verbose = atoi (optarg);
742 VERBOSE (INFO, printf ("verbose: %d\n", verbose));
743 break;
744 case 'h':
745 default:
746 usage (c != 'h');
747 }
748 }
749 if (argc - optind != 0) {
750 fprintf (stderr, "%s: invalid option -- %s\n", progname, argv[optind]);
751 usage (1);
752 }
753 VERBOSE (DEBUG, PRINTF ("end processing arguments\n"));
754
755 switch (mode) {
756 case COMPRESS:
757 table = create_table (input);
758 if (table == NULL) break;
759 VERBOSE (INFO, print_occ_table (table));
760
761 leafs = init_forest (table);
762 if (leafs == NULL) break;
763 root = create_tree (leafs);
764 if (root == NULL) break;
765 codes = create_code (root);
766 if (codes == NULL) break;
767 VERBOSE (INFO, print_code_table (codes));
768 header = encode_header_table (codes, table);
769 if (header == NULL) break;
770 VERBOSE (INFO, print_header (header));
771 rc = write_compress (output, input, codes, header);
772 break;
773 case DECOMPRESS:
774 codes = read_header (input);
775 if (codes == NULL) break;
776 VERBOSE (INFO, print_code_table (codes));
777 rc = write_decompress (output, input, codes);
778 break;
779 }
780
781 /* clean everything */
782 if (header) free (header);
783 if (codes) free (codes);
784 if (root) free_tree (root);
785 if (leafs) free (leafs);
786 if (table) free (table);
787
788 return rc;
789 }
790
791 // test: compress.exe -h
792 // test: compress.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
793 // test: compress.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }'
794 // test: compress.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
795 // test: compress.exe -c -i compress.c -o compress.mz
796 // test: ls -sS1 compress.c compress.mz | tail -1 | grep compress.mz
797 // test: compress.exe -d -i compress.mz -o tmp.c
798 // test: cmp compress.c tmp.c
799 // test: rm compress.mz tmp.c
800
801 // vim: ts=4 sw=4 et