home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / lzhmvs.zip / LZHMVS.C < prev    next >
C/C++ Source or Header  |  1994-03-18  |  24KB  |  755 lines

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