1ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes/* 2ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes * pufftest.c 304351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes * Copyright (C) 2002-2013 Mark Adler 4ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes * For conditions of distribution and use, see copyright notice in puff.h 504351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes * version 2.3, 21 Jan 2013 6ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes */ 7ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 8ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes/* Example of how to use puff(). 9ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 10ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes Usage: puff [-w] [-f] [-nnn] file 11ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes ... | puff [-w] [-f] [-nnn] 12ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 13ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes where file is the input file with deflate data, nnn is the number of bytes 14ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes of input to skip before inflating (e.g. to skip a zlib or gzip header), and 15ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes -w is used to write the decompressed data to stdout. -f is for coverage 16ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes testing, and causes pufftest to fail with not enough output space (-f does 17ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes a write like -w, so -w is not required). */ 18ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 19ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#include <stdio.h> 20ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#include <stdlib.h> 21ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#include "puff.h" 22ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 23ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) 24ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# include <fcntl.h> 25ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# include <io.h> 26ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) 27ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#else 28ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define SET_BINARY_MODE(file) 29ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#endif 30ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 31ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#define local static 32ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 33ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes/* Return size times approximately the cube root of 2, keeping the result as 1, 34ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 3, or 5 times a power of 2 -- the result is always > size, until the result 35ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes is the maximum value of an unsigned long, where it remains. This is useful 36ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes to keep reallocations less than ~33% over the actual data. */ 37ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hugheslocal size_t bythirds(size_t size) 38ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes{ 39ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes int n; 40ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes size_t m; 41ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 42ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes m = size; 43ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes for (n = 0; m; n++) 44ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes m >>= 1; 45ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (n < 3) 46ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return size + 1; 47ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes n -= 3; 48ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes m = size >> n; 49ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes m += m == 6 ? 2 : 1; 50ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes m <<= n; 51ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return m > size ? m : (size_t)(-1); 52ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes} 53ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 54ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes/* Read the input file *name, or stdin if name is NULL, into allocated memory. 55ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes Reallocate to larger buffers until the entire file is read in. Return a 56ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes pointer to the allocated data, or NULL if there was a memory allocation 57ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes failure. *len is the number of bytes of data read from the input file (even 58ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if load() returns NULL). If the input file was empty or could not be opened 59ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes or read, *len is zero. */ 60ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hugheslocal void *load(const char *name, size_t *len) 61ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes{ 62ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes size_t size; 63ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes void *buf, *swap; 64ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes FILE *in; 65ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 66ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes *len = 0; 67ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes buf = malloc(size = 4096); 68ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (buf == NULL) 69ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return NULL; 70ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes in = name == NULL ? stdin : fopen(name, "rb"); 71ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (in != NULL) { 72ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes for (;;) { 73ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes *len += fread((char *)buf + *len, 1, size - *len, in); 74ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (*len < size) break; 75ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes size = bythirds(size); 76ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (size == *len || (swap = realloc(buf, size)) == NULL) { 77ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes free(buf); 78ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes buf = NULL; 79ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes break; 80ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 81ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes buf = swap; 82ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 83ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fclose(in); 84ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 85ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return buf; 86ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes} 87ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 88ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughesint main(int argc, char **argv) 89ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes{ 90ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes int ret, put = 0, fail = 0; 91ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes unsigned skip = 0; 92ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes char *arg, *name = NULL; 93ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes unsigned char *source = NULL, *dest; 94ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes size_t len = 0; 95ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes unsigned long sourcelen, destlen; 96ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 97ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes /* process arguments */ 98ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes while (arg = *++argv, --argc) 99ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (arg[0] == '-') { 100ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (arg[1] == 'w' && arg[2] == 0) 101ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes put = 1; 102ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes else if (arg[1] == 'f' && arg[2] == 0) 103ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fail = 1, put = 1; 104ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes else if (arg[1] >= '0' && arg[1] <= '9') 105ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes skip = (unsigned)atoi(arg + 1); 106ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes else { 107ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fprintf(stderr, "invalid option %s\n", arg); 108ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return 3; 109ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 110ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 111ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes else if (name != NULL) { 112ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fprintf(stderr, "only one file name allowed\n"); 113ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return 3; 114ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 115ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes else 116ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes name = arg; 117ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes source = load(name, &len); 118ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (source == NULL) { 119ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fprintf(stderr, "memory allocation failure\n"); 120ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return 4; 121ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 122ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (len == 0) { 123ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fprintf(stderr, "could not read %s, or it was empty\n", 124ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes name == NULL ? "<stdin>" : name); 125ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes free(source); 126ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return 3; 127ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 128ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (skip >= len) { 129ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fprintf(stderr, "skip request of %d leaves no input\n", skip); 130ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes free(source); 131ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return 3; 132ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 133ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 134ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes /* test inflate data with offset skip */ 135ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes len -= skip; 136ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes sourcelen = (unsigned long)len; 137ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes ret = puff(NIL, &destlen, source + skip, &sourcelen); 138ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (ret) 139ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fprintf(stderr, "puff() failed with return code %d\n", ret); 140ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes else { 141ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen); 142ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n", 143ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes len - sourcelen); 144ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 145ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 146ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes /* if requested, inflate again and write decompressd data to stdout */ 147ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (put && ret == 0) { 148ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (fail) 149ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes destlen >>= 1; 150ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes dest = malloc(destlen); 151ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (dest == NULL) { 152ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fprintf(stderr, "memory allocation failure\n"); 153ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes free(source); 154ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return 4; 155ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 156ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes puff(dest, &destlen, source + skip, &sourcelen); 157ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes SET_BINARY_MODE(stdout); 158ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes fwrite(dest, 1, destlen, stdout); 159ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes free(dest); 160ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } 161ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 162ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes /* clean up */ 163ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes free(source); 164ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return ret; 165ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes} 166