summaryrefslogtreecommitdiff
path: root/contrib/puff
diff options
context:
space:
mode:
authorMark Adler <madler@alumni.caltech.edu>2011-09-11 11:04:49 -0700
committerMark Adler <madler@alumni.caltech.edu>2011-09-11 11:04:49 -0700
commit10daf0d4d7815447799d555d04d30325836e1d44 (patch)
tree75579fbe11e42dc3197acca53f5f887ac3808b57 /contrib/puff
parent9712272c78b9d9c93746d9c8e156a3728c65ca72 (diff)
downloadzlib-1.2.5.1.tar.gz
zlib-1.2.5.1.tar.bz2
zlib-1.2.5.1.zip
zlib 1.2.5.1v1.2.5.1
Diffstat (limited to 'contrib/puff')
-rw-r--r--contrib/puff/Makefile40
-rw-r--r--contrib/puff/puff.c252
-rw-r--r--contrib/puff/puff.h8
-rw-r--r--contrib/puff/pufftest.c165
-rw-r--r--contrib/puff/zeros.rawbin1213 -> 2517 bytes
5 files changed, 275 insertions, 190 deletions
diff --git a/contrib/puff/Makefile b/contrib/puff/Makefile
index b6b6940..0e2594c 100644
--- a/contrib/puff/Makefile
+++ b/contrib/puff/Makefile
@@ -1,8 +1,42 @@
1puff: puff.c puff.h 1CFLAGS=-O
2 cc -DTEST -o puff puff.c 2
3puff: puff.o pufftest.o
4
5puff.o: puff.h
6
7pufftest.o: puff.h
3 8
4test: puff 9test: puff
5 puff zeros.raw 10 puff zeros.raw
6 11
12puft: puff.c puff.h pufftest.o
13 cc -fprofile-arcs -ftest-coverage -o puft puff.c pufftest.o
14
15# puff full coverage test (should say 100%)
16cov: puft
17 @rm -f *.gcov *.gcda
18 @puft -w zeros.raw 2>&1 | cat > /dev/null
19 @echo '04' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2
20 @echo '00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2
21 @echo '00 00 00 00 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 254
22 @echo '00 01 00 fe ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2
23 @echo '01 01 00 fe ff 0a' | xxd -r -p | puft -f 2>&1 | cat > /dev/null
24 @echo '02 7e ff ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 246
25 @echo '02' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2
26 @echo '04 80 49 92 24 49 92 24 0f b4 ff ff c3 04' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2
27 @echo '04 80 49 92 24 49 92 24 71 ff ff 93 11 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 249
28 @echo '04 c0 81 08 00 00 00 00 20 7f eb 0b 00 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 246
29 @echo '0b 00 00' | xxd -r -p | puft -f 2>&1 | cat > /dev/null
30 @echo '1a 07' | xxd -r -p | puft 2> /dev/null || test $$? -eq 246
31 @echo '0c c0 81 00 00 00 00 00 90 ff 6b 04' | xxd -r -p | puft 2> /dev/null || test $$? -eq 245
32 @puft -f zeros.raw 2>&1 | cat > /dev/null
33 @echo 'fc 00 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 253
34 @echo '04 00 fe ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 252
35 @echo '04 00 24 49' | xxd -r -p | puft 2> /dev/null || test $$? -eq 251
36 @echo '04 80 49 92 24 49 92 24 0f b4 ff ff c3 84' | xxd -r -p | puft 2> /dev/null || test $$? -eq 248
37 @echo '04 00 24 e9 ff ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 250
38 @echo '04 00 24 e9 ff 6d' | xxd -r -p | puft 2> /dev/null || test $$? -eq 247
39 @gcov -n puff.c
40
7clean: 41clean:
8 rm -f puff puff.o 42 rm -f puff puft *.o *.gc*
diff --git a/contrib/puff/puff.c b/contrib/puff/puff.c
index 650694e..df8470c 100644
--- a/contrib/puff/puff.c
+++ b/contrib/puff/puff.c
@@ -2,7 +2,7 @@
2 * puff.c 2 * puff.c
3 * Copyright (C) 2002-2010 Mark Adler 3 * Copyright (C) 2002-2010 Mark Adler
4 * For conditions of distribution and use, see copyright notice in puff.h 4 * For conditions of distribution and use, see copyright notice in puff.h
5 * version 2.1, 4 Apr 2010 5 * version 2.2, 25 Apr 2010
6 * 6 *
7 * puff.c is a simple inflate written to be an unambiguous way to specify the 7 * puff.c is a simple inflate written to be an unambiguous way to specify the
8 * deflate format. It is not written for speed but rather simplicity. As a 8 * deflate format. It is not written for speed but rather simplicity. As a
@@ -49,9 +49,9 @@
49 * - Fix fixed codes table error 49 * - Fix fixed codes table error
50 * - Provide a scanning mode for determining size of 50 * - Provide a scanning mode for determining size of
51 * uncompressed data 51 * uncompressed data
52 * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Jean-loup] 52 * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Gailly]
53 * - Add a puff.h file for the interface 53 * - Add a puff.h file for the interface
54 * - Add braces in puff() for else do [Jean-loup] 54 * - Add braces in puff() for else do [Gailly]
55 * - Use indexes instead of pointers for readability 55 * - Use indexes instead of pointers for readability
56 * 1.4 31 Mar 2002 - Simplify construct() code set check 56 * 1.4 31 Mar 2002 - Simplify construct() code set check
57 * - Fix some comments 57 * - Fix some comments
@@ -69,13 +69,19 @@
69 * - Allow TEST code to read from piped stdin 69 * - Allow TEST code to read from piped stdin
70 * 2.1 4 Apr 2010 - Avoid variable initialization for happier compilers 70 * 2.1 4 Apr 2010 - Avoid variable initialization for happier compilers
71 * - Avoid unsigned comparisons for even happier compilers 71 * - Avoid unsigned comparisons for even happier compilers
72 * 2.2 25 Apr 2010 - Fix bug in variable initializations [Oberhumer]
73 * - Add const where appropriate [Oberhumer]
74 * - Split if's and ?'s for coverage testing
75 * - Break out test code to separate file
76 * - Move NIL to puff.h
77 * - Allow incomplete code only if single code length is 1
78 * - Add full code coverage test to Makefile
72 */ 79 */
73 80
74#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */ 81#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */
75#include "puff.h" /* prototype for puff() */ 82#include "puff.h" /* prototype for puff() */
76 83
77#define local static /* for local function definitions */ 84#define local static /* for local function definitions */
78#define NIL ((unsigned char *)0) /* for no output option */
79 85
80/* 86/*
81 * Maximums for allocations and loops. It is not useful to change these -- 87 * Maximums for allocations and loops. It is not useful to change these --
@@ -95,7 +101,7 @@ struct state {
95 unsigned long outcnt; /* bytes written to out so far */ 101 unsigned long outcnt; /* bytes written to out so far */
96 102
97 /* input state */ 103 /* input state */
98 unsigned char *in; /* input buffer */ 104 const unsigned char *in; /* input buffer */
99 unsigned long inlen; /* available input at in */ 105 unsigned long inlen; /* available input at in */
100 unsigned long incnt; /* bytes read so far */ 106 unsigned long incnt; /* bytes read so far */
101 int bitbuf; /* bit buffer */ 107 int bitbuf; /* bit buffer */
@@ -123,7 +129,8 @@ local int bits(struct state *s, int need)
123 /* load at least need bits into val */ 129 /* load at least need bits into val */
124 val = s->bitbuf; 130 val = s->bitbuf;
125 while (s->bitcnt < need) { 131 while (s->bitcnt < need) {
126 if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */ 132 if (s->incnt == s->inlen)
133 longjmp(s->env, 1); /* out of input */
127 val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */ 134 val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */
128 s->bitcnt += 8; 135 s->bitcnt += 8;
129 } 136 }
@@ -162,7 +169,8 @@ local int stored(struct state *s)
162 s->bitcnt = 0; 169 s->bitcnt = 0;
163 170
164 /* get length and check against its one's complement */ 171 /* get length and check against its one's complement */
165 if (s->incnt + 4 > s->inlen) return 2; /* not enough input */ 172 if (s->incnt + 4 > s->inlen)
173 return 2; /* not enough input */
166 len = s->in[s->incnt++]; 174 len = s->in[s->incnt++];
167 len |= s->in[s->incnt++] << 8; 175 len |= s->in[s->incnt++] << 8;
168 if (s->in[s->incnt++] != (~len & 0xff) || 176 if (s->in[s->incnt++] != (~len & 0xff) ||
@@ -170,7 +178,8 @@ local int stored(struct state *s)
170 return -2; /* didn't match complement! */ 178 return -2; /* didn't match complement! */
171 179
172 /* copy len bytes from in to out */ 180 /* copy len bytes from in to out */
173 if (s->incnt + len > s->inlen) return 2; /* not enough input */ 181 if (s->incnt + len > s->inlen)
182 return 2; /* not enough input */
174 if (s->out != NIL) { 183 if (s->out != NIL) {
175 if (s->outcnt + len > s->outlen) 184 if (s->outcnt + len > s->outlen)
176 return 1; /* not enough output space */ 185 return 1; /* not enough output space */
@@ -222,7 +231,7 @@ struct huffman {
222 * in the deflate format. See the format notes for fixed() and dynamic(). 231 * in the deflate format. See the format notes for fixed() and dynamic().
223 */ 232 */
224#ifdef SLOW 233#ifdef SLOW
225local int decode(struct state *s, struct huffman *h) 234local int decode(struct state *s, const struct huffman *h)
226{ 235{
227 int len; /* current number of bits in code */ 236 int len; /* current number of bits in code */
228 int code; /* len bits being decoded */ 237 int code; /* len bits being decoded */
@@ -250,7 +259,7 @@ local int decode(struct state *s, struct huffman *h)
250 * a few percent larger. 259 * a few percent larger.
251 */ 260 */
252#else /* !SLOW */ 261#else /* !SLOW */
253local int decode(struct state *s, struct huffman *h) 262local int decode(struct state *s, const struct huffman *h)
254{ 263{
255 int len; /* current number of bits in code */ 264 int len; /* current number of bits in code */
256 int code; /* len bits being decoded */ 265 int code; /* len bits being decoded */
@@ -283,10 +292,13 @@ local int decode(struct state *s, struct huffman *h)
283 len++; 292 len++;
284 } 293 }
285 left = (MAXBITS+1) - len; 294 left = (MAXBITS+1) - len;
286 if (left == 0) break; 295 if (left == 0)
287 if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */ 296 break;
297 if (s->incnt == s->inlen)
298 longjmp(s->env, 1); /* out of input */
288 bitbuf = s->in[s->incnt++]; 299 bitbuf = s->in[s->incnt++];
289 if (left > 8) left = 8; 300 if (left > 8)
301 left = 8;
290 } 302 }
291 return -10; /* ran out of codes */ 303 return -10; /* ran out of codes */
292} 304}
@@ -324,7 +336,7 @@ local int decode(struct state *s, struct huffman *h)
324 * - Within a given code length, the symbols are kept in ascending order for 336 * - Within a given code length, the symbols are kept in ascending order for
325 * the code bits definition. 337 * the code bits definition.
326 */ 338 */
327local int construct(struct huffman *h, short *length, int n) 339local int construct(struct huffman *h, const short *length, int n)
328{ 340{
329 int symbol; /* current symbol when stepping through length[] */ 341 int symbol; /* current symbol when stepping through length[] */
330 int len; /* current length when stepping through h->count[] */ 342 int len; /* current length when stepping through h->count[] */
@@ -344,7 +356,8 @@ local int construct(struct huffman *h, short *length, int n)
344 for (len = 1; len <= MAXBITS; len++) { 356 for (len = 1; len <= MAXBITS; len++) {
345 left <<= 1; /* one more bit, double codes left */ 357 left <<= 1; /* one more bit, double codes left */
346 left -= h->count[len]; /* deduct count from possible codes */ 358 left -= h->count[len]; /* deduct count from possible codes */
347 if (left < 0) return left; /* over-subscribed--return negative */ 359 if (left < 0)
360 return left; /* over-subscribed--return negative */
348 } /* left > 0 means incomplete */ 361 } /* left > 0 means incomplete */
349 362
350 /* generate offsets into symbol table for each length for sorting */ 363 /* generate offsets into symbol table for each length for sorting */
@@ -420,8 +433,8 @@ local int construct(struct huffman *h, short *length, int n)
420 * defined to do the wrong thing in this case. 433 * defined to do the wrong thing in this case.
421 */ 434 */
422local int codes(struct state *s, 435local int codes(struct state *s,
423 struct huffman *lencode, 436 const struct huffman *lencode,
424 struct huffman *distcode) 437 const struct huffman *distcode)
425{ 438{
426 int symbol; /* decoded symbol */ 439 int symbol; /* decoded symbol */
427 int len; /* length for copy */ 440 int len; /* length for copy */
@@ -444,11 +457,13 @@ local int codes(struct state *s,
444 /* decode literals and length/distance pairs */ 457 /* decode literals and length/distance pairs */
445 do { 458 do {
446 symbol = decode(s, lencode); 459 symbol = decode(s, lencode);
447 if (symbol < 0) return symbol; /* invalid symbol */ 460 if (symbol < 0)
461 return symbol; /* invalid symbol */
448 if (symbol < 256) { /* literal: symbol is the byte */ 462 if (symbol < 256) { /* literal: symbol is the byte */
449 /* write out the literal */ 463 /* write out the literal */
450 if (s->out != NIL) { 464 if (s->out != NIL) {
451 if (s->outcnt == s->outlen) return 1; 465 if (s->outcnt == s->outlen)
466 return 1;
452 s->out[s->outcnt] = symbol; 467 s->out[s->outcnt] = symbol;
453 } 468 }
454 s->outcnt++; 469 s->outcnt++;
@@ -456,12 +471,14 @@ local int codes(struct state *s,
456 else if (symbol > 256) { /* length */ 471 else if (symbol > 256) { /* length */
457 /* get and compute length */ 472 /* get and compute length */
458 symbol -= 257; 473 symbol -= 257;
459 if (symbol >= 29) return -10; /* invalid fixed code */ 474 if (symbol >= 29)
475 return -10; /* invalid fixed code */
460 len = lens[symbol] + bits(s, lext[symbol]); 476 len = lens[symbol] + bits(s, lext[symbol]);
461 477
462 /* get and check distance */ 478 /* get and check distance */
463 symbol = decode(s, distcode); 479 symbol = decode(s, distcode);
464 if (symbol < 0) return symbol; /* invalid symbol */ 480 if (symbol < 0)
481 return symbol; /* invalid symbol */
465 dist = dists[symbol] + bits(s, dext[symbol]); 482 dist = dists[symbol] + bits(s, dext[symbol]);
466#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR 483#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
467 if (dist > s->outcnt) 484 if (dist > s->outcnt)
@@ -470,13 +487,15 @@ local int codes(struct state *s,
470 487
471 /* copy length bytes from distance bytes back */ 488 /* copy length bytes from distance bytes back */
472 if (s->out != NIL) { 489 if (s->out != NIL) {
473 if (s->outcnt + len > s->outlen) return 1; 490 if (s->outcnt + len > s->outlen)
491 return 1;
474 while (len--) { 492 while (len--) {
475 s->out[s->outcnt] = 493 s->out[s->outcnt] =
476#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR 494#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
477 dist > s->outcnt ? 0 : 495 dist > s->outcnt ?
496 0 :
478#endif 497#endif
479 s->out[s->outcnt - dist]; 498 s->out[s->outcnt - dist];
480 s->outcnt++; 499 s->outcnt++;
481 } 500 }
482 } 501 }
@@ -525,6 +544,12 @@ local int fixed(struct state *s)
525 int symbol; 544 int symbol;
526 short lengths[FIXLCODES]; 545 short lengths[FIXLCODES];
527 546
547 /* construct lencode and distcode */
548 lencode.count = lencnt;
549 lencode.symbol = lensym;
550 distcode.count = distcnt;
551 distcode.symbol = distsym;
552
528 /* literal/length table */ 553 /* literal/length table */
529 for (symbol = 0; symbol < 144; symbol++) 554 for (symbol = 0; symbol < 144; symbol++)
530 lengths[symbol] = 8; 555 lengths[symbol] = 8;
@@ -541,12 +566,6 @@ local int fixed(struct state *s)
541 lengths[symbol] = 5; 566 lengths[symbol] = 5;
542 construct(&distcode, lengths, MAXDCODES); 567 construct(&distcode, lengths, MAXDCODES);
543 568
544 /* construct lencode and distcode */
545 lencode.count = lencnt;
546 lencode.symbol = lensym;
547 distcode.count = distcnt;
548 distcode.symbol = distsym;
549
550 /* do this just once */ 569 /* do this just once */
551 virgin = 0; 570 virgin = 0;
552 } 571 }
@@ -675,7 +694,8 @@ local int dynamic(struct state *s)
675 694
676 /* build huffman table for code lengths codes (use lencode temporarily) */ 695 /* build huffman table for code lengths codes (use lencode temporarily) */
677 err = construct(&lencode, lengths, 19); 696 err = construct(&lencode, lengths, 19);
678 if (err != 0) return -4; /* require complete code set here */ 697 if (err != 0) /* require complete code set here */
698 return -4;
679 699
680 /* read length/literal and distance code length tables */ 700 /* read length/literal and distance code length tables */
681 index = 0; 701 index = 0;
@@ -689,7 +709,8 @@ local int dynamic(struct state *s)
689 else { /* repeat instruction */ 709 else { /* repeat instruction */
690 len = 0; /* assume repeating zeros */ 710 len = 0; /* assume repeating zeros */
691 if (symbol == 16) { /* repeat last length 3..6 times */ 711 if (symbol == 16) { /* repeat last length 3..6 times */
692 if (index == 0) return -5; /* no last length! */ 712 if (index == 0)
713 return -5; /* no last length! */
693 len = lengths[index - 1]; /* last length */ 714 len = lengths[index - 1]; /* last length */
694 symbol = 3 + bits(s, 2); 715 symbol = 3 + bits(s, 2);
695 } 716 }
@@ -710,13 +731,13 @@ local int dynamic(struct state *s)
710 731
711 /* build huffman table for literal/length codes */ 732 /* build huffman table for literal/length codes */
712 err = construct(&lencode, lengths, nlen); 733 err = construct(&lencode, lengths, nlen);
713 if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) 734 if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1]))
714 return -7; /* only allow incomplete codes if just one code */ 735 return -7; /* incomplete code ok only for single length 1 code */
715 736
716 /* build huffman table for distance codes */ 737 /* build huffman table for distance codes */
717 err = construct(&distcode, lengths + nlen, ndist); 738 err = construct(&distcode, lengths + nlen, ndist);
718 if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) 739 if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1]))
719 return -8; /* only allow incomplete codes if just one code */ 740 return -8; /* incomplete code ok only for single length 1 code */
720 741
721 /* decode data until end-of-block code */ 742 /* decode data until end-of-block code */
722 return codes(s, &lencode, &distcode); 743 return codes(s, &lencode, &distcode);
@@ -768,7 +789,7 @@ local int dynamic(struct state *s)
768 */ 789 */
769int puff(unsigned char *dest, /* pointer to destination pointer */ 790int puff(unsigned char *dest, /* pointer to destination pointer */
770 unsigned long *destlen, /* amount of output space */ 791 unsigned long *destlen, /* amount of output space */
771 unsigned char *source, /* pointer to source data pointer */ 792 const unsigned char *source, /* pointer to source data pointer */
772 unsigned long *sourcelen) /* amount of input available */ 793 unsigned long *sourcelen) /* amount of input available */
773{ 794{
774 struct state s; /* input/output state */ 795 struct state s; /* input/output state */
@@ -795,11 +816,15 @@ int puff(unsigned char *dest, /* pointer to destination pointer */
795 do { 816 do {
796 last = bits(&s, 1); /* one if last block */ 817 last = bits(&s, 1); /* one if last block */
797 type = bits(&s, 2); /* block type 0..3 */ 818 type = bits(&s, 2); /* block type 0..3 */
798 err = type == 0 ? stored(&s) : 819 err = type == 0 ?
799 (type == 1 ? fixed(&s) : 820 stored(&s) :
800 (type == 2 ? dynamic(&s) : 821 (type == 1 ?
801 -1)); /* type == 3, invalid */ 822 fixed(&s) :
802 if (err != 0) break; /* return with error */ 823 (type == 2 ?
824 dynamic(&s) :
825 -1)); /* type == 3, invalid */
826 if (err != 0)
827 break; /* return with error */
803 } while (!last); 828 } while (!last);
804 } 829 }
805 830
@@ -810,146 +835,3 @@ int puff(unsigned char *dest, /* pointer to destination pointer */
810 } 835 }
811 return err; 836 return err;
812} 837}
813
814#ifdef TEST
815/* Examples of how to use puff().
816
817 Usage: puff [-w] [-nnn] file
818 ... | puff [-w] [-nnn]
819
820 where file is the input file with deflate data, nnn is the number of bytes
821 of input to skip before inflating (e.g. to skip a zlib or gzip header), and
822 -w is used to write the decompressed data to stdout */
823
824#include <stdio.h>
825#include <stdlib.h>
826
827/* Return size times approximately the cube root of 2, keeping the result as 1,
828 3, or 5 times a power of 2 -- the result is always > size, until the result
829 is the maximum value of an unsigned long, where it remains. This is useful
830 to keep reallocations less than ~33% over the actual data. */
831local size_t bythirds(size_t size)
832{
833 int n;
834 size_t m;
835
836 m = size;
837 for (n = 0; m; n++)
838 m >>= 1;
839 if (n < 3)
840 return size + 1;
841 n -= 3;
842 m = size >> n;
843 m += m == 6 ? 2 : 1;
844 m <<= n;
845 return m > size ? m : (size_t)(-1);
846}
847
848/* Read the input file *name, or stdin if name is NULL, into allocated memory.
849 Reallocate to larger buffers until the entire file is read in. Return a
850 pointer to the allocated data, or NULL if there was a memory allocation
851 failure. *len is the number of bytes of data read from the input file (even
852 if load() returns NULL). If the input file was empty or could not be opened
853 or read, *len is zero. */
854local void *load(char *name, size_t *len)
855{
856 size_t size;
857 void *buf, *swap;
858 FILE *in;
859
860 *len = 0;
861 buf = malloc(size = 4096);
862 if (buf == NULL)
863 return NULL;
864 in = name == NULL ? stdin : fopen(name, "rb");
865 if (in != NULL) {
866 for (;;) {
867 *len += fread((char *)buf + *len, 1, size - *len, in);
868 if (*len < size) break;
869 size = bythirds(size);
870 if (size == *len || (swap = realloc(buf, size)) == NULL) {
871 free(buf);
872 buf = NULL;
873 break;
874 }
875 buf = swap;
876 }
877 fclose(in);
878 }
879 return buf;
880}
881
882int main(int argc, char **argv)
883{
884 int ret, put = 0;
885 unsigned skip = 0;
886 char *arg, *name = NULL;
887 unsigned char *source = NULL, *dest;
888 size_t len = 0;
889 unsigned long sourcelen, destlen;
890
891 /* process arguments */
892 while (arg = *++argv, --argc)
893 if (arg[0] == '-') {
894 if (arg[1] == 'w' && arg[2] == 0)
895 put = 1;
896 else if (arg[1] >= '0' && arg[1] <= '9')
897 skip = (unsigned)atoi(arg + 1);
898 else {
899 fprintf(stderr, "invalid option %s\n", arg);
900 return 3;
901 }
902 }
903 else if (name != NULL) {
904 fprintf(stderr, "only one file name allowed\n");
905 return 3;
906 }
907 else
908 name = arg;
909 source = load(name, &len);
910 if (source == NULL) {
911 fprintf(stderr, "memory allocation failure\n");
912 return 4;
913 }
914 if (len == 0) {
915 fprintf(stderr, "could not read %s, or it was empty\n",
916 name == NULL ? "<stdin>" : name);
917 free(source);
918 return 3;
919 }
920 if (skip >= len) {
921 fprintf(stderr, "skip request of %d leaves no input\n", skip);
922 free(source);
923 return 3;
924 }
925
926 /* test inflate data with offset skip */
927 len -= skip;
928 sourcelen = (unsigned long)len;
929 ret = puff(NIL, &destlen, source + skip, &sourcelen);
930 if (ret)
931 fprintf(stderr, "puff() failed with return code %d\n", ret);
932 else {
933 fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen);
934 if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n",
935 len - sourcelen);
936 }
937
938 /* if requested, inflate again and write decompressd data to stdout */
939 if (put) {
940 dest = malloc(destlen);
941 if (dest == NULL) {
942 fprintf(stderr, "memory allocation failure\n");
943 free(source);
944 return 4;
945 }
946 puff(dest, &destlen, source + skip, &sourcelen);
947 fwrite(dest, 1, destlen, stdout);
948 free(dest);
949 }
950
951 /* clean up */
952 free(source);
953 return ret;
954}
955#endif
diff --git a/contrib/puff/puff.h b/contrib/puff/puff.h
index 88d1b38..6a0080a 100644
--- a/contrib/puff/puff.h
+++ b/contrib/puff/puff.h
@@ -1,6 +1,6 @@
1/* puff.h 1/* puff.h
2 Copyright (C) 2002-2010 Mark Adler, all rights reserved 2 Copyright (C) 2002-2010 Mark Adler, all rights reserved
3 version 2.1, 4 Apr 2010 3 version 2.2, 25 Apr 2010
4 4
5 This software is provided 'as-is', without any express or implied 5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the author be held liable for any damages 6 warranty. In no event will the author be held liable for any damages
@@ -25,7 +25,11 @@
25/* 25/*
26 * See puff.c for purpose and usage. 26 * See puff.c for purpose and usage.
27 */ 27 */
28#ifndef NIL
29# define NIL ((unsigned char *)0) /* for no output option */
30#endif
31
28int puff(unsigned char *dest, /* pointer to destination pointer */ 32int puff(unsigned char *dest, /* pointer to destination pointer */
29 unsigned long *destlen, /* amount of output space */ 33 unsigned long *destlen, /* amount of output space */
30 unsigned char *source, /* pointer to source data pointer */ 34 const unsigned char *source, /* pointer to source data pointer */
31 unsigned long *sourcelen); /* amount of input available */ 35 unsigned long *sourcelen); /* amount of input available */
diff --git a/contrib/puff/pufftest.c b/contrib/puff/pufftest.c
new file mode 100644
index 0000000..76e35f6
--- /dev/null
+++ b/contrib/puff/pufftest.c
@@ -0,0 +1,165 @@
1/*
2 * pufftest.c
3 * Copyright (C) 2002-2010 Mark Adler
4 * For conditions of distribution and use, see copyright notice in puff.h
5 * version 2.2, 25 Apr 2010
6 */
7
8/* Example of how to use puff().
9
10 Usage: puff [-w] [-f] [-nnn] file
11 ... | puff [-w] [-f] [-nnn]
12
13 where file is the input file with deflate data, nnn is the number of bytes
14 of input to skip before inflating (e.g. to skip a zlib or gzip header), and
15 -w is used to write the decompressed data to stdout. -f is for coverage
16 testing, and causes pufftest to fail with not enough output space (-f does
17 a write like -w, so -w is not required). */
18
19#include <stdio.h>
20#include <stdlib.h>
21#include "puff.h"
22
23#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
24# include <fcntl.h>
25# include <io.h>
26# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
27#else
28# define SET_BINARY_MODE(file)
29#endif
30
31#define local static
32
33/* Return size times approximately the cube root of 2, keeping the result as 1,
34 3, or 5 times a power of 2 -- the result is always > size, until the result
35 is the maximum value of an unsigned long, where it remains. This is useful
36 to keep reallocations less than ~33% over the actual data. */
37local size_t bythirds(size_t size)
38{
39 int n;
40 size_t m;
41
42 m = size;
43 for (n = 0; m; n++)
44 m >>= 1;
45 if (n < 3)
46 return size + 1;
47 n -= 3;
48 m = size >> n;
49 m += m == 6 ? 2 : 1;
50 m <<= n;
51 return m > size ? m : (size_t)(-1);
52}
53
54/* Read the input file *name, or stdin if name is NULL, into allocated memory.
55 Reallocate to larger buffers until the entire file is read in. Return a
56 pointer to the allocated data, or NULL if there was a memory allocation
57 failure. *len is the number of bytes of data read from the input file (even
58 if load() returns NULL). If the input file was empty or could not be opened
59 or read, *len is zero. */
60local void *load(const char *name, size_t *len)
61{
62 size_t size;
63 void *buf, *swap;
64 FILE *in;
65
66 *len = 0;
67 buf = malloc(size = 4096);
68 if (buf == NULL)
69 return NULL;
70 in = name == NULL ? stdin : fopen(name, "rb");
71 if (in != NULL) {
72 for (;;) {
73 *len += fread((char *)buf + *len, 1, size - *len, in);
74 if (*len < size) break;
75 size = bythirds(size);
76 if (size == *len || (swap = realloc(buf, size)) == NULL) {
77 free(buf);
78 buf = NULL;
79 break;
80 }
81 buf = swap;
82 }
83 fclose(in);
84 }
85 return buf;
86}
87
88int main(int argc, char **argv)
89{
90 int ret, put = 0, fail = 0;
91 unsigned skip = 0;
92 char *arg, *name = NULL;
93 unsigned char *source = NULL, *dest;
94 size_t len = 0;
95 unsigned long sourcelen, destlen;
96
97 /* process arguments */
98 while (arg = *++argv, --argc)
99 if (arg[0] == '-') {
100 if (arg[1] == 'w' && arg[2] == 0)
101 put = 1;
102 else if (arg[1] == 'f' && arg[2] == 0)
103 fail = 1, put = 1;
104 else if (arg[1] >= '0' && arg[1] <= '9')
105 skip = (unsigned)atoi(arg + 1);
106 else {
107 fprintf(stderr, "invalid option %s\n", arg);
108 return 3;
109 }
110 }
111 else if (name != NULL) {
112 fprintf(stderr, "only one file name allowed\n");
113 return 3;
114 }
115 else
116 name = arg;
117 source = load(name, &len);
118 if (source == NULL) {
119 fprintf(stderr, "memory allocation failure\n");
120 return 4;
121 }
122 if (len == 0) {
123 fprintf(stderr, "could not read %s, or it was empty\n",
124 name == NULL ? "<stdin>" : name);
125 free(source);
126 return 3;
127 }
128 if (skip >= len) {
129 fprintf(stderr, "skip request of %d leaves no input\n", skip);
130 free(source);
131 return 3;
132 }
133
134 /* test inflate data with offset skip */
135 len -= skip;
136 sourcelen = (unsigned long)len;
137 ret = puff(NIL, &destlen, source + skip, &sourcelen);
138 if (ret)
139 fprintf(stderr, "puff() failed with return code %d\n", ret);
140 else {
141 fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen);
142 if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n",
143 len - sourcelen);
144 }
145
146 /* if requested, inflate again and write decompressd data to stdout */
147 if (put && ret == 0) {
148 if (fail)
149 destlen >>= 1;
150 dest = malloc(destlen);
151 if (dest == NULL) {
152 fprintf(stderr, "memory allocation failure\n");
153 free(source);
154 return 4;
155 }
156 puff(dest, &destlen, source + skip, &sourcelen);
157 SET_BINARY_MODE(stdout);
158 fwrite(dest, 1, destlen, stdout);
159 free(dest);
160 }
161
162 /* clean up */
163 free(source);
164 return ret;
165}
diff --git a/contrib/puff/zeros.raw b/contrib/puff/zeros.raw
index 637b7be..0a90e76 100644
--- a/contrib/puff/zeros.raw
+++ b/contrib/puff/zeros.raw
Binary files differ