changeset 1204:a0f08d393def

Update inflate code: fixed tables, bugfixes, zcat alias.
author Rob Landley <rob@landley.net>
date Fri, 21 Feb 2014 22:21:59 -0600
parents 2a68f22aa286
children bd745ae2b115
files toys/pending/compress.c
diffstat 1 files changed, 52 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/toys/pending/compress.c	Sun Feb 16 17:31:33 2014 -0600
+++ b/toys/pending/compress.c	Fri Feb 21 22:21:59 2014 -0600
@@ -11,9 +11,11 @@
  * LSB 4.1 has gzip, gunzip, and zcat
  * TODO: zip -d DIR -x LIST -list -quiet -no overwrite -overwrite -p to stdout
 
-// Accept many different kinds of command line argument:
+// Accept many different kinds of command line argument.
+// Leave Lrg at end so flag values line up.
 
-USE_COMPRESS(NEWTOY(compress, "zglrcd9[-cd][!zglr]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_COMPRESS(NEWTOY(compress, "zcd9Lrg[-cd][!zgLr]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_COMPRESS(NEWTOY(zcat, "aLrg[!aLrg]", TOYFLAG_USR|TOYFLAG_BIN))
 
 //zip unzip gzip gunzip zcat
 
@@ -25,12 +27,17 @@
 
     Compress or decompress file (or stdin) using "deflate" algorithm.
 
-    -c	compress
-    -d	decompress
-    -g	gzip
-    -l	zlib
-    -r	raw (default)
-    -z	zip
+    -c	compress with -g gzip (default)  -L zlib  -r raw  -z zip
+    -d	decompress (autodetects type)
+
+config ZCAT
+  bool "zcat"
+  default n
+  depends on COMPRESS
+  help
+    usage: zcat [FILE...]
+
+    Decompress deflated file(s) to stdout
 */
 
 #define FOR_compress
@@ -40,6 +47,7 @@
   // base offset and extra bits tables (length and distance)
   char lenbits[29], distbits[30];
   unsigned short lenbase[29], distbase[30];
+  void *fixdisthuff, *fixlithuff;
 
   unsigned (*crcfunc)(char *data, int len);
   unsigned crc;
@@ -102,7 +110,7 @@
     int click = bb->bitpos >> 3, blow, blen;
 
     // Load more data if buffer empty
-    if (click == bb->len) bitbuf_skip(bb, 0);
+    if (click == bb->len) bitbuf_skip(bb, click = 0);
 
     // grab bits from next byte
     blow = bb->bitpos & 7;
@@ -123,7 +131,7 @@
 
   if (!(TT.outlen & 32767)) {
     xwrite(TT.outfd, TT.outbuf, 32768);
-    if (TT.crcfunc) TT.crcfunc(0, 32768);
+    TT.crcfunc(0, 32768);
   }
 }
 
@@ -180,11 +188,6 @@
 // Decompress deflated data from bitbuf to filehandle.
 static void inflate(struct bitbuf *bb)
 {
-  struct huff *disthuff, *lithuff, *fixdisthuff = (struct huff *)(toybuf+2048),
-               *fixlithuff = (struct huff *)(toybuf+2560);
-
-//  len2huff(
-
   TT.crc = ~0;
   // repeat until spanked
   for (;;) {
@@ -195,17 +198,17 @@
 
     if (type == 3) error_exit("bad type");
 
-    // no compression?
+    // Uncompressed block?
     if (!type) {
       int len, nlen;
 
       // Align to byte, read length
-      bitbuf_skip(bb, bb->bitpos & 7);
+      bitbuf_skip(bb, (8-bb->bitpos)&7);
       len = bitbuf_get(bb, 16);
       nlen = bitbuf_get(bb, 16);
       if (len != (0xffff & ~nlen)) error_exit("bad len");
 
-      // Dump output data
+      // Dump literal output data
       while (len) {
         int pos = bb->bitpos >> 3, bblen = bb->len - pos;
         char *p = bb->buf+pos;
@@ -220,10 +223,11 @@
 
     // Compressed block
     } else {
+      struct huff *disthuff, *lithuff;
 
       // Dynamic huffman codes?
       if (type == 2) {
-        struct huff *h2 = (struct huff *)(toybuf+512);
+        struct huff *h2 = ((struct huff *)toybuf)+1;
         int i, litlen, distlen, hufflen;
         char *hufflen_order = "\x10\x11\x12\0\x08\x07\x09\x06\x0a\x05\x0b"
                               "\x04\x0c\x03\x0d\x02\x0e\x01\x0f", *bits;
@@ -258,19 +262,23 @@
         }
         if (i > litlen+distlen) error_exit("bad tree");
 
-        len2huff(lithuff = (struct huff *)(toybuf+1024), bits, litlen);
-        len2huff(disthuff = (struct huff *)(toybuf+1536), bits+litlen, distlen);
+        len2huff(lithuff = ((struct huff *)toybuf)+2, bits, litlen);
+        len2huff(disthuff = ((struct huff *)toybuf)+3, bits+litlen, distlen);
 
       // Static huffman codes
       } else {
-        lithuff = fixlithuff;
-        disthuff = fixdisthuff;
-error_exit("todo static huffman init");
+        lithuff = TT.fixlithuff;
+        disthuff = TT.fixdisthuff;
       }
+
+      // Use huffman tables to decode block of compressed symbols
       for (;;) {
         int sym = huff_and_puff(bb, lithuff);
 
+        // Literal?
         if (sym < 256) outbuf_crc(sym);
+
+        // Copy range?
         else if (sym > 256) {
           int len, dist;
 
@@ -281,10 +289,13 @@
           sym = TT.outlen & 32767;
 
           while (len--) outbuf_crc(TT.outbuf[(TT.outlen-dist) & 32767]);
+
+        // End of block
         } else break;
       }
     }
 
+    // Was that the last block?
     if (final) break;
   }
   if (TT.outlen & 32767) xwrite(TT.outfd, TT.outbuf, TT.outlen & 32767);
@@ -317,6 +328,12 @@
     if (i>3 && !(i&1)) n++;
     TT.distbits[i] = n;
   }
+
+  // Init fixed huffman tables
+  for (i=0; i<288; i++) toybuf[i] = 8 + (i>143) - ((i>255)<<1) + (i>279);
+  len2huff(TT.fixlithuff = ((struct huff *)toybuf)+4, toybuf, 288);
+  memset(toybuf, 5, 30);
+  len2huff(TT.fixdisthuff = ((struct huff *)toybuf)+5, toybuf, 30);
 }
 
 // Return true/false whether we consumed a gzip header.
@@ -338,7 +355,7 @@
   return 1;
 }
 
-static void do_gzip(int fd, char *name)
+static void do_zcat(int fd, char *name)
 {
   struct bitbuf *bb = bitbuf_init(fd, sizeof(toybuf));
 
@@ -355,7 +372,16 @@
 
 void compress_main(void)
 {
+  zcat_main();
+}
+
+//#define CLEANUP_compress
+//#define FOR_zcat
+//#include "generated/flags.h"
+
+void zcat_main(void)
+{
   init_deflate();
 
-  loopfiles(toys.optargs, do_gzip);
+  loopfiles(toys.optargs, do_zcat);
 }