home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / archiver / lzarc / lzhuf.c < prev    next >
C/C++ Source or Header  |  1989-05-29  |  21KB  |  636 lines

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