]> git.llucax.com Git - z.facultad/75.06/jacu.git/blob - src/lzhuff/lzhuf.c
Minioptimizacion para que la tabla de orden-(-1) se ajuste mejor a archivos de texto...
[z.facultad/75.06/jacu.git] / src / lzhuff / lzhuf.c
1 /**************************************************************
2     lzhuf.c
3     written by Haruyasu Yoshizaki 1988/11/20
4     some minor changes 1989/04/06
5     comments translated by Haruhiko Okumura 1989/04/07
6     getbit and getbyte modified 1990/03/23 by Paul Edwards
7       so that they would work on machines where integers are
8       not necessarily 16 bits (although ANSI guarantees a
9       minimum of 16).  This program has compiled and run with
10       no errors under Turbo C 2.0, Power C, and SAS/C 4.5
11       (running on an IBM mainframe under MVS/XA 2.2).  Could
12       people please use YYYY/MM/DD date format so that everyone
13       in the world can know what format the date is in?
14     external storage of filesize changed 1990/04/18 by Paul Edwards to
15       Intel's "little endian" rather than a machine-dependant style so
16       that files produced on one machine with lzhuf can be decoded on
17       any other.  "little endian" style was chosen since lzhuf
18       originated on PC's, and therefore they should dictate the
19       standard.
20     initialization of something predicting spaces changed 1990/04/22 by
21       Paul Edwards so that when the compressed file is taken somewhere
22       else, it will decode properly, without changing ascii spaces to
23       ebcdic spaces.  This was done by changing the ' ' (space literal)
24       to 0x20 (which is the far most likely character to occur, if you
25       don't know what environment it will be running on.
26 **************************************************************/
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31
32 FILE  *infile, *outfile;
33 static unsigned long int  textsize = 0, codesize = 0, printcount = 0;
34
35 char wterr[] = "Can't write.";
36
37 static void Error(char *message)
38 {
39     printf("\n%s\n", message);
40     exit(EXIT_FAILURE);
41 }
42
43 /********** LZSS compression **********/
44
45 #define N       4096    /* buffer size */
46 #define F       60  /* lookahead buffer size */
47 #define THRESHOLD   2
48 #define NIL     N   /* leaf of tree */
49
50 unsigned char
51         text_buf[N + F - 1];
52 static int     match_position, match_length,
53         lson[N + 1], rson[N + 257], dad[N + 1];
54
55 static void InitTree(void)  /* initialize trees */
56 {
57     int  i;
58
59     for (i = N + 1; i <= N + 256; i++)
60         rson[i] = NIL;        /* root */
61     for (i = 0; i < N; i++)
62         dad[i] = NIL;         /* node */
63 }
64
65 static void InsertNode(int r)  /* insert to tree */
66 {
67     int  i, p, cmp;
68     unsigned char  *key;
69     unsigned c;
70
71     cmp = 1;
72     key = &text_buf[r];
73     p = N + 1 + key[0];
74     rson[r] = lson[r] = NIL;
75     match_length = 0;
76     for ( ; ; ) {
77         if (cmp >= 0) {
78             if (rson[p] != NIL)
79                 p = rson[p];
80             else {
81                 rson[p] = r;
82                 dad[r] = p;
83                 return;
84             }
85         } else {
86             if (lson[p] != NIL)
87                 p = lson[p];
88             else {
89                 lson[p] = r;
90                 dad[r] = p;
91                 return;
92             }
93         }
94         for (i = 1; i < F; i++)
95             if ((cmp = key[i] - text_buf[p + i]) != 0)
96                 break;
97         if (i > THRESHOLD) {
98             if (i > match_length) {
99                 match_position = ((r - p) & (N - 1)) - 1;
100                 if ((match_length = i) >= F)
101                     break;
102             }
103             if (i == match_length) {
104                 if ((c = ((r - p) & (N-1)) - 1) < (unsigned)match_position) {
105                     match_position = c;
106                 }
107             }
108         }
109     }
110     dad[r] = dad[p];
111     lson[r] = lson[p];
112     rson[r] = rson[p];
113     dad[lson[p]] = r;
114     dad[rson[p]] = r;
115     if (rson[dad[p]] == p)
116         rson[dad[p]] = r;
117     else
118         lson[dad[p]] = r;
119     dad[p] = NIL; /* remove p */
120 }
121
122 static void DeleteNode(int p)  /* remove from tree */
123 {
124     int  q;
125
126     if (dad[p] == NIL)
127         return;         /* not registered */
128     if (rson[p] == NIL)
129         q = lson[p];
130     else
131     if (lson[p] == NIL)
132         q = rson[p];
133     else {
134         q = lson[p];
135         if (rson[q] != NIL) {
136             do {
137                 q = rson[q];
138             } while (rson[q] != NIL);
139             rson[dad[q]] = lson[q];
140             dad[lson[q]] = dad[q];
141             lson[q] = lson[p];
142             dad[lson[p]] = q;
143         }
144         rson[q] = rson[p];
145         dad[rson[p]] = q;
146     }
147     dad[q] = dad[p];
148     if (rson[dad[p]] == p)
149         rson[dad[p]] = q;
150     else
151         lson[dad[p]] = q;
152     dad[p] = NIL;
153 }
154
155 /* Huffman coding */
156
157 #define N_CHAR      (256 - THRESHOLD + F)
158                 /* kinds of characters (character code = 0..N_CHAR-1) */
159 #define T       (N_CHAR * 2 - 1)    /* size of table */
160 #define R       (T - 1)         /* position of root */
161 #define MAX_FREQ    0x8000      /* updates tree when the */
162 typedef unsigned char uchar;
163
164
165 /* table for encoding and decoding the upper 6 bits of position */
166
167 /* for encoding */
168 uchar p_len[64] = {
169     0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
170     0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
171     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
172     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
173     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
174     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
175     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
176     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
177 };
178
179 uchar p_code[64] = {
180     0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
181     0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
182     0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
183     0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
184     0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
185     0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
186     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
187     0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
188 };
189
190 /* for decoding */
191 uchar d_code[256] = {
192     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
197     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
198     0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
199     0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
200     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
201     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
202     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
203     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
204     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
205     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
206     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
207     0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
208     0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
209     0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
210     0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
211     0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
212     0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
213     0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
214     0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
215     0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
216     0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
217     0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
218     0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
219     0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
220     0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
221     0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
222     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
223     0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
224 };
225
226 uchar d_len[256] = {
227     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
228     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
229     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
230     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
231     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
232     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
233     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
234     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
235     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
236     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
237     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
238     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
239     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
240     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
241     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
242     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
243     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
244     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
245     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
246     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
247     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
248     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
249     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
250     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
251     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
252     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
253     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
254     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
255     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
256     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
257     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
258     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
259 };
260
261 unsigned freq[T + 1]; /* frequency table */
262
263 int prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */
264             /* elements [T..T + N_CHAR - 1] which are used to get */
265             /* the positions of leaves corresponding to the codes. */
266
267 int son[T];   /* pointers to child nodes (son[], son[] + 1) */
268
269 unsigned getbuf = 0;
270 uchar getlen = 0;
271
272 static int GetBit(void)    /* get one bit */
273 {
274     unsigned i;
275
276     while (getlen <= 8) {
277         if ((int)(i = getc(infile)) < 0) i = 0;
278         getbuf |= i << (8 - getlen);
279         getlen += 8;
280     }
281     i = getbuf;
282     getbuf <<= 1;
283     getlen--;
284     return (int)((i & 0x8000) >> 15);
285 }
286
287 static int GetByte(void)   /* get one byte */
288 {
289     unsigned i;
290
291     while (getlen <= 8) {
292         if ((int)(i = getc(infile)) < 0) i = 0;
293         getbuf |= i << (8 - getlen);
294         getlen += 8;
295     }
296     i = getbuf;
297     getbuf <<= 8;
298     getlen -= 8;
299     return (int)((i & 0xff00) >> 8);
300 }
301
302 unsigned putbuf = 0;
303 uchar putlen = 0;
304
305 static void Putcode(int l, unsigned c)     /* output c bits of code */
306 {
307     putbuf |= c >> putlen;
308     if ((putlen += l) >= 8) {
309         if (putc(putbuf >> 8, outfile) == EOF) {
310             Error(wterr);
311         }
312         if ((putlen -= 8) >= 8) {
313             if (putc(putbuf, outfile) == EOF) {
314                 Error(wterr);
315             }
316             codesize += 2;
317             putlen -= 8;
318             putbuf = c << (l - putlen);
319         } else {
320             putbuf <<= 8;
321             codesize++;
322         }
323     }
324 }
325
326
327 /* initialization of tree */
328
329 static void StartHuff(void)
330 {
331     int i, j;
332
333     for (i = 0; i < N_CHAR; i++) {
334         freq[i] = 1;
335         son[i] = i + T;
336         prnt[i + T] = i;
337     }
338     i = 0; j = N_CHAR;
339     while (j <= R) {
340         freq[j] = freq[i] + freq[i + 1];
341         son[j] = i;
342         prnt[i] = prnt[i + 1] = j;
343         i += 2; j++;
344     }
345     freq[T] = 0xffff;
346     prnt[R] = 0;
347 }
348
349
350 /* reconstruction of tree */
351
352 static void reconst(void)
353 {
354     int i, j, k;
355     unsigned f, l;
356
357     /* collect leaf nodes in the first half of the table */
358     /* and replace the freq by (freq + 1) / 2. */
359     j = 0;
360     for (i = 0; i < T; i++) {
361         if (son[i] >= T) {
362             freq[j] = (freq[i] + 1) / 2;
363             son[j] = son[i];
364             j++;
365         }
366     }
367     /* begin constructing tree by connecting sons */
368     for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
369         k = i + 1;
370         f = freq[j] = freq[i] + freq[k];
371         for (k = j - 1; f < freq[k]; k--);
372         k++;
373         l = (j - k) * 2;
374         memmove(&freq[k + 1], &freq[k], l);
375         freq[k] = f;
376         memmove(&son[k + 1], &son[k], l);
377         son[k] = i;
378     }
379     /* connect prnt */
380     for (i = 0; i < T; i++) {
381         if ((k = son[i]) >= T) {
382             prnt[k] = i;
383         } else {
384             prnt[k] = prnt[k + 1] = i;
385         }
386     }
387 }
388
389
390 /* increment frequency of given code by one, and update tree */
391
392 static void update(int c)
393 {
394     int i, j, k, l;
395
396     if (freq[R] == MAX_FREQ) {
397         reconst();
398     }
399     c = prnt[c + T];
400     do {
401         k = ++freq[c];
402
403         /* if the order is disturbed, exchange nodes */
404         if ((unsigned)k > freq[l = c + 1]) {
405             while ((unsigned)k > freq[++l]);
406             l--;
407             freq[c] = freq[l];
408             freq[l] = k;
409
410             i = son[c];
411             prnt[i] = l;
412             if (i < T) prnt[i + 1] = l;
413
414             j = son[l];
415             son[l] = i;
416
417             prnt[j] = c;
418             if (j < T) prnt[j + 1] = c;
419             son[c] = j;
420
421             c = l;
422         }
423     } while ((c = prnt[c]) != 0); /* repeat up to root */
424 }
425
426 unsigned code, len;
427
428 static void EncodeChar(unsigned c)
429 {
430     unsigned i;
431     int j, k;
432
433     i = 0;
434     j = 0;
435     k = prnt[c + T];
436
437     /* travel from leaf to root */
438     do {
439         i >>= 1;
440
441         /* if node's address is odd-numbered, choose bigger brother node */
442         if (k & 1) i += 0x8000;
443
444         j++;
445     } while ((k = prnt[k]) != R);
446     Putcode(j, i);
447     code = i;
448     len = j;
449     update(c);
450 }
451
452 static void EncodePosition(unsigned c)
453 {
454     unsigned i;
455
456     /* output upper 6 bits by table lookup */
457     i = c >> 6;
458     Putcode(p_len[i], (unsigned)p_code[i] << 8);
459
460     /* output lower 6 bits verbatim */
461     Putcode(6, (c & 0x3f) << 10);
462 }
463
464 static void EncodeEnd(void)
465 {
466     if (putlen) {
467         if (putc(putbuf >> 8, outfile) == EOF) {
468             Error(wterr);
469         }
470         codesize++;
471     }
472 }
473
474 static int DecodeChar(void)
475 {
476     unsigned c;
477
478     c = son[R];
479
480     /* travel from root to leaf, */
481     /* choosing the smaller child node (son[]) if the read bit is 0, */
482     /* the bigger (son[]+1} if 1 */
483     while (c < T) {
484         c += GetBit();
485         c = son[c];
486     }
487     c -= T;
488     update(c);
489     return (int)c;
490 }
491
492 static int DecodePosition(void)
493 {
494     unsigned i, j, c;
495
496     /* recover upper 6 bits from table */
497     i = GetByte();
498     c = (unsigned)d_code[i] << 6;
499     j = d_len[i];
500
501     /* read lower 6 bits verbatim */
502     j -= 2;
503     while (j--) {
504         i = (i << 1) + GetBit();
505     }
506     return (int)(c | (i & 0x3f));
507 }
508
509 /* compression */
510
511 static void Encode(void)  /* compression */
512 {
513     int  i, c, len, r, s, last_match_length;
514
515     fseek(infile, 0L, 2);
516     textsize = ftell(infile);
517     fputc((int)((textsize & 0xff)),outfile);
518     fputc((int)((textsize & 0xff00) >> 8),outfile);
519     fputc((int)((textsize & 0xff0000L) >> 16),outfile);
520     fputc((int)((textsize & 0xff000000L) >> 24),outfile);
521     if (ferror(outfile))
522         Error(wterr);   /* output size of text */
523     if (textsize == 0)
524         return;
525     rewind(infile);
526     textsize = 0;           /* rewind and re-read */
527     StartHuff();
528     InitTree();
529     s = 0;
530     r = N - F;
531     for (i = s; i < r; i++)
532         text_buf[i] = 0x20;
533     for (len = 0; len < F && (c = getc(infile)) != EOF; len++)
534         text_buf[r + len] = (unsigned char)c;
535     textsize = len;
536     for (i = 1; i <= F; i++)
537         InsertNode(r - i);
538     InsertNode(r);
539     do {
540         if (match_length > len)
541             match_length = len;
542         if (match_length <= THRESHOLD) {
543             match_length = 1;
544             EncodeChar(text_buf[r]);
545         } else {
546             EncodeChar(255 - THRESHOLD + match_length);
547             EncodePosition(match_position);
548         }
549         last_match_length = match_length;
550         for (i = 0; i < last_match_length &&
551                 (c = getc(infile)) != EOF; i++) {
552             DeleteNode(s);
553             text_buf[s] = (unsigned char)c;
554             if (s < F - 1)
555                 text_buf[s + N] = (unsigned char)c;
556             s = (s + 1) & (N - 1);
557             r = (r + 1) & (N - 1);
558             InsertNode(r);
559         }
560         if ((textsize += i) > printcount) {
561             printf("%12ld\r", textsize);
562             printcount += 1024;
563         }
564         while (i++ < last_match_length) {
565             DeleteNode(s);
566             s = (s + 1) & (N - 1);
567             r = (r + 1) & (N - 1);
568             if (--len) InsertNode(r);
569         }
570     } while (len > 0);
571     EncodeEnd();
572     printf("In : %ld bytes\n", textsize);
573     printf("Out: %ld bytes\n", codesize);
574     printf("Out/In: %.3f\n", 1.0 * codesize / textsize);
575 }
576
577 static void Decode(void)  /* recover */
578 {
579     int  i, j, k, r, c;
580     unsigned long int  count;
581
582     textsize = (fgetc(infile));
583     textsize |= (fgetc(infile) << 8);
584     textsize |= (fgetc(infile) << 16);
585     textsize |= (fgetc(infile) << 24);
586     if (ferror(infile))
587         Error("Can't read");  /* read size of text */
588     if (textsize == 0)
589         return;
590     StartHuff();
591     for (i = 0; i < N - F; i++)
592         text_buf[i] = 0x20;
593     r = N - F;
594     for (count = 0; count < textsize; ) {
595         c = DecodeChar();
596         if (c < 256) {
597             if (putc(c, outfile) == EOF) {
598                 Error(wterr);
599             }
600             text_buf[r++] = (unsigned char)c;
601             r &= (N - 1);
602             count++;
603         } else {
604             i = (r - DecodePosition() - 1) & (N - 1);
605             j = c - 255 + THRESHOLD;
606             for (k = 0; k < j; k++) {
607                 c = text_buf[(i + k) & (N - 1)];
608                 if (putc(c, outfile) == EOF) {
609                     Error(wterr);
610                 }
611                 text_buf[r++] = (unsigned char)c;
612                 r &= (N - 1);
613                 count++;
614             }
615         }
616         if (count > printcount) {
617             printf("%12ld\r", count);
618             printcount += 1024;
619         }
620     }
621     printf("%12ld\n", count);
622 }
623
624 int main(int argc, char *argv[])
625 {
626     char  *s;
627
628     if (argc != 4) {
629         printf("'lzhuf e file1 file2' encodes file1 into file2.\n"
630                "'lzhuf d file2 file1' decodes file2 into file1.\n");
631         return EXIT_FAILURE;
632     }
633     if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
634      || (s = argv[2], (infile = fopen(s, "rb")) == NULL)
635      || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
636         printf("??? %s\n", s);
637         return EXIT_FAILURE;
638     }
639     if (toupper(*argv[1]) == 'E')
640         Encode();
641     else
642         Decode();
643     fclose(infile);
644     fclose(outfile);
645     return EXIT_SUCCESS;
646 }