Main Page | Class List | Directories | File List | Class Members | File Members

unlzh.c

Go to the documentation of this file.
00001 /* unlzh.c -- decompress files in SCO compress -H (LZH) format.
00002  * The code in this file is directly derived from the public domain 'ar002'
00003  * written by Haruhiko Okumura.
00004  */
00005 
00006 #ifdef RCSID
00007 static char rcsid[] = "$Id: unlzh.c,v 1.4 2006/11/20 08:40:34 eggert Exp $";
00008 #endif
00009 
00010 #include <config.h>
00011 #include <stdio.h>
00012 
00013 #include "tailor.h"
00014 #include "gzip.h"
00015 #include "lzw.h" /* just for consistency checking */
00016 
00017 /* decode.c */
00018 
00019 local unsigned  decode  OF((unsigned count, uch buffer[]));
00020 local void decode_start OF((void));
00021 
00022 /* huf.c */
00023 local void huf_decode_start OF((void));
00024 local unsigned decode_c     OF((void));
00025 local unsigned decode_p     OF((void));
00026 local void read_pt_len      OF((int nn, int nbit, int i_special));
00027 local void read_c_len       OF((void));
00028 
00029 /* io.c */
00030 local void fillbuf      OF((int n));
00031 local unsigned getbits  OF((int n));
00032 local void init_getbits OF((void));
00033 
00034 /* maketbl.c */
00035 
00036 local void make_table OF((int nchar, uch bitlen[],
00037                           int tablebits, ush table[]));
00038 
00039 
00040 #define DICBIT    13    /* 12(-lh4-) or 13(-lh5-) */
00041 #define DICSIZ ((unsigned) 1 << DICBIT)
00042 
00043 #ifndef CHAR_BIT
00044 #  define CHAR_BIT 8
00045 #endif
00046 
00047 #ifndef UCHAR_MAX
00048 #  define UCHAR_MAX 255
00049 #endif
00050 
00051 #define BITBUFSIZ (CHAR_BIT * 2 * sizeof(char))
00052 /* Do not use CHAR_BIT * sizeof(bitbuf), does not work on machines
00053  * for which short is not on 16 bits (Cray).
00054  */
00055 
00056 /* encode.c and decode.c */
00057 
00058 #define MAXMATCH 256    /* formerly F (not more than UCHAR_MAX + 1) */
00059 #define THRESHOLD  3    /* choose optimal value */
00060 
00061 /* huf.c */
00062 
00063 #define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
00064         /* alphabet = {0, 1, 2, ..., NC - 1} */
00065 #define CBIT 9  /* $\lfloor \log_2 NC \rfloor + 1$ */
00066 #define CODE_BIT  16  /* codeword length */
00067 
00068 #define NP (DICBIT + 1)
00069 #define NT (CODE_BIT + 3)
00070 #define PBIT 4  /* smallest integer such that (1U << PBIT) > NP */
00071 #define TBIT 5  /* smallest integer such that (1U << TBIT) > NT */
00072 #define NPT (1 << TBIT)
00073 
00074 /* local ush left[2 * NC - 1]; */
00075 /* local ush right[2 * NC - 1]; */
00076 #define left  prev
00077 #define right head
00078 #if NC > (1<<(BITS-2))
00079     error cannot overlay left+right and prev
00080 #endif
00081 
00082 /* local uch c_len[NC]; */
00083 #define c_len outbuf
00084 #if NC > OUTBUFSIZ
00085     error cannot overlay c_len and outbuf
00086 #endif
00087 
00088 local uch pt_len[NPT];
00089 local unsigned blocksize;
00090 local ush pt_table[256];
00091 
00092 /* local ush c_table[4096]; */
00093 #define c_table d_buf
00094 #if (DIST_BUFSIZE-1) < 4095
00095     error cannot overlay c_table and d_buf
00096 #endif
00097 
00098 /***********************************************************
00099         io.c -- input/output
00100 ***********************************************************/
00101 
00102 local ush       bitbuf;
00103 local unsigned  subbitbuf;
00104 local int       bitcount;
00105 
00106 local void fillbuf(n)  /* Shift bitbuf n bits left, read n bits */
00107     int n;
00108 {
00109     bitbuf <<= n;
00110     while (n > bitcount) {
00111         bitbuf |= subbitbuf << (n -= bitcount);
00112         subbitbuf = (unsigned)try_byte();
00113         if ((int)subbitbuf == EOF) subbitbuf = 0;
00114         bitcount = CHAR_BIT;
00115     }
00116     bitbuf |= subbitbuf >> (bitcount -= n);
00117 }
00118 
00119 local unsigned getbits(n)
00120     int n;
00121 {
00122     unsigned x;
00123 
00124     x = bitbuf >> (BITBUFSIZ - n);  fillbuf(n);
00125     return x;
00126 }
00127 
00128 local void init_getbits()
00129 {
00130     bitbuf = 0;  subbitbuf = 0;  bitcount = 0;
00131     fillbuf(BITBUFSIZ);
00132 }
00133 
00134 /***********************************************************
00135         maketbl.c -- make table for decoding
00136 ***********************************************************/
00137 
00138 local void make_table(nchar, bitlen, tablebits, table)
00139     int nchar;
00140     uch bitlen[];
00141     int tablebits;
00142     ush table[];
00143 {
00144     ush count[17], weight[17], start[18], *p;
00145     unsigned i, k, len, ch, jutbits, avail, nextcode, mask;
00146 
00147     for (i = 1; i <= 16; i++) count[i] = 0;
00148     for (i = 0; i < (unsigned)nchar; i++) count[bitlen[i]]++;
00149 
00150     start[1] = 0;
00151     for (i = 1; i <= 16; i++)
00152         start[i + 1] = start[i] + (count[i] << (16 - i));
00153     if ((start[17] & 0xffff) != 0)
00154       gzip_error ("Bad table\n");
00155 
00156     jutbits = 16 - tablebits;
00157     for (i = 1; i <= (unsigned)tablebits; i++) {
00158         start[i] >>= jutbits;
00159         weight[i] = (unsigned) 1 << (tablebits - i);
00160     }
00161     while (i <= 16) {
00162         weight[i] = (unsigned) 1 << (16 - i);
00163         i++;
00164     }
00165 
00166     i = start[tablebits + 1] >> jutbits;
00167     if (i != 0) {
00168         k = 1 << tablebits;
00169         while (i != k) table[i++] = 0;
00170     }
00171 
00172     avail = nchar;
00173     mask = (unsigned) 1 << (15 - tablebits);
00174     for (ch = 0; ch < (unsigned)nchar; ch++) {
00175         if ((len = bitlen[ch]) == 0) continue;
00176         nextcode = start[len] + weight[len];
00177         if (len <= (unsigned)tablebits) {
00178             if ((unsigned) 1 << tablebits < nextcode)
00179               gzip_error ("Bad table\n");
00180             for (i = start[len]; i < nextcode; i++) table[i] = ch;
00181         } else {
00182             k = start[len];
00183             p = &table[k >> jutbits];
00184             i = len - tablebits;
00185             while (i != 0) {
00186                 if (*p == 0) {
00187                     right[avail] = left[avail] = 0;
00188                     *p = avail++;
00189                 }
00190                 if (k & mask) p = &right[*p];
00191                 else          p = &left[*p];
00192                 k <<= 1;  i--;
00193             }
00194             *p = ch;
00195         }
00196         start[len] = nextcode;
00197     }
00198 }
00199 
00200 /***********************************************************
00201         huf.c -- static Huffman
00202 ***********************************************************/
00203 
00204 local void read_pt_len(nn, nbit, i_special)
00205     int nn;
00206     int nbit;
00207     int i_special;
00208 {
00209     int i, c, n;
00210     unsigned mask;
00211 
00212     n = getbits(nbit);
00213     if (n == 0) {
00214         c = getbits(nbit);
00215         for (i = 0; i < nn; i++) pt_len[i] = 0;
00216         for (i = 0; i < 256; i++) pt_table[i] = c;
00217     } else {
00218         i = 0;
00219         while (i < n) {
00220             c = bitbuf >> (BITBUFSIZ - 3);
00221             if (c == 7) {
00222                 mask = (unsigned) 1 << (BITBUFSIZ - 1 - 3);
00223                 while (mask & bitbuf) {  mask >>= 1;  c++;  }
00224                 if (16 < c)
00225                   gzip_error ("Bad table\n");
00226             }
00227             fillbuf((c < 7) ? 3 : c - 3);
00228             pt_len[i++] = c;
00229             if (i == i_special) {
00230                 c = getbits(2);
00231                 while (--c >= 0) pt_len[i++] = 0;
00232             }
00233         }
00234         while (i < nn) pt_len[i++] = 0;
00235         make_table(nn, pt_len, 8, pt_table);
00236     }
00237 }
00238 
00239 local void read_c_len()
00240 {
00241     int i, c, n;
00242     unsigned mask;
00243 
00244     n = getbits(CBIT);
00245     if (n == 0) {
00246         c = getbits(CBIT);
00247         for (i = 0; i < NC; i++) c_len[i] = 0;
00248         for (i = 0; i < 4096; i++) c_table[i] = c;
00249     } else {
00250         i = 0;
00251         while (i < n) {
00252             c = pt_table[bitbuf >> (BITBUFSIZ - 8)];
00253             if (c >= NT) {
00254                 mask = (unsigned) 1 << (BITBUFSIZ - 1 - 8);
00255                 do {
00256                     if (bitbuf & mask) c = right[c];
00257                     else               c = left [c];
00258                     mask >>= 1;
00259                 } while (c >= NT);
00260             }
00261             fillbuf((int) pt_len[c]);
00262             if (c <= 2) {
00263                 if      (c == 0) c = 1;
00264                 else if (c == 1) c = getbits(4) + 3;
00265                 else             c = getbits(CBIT) + 20;
00266                 while (--c >= 0) c_len[i++] = 0;
00267             } else c_len[i++] = c - 2;
00268         }
00269         while (i < NC) c_len[i++] = 0;
00270         make_table(NC, c_len, 12, c_table);
00271     }
00272 }
00273 
00274 local unsigned decode_c()
00275 {
00276     unsigned j, mask;
00277 
00278     if (blocksize == 0) {
00279         blocksize = getbits(16);
00280         if (blocksize == 0) {
00281             return NC; /* end of file */
00282         }
00283         read_pt_len(NT, TBIT, 3);
00284         read_c_len();
00285         read_pt_len(NP, PBIT, -1);
00286     }
00287     blocksize--;
00288     j = c_table[bitbuf >> (BITBUFSIZ - 12)];
00289     if (j >= NC) {
00290         mask = (unsigned) 1 << (BITBUFSIZ - 1 - 12);
00291         do {
00292             if (bitbuf & mask) j = right[j];
00293             else               j = left [j];
00294             mask >>= 1;
00295         } while (j >= NC);
00296     }
00297     fillbuf((int) c_len[j]);
00298     return j;
00299 }
00300 
00301 local unsigned decode_p()
00302 {
00303     unsigned j, mask;
00304 
00305     j = pt_table[bitbuf >> (BITBUFSIZ - 8)];
00306     if (j >= NP) {
00307         mask = (unsigned) 1 << (BITBUFSIZ - 1 - 8);
00308         do {
00309             if (bitbuf & mask) j = right[j];
00310             else               j = left [j];
00311             mask >>= 1;
00312         } while (j >= NP);
00313     }
00314     fillbuf((int) pt_len[j]);
00315     if (j != 0) j = ((unsigned) 1 << (j - 1)) + getbits((int) (j - 1));
00316     return j;
00317 }
00318 
00319 local void huf_decode_start()
00320 {
00321     init_getbits();  blocksize = 0;
00322 }
00323 
00324 /***********************************************************
00325         decode.c
00326 ***********************************************************/
00327 
00328 local int j;    /* remaining bytes to copy */
00329 local int done; /* set at end of input */
00330 
00331 local void decode_start()
00332 {
00333     huf_decode_start();
00334     j = 0;
00335     done = 0;
00336 }
00337 
00338 /* Decode the input and return the number of decoded bytes put in buffer
00339  */
00340 local unsigned decode(count, buffer)
00341     unsigned count;
00342     uch buffer[];
00343     /* The calling function must keep the number of
00344        bytes to be processed.  This function decodes
00345        either 'count' bytes or 'DICSIZ' bytes, whichever
00346        is smaller, into the array 'buffer[]' of size
00347        'DICSIZ' or more.
00348        Call decode_start() once for each new file
00349        before calling this function.
00350      */
00351 {
00352     local unsigned i;
00353     unsigned r, c;
00354 
00355     r = 0;
00356     while (--j >= 0) {
00357         buffer[r] = buffer[i];
00358         i = (i + 1) & (DICSIZ - 1);
00359         if (++r == count) return r;
00360     }
00361     for ( ; ; ) {
00362         c = decode_c();
00363         if (c == NC) {
00364             done = 1;
00365             return r;
00366         }
00367         if (c <= UCHAR_MAX) {
00368             buffer[r] = c;
00369             if (++r == count) return r;
00370         } else {
00371             j = c - (UCHAR_MAX + 1 - THRESHOLD);
00372             i = (r - decode_p() - 1) & (DICSIZ - 1);
00373             while (--j >= 0) {
00374                 buffer[r] = buffer[i];
00375                 i = (i + 1) & (DICSIZ - 1);
00376                 if (++r == count) return r;
00377             }
00378         }
00379     }
00380 }
00381 
00382 
00383 /* ===========================================================================
00384  * Unlzh in to out. Return OK or ERROR.
00385  */
00386 int unlzh(in, out)
00387     int in;
00388     int out;
00389 {
00390     unsigned n;
00391     ifd = in;
00392     ofd = out;
00393 
00394     decode_start();
00395     while (!done) {
00396         n = decode((unsigned) DICSIZ, window);
00397         if (!test && n > 0) {
00398             write_buf(out, (char*)window, n);
00399         }
00400     }
00401     return OK;
00402 }

© sourcejam.com 2005-2008