home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / prog / source / lzhuffsr.lzh / LZHUF.C next >
Text File  |  1989-04-01  |  15KB  |  633 lines

  1. /*
  2.  * LZHUF.C English version 1.0
  3.  * Based on Japanese version 29-NOV-1988
  4.  * LZSS coded by Haruhiko OKUMURA
  5.  * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
  6.  * Edited and translated to English by Kenji RIKITAKE
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13.  
  14. /* These values are Turbo-C dependent;
  15.    EXIT_SUCCESS, EXIT_FAILURE
  16.    renamed by Kenji */
  17.  
  18. #define EXIT_OK 0
  19. #define EXIT_FAILED -1
  20.  
  21. FILE  *infile, *outfile;
  22. unsigned long int  textsize = 0, codesize = 0, printcount = 0;
  23.  
  24. void Error(char *message)
  25. {
  26.     printf("\n%s\n", message);
  27.     exit(EXIT_FAILED);
  28. }
  29.  
  30. /* LZSS Parameters */
  31.  
  32. #define N        4096    /* Size of string buffer */
  33. #define F        60    /* Size of look-ahead buffer */
  34. #define THRESHOLD    2
  35. #define NIL        N    /* End of tree's node  */
  36.  
  37. unsigned char
  38.         text_buf[N + F - 1];
  39. int        match_position, match_length,
  40.         lson[N + 1], rson[N + 257], dad[N + 1];
  41.  
  42. void InitTree(void)  /* Initializing tree */
  43. {
  44.     int  i;
  45.  
  46.     for (i = N + 1; i <= N + 256; i++)
  47.         rson[i] = NIL;            /* root */
  48.     for (i = 0; i < N; i++)
  49.         dad[i] = NIL;            /* node */
  50. }
  51.  
  52. void InsertNode(int r)  /* Inserting node to the tree */
  53. {
  54.     int  i, p, cmp;
  55.     unsigned char  *key;
  56.     unsigned c;
  57.  
  58.     cmp = 1;
  59.     key = &text_buf[r];
  60.     p = N + 1 + key[0];
  61.     rson[r] = lson[r] = NIL;
  62.     match_length = 0;
  63.     for ( ; ; ) {
  64.         if (cmp >= 0) {
  65.             if (rson[p] != NIL)
  66.                 p = rson[p];
  67.             else {
  68.                 rson[p] = r;
  69.                 dad[r] = p;
  70.                 return;
  71.             }
  72.         } else {
  73.             if (lson[p] != NIL)
  74.                 p = lson[p];
  75.             else {
  76.                 lson[p] = r;
  77.                 dad[r] = p;
  78.                 return;
  79.             }
  80.         }
  81.         for (i = 1; i < F; i++)
  82.             if ((cmp = key[i] - text_buf[p + i]) != 0)
  83.                 break;
  84.         if (i > THRESHOLD) {
  85.             if (i > match_length) {
  86.                 match_position = ((r - p) & (N - 1)) - 1;
  87.                 if ((match_length = i) >= F)
  88.                     break;
  89.             }
  90.             if (i == match_length) {
  91.                 if ((c = ((r - p) & (N - 1)) - 1) < match_position) {
  92.                     match_position = c;
  93.                 }
  94.             }
  95.         }
  96.     }
  97.     dad[r] = dad[p];
  98.     lson[r] = lson[p];
  99.     rson[r] = rson[p];
  100.     dad[lson[p]] = r;
  101.     dad[rson[p]] = r;
  102.     if (rson[dad[p]] == p)
  103.         rson[dad[p]] = r;
  104.     else
  105.         lson[dad[p]] = r;
  106.     dad[p] = NIL;  /* remove p */
  107. }
  108.  
  109. void DeleteNode(int p)  /* Deleting node from the tree */
  110. {
  111.     int  q;
  112.  
  113.     if (dad[p] == NIL)
  114.         return;            /* unregistered */
  115.     if (rson[p] == NIL)
  116.         q = lson[p];
  117.     else
  118.     if (lson[p] == NIL)
  119.         q = rson[p];
  120.     else {
  121.         q = lson[p];
  122.         if (rson[q] != NIL) {
  123.             do {
  124.                 q = rson[q];
  125.             } while (rson[q] != NIL);
  126.             rson[dad[q]] = lson[q];
  127.             dad[lson[q]] = dad[q];
  128.             lson[q] = lson[p];
  129.             dad[lson[p]] = q;
  130.         }
  131.         rson[q] = rson[p];
  132.         dad[rson[p]] = q;
  133.     }
  134.     dad[q] = dad[p];
  135.     if (rson[dad[p]] == p)
  136.         rson[dad[p]] = q;
  137.     else
  138.         lson[dad[p]] = q;
  139.     dad[p] = NIL;
  140. }
  141.  
  142. /* Huffman coding parameters */
  143.  
  144. #define N_CHAR      (256 - THRESHOLD + F)
  145.                 /* character code (= 0..N_CHAR-1) */
  146. #define T         (N_CHAR * 2 - 1)    /* Size of table */
  147. #define R         (T - 1)            /* root position */
  148. #define MAX_FREQ    0x8000
  149.                     /* update when cumulative frequency */
  150.                     /* reaches to this value */
  151.  
  152. typedef unsigned char uchar;
  153.  
  154. /*
  155.  * Tables for encoding/decoding upper 6 bits of
  156.  * sliding dictionary pointer
  157.  */
  158. /* encoder table */
  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. /* decoder table */
  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];    /* cumulative freq table */
  253.  
  254. /*
  255.  * pointing parent nodes.
  256.  * area [T..(T + N_CHAR - 1)] are pointers for leaves
  257.  */
  258. int prnt[T + N_CHAR];
  259.  
  260. /* pointing children nodes (son[], son[] + 1)*/
  261. int son[T];
  262.  
  263. unsigned getbuf = 0;
  264. uchar getlen = 0;
  265.  
  266. int GetBit(void)    /* get one bit */
  267. {
  268.     int i;
  269.  
  270.     while (getlen <= 8) {
  271.         if ((i = getc(infile)) < 0) i = 0;
  272.         getbuf |= i << (8 - getlen);
  273.         getlen += 8;
  274.     }
  275.     i = getbuf;
  276.     getbuf <<= 1;
  277.     getlen--;
  278.     return (i < 0);
  279. }
  280.  
  281. int GetByte(void)    /* get a byte */
  282. {
  283.     unsigned i;
  284.  
  285.     while (getlen <= 8) {
  286.         if ((i = getc(infile)) < 0) i = 0;
  287.         getbuf |= i << (8 - getlen);
  288.         getlen += 8;
  289.     }
  290.     i = getbuf;
  291.     getbuf <<= 8;
  292.     getlen -= 8;
  293.     return i >> 8;
  294. }
  295.  
  296. unsigned putbuf = 0;
  297. uchar putlen = 0;
  298.  
  299. void Putcode(int l, unsigned c)        /* output c bits */
  300. {
  301.     putbuf |= c >> putlen;
  302.     if ((putlen += l) >= 8) {
  303.         putc(putbuf >> 8, outfile);
  304.         if ((putlen -= 8) >= 8) {
  305.             putc(putbuf, outfile);
  306.             codesize += 2;
  307.             putlen -= 8;
  308.             putbuf = c << (l - putlen);
  309.         } else {
  310.             putbuf <<= 8;
  311.             codesize++;
  312.         }
  313.     }
  314. }
  315.  
  316.  
  317. /* initialize freq tree */
  318.  
  319. void StartHuff()
  320. {
  321.     int i, j;
  322.  
  323.     for (i = 0; i < N_CHAR; i++) {
  324.         freq[i] = 1;
  325.         son[i] = i + T;
  326.         prnt[i + T] = i;
  327.     }
  328.     i = 0; j = N_CHAR;
  329.     while (j <= R) {
  330.         freq[j] = freq[i] + freq[i + 1];
  331.         son[j] = i;
  332.         prnt[i] = prnt[i + 1] = j;
  333.         i += 2; j++;
  334.     }
  335.     freq[T] = 0xffff;
  336.     prnt[R] = 0;
  337. }
  338.  
  339.  
  340. /* reconstruct freq tree */
  341.  
  342. void reconst()
  343. {
  344.     int i, j, k;
  345.     unsigned f, l;
  346.  
  347.     /* halven cumulative freq for leaf nodes */
  348.     j = 0;
  349.     for (i = 0; i < T; i++) {
  350.         if (son[i] >= T) {
  351.             freq[j] = (freq[i] + 1) / 2;
  352.             son[j] = son[i];
  353.             j++;
  354.         }
  355.     }
  356.     /* make a tree : first, connect children nodes */
  357.     for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
  358.         k = i + 1;
  359.         f = freq[j] = freq[i] + freq[k];
  360.         for (k = j - 1; f < freq[k]; k--);
  361.         k++;
  362.         l = (j - k) * 2;
  363.         
  364.         /* movmem() is Turbo-C dependent
  365.            rewritten to memmove() by Kenji */
  366.         
  367.         /* movmem(&freq[k], &freq[k + 1], l); */
  368.         (void)memmove(&freq[k + 1], &freq[k], l);
  369.         freq[k] = f;
  370.         /* movmem(&son[k], &son[k + 1], l); */
  371.         (void)memmove(&son[k + 1], &son[k], l);
  372.         son[k] = i;
  373.     }
  374.     /* connect parent nodes */
  375.     for (i = 0; i < T; i++) {
  376.         if ((k = son[i]) >= T) {
  377.             prnt[k] = i;
  378.         } else {
  379.             prnt[k] = prnt[k + 1] = i;
  380.         }
  381.     }
  382. }
  383.  
  384.  
  385. /* update freq tree */
  386.  
  387. void update(int c)
  388. {
  389.     int i, j, k, l;
  390.  
  391.     if (freq[R] == MAX_FREQ) {
  392.         reconst();
  393.     }
  394.     c = prnt[c + T];
  395.     do {
  396.         k = ++freq[c];
  397.  
  398.         /* swap nodes to keep the tree freq-ordered */
  399.         if (k > freq[l = c + 1]) {
  400.             while (k > freq[++l]);
  401.             l--;
  402.             freq[c] = freq[l];
  403.             freq[l] = k;
  404.  
  405.             i = son[c];
  406.             prnt[i] = l;
  407.             if (i < T) prnt[i + 1] = l;
  408.  
  409.             j = son[l];
  410.             son[l] = i;
  411.  
  412.             prnt[j] = c;
  413.             if (j < T) prnt[j + 1] = c;
  414.             son[c] = j;
  415.  
  416.             c = l;
  417.         }
  418.     } while ((c = prnt[c]) != 0);    /* do it until reaching the root */
  419. }
  420.  
  421. unsigned code, len;
  422.  
  423. void EncodeChar(unsigned c)
  424. {
  425.     unsigned i;
  426.     int j, k;
  427.  
  428.     i = 0;
  429.     j = 0;
  430.     k = prnt[c + T];
  431.  
  432.     /* search connections from leaf node to the root */
  433.     do {
  434.         i >>= 1;
  435.  
  436.         /*
  437.         if node's address is odd, output 1
  438.         else output 0
  439.         */
  440.         if (k & 1) i += 0x8000;
  441.  
  442.         j++;
  443.     } while ((k = prnt[k]) != R);
  444.     Putcode(j, i);
  445.     code = i;
  446.     len = j;
  447.     update(c);
  448. }
  449.  
  450. void EncodePosition(unsigned c)
  451. {
  452.     unsigned i;
  453.  
  454.     /* output upper 6 bits with encoding */
  455.     i = c >> 6;
  456.     Putcode(p_len[i], (unsigned)p_code[i] << 8);
  457.  
  458.     /* output lower 6 bits directly */
  459.     Putcode(6, (c & 0x3f) << 10);
  460. }
  461.  
  462. void EncodeEnd()
  463. {
  464.     if (putlen) {
  465.         putc(putbuf >> 8, outfile);
  466.         codesize++;
  467.     }
  468. }
  469.  
  470. int DecodeChar()
  471. {
  472.     unsigned c;
  473.  
  474.     c = son[R];
  475.  
  476.     /*
  477.      * start searching tree from the root to leaves.
  478.      * choose node #(son[]) if input bit == 0
  479.      * else choose #(son[]+1) (input bit == 1)
  480.      */
  481.     while (c < T) {
  482.         c += GetBit();
  483.         c = son[c];
  484.     }
  485.     c -= T;
  486.     update(c);
  487.     return c;
  488. }
  489.  
  490. int DecodePosition()
  491. {
  492.     unsigned i, j, c;
  493.  
  494.     /* decode upper 6 bits from given table */
  495.     i = GetByte();
  496.     c = (unsigned)d_code[i] << 6;
  497.     j = d_len[i];
  498.  
  499.     /* input lower 6 bits directly */
  500.     j -= 2;
  501.     while (j--) {
  502.         i = (i << 1) + GetBit();
  503.     }
  504.     return c | i & 0x3f;
  505. }
  506.  
  507. /* Compression */
  508.  
  509. void Encode(void)  /* Encoding/Compressing */
  510. {
  511.     int  i, c, len, r, s, last_match_length;
  512.  
  513.     fseek(infile, 0L, 2);
  514.     textsize = ftell(infile);
  515.     if (fwrite(&textsize, sizeof textsize, 1, outfile) < 1)
  516.         Error("Unable to write");    /* write size of original text */
  517.     if (textsize == 0)
  518.         return;
  519.     rewind(infile);
  520.     textsize = 0;            /* rewind and rescan */
  521.     StartHuff();
  522.     InitTree();
  523.     s = 0;
  524.     r = N - F;
  525.     for (i = s; i < r; i++)
  526.         text_buf[i] = ' ';
  527.     for (len = 0; len < F && (c = getc(infile)) != EOF; len++)
  528.         text_buf[r + len] = c;
  529.     textsize = len;
  530.     for (i = 1; i <= F; i++)
  531.         InsertNode(r - i);
  532.     InsertNode(r);
  533.     do {
  534.         if (match_length > len)
  535.             match_length = len;
  536.         if (match_length <= THRESHOLD) {
  537.             match_length = 1;
  538.             EncodeChar(text_buf[r]);
  539.         } else {
  540.             EncodeChar(255 - THRESHOLD + match_length);
  541.             EncodePosition(match_position);
  542.         }
  543.         last_match_length = match_length;
  544.         for (i = 0; i < last_match_length &&
  545.                 (c = getc(infile)) != EOF; i++) {
  546.             DeleteNode(s);
  547.             text_buf[s] = c;
  548.             if (s < F - 1)
  549.                 text_buf[s + N] = c;
  550.             s = (s + 1) & (N - 1);
  551.             r = (r + 1) & (N - 1);
  552.             InsertNode(r);
  553.         }
  554.         if ((textsize += i) > printcount) {
  555.             printf("%12ld\r", textsize);
  556.             printcount += 1024;
  557.         }
  558.         while (i++ < last_match_length) {
  559.             DeleteNode(s);
  560.             s = (s + 1) & (N - 1);
  561.             r = (r + 1) & (N - 1);
  562.             if (--len) InsertNode(r);
  563.         }
  564.     } while (len > 0);
  565.     EncodeEnd();
  566.     printf("input: %ld bytes\n", textsize);
  567.     printf("output: %ld bytes\n", codesize);
  568.     printf("output/input: %.3f\n", (double)codesize / textsize);
  569. }
  570.  
  571. void Decode(void)  /* Decoding/Uncompressing */
  572. {
  573.     int  i, j, k, r, c;
  574.     unsigned long int  count;
  575.  
  576.     if (fread(&textsize, sizeof textsize, 1, infile) < 1)
  577.         Error("Unable to read");  /* read size of original text */
  578.     if (textsize == 0)
  579.         return;
  580.     StartHuff();
  581.     for (i = 0; i < N - F; i++)
  582.         text_buf[i] = ' ';
  583.     r = N - F;
  584.     for (count = 0; count < textsize; ) {
  585.         c = DecodeChar();
  586.         if (c < 256) {
  587.             putc(c, outfile);
  588.             text_buf[r++] = c;
  589.             r &= (N - 1);
  590.             count++;
  591.         } else {
  592.             i = (r - DecodePosition() - 1) & (N - 1);
  593.             j = c - 255 + THRESHOLD;
  594.             for (k = 0; k < j; k++) {
  595.                 c = text_buf[(i + k) & (N - 1)];
  596.                 putc(c, outfile);
  597.                 text_buf[r++] = c;
  598.                 r &= (N - 1);
  599.                 count++;
  600.             }
  601.         }
  602.         if (count > printcount) {
  603.             printf("%12ld\r", count);
  604.             printcount += 1024;
  605.         }
  606.     }
  607.     printf("%12ld\n", count);
  608. }
  609.  
  610. int main(int argc, char *argv[])
  611. {
  612.     char  *s;
  613.  
  614.     if (argc != 4) {
  615.         printf("Usage:lzhuf e(compression)|d(uncompression)"
  616.             " infile outfile\n");
  617.         return EXIT_FAILED;
  618.     }
  619.     if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
  620.      || (s = argv[2], (infile  = fopen(s, "rb")) == NULL)
  621.      || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
  622.         printf("$@HHH(J %s\n", s);
  623.         return EXIT_FAILED;
  624.     }
  625.     if (toupper(*argv[1]) == 'E')
  626.         Encode();
  627.     else
  628.         Decode();
  629.     fclose(infile);
  630.     fclose(outfile);
  631.     return EXIT_OK;
  632. }
  633.