master xplshn/aruu / cmd / pseudo / gzip.c
  1/* see LICENSE file for copyright and license details */
  2
  3/* deflate decoder adapted from puff.c, mark adlers rfc 1951 reference
  4 * decoder. zlib license: copyright (c) 2002-2013 mark adler, provided
  5 * as-is, free to use/alter/redistribute, origin not misrepresented,
  6 * this notice kept. see zlib.net */
  7
  8#include <setjmp.h>
  9#include <stdint.h>
 10#include <stdio.h>
 11#include <stdlib.h>
 12#include <string.h>
 13#include <time.h>
 14#include <unistd.h>
 15
 16#include "util.h"
 17
 18#define MAXBITS   15
 19#define MAXLCODES 286
 20#define MAXDCODES 30
 21#define MAXCODES  (MAXLCODES + MAXDCODES)
 22#define FIXLCODES 288
 23
 24struct InflateState {
 25  unsigned char *out;
 26  unsigned long  outlen;
 27  unsigned long  outcnt;
 28
 29  const unsigned char *in;
 30  unsigned long         inlen;
 31  unsigned long         incnt;
 32  int                   bitbuf;
 33  int                   bitcnt;
 34
 35  jmp_buf env;
 36};
 37
 38struct Huffman {
 39  short *count;
 40  short *symbol;
 41};
 42
 43static int
 44inflate_bits(struct InflateState *s, int need)
 45{
 46  long val;
 47
 48  val = s->bitbuf;
 49  while (s->bitcnt < need) {
 50    if (s->incnt == s->inlen)
 51      longjmp(s->env, 1);
 52    val |= (long)(s->in[s->incnt++]) << s->bitcnt;
 53    s->bitcnt += 8;
 54  }
 55
 56  s->bitbuf = (int)(val >> need);
 57  s->bitcnt -= need;
 58
 59  return (int)(val & ((1L << need) - 1));
 60}
 61
 62static int
 63inflate_stored(struct InflateState *s)
 64{
 65  unsigned len;
 66
 67  s->bitbuf = 0;
 68  s->bitcnt = 0;
 69
 70  if (s->incnt + 4 > s->inlen)
 71    return 2;
 72  len = s->in[s->incnt++];
 73  len |= s->in[s->incnt++] << 8;
 74  if (s->in[s->incnt++] != (~len & 0xff) || s->in[s->incnt++] != ((~len >> 8) & 0xff))
 75    return -2;
 76
 77  if (s->incnt + len > s->inlen)
 78    return 2;
 79  if (s->out != NULL) {
 80    if (s->outcnt + len > s->outlen)
 81      return 1;
 82    while (len--)
 83      s->out[s->outcnt++] = s->in[s->incnt++];
 84  } else {
 85    s->outcnt += len;
 86    s->incnt += len;
 87  }
 88
 89  return 0;
 90}
 91
 92/* codes are bit-reversed on the wire, rebuilt one bit at a time here */
 93static int
 94inflate_decode(struct InflateState *s, const struct Huffman *h)
 95{
 96  int    len, code, first, count, index;
 97  int    bitbuf, left;
 98  short *next;
 99
100  bitbuf = s->bitbuf;
101  left   = s->bitcnt;
102  code = first = index = 0;
103  len          = 1;
104  next         = h->count + 1;
105  for (;;) {
106    while (left--) {
107      code |= bitbuf & 1;
108      bitbuf >>= 1;
109      count = *next++;
110      if (code - count < first) {
111        s->bitbuf = bitbuf;
112        s->bitcnt = (s->bitcnt - len) & 7;
113        return h->symbol[index + (code - first)];
114      }
115      index += count;
116      first += count;
117      first <<= 1;
118      code <<= 1;
119      len++;
120    }
121    left = (MAXBITS + 1) - len;
122    if (left == 0)
123      break;
124    if (s->incnt == s->inlen)
125      longjmp(s->env, 1);
126    bitbuf = s->in[s->incnt++];
127    if (left > 8)
128      left = 8;
129  }
130  return -10;
131}
132
133/* 0: complete code, > 0: incomplete but usable, < 0: over-subscribed */
134static int
135huffman_construct(struct Huffman *h, const short *length, int n)
136{
137  int   symbol, len, left;
138  short offs[MAXBITS + 1];
139
140  for (len = 0; len <= MAXBITS; len++)
141    h->count[len] = 0;
142  for (symbol = 0; symbol < n; symbol++)
143    (h->count[length[symbol]])++;
144  if (h->count[0] == n)
145    return 0;
146
147  left = 1;
148  for (len = 1; len <= MAXBITS; len++) {
149    left <<= 1;
150    left -= h->count[len];
151    if (left < 0)
152      return left;
153  }
154
155  offs[1] = 0;
156  for (len = 1; len < MAXBITS; len++)
157    offs[len + 1] = offs[len] + h->count[len];
158
159  for (symbol = 0; symbol < n; symbol++)
160    if (length[symbol] != 0)
161      h->symbol[offs[length[symbol]]++] = symbol;
162
163  return left;
164}
165
166static int
167inflate_codes(struct InflateState *s, const struct Huffman *lencode, const struct Huffman *distcode)
168{
169  int            symbol, len;
170  unsigned       dist;
171  static const short lens[29] = {3,  4,  5,  6,  7,  8,  9,  10, 11,  13,  15,  17,  19,
172                                  23, 27, 31, 35, 43, 51, 59, 67, 83,  99,  115, 131,
173                                  163, 195, 227, 258};
174  static const short lext[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2,
175                                  2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
176  static const short dists[30] = {1,    2,    3,    4,    5,    7,    9,    13,   17,    25,
177                                   33,   49,   65,   97,   129,  193,  257,  385,  513,   769,
178                                   1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
179  static const short dext[30] = {0, 0, 0, 0, 1, 1, 2, 2, 3,  3,  4,  4,  5,  5,  6,
180                                  6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
181
182  do {
183    symbol = inflate_decode(s, lencode);
184    if (symbol < 0)
185      return symbol;
186    if (symbol < 256) {
187      if (s->out != NULL) {
188        if (s->outcnt == s->outlen)
189          return 1;
190        s->out[s->outcnt] = symbol;
191      }
192      s->outcnt++;
193    } else if (symbol > 256) {
194      symbol -= 257;
195      if (symbol >= 29)
196        return -10;
197      len = lens[symbol] + inflate_bits(s, lext[symbol]);
198
199      symbol = inflate_decode(s, distcode);
200      if (symbol < 0)
201        return symbol;
202      dist = dists[symbol] + inflate_bits(s, dext[symbol]);
203      if (dist > s->outcnt)
204        return -11;
205
206      if (s->out != NULL) {
207        if (s->outcnt + len > s->outlen)
208          return 1;
209        while (len--) {
210          s->out[s->outcnt] = s->out[s->outcnt - dist];
211          s->outcnt++;
212        }
213      } else {
214        s->outcnt += len;
215      }
216    }
217  } while (symbol != 256);
218
219  return 0;
220}
221
222static int
223inflate_fixed(struct InflateState *s)
224{
225  static int          built;
226  static short        lencnt[MAXBITS + 1], lensym[FIXLCODES];
227  static short        distcnt[MAXBITS + 1], distsym[MAXDCODES];
228  static struct Huffman lencode, distcode;
229
230  if (!built) {
231    int   symbol;
232    short lengths[FIXLCODES];
233
234    lencode.count  = lencnt;
235    lencode.symbol = lensym;
236    distcode.count  = distcnt;
237    distcode.symbol = distsym;
238
239    for (symbol = 0; symbol < 144; symbol++)
240      lengths[symbol] = 8;
241    for (; symbol < 256; symbol++)
242      lengths[symbol] = 9;
243    for (; symbol < 280; symbol++)
244      lengths[symbol] = 7;
245    for (; symbol < FIXLCODES; symbol++)
246      lengths[symbol] = 8;
247    huffman_construct(&lencode, lengths, FIXLCODES);
248
249    for (symbol = 0; symbol < MAXDCODES; symbol++)
250      lengths[symbol] = 5;
251    huffman_construct(&distcode, lengths, MAXDCODES);
252
253    built = 1;
254  }
255
256  return inflate_codes(s, &lencode, &distcode);
257}
258
259static int
260inflate_dynamic(struct InflateState *s)
261{
262  int            nlen, ndist, ncode, index, err;
263  short          lengths[MAXCODES];
264  short          lencnt[MAXBITS + 1], lensym[MAXLCODES];
265  short          distcnt[MAXBITS + 1], distsym[MAXDCODES];
266  struct Huffman lencode, distcode;
267  static const short order[19] = {16, 17, 18, 0, 8,  7, 9,  6, 10, 5,
268                                   11, 4,  12, 3, 13, 2, 14, 1, 15};
269
270  lencode.count  = lencnt;
271  lencode.symbol = lensym;
272  distcode.count  = distcnt;
273  distcode.symbol = distsym;
274
275  nlen  = inflate_bits(s, 5) + 257;
276  ndist = inflate_bits(s, 5) + 1;
277  ncode = inflate_bits(s, 4) + 4;
278  if (nlen > MAXLCODES || ndist > MAXDCODES)
279    return -3;
280
281  for (index = 0; index < ncode; index++)
282    lengths[order[index]] = inflate_bits(s, 3);
283  for (; index < 19; index++)
284    lengths[order[index]] = 0;
285
286  err = huffman_construct(&lencode, lengths, 19);
287  if (err != 0)
288    return -4;
289
290  index = 0;
291  while (index < nlen + ndist) {
292    int symbol, len;
293
294    symbol = inflate_decode(s, &lencode);
295    if (symbol < 0)
296      return symbol;
297    if (symbol < 16) {
298      lengths[index++] = symbol;
299    } else {
300      len = 0;
301      if (symbol == 16) {
302        if (index == 0)
303          return -5;
304        len    = lengths[index - 1];
305        symbol = 3 + inflate_bits(s, 2);
306      } else if (symbol == 17) {
307        symbol = 3 + inflate_bits(s, 3);
308      } else {
309        symbol = 11 + inflate_bits(s, 7);
310      }
311      if (index + symbol > nlen + ndist)
312        return -6;
313      while (symbol--)
314        lengths[index++] = len;
315    }
316  }
317
318  if (lengths[256] == 0)
319    return -9;
320
321  err = huffman_construct(&lencode, lengths, nlen);
322  if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1]))
323    return -7;
324
325  err = huffman_construct(&distcode, lengths + nlen, ndist);
326  if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1]))
327    return -8;
328
329  return inflate_codes(s, &lencode, &distcode);
330}
331
332/* raw deflate (rfc 1951) decoder; dest null just computes destlen */
333static int
334inflate_raw(unsigned char *dest, unsigned long *destlen, const unsigned char *source,
335            unsigned long *sourcelen)
336{
337  struct InflateState s;
338  int                 last, type, err;
339
340  s.out    = dest;
341  s.outlen = *destlen;
342  s.outcnt = 0;
343
344  s.in     = source;
345  s.inlen  = *sourcelen;
346  s.incnt  = 0;
347  s.bitbuf = 0;
348  s.bitcnt = 0;
349
350  if (setjmp(s.env) != 0) {
351    err = 2;
352  } else {
353    do {
354      last = inflate_bits(&s, 1);
355      type = inflate_bits(&s, 2);
356      err  = type == 0   ? inflate_stored(&s)
357             : type == 1 ? inflate_fixed(&s)
358             : type == 2 ? inflate_dynamic(&s)
359                          : -1;
360      if (err != 0)
361        break;
362    } while (!last);
363  }
364
365  if (err <= 0) {
366    *destlen   = s.outcnt;
367    *sourcelen = s.incnt;
368  }
369  return err;
370}
371
372static uint32_t crc32_table[256];
373
374static void
375crc32_init(void)
376{
377  uint32_t c;
378  int      n, k;
379
380  for (n = 0; n < 256; n++) {
381    c = (uint32_t)n;
382    for (k = 0; k < 8; k++)
383      c = (c & 1) ? (0xedb88320u ^ (c >> 1)) : (c >> 1);
384    crc32_table[n] = c;
385  }
386}
387
388static uint32_t
389crc32_update(uint32_t crc, const unsigned char *buf, size_t len)
390{
391  crc = ~crc;
392  while (len--)
393    crc = crc32_table[(crc ^ *buf++) & 0xff] ^ (crc >> 8);
394  return ~crc;
395}
396
397static uint32_t
398get_le32(const unsigned char *p)
399{
400  return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
401}
402
403static void
404put_le32(unsigned char *p, uint32_t v)
405{
406  p[0] = v & 0xff;
407  p[1] = (v >> 8) & 0xff;
408  p[2] = (v >> 16) & 0xff;
409  p[3] = (v >> 24) & 0xff;
410}
411
412/* FLG bits in the gzip header (rfc 1952) */
413enum GzipFlag {
414  GZ_FTEXT    = 1 << 0,
415  GZ_FHCRC    = 1 << 1,
416  GZ_FEXTRA   = 1 << 2,
417  GZ_FNAME    = 1 << 3,
418  GZ_FCOMMENT = 1 << 4,
419};
420
421static unsigned char *
422read_all(FILE *fp, size_t *len)
423{
424  unsigned char *buf;
425  size_t         cap, n;
426  ssize_t        r;
427
428  cap = 1 << 16;
429  buf = emalloc(cap);
430  n   = 0;
431  for (;;) {
432    if (n == cap) {
433      cap *= 2;
434      buf = erealloc(buf, cap);
435    }
436    r = fread(buf + n, 1, cap - n, fp);
437    if (r <= 0)
438      break;
439    n += (size_t)r;
440  }
441  if (ferror(fp))
442    eprintf("read:");
443  *len = n;
444  return buf;
445}
446
447/* decodes one gzip member; multi-member streams are not supported */
448static void
449gunzip(const unsigned char *in, size_t inlen, FILE *out)
450{
451  size_t   pos, hdr;
452  unsigned flg;
453  unsigned char *dest;
454  unsigned long  destlen, srclen;
455  uint32_t       want_crc, want_isize, got_crc;
456  int            err;
457
458  if (inlen < 18 || in[0] != 0x1f || in[1] != 0x8b)
459    eprintf("gzip: not in gzip format\n");
460  if (in[2] != 8)
461    eprintf("gzip: unsupported compression method\n");
462
463  flg = in[3];
464  pos = 10;
465
466  if (flg & GZ_FEXTRA) {
467    unsigned xlen;
468    if (pos + 2 > inlen)
469      eprintf("gzip: truncated header\n");
470    xlen = in[pos] | (in[pos + 1] << 8);
471    pos += 2 + xlen;
472  }
473  if (flg & GZ_FNAME) {
474    while (pos < inlen && in[pos] != '\0')
475      pos++;
476    pos++;
477  }
478  if (flg & GZ_FCOMMENT) {
479    while (pos < inlen && in[pos] != '\0')
480      pos++;
481    pos++;
482  }
483  if (flg & GZ_FHCRC)
484    pos += 2;
485  if (pos + 8 > inlen)
486    eprintf("gzip: truncated header\n");
487
488  hdr = pos;
489
490  /* first pass just measures destlen, second pass does the real decode */
491  destlen = 0;
492  srclen  = (unsigned long)(inlen - hdr - 8);
493  err     = inflate_raw(NULL, &destlen, in + hdr, &srclen);
494  if (err != 0)
495    eprintf("gzip: corrupt compressed data\n");
496
497  dest    = emalloc(destlen ? destlen : 1);
498  srclen  = (unsigned long)(inlen - hdr - 8);
499  destlen = destlen ? destlen : 1;
500  err     = inflate_raw(dest, &destlen, in + hdr, &srclen);
501  if (err != 0)
502    eprintf("gzip: corrupt compressed data\n");
503
504  want_crc   = get_le32(in + hdr + srclen);
505  want_isize = get_le32(in + hdr + srclen + 4);
506  got_crc    = crc32_update(0, dest, destlen);
507  if (got_crc != want_crc)
508    eprintf("gzip: crc mismatch\n");
509  if ((uint32_t)destlen != want_isize)
510    eprintf("gzip: size mismatch\n");
511
512  if (fwrite(dest, 1, destlen, out) != destlen)
513    eprintf("write:");
514  free(dest);
515}
516
517/* stored (uncompressed) deflate blocks: no compression, always valid */
518static void
519gzip_write_stored(const unsigned char *in, size_t len, FILE *out)
520{
521  unsigned char hdr[5];
522  size_t        chunk;
523  int           last;
524
525  if (len == 0) {
526    hdr[0] = 1;
527    hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0;
528    if (fwrite(hdr, 1, 5, out) != 5)
529      eprintf("write:");
530    return;
531  }
532
533  while (len > 0) {
534    chunk = len > 65535 ? 65535 : len;
535    last  = chunk == len;
536
537    hdr[0] = last ? 1 : 0;
538    hdr[1] = chunk & 0xff;
539    hdr[2] = (chunk >> 8) & 0xff;
540    hdr[3] = (~chunk) & 0xff;
541    hdr[4] = ((~chunk) >> 8) & 0xff;
542
543    if (fwrite(hdr, 1, 5, out) != 5 || fwrite(in, 1, chunk, out) != chunk)
544      eprintf("write:");
545
546    in += chunk;
547    len -= chunk;
548  }
549}
550
551static void
552gzip_compress(const unsigned char *in, size_t len, const char *name, FILE *out)
553{
554  unsigned char hdr[10];
555  unsigned char trl[8];
556  uint32_t      crc;
557
558  hdr[0] = 0x1f;
559  hdr[1] = 0x8b;
560  hdr[2] = 8;
561  hdr[3] = name ? GZ_FNAME : 0;
562  put_le32(hdr + 4, 0);
563  hdr[8] = 0;
564  hdr[9] = 255;
565  if (fwrite(hdr, 1, 10, out) != 10)
566    eprintf("write:");
567  if (name && (fwrite(name, 1, strlen(name) + 1, out) != strlen(name) + 1))
568    eprintf("write:");
569
570  gzip_write_stored(in, len, out);
571
572  crc = crc32_update(0, in, len);
573  put_le32(trl, crc);
574  put_le32(trl + 4, (uint32_t)len);
575  if (fwrite(trl, 1, 8, out) != 8)
576    eprintf("write:");
577}
578
579static char *
580strip_gz_suffix(const char *name)
581{
582  size_t n = strlen(name);
583  if (n > 3 && strcmp(name + n - 3, ".gz") == 0)
584    return estrndup(name, n - 3);
585  return NULL;
586}
587
588static void
589usage(void)
590{
591  eprintf("usage: %s [-cdfkn] [-1..-9] [file ...]\n", argv0);
592}
593
594// ?man gzip: compress or decompress files
595// ?man arguments: [file ...]
596// ?man with no files, reads standard input and writes standard output
597// ?man compressing replaces each file with file.gz; decompressing
598// ?man reverses that. only single-member gzip streams are read back
599int
600main(int argc, char *argv[])
601{
602  int  dflag = 0, cflag = 0, fflag = 0, kflag = 0, nflag = 0;
603  int  i;
604  char outname[4096];
605
606  ARGBEGIN
607  {
608    // ?man -c: write to standard output, keep the input file
609    case 'c':
610      cflag = 1;
611      break;
612    // ?man -d: decompress instead of compress
613    case 'd':
614      dflag = 1;
615      break;
616    // ?man -f: accepted for compatibility, no effect
617    case 'f':
618      fflag = 1;
619      break;
620    // ?man -k: keep the input file instead of removing it
621    case 'k':
622      kflag = 1;
623      break;
624    // ?man -n: omit the original file name from the header
625    case 'n':
626      nflag = 1;
627      break;
628    // ?man -1: accepted for compatibility, no effect (stored blocks only)
629    case '1':
630    case '2':
631    case '3':
632    case '4':
633    case '5':
634    case '6':
635    case '7':
636    case '8':
637    case '9':
638      break;
639    default:
640      usage();
641  }
642  ARGEND
643
644  (void)fflag;
645  crc32_init();
646
647  if (argc == 0) {
648    unsigned char *buf;
649    size_t         len;
650
651    buf = read_all(stdin, &len);
652    if (dflag)
653      gunzip(buf, len, stdout);
654    else
655      gzip_compress(buf, len, NULL, stdout);
656    free(buf);
657    return 0;
658  }
659
660  for (i = 0; i < argc; i++) {
661    FILE          *fp;
662    unsigned char *buf;
663    size_t         len;
664    char          *stripped;
665
666    fp = fopen(argv[i], "rb");
667    if (!fp) {
668      weprintf("open %s:", argv[i]);
669      continue;
670    }
671    buf = read_all(fp, &len);
672    fclose(fp);
673
674    if (dflag) {
675      if (cflag) {
676        gunzip(buf, len, stdout);
677      } else {
678        stripped = strip_gz_suffix(argv[i]);
679        if (!stripped)
680          eprintf("gzip: %s: unknown suffix, ignored\n", argv[i]);
681        strlcpy(outname, stripped, sizeof(outname));
682        free(stripped);
683
684        fp = fopen(outname, "wb");
685        if (!fp)
686          eprintf("open %s:", outname);
687        gunzip(buf, len, fp);
688        if (fclose(fp))
689          eprintf("close %s:", outname);
690        if (!kflag && unlink(argv[i]) < 0)
691          weprintf("unlink %s:", argv[i]);
692      }
693    } else {
694      if (cflag) {
695        gzip_compress(buf, len, NULL, stdout);
696      } else {
697        strlcpy(outname, argv[i], sizeof(outname));
698        strlcat(outname, ".gz", sizeof(outname));
699
700        fp = fopen(outname, "wb");
701        if (!fp)
702          eprintf("open %s:", outname);
703        gzip_compress(buf, len, nflag ? NULL : argv[i], fp);
704        if (fclose(fp))
705          eprintf("close %s:", outname);
706        if (!kflag && unlink(argv[i]) < 0)
707          weprintf("unlink %s:", argv[i]);
708      }
709    }
710
711    free(buf);
712  }
713
714  return 0;
715}