OSDN Git Service

Update inflate code: fixed tables, bugfixes, zcat alias.
authorRob Landley <rob@landley.net>
Sat, 22 Feb 2014 04:21:59 +0000 (22:21 -0600)
committerRob Landley <rob@landley.net>
Sat, 22 Feb 2014 04:21:59 +0000 (22:21 -0600)
toys/pending/compress.c

index acc7d62..9c9ae2e 100644 (file)
  * 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 @@ config COMPRESS
 
     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 @@ GLOBALS(
   // 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 bitbuf_get(struct bitbuf *bb, int bits)
     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 @@ static void outbuf_crc(char sym)
 
   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 @@ static unsigned huff_and_puff(struct bitbuf *bb, struct huff *huff)
 // 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 @@ static void inflate(struct bitbuf *bb)
 
     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 @@ static void inflate(struct bitbuf *bb)
 
     // 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 @@ static void inflate(struct bitbuf *bb)
         }
         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 @@ error_exit("todo static huffman init");
           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 @@ static void init_deflate(void)
     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 @@ static int is_gzip(struct bitbuf *bb)
   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 @@ static void do_gzip(int fd, char *name)
 
 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);
 }