home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / lzhmvs.zip / LZHDOS.C < prev    next >
Text File  |  1994-03-18  |  23KB  |  718 lines

  1. /**********************************************************************
  2.     DOS LZH based on lzhuf.c
  3.     written by Haruyasu Yoshizaki 1988/11/20
  4.     see MVS LZH listing for comments
  5.     DOS version modified 1993/03/05 by Pierre Dion.
  6.       Added Translate() for ASCII to EBCDIC translation and inserting
  7.       0x0D and 0x0A (DOS CR LF) for decoding MVS record format.
  8.       Encoded file header modified to designate origin 0x1E for
  9.       MVS and 0x1F for DOS.
  10. ***********************************************************************/
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16.  
  17. FILE  *infile, *outfile;
  18. static unsigned long int  textsize = 0, codesize = 0, printcount = 0;
  19. char wterr[] = "Can't write.";
  20.  
  21. unsigned long int llen = 0;
  22. unsigned char origin = 0x1F;  /* ascii origin  */
  23.             /* ebcdic to ascii translation code page 437 */
  24. unsigned char ascii[256] = { 
  25.            0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
  26.            0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
  27.            0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
  28.            0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
  29.            0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
  30.            0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
  31.            0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
  32.            0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
  33.            0x20, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
  34.            0xA7, 0xA8, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x5D,
  35.            0x26, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
  36.            0xB0, 0xB1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
  37.            0x2D, 0x2F, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
  38.            0xB8, 0xB9, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
  39.            0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1,
  40.            0xC2, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
  41.            0xC3, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
  42.            0x68, 0x69, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
  43.            0xCA, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
  44.            0x71, 0x72, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0,
  45.            0xD1, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
  46.            0x79, 0x7A, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
  47.            0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
  48.            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
  49.            0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
  50.            0x48, 0x49, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED,
  51.            0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
  52.            0x51, 0x52, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3,
  53.            0x5C, 0x9F, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
  54.            0x59, 0x5A, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9,
  55.            0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
  56.            0x38, 0x39, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
  57.    };
  58. /*************  Start of LZHUF unchanged code section ***************/
  59. /***************  Start of LZHUF unchanged code section ***************/
  60.  
  61.  
  62. static void Error(char *message)
  63. {
  64.     fprintf(stderr,"\n%s\n", message);
  65.     exit(EXIT_FAILURE);
  66. }
  67.  
  68. /********** LZSS compression **********/
  69.  
  70. #define N       4096    /* buffer size */
  71. #define F       15  /* lookahead buffer size */
  72. #define THRESHOLD   2
  73. #define NIL     N   /* leaf of tree */
  74.  
  75. unsigned char  text_buf[N + F - 1];
  76.  
  77. static unsigned short  match_position, match_length,
  78.                        lson[N + 1], rson[N + 257], dad[N + 1];
  79.  
  80. static void InitTree(void)  /* initialize trees */
  81. {
  82.     short i;
  83.  
  84.     for (i = N + 1; i <= N + 256; i++)
  85.         rson[i] = NIL;        /* root */
  86.     for (i = 0; i < N; i++)
  87.         dad[i] = NIL;         /* node */
  88. }
  89.  
  90. static void InsertNode(short r)  /* insert to tree */
  91. {
  92.     short  i, p, cmp;
  93.     unsigned char  *key;
  94.     unsigned short c;
  95.  
  96.     cmp = 1;
  97.     key = &text_buf[r];
  98.     p = N + 1 + key[0];
  99.     rson[r] = lson[r] = NIL;
  100.     match_length = 0;
  101.     for ( ; ; ) {
  102.         if (cmp >= 0) {
  103.             if (rson[p] != NIL)
  104.                 p = rson[p];
  105.             else {
  106.                 rson[p] = r;
  107.                 dad[r] = p;
  108.                 return;
  109.             }
  110.         } else {
  111.             if (lson[p] != NIL)
  112.                 p = lson[p];
  113.             else {
  114.                 lson[p] = r;
  115.                 dad[r] = p;
  116.                 return;
  117.             }
  118.         }
  119.         for (i = 1; i < F; i++)
  120.             if ((cmp = key[i] - text_buf[p + i]) != 0)
  121.                 break;
  122.         if (i > THRESHOLD) {
  123.             if (i > match_length) {
  124.                 match_position = ((r - p) & (N - 1)) - 1;
  125.                 if ((match_length = i) >= F)
  126.                     break;
  127.             }
  128.             if (i == match_length) {
  129.                 if ((c = ((r - p) & (N - 1)) - 1) < match_position) {
  130.                     match_position = c;
  131.                 }
  132.             }
  133.         }
  134.     }
  135.     dad[r] = dad[p];
  136.     lson[r] = lson[p];
  137.     rson[r] = rson[p];
  138.     dad[lson[p]] = r;
  139.     dad[rson[p]] = r;
  140.     if (rson[dad[p]] == p)
  141.         rson[dad[p]] = r;
  142.     else
  143.         lson[dad[p]] = r;
  144.     dad[p] = NIL; /* remove p */
  145. }
  146.  
  147. static void DeleteNode(short p)  /* remove from tree */
  148. {
  149.     short  q;
  150.  
  151.     if (dad[p] == NIL)
  152.         return;         /* not registered */
  153.     if (rson[p] == NIL)
  154.         q = lson[p];
  155.     else
  156.     if (lson[p] == NIL)
  157.         q = rson[p];
  158.     else {
  159.         q = lson[p];
  160.         if (rson[q] != NIL) {
  161.             do {
  162.                 q = rson[q];
  163.             } while (rson[q] != NIL);
  164.             rson[dad[q]] = lson[q];
  165.             dad[lson[q]] = dad[q];
  166.             lson[q] = lson[p];
  167.             dad[lson[p]] = q;
  168.         }
  169.         rson[q] = rson[p];
  170.         dad[rson[p]] = q;
  171.     }
  172.     dad[q] = dad[p];
  173.     if (rson[dad[p]] == p)
  174.         rson[dad[p]] = q;
  175.     else
  176.         lson[dad[p]] = q;
  177.     dad[p] = NIL;
  178. }
  179.  
  180. /* Huffman coding */
  181.  
  182. #define N_CHAR      (256 - THRESHOLD + F)
  183.                 /* kinds of characters (character code = 0..N_CHAR-1) */
  184. #define T       (N_CHAR * 2 - 1)    /* size of table */
  185. #define R       (T - 1)         /* position of root */
  186. #define MAX_FREQ    0x8000      /* updates tree when the */
  187.                     /* root frequency comes to this value. */
  188.  
  189. typedef unsigned char uchar;
  190.  
  191.  
  192. /* table for encoding and decoding the upper 6 bits of position */
  193.  
  194. /* for encoding */
  195. uchar p_len[64] = {
  196.     0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
  197.     0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
  198.     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  199.     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  200.     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  201.     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  202.     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  203.     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
  204. };
  205. uchar p_code[64] = {
  206.     0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
  207.     0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
  208.     0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
  209.     0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
  210.     0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
  211.     0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
  212.     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
  213.     0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
  214. };
  215.  
  216. /* for decoding */
  217. uchar d_code[256] = {
  218.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  219.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  220.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  221.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  222.     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  223.     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  224.     0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
  225.     0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
  226.     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  227.     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  228.     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  229.     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  230.     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  231.     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  232.     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  233.     0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
  234.     0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
  235.     0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
  236.     0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
  237.     0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
  238.     0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
  239.     0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
  240.     0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
  241.     0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
  242.     0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
  243.     0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
  244.     0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
  245.     0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
  246.     0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
  247.     0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
  248.     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
  249.     0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
  250. };
  251.  
  252. uchar d_len[256] = {
  253.     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  254.     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  255.     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  256.     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  257.     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  258.     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  259.     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  260.     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  261.     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  262.     0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  263.     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  264.     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  265.     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  266.     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  267.     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  268.     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  269.     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  270.     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  271.     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  272.     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  273.     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  274.     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  275.     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  276.     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  277.     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  278.     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  279.     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  280.     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  281.     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  282.     0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  283.     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  284.     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  285. };
  286.  
  287. unsigned short freq[T + 1]; /* frequency table */
  288.  
  289. short prnt[T + N_CHAR];/* pointers to parent nodes, except for the */
  290.             /* elements [T..T + N_CHAR - 1] which are used to get */
  291.             /* the positions of leaves corresponding to the codes. */
  292.  
  293. short son[T];   /* pointers to child nodes (son[], son[] + 1) */
  294.  
  295. unsigned short getbuf = 0;
  296. uchar getlen = 0;
  297.  
  298. static short GetBit(void)    /* get one bit */
  299. {
  300.     unsigned short i;
  301.  
  302.     while (getlen <= 8) {
  303.         if ((short)(i = getc(infile)) < 0) i = 0;
  304.         getbuf |= i << (8 - getlen);
  305.         getlen += 8;
  306.     }
  307.     i = getbuf;
  308.     getbuf <<= 1;
  309.     getlen--;
  310.     return (short)((i & 0x8000) >> 15);
  311. }
  312.  
  313. static short GetByte(void)   /* get one byte */
  314. {
  315.     unsigned short i;
  316.  
  317.     while (getlen <= 8) {
  318.         if ((short)(i = getc(infile)) < 0) i = 0;
  319.         getbuf |= i << (8 - getlen);
  320.         getlen += 8;
  321.     }
  322.     i = getbuf;
  323.     getbuf <<= 8;
  324.     getlen -= 8;
  325.     return (short)((i & 0xff00) >> 8);
  326. }
  327.  
  328. unsigned short putbuf = 0;
  329. uchar putlen = 0;
  330.  
  331.  
  332. /* output c bits of code */
  333.                                               
  334. static void Putcode(short l, unsigned long c)   
  335. {
  336.     putbuf |= c >> putlen;
  337.     if ((putlen += l) >= 8) {
  338.         if (putc(putbuf >> 8, outfile) == EOF) {
  339.             Error(wterr);
  340.         }
  341.         if ((putlen -= 8) >= 8) {
  342.             if (putc(putbuf, outfile) == EOF) {
  343.                Error(wterr);
  344.             }
  345.             codesize += 2;
  346.             putlen -= 8;
  347.             putbuf = c << (l - putlen);
  348.         } else {
  349.             putbuf <<= 8;
  350.             codesize++;
  351.         }
  352.     }
  353. }
  354.  
  355.  
  356. /* initialization of tree */
  357.  
  358. static void StartHuff(void)
  359. {
  360.     short i, j;
  361.  
  362.     for (i = 0; i < N_CHAR; i++) {
  363.         freq[i] = 1;
  364.         son[i] = i + T;
  365.         prnt[i + T] = i;
  366.     }
  367.     i = 0; j = N_CHAR;
  368.     while (j <= R) {
  369.         freq[j] = freq[i] + freq[i + 1];
  370.         son[j] = i;
  371.         prnt[i] = prnt[i + 1] = j;
  372.         i += 2; j++;
  373.     }
  374.     freq[T] = 0xffff;
  375.     prnt[R] = 0;
  376. }
  377.  
  378.  
  379. /* reconstruction of tree */
  380.  
  381. static void reconst(void)
  382. {
  383.     short i, j, k;
  384.     unsigned short f, l;
  385.  
  386.     /* collect leaf nodes in the first half of the table */
  387.     /* and replace the freq by (freq + 1) / 2. */
  388.     j = 0;
  389.     for (i = 0; i < T; i++) {
  390.         if (son[i] >= T) {
  391.             freq[j] = (freq[i] + 1) / 2;
  392.             son[j] = son[i];
  393.             j++;
  394.         }
  395.     }
  396.     /* begin constructing tree by connecting sons */
  397.     for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
  398.         k = i + 1;
  399.         f = freq[j] = freq[i] + freq[k];
  400.         for (k = j - 1; f < freq[k]; k--);
  401.         k++;
  402.         l = (j - k) * 2;
  403.         memmove(&freq[k + 1], &freq[k], l);
  404.         freq[k] = f;
  405.         memmove(&son[k + 1], &son[k], l);
  406.         son[k] = i;
  407.     }
  408.     /* connect prnt */
  409.     for (i = 0; i < T; i++) {
  410.         if ( (k = son[i]) >= T ) {
  411.              prnt[k] = i;
  412.         } else {
  413.              prnt[k] = prnt[ k + 1 ] = i;
  414.         }
  415.     }
  416. }
  417.  
  418.  
  419. /* increment frequency of given code by one, and update tree */
  420. static void update(unsigned short c)
  421. {
  422.     short i, j, k, l;
  423.  
  424.     if (freq[R] == MAX_FREQ) {
  425.         reconst();
  426.     }
  427.     c = prnt[c + T];
  428.     do {
  429.         k = ++freq[c];
  430.  
  431.         /* if the order is disturbed, exchange nodes */
  432.         if (k > freq[l = c + 1]) {
  433.             while (k > freq[++l]);
  434.             l--;
  435.             freq[c] = freq[l];
  436.             freq[l] = k;
  437.  
  438.             i = son[c];
  439.             prnt[i] = l;
  440.             if (i < T) prnt[i + 1] = l;
  441.  
  442.             j = son[l];
  443.             son[l] = i;
  444.  
  445.             prnt[j] = c;
  446.             if (j < T) prnt[j + 1] = c;
  447.             son[c] = j;
  448.  
  449.             c = l;
  450.         }
  451.     } while ((c = prnt[c]) != 0); /* repeat up to root */
  452. }
  453. unsigned short code, len;
  454.  
  455. static void EncodeChar(unsigned short c)
  456. {
  457.     unsigned short i;
  458.     short j, k;
  459.     i = 0;
  460.     j = 0;
  461.     k = prnt[c + T];
  462.  
  463.     /* travel from leaf to root */
  464.     do {
  465.         i >>= 1;
  466.  
  467.         /* if node's address is odd-numbered, choose bigger brother node */
  468.         if (k & 1) i += 0x8000;
  469.  
  470.         j++;
  471.     } while ((k = prnt[k]) != R);
  472.     Putcode(j, i);
  473.     code = i;
  474.     len = j;
  475.     update(c);
  476. }
  477.  
  478. static void EncodePosition(unsigned short c)
  479. {
  480.     unsigned short i;
  481.  
  482.     /* output upper 6 bits by table lookup */
  483.     i = c >> 6;
  484.     Putcode((short) p_len[i],(unsigned long) p_code[i] << 8);
  485.     /* output lower 6 bits verbatim */
  486.     Putcode(6, (c & 0x3f) << 10);
  487. }
  488.  
  489. static void EncodeEnd(void)
  490. {
  491.     if (putlen) {
  492.         if (putc(putbuf >> 8, outfile) == EOF) {
  493.             Error(wterr);
  494.         }
  495.         codesize++;
  496.     }
  497. }
  498.  
  499. static short DecodeChar(void)
  500. {
  501.    unsigned short c;
  502.  
  503.     c = son[R];
  504.  
  505.     /* travel from root to leaf, */
  506.     /* choosing the smaller child node (son[]) if the read bit is 0, */
  507.     /* the bigger (son[]+1) if 1 */
  508.     while (c < T) {
  509.         c += GetBit();
  510.         c = son[c];
  511.  
  512.     }
  513.     c -= T;
  514.     update(c);
  515.     return (short)c;
  516. }
  517.  
  518. static short DecodePosition(void)
  519. {
  520.     unsigned short i, j, c;
  521.  
  522.     /* recover upper 6 bits from table */
  523.     i = GetByte();
  524.     c = (unsigned short)d_code[i] << 6;
  525.     j = d_len[i];
  526.  
  527.     /* read lower 6 bits verbatim */
  528.     j -= 2;
  529.     while (j--) {
  530.         i = (i << 1) + GetBit();
  531.     }
  532.     return (short)(c | (i & 0x3f));
  533. }
  534.  
  535. /******************* End of LZHUF unchanged code section ***************/
  536. /*************  End of LZHUF unchanged code section ******************/
  537. /* translate ebcdic to ascii and record length control */
  538. static void Translate( unsigned short c )
  539. {
  540.     static unsigned short lpos = 0;
  541.     if ( origin == 0x1E ) {   /* MVS origin - DOS decoding */
  542.          /* convert ebcdic to ascii from table */
  543.         if ( putc( ascii[c], outfile ) == EOF ) Error(wterr);
  544.          /* perform record length control as requested */ 
  545.         if (llen > 0) {
  546.              if (lpos == llen) {    
  547.                   /* insert end of record DOS CR LF */
  548.                  if ( ( putc( 0x0D, outfile ) == EOF ) ||
  549.                       ( putc( 0x0A, outfile ) == EOF ) ) Error(wterr);
  550.                   /* reset line position */    
  551.                  lpos = 0;
  552.              } else {
  553.                   /* keep track of line position */
  554.                  lpos++;
  555.              }
  556.         }
  557.     } else {                /* DOS origin - MVS decoding */
  558.         if ( putc( c, outfile ) == EOF ) Error(wterr);
  559.     }
  560. }
  561. /* compression */
  562. static void Encode(void)  /* compression */
  563. {
  564.     short  i, c, len, r, s, last_match_length;
  565.     unsigned long bar = 0;
  566.     fseek(infile, 0L, 2);
  567.     textsize = ftell(infile);
  568.     fputc(0x1F,outfile);  /* output ascii origin */
  569.     fputc((short)((textsize & 0xff000000L) >> 24),outfile);
  570.     fputc((short)((textsize & 0xff0000L) >> 16),outfile);
  571.     fputc((short)((textsize & 0xff00) >> 8),outfile);
  572.     fputc((short)((textsize & 0xff)),outfile);
  573.     if (ferror(outfile))
  574.         Error(wterr);   /* output size of text */
  575.     if (textsize == 0)
  576.         return;
  577.     bar = textsize / 39;  /* encode status bar */
  578.     printf("In : %ld bytes\n"
  579.               "--10--20--30--40--50--60--70--80--90--100\%\r", textsize);
  580.     rewind(infile);
  581.     textsize = 0;           /* rewind and re-read */
  582.     StartHuff();
  583.     InitTree();
  584.     s = 0;
  585.     r = N - F;
  586.     for (i = s; i < r; i++)
  587.         text_buf[i] = 0x20;
  588.     for (len = 0; len < F && (c = getc(infile)) != EOF; len++)
  589.         text_buf[r + len] = c;
  590.     textsize = len;
  591.     for (i = 1; i <= F; i++)
  592.         InsertNode(r - i);
  593.     InsertNode(r);
  594.     do {
  595.         if (match_length > len)
  596.             match_length = len;
  597.         if (match_length <= THRESHOLD) {
  598.             match_length = 1;
  599.             EncodeChar(text_buf[r]);
  600.         } else {
  601.             EncodeChar(255 - THRESHOLD + match_length);
  602.             EncodePosition(match_position);
  603.         }
  604.         last_match_length = match_length;
  605.         for (i = 0; i < last_match_length &&
  606.                 (c = getc(infile)) != EOF; i++) {
  607.             DeleteNode(s);
  608.             text_buf[s] = c;
  609.             if (s < F - 1)
  610.                 text_buf[s + N] = c;
  611.             s = (s + 1) & (N - 1);
  612.             r = (r + 1) & (N - 1);
  613.             InsertNode(r);
  614.         }
  615.         if ((textsize += i) > printcount) {
  616.             printcount += bar;
  617.             printf("%c",0xFE);
  618.         }
  619.         while (i++ < last_match_length) {
  620.             DeleteNode(s);
  621.             s = (s + 1) & (N - 1);
  622.             r = (r + 1) & (N - 1);
  623.             if (--len) InsertNode(r);
  624.         }
  625.     } while (len > 0);
  626.     EncodeEnd();
  627.     printf("    \nOut: %ld bytes\n", codesize);
  628.     printf("Out/In: %.3f\n", (double)codesize / textsize);
  629. }
  630. static void Decode(void)  /* recover */
  631. {
  632.     unsigned short i, j, k, r, c;
  633.     unsigned long count, bar = 0;
  634.  
  635.     textsize = (unsigned char) fgetc(infile);
  636.     textsize <<= 8;
  637.     textsize |= (unsigned char) fgetc(infile);
  638.     textsize <<= 8;
  639.     textsize |= (unsigned char) fgetc(infile);
  640.     textsize <<= 8;
  641.     textsize |= (unsigned char) fgetc(infile);
  642.     if (ferror(infile))
  643.         Error("Can't read");  /* read size of text */
  644.     if (textsize == 0)
  645.         return;
  646.     bar = textsize / 40;  /* decode status bar */
  647.     printf("In : %ld bytes\n"
  648.               "--10--20--30--40--50--60--70--80--90--100\%\r", textsize);
  649.     StartHuff();
  650.     for (i = 0; i < N - F; i++)
  651.         text_buf[i] = 0x20;
  652.     r = N - F;
  653.     for (count = 0; count < textsize; ) {
  654.         c = DecodeChar();
  655.         if (c < 256) {
  656.             Translate(c);
  657.             text_buf[r++] = c;
  658.             r &= (N - 1);
  659.             count++;
  660.         } else {
  661.             i = (r - DecodePosition() - 1) & (N - 1);
  662.             j = c - 255 + THRESHOLD;
  663.             for (k = 0; k < j; k++) {
  664.                  c = text_buf[(i + k) & (N - 1)];
  665.                  Translate(c);
  666.                  text_buf[r++] = c;
  667.                  r &= (N - 1);
  668.                  count++;
  669.             }
  670.         }
  671.         if (count > printcount) {
  672.             printcount += bar;
  673.             printf("%c",0xFE);
  674.         }
  675.     }
  676.     printf("   \nRestored\n");
  677. }
  678. short main(short argc, char *argv[])
  679. {
  680.     char  *s;
  681.     printf("\nLZH ver 1.02 - Multi-platform Data Compression/Decoding,\n"
  682.            "Based on LZHUF written by Haruyasu Yoshizaki 1988 (Japan),\n"
  683.            "               modified by Paul Edwards 1990 (Australia),\n"
  684.            "                       and Mark Nelson 1990  (USA),\n"
  685.            "IBM/MVSPC/DOS by Pierre Dion 1993 (Canada),\n\n");
  686.  
  687.     if (argc < 4) {
  688.         printf("'lzh e file1 file2' encodes file1 into file2.\n"
  689.                "'lzh d file2 file1 l' decodes file2 into file1.\n"
  690.                "      'l' (optional) specifies line length for crlf\n"
  691.                "          as defined by the original ebcdic file and\n"
  692.                "          must be expressed as an integer.\n"
  693.                " Examples: lzh e datafile compfile\n"
  694.                "           lzh d compfile datafile 150\n");
  695.         return EXIT_FAILURE;
  696.     }
  697.     if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
  698.      || (s = argv[2], (infile = fopen(s, "rb")) == NULL)
  699.      || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
  700.         printf("??? %s\n", s);
  701.         return EXIT_FAILURE;
  702.     }
  703.     if (toupper(*argv[1]) == 'E') {
  704.         Encode();
  705.     } else {
  706.         if (argv[4] != NULL) llen = atol(argv[4]);
  707.  
  708.         origin = fgetc(infile);  /* read infile origin */
  709.  
  710.         if ( origin == 0x1E || origin == 0x1F )  /* MVS or DOS */
  711.             Decode();
  712.         else
  713.             printf("\nError: %s is not a LZH compressed file.\n",argv[2]);
  714.     }
  715.     fclose(infile);
  716.     fclose(outfile);
  717.     return EXIT_SUCCESS;
  718. }