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