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