kusano fc6ab3
/*
kusano fc6ab3
 * pufftest.c
kusano fc6ab3
 * Copyright (C) 2002-2013 Mark Adler
kusano fc6ab3
 * For conditions of distribution and use, see copyright notice in puff.h
kusano fc6ab3
 * version 2.3, 21 Jan 2013
kusano fc6ab3
 */
kusano fc6ab3
kusano fc6ab3
/* Example of how to use puff().
kusano fc6ab3
kusano fc6ab3
   Usage: puff [-w] [-f] [-nnn] file
kusano fc6ab3
          ... | puff [-w] [-f] [-nnn]
kusano fc6ab3
kusano fc6ab3
   where file is the input file with deflate data, nnn is the number of bytes
kusano fc6ab3
   of input to skip before inflating (e.g. to skip a zlib or gzip header), and
kusano fc6ab3
   -w is used to write the decompressed data to stdout.  -f is for coverage
kusano fc6ab3
   testing, and causes pufftest to fail with not enough output space (-f does
kusano fc6ab3
   a write like -w, so -w is not required). */
kusano fc6ab3
kusano fc6ab3
#include <stdio.h></stdio.h>
kusano fc6ab3
#include <stdlib.h></stdlib.h>
kusano fc6ab3
#include "puff.h"
kusano fc6ab3
kusano fc6ab3
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
kusano fc6ab3
#  include <fcntl.h></fcntl.h>
kusano fc6ab3
#  include <io.h></io.h>
kusano fc6ab3
#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
kusano fc6ab3
#else
kusano fc6ab3
#  define SET_BINARY_MODE(file)
kusano fc6ab3
#endif
kusano fc6ab3
kusano fc6ab3
#define local static
kusano fc6ab3
kusano fc6ab3
/* Return size times approximately the cube root of 2, keeping the result as 1,
kusano fc6ab3
   3, or 5 times a power of 2 -- the result is always > size, until the result
kusano fc6ab3
   is the maximum value of an unsigned long, where it remains.  This is useful
kusano fc6ab3
   to keep reallocations less than ~33% over the actual data. */
kusano fc6ab3
local size_t bythirds(size_t size)
kusano fc6ab3
{
kusano fc6ab3
    int n;
kusano fc6ab3
    size_t m;
kusano fc6ab3
kusano fc6ab3
    m = size;
kusano fc6ab3
    for (n = 0; m; n++)
kusano fc6ab3
        m >>= 1;
kusano fc6ab3
    if (n < 3)
kusano fc6ab3
        return size + 1;
kusano fc6ab3
    n -= 3;
kusano fc6ab3
    m = size >> n;
kusano fc6ab3
    m += m == 6 ? 2 : 1;
kusano fc6ab3
    m <<= n;
kusano fc6ab3
    return m > size ? m : (size_t)(-1);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* Read the input file *name, or stdin if name is NULL, into allocated memory.
kusano fc6ab3
   Reallocate to larger buffers until the entire file is read in.  Return a
kusano fc6ab3
   pointer to the allocated data, or NULL if there was a memory allocation
kusano fc6ab3
   failure.  *len is the number of bytes of data read from the input file (even
kusano fc6ab3
   if load() returns NULL).  If the input file was empty or could not be opened
kusano fc6ab3
   or read, *len is zero. */
kusano fc6ab3
local void *load(const char *name, size_t *len)
kusano fc6ab3
{
kusano fc6ab3
    size_t size;
kusano fc6ab3
    void *buf, *swap;
kusano fc6ab3
    FILE *in;
kusano fc6ab3
kusano fc6ab3
    *len = 0;
kusano fc6ab3
    buf = malloc(size = 4096);
kusano fc6ab3
    if (buf == NULL)
kusano fc6ab3
        return NULL;
kusano fc6ab3
    in = name == NULL ? stdin : fopen(name, "rb");
kusano fc6ab3
    if (in != NULL) {
kusano fc6ab3
        for (;;) {
kusano fc6ab3
            *len += fread((char *)buf + *len, 1, size - *len, in);
kusano fc6ab3
            if (*len < size) break;
kusano fc6ab3
            size = bythirds(size);
kusano fc6ab3
            if (size == *len || (swap = realloc(buf, size)) == NULL) {
kusano fc6ab3
                free(buf);
kusano fc6ab3
                buf = NULL;
kusano fc6ab3
                break;
kusano fc6ab3
            }
kusano fc6ab3
            buf = swap;
kusano fc6ab3
        }
kusano fc6ab3
        fclose(in);
kusano fc6ab3
    }
kusano fc6ab3
    return buf;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
int main(int argc, char **argv)
kusano fc6ab3
{
kusano fc6ab3
    int ret, put = 0, fail = 0;
kusano fc6ab3
    unsigned skip = 0;
kusano fc6ab3
    char *arg, *name = NULL;
kusano fc6ab3
    unsigned char *source = NULL, *dest;
kusano fc6ab3
    size_t len = 0;
kusano fc6ab3
    unsigned long sourcelen, destlen;
kusano fc6ab3
kusano fc6ab3
    /* process arguments */
kusano fc6ab3
    while (arg = *++argv, --argc)
kusano fc6ab3
        if (arg[0] == '-') {
kusano fc6ab3
            if (arg[1] == 'w' && arg[2] == 0)
kusano fc6ab3
                put = 1;
kusano fc6ab3
            else if (arg[1] == 'f' && arg[2] == 0)
kusano fc6ab3
                fail = 1, put = 1;
kusano fc6ab3
            else if (arg[1] >= '0' && arg[1] <= '9')
kusano fc6ab3
                skip = (unsigned)atoi(arg + 1);
kusano fc6ab3
            else {
kusano fc6ab3
                fprintf(stderr, "invalid option %s\n", arg);
kusano fc6ab3
                return 3;
kusano fc6ab3
            }
kusano fc6ab3
        }
kusano fc6ab3
        else if (name != NULL) {
kusano fc6ab3
            fprintf(stderr, "only one file name allowed\n");
kusano fc6ab3
            return 3;
kusano fc6ab3
        }
kusano fc6ab3
        else
kusano fc6ab3
            name = arg;
kusano fc6ab3
    source = load(name, &len);
kusano fc6ab3
    if (source == NULL) {
kusano fc6ab3
        fprintf(stderr, "memory allocation failure\n");
kusano fc6ab3
        return 4;
kusano fc6ab3
    }
kusano fc6ab3
    if (len == 0) {
kusano fc6ab3
        fprintf(stderr, "could not read %s, or it was empty\n",
kusano fc6ab3
                name == NULL ? "<stdin>" : name);</stdin>
kusano fc6ab3
        free(source);
kusano fc6ab3
        return 3;
kusano fc6ab3
    }
kusano fc6ab3
    if (skip >= len) {
kusano fc6ab3
        fprintf(stderr, "skip request of %d leaves no input\n", skip);
kusano fc6ab3
        free(source);
kusano fc6ab3
        return 3;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* test inflate data with offset skip */
kusano fc6ab3
    len -= skip;
kusano fc6ab3
    sourcelen = (unsigned long)len;
kusano fc6ab3
    ret = puff(NIL, &destlen, source + skip, &sourcelen);
kusano fc6ab3
    if (ret)
kusano fc6ab3
        fprintf(stderr, "puff() failed with return code %d\n", ret);
kusano fc6ab3
    else {
kusano fc6ab3
        fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen);
kusano fc6ab3
        if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n",
kusano fc6ab3
                                     len - sourcelen);
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* if requested, inflate again and write decompressd data to stdout */
kusano fc6ab3
    if (put && ret == 0) {
kusano fc6ab3
        if (fail)
kusano fc6ab3
            destlen >>= 1;
kusano fc6ab3
        dest = malloc(destlen);
kusano fc6ab3
        if (dest == NULL) {
kusano fc6ab3
            fprintf(stderr, "memory allocation failure\n");
kusano fc6ab3
            free(source);
kusano fc6ab3
            return 4;
kusano fc6ab3
        }
kusano fc6ab3
        puff(dest, &destlen, source + skip, &sourcelen);
kusano fc6ab3
        SET_BINARY_MODE(stdout);
kusano fc6ab3
        fwrite(dest, 1, destlen, stdout);
kusano fc6ab3
        free(dest);
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* clean up */
kusano fc6ab3
    free(source);
kusano fc6ab3
    return ret;
kusano fc6ab3
}