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