1275793eaSopenharmony_ci/*
2275793eaSopenharmony_ci * pufftest.c
3275793eaSopenharmony_ci * Copyright (C) 2002-2013 Mark Adler
4275793eaSopenharmony_ci * For conditions of distribution and use, see copyright notice in puff.h
5275793eaSopenharmony_ci * version 2.3, 21 Jan 2013
6275793eaSopenharmony_ci */
7275793eaSopenharmony_ci
8275793eaSopenharmony_ci/* Example of how to use puff().
9275793eaSopenharmony_ci
10275793eaSopenharmony_ci   Usage: puff [-w] [-f] [-nnn] file
11275793eaSopenharmony_ci          ... | puff [-w] [-f] [-nnn]
12275793eaSopenharmony_ci
13275793eaSopenharmony_ci   where file is the input file with deflate data, nnn is the number of bytes
14275793eaSopenharmony_ci   of input to skip before inflating (e.g. to skip a zlib or gzip header), and
15275793eaSopenharmony_ci   -w is used to write the decompressed data to stdout.  -f is for coverage
16275793eaSopenharmony_ci   testing, and causes pufftest to fail with not enough output space (-f does
17275793eaSopenharmony_ci   a write like -w, so -w is not required). */
18275793eaSopenharmony_ci
19275793eaSopenharmony_ci#include <stdio.h>
20275793eaSopenharmony_ci#include <stdlib.h>
21275793eaSopenharmony_ci#include "puff.h"
22275793eaSopenharmony_ci
23275793eaSopenharmony_ci#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
24275793eaSopenharmony_ci#  include <fcntl.h>
25275793eaSopenharmony_ci#  include <io.h>
26275793eaSopenharmony_ci#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
27275793eaSopenharmony_ci#else
28275793eaSopenharmony_ci#  define SET_BINARY_MODE(file)
29275793eaSopenharmony_ci#endif
30275793eaSopenharmony_ci
31275793eaSopenharmony_ci#define local static
32275793eaSopenharmony_ci
33275793eaSopenharmony_ci/* Return size times approximately the cube root of 2, keeping the result as 1,
34275793eaSopenharmony_ci   3, or 5 times a power of 2 -- the result is always > size, until the result
35275793eaSopenharmony_ci   is the maximum value of an unsigned long, where it remains.  This is useful
36275793eaSopenharmony_ci   to keep reallocations less than ~33% over the actual data. */
37275793eaSopenharmony_cilocal size_t bythirds(size_t size)
38275793eaSopenharmony_ci{
39275793eaSopenharmony_ci    int n;
40275793eaSopenharmony_ci    size_t m;
41275793eaSopenharmony_ci
42275793eaSopenharmony_ci    m = size;
43275793eaSopenharmony_ci    for (n = 0; m; n++)
44275793eaSopenharmony_ci        m >>= 1;
45275793eaSopenharmony_ci    if (n < 3)
46275793eaSopenharmony_ci        return size + 1;
47275793eaSopenharmony_ci    n -= 3;
48275793eaSopenharmony_ci    m = size >> n;
49275793eaSopenharmony_ci    m += m == 6 ? 2 : 1;
50275793eaSopenharmony_ci    m <<= n;
51275793eaSopenharmony_ci    return m > size ? m : (size_t)(-1);
52275793eaSopenharmony_ci}
53275793eaSopenharmony_ci
54275793eaSopenharmony_ci/* Read the input file *name, or stdin if name is NULL, into allocated memory.
55275793eaSopenharmony_ci   Reallocate to larger buffers until the entire file is read in.  Return a
56275793eaSopenharmony_ci   pointer to the allocated data, or NULL if there was a memory allocation
57275793eaSopenharmony_ci   failure.  *len is the number of bytes of data read from the input file (even
58275793eaSopenharmony_ci   if load() returns NULL).  If the input file was empty or could not be opened
59275793eaSopenharmony_ci   or read, *len is zero. */
60275793eaSopenharmony_cilocal void *load(const char *name, size_t *len)
61275793eaSopenharmony_ci{
62275793eaSopenharmony_ci    size_t size;
63275793eaSopenharmony_ci    void *buf, *swap;
64275793eaSopenharmony_ci    FILE *in;
65275793eaSopenharmony_ci
66275793eaSopenharmony_ci    *len = 0;
67275793eaSopenharmony_ci    buf = malloc(size = 4096);
68275793eaSopenharmony_ci    if (buf == NULL)
69275793eaSopenharmony_ci        return NULL;
70275793eaSopenharmony_ci    in = name == NULL ? stdin : fopen(name, "rb");
71275793eaSopenharmony_ci    if (in != NULL) {
72275793eaSopenharmony_ci        for (;;) {
73275793eaSopenharmony_ci            *len += fread((char *)buf + *len, 1, size - *len, in);
74275793eaSopenharmony_ci            if (*len < size) break;
75275793eaSopenharmony_ci            size = bythirds(size);
76275793eaSopenharmony_ci            if (size == *len || (swap = realloc(buf, size)) == NULL) {
77275793eaSopenharmony_ci                free(buf);
78275793eaSopenharmony_ci                buf = NULL;
79275793eaSopenharmony_ci                break;
80275793eaSopenharmony_ci            }
81275793eaSopenharmony_ci            buf = swap;
82275793eaSopenharmony_ci        }
83275793eaSopenharmony_ci        fclose(in);
84275793eaSopenharmony_ci    }
85275793eaSopenharmony_ci    return buf;
86275793eaSopenharmony_ci}
87275793eaSopenharmony_ci
88275793eaSopenharmony_ciint main(int argc, char **argv)
89275793eaSopenharmony_ci{
90275793eaSopenharmony_ci    int ret, put = 0, fail = 0;
91275793eaSopenharmony_ci    unsigned skip = 0;
92275793eaSopenharmony_ci    char *arg, *name = NULL;
93275793eaSopenharmony_ci    unsigned char *source = NULL, *dest;
94275793eaSopenharmony_ci    size_t len = 0;
95275793eaSopenharmony_ci    unsigned long sourcelen, destlen;
96275793eaSopenharmony_ci
97275793eaSopenharmony_ci    /* process arguments */
98275793eaSopenharmony_ci    while (arg = *++argv, --argc)
99275793eaSopenharmony_ci        if (arg[0] == '-') {
100275793eaSopenharmony_ci            if (arg[1] == 'w' && arg[2] == 0)
101275793eaSopenharmony_ci                put = 1;
102275793eaSopenharmony_ci            else if (arg[1] == 'f' && arg[2] == 0)
103275793eaSopenharmony_ci                fail = 1, put = 1;
104275793eaSopenharmony_ci            else if (arg[1] >= '0' && arg[1] <= '9')
105275793eaSopenharmony_ci                skip = (unsigned)atoi(arg + 1);
106275793eaSopenharmony_ci            else {
107275793eaSopenharmony_ci                fprintf(stderr, "invalid option %s\n", arg);
108275793eaSopenharmony_ci                return 3;
109275793eaSopenharmony_ci            }
110275793eaSopenharmony_ci        }
111275793eaSopenharmony_ci        else if (name != NULL) {
112275793eaSopenharmony_ci            fprintf(stderr, "only one file name allowed\n");
113275793eaSopenharmony_ci            return 3;
114275793eaSopenharmony_ci        }
115275793eaSopenharmony_ci        else
116275793eaSopenharmony_ci            name = arg;
117275793eaSopenharmony_ci    source = load(name, &len);
118275793eaSopenharmony_ci    if (source == NULL) {
119275793eaSopenharmony_ci        fprintf(stderr, "memory allocation failure\n");
120275793eaSopenharmony_ci        return 4;
121275793eaSopenharmony_ci    }
122275793eaSopenharmony_ci    if (len == 0) {
123275793eaSopenharmony_ci        fprintf(stderr, "could not read %s, or it was empty\n",
124275793eaSopenharmony_ci                name == NULL ? "<stdin>" : name);
125275793eaSopenharmony_ci        free(source);
126275793eaSopenharmony_ci        return 3;
127275793eaSopenharmony_ci    }
128275793eaSopenharmony_ci    if (skip >= len) {
129275793eaSopenharmony_ci        fprintf(stderr, "skip request of %d leaves no input\n", skip);
130275793eaSopenharmony_ci        free(source);
131275793eaSopenharmony_ci        return 3;
132275793eaSopenharmony_ci    }
133275793eaSopenharmony_ci
134275793eaSopenharmony_ci    /* test inflate data with offset skip */
135275793eaSopenharmony_ci    len -= skip;
136275793eaSopenharmony_ci    sourcelen = (unsigned long)len;
137275793eaSopenharmony_ci    ret = puff(NIL, &destlen, source + skip, &sourcelen);
138275793eaSopenharmony_ci    if (ret)
139275793eaSopenharmony_ci        fprintf(stderr, "puff() failed with return code %d\n", ret);
140275793eaSopenharmony_ci    else {
141275793eaSopenharmony_ci        fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen);
142275793eaSopenharmony_ci        if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n",
143275793eaSopenharmony_ci                                     len - sourcelen);
144275793eaSopenharmony_ci    }
145275793eaSopenharmony_ci
146275793eaSopenharmony_ci    /* if requested, inflate again and write decompressed data to stdout */
147275793eaSopenharmony_ci    if (put && ret == 0) {
148275793eaSopenharmony_ci        if (fail)
149275793eaSopenharmony_ci            destlen >>= 1;
150275793eaSopenharmony_ci        dest = malloc(destlen);
151275793eaSopenharmony_ci        if (dest == NULL) {
152275793eaSopenharmony_ci            fprintf(stderr, "memory allocation failure\n");
153275793eaSopenharmony_ci            free(source);
154275793eaSopenharmony_ci            return 4;
155275793eaSopenharmony_ci        }
156275793eaSopenharmony_ci        puff(dest, &destlen, source + skip, &sourcelen);
157275793eaSopenharmony_ci        SET_BINARY_MODE(stdout);
158275793eaSopenharmony_ci        fwrite(dest, 1, destlen, stdout);
159275793eaSopenharmony_ci        free(dest);
160275793eaSopenharmony_ci    }
161275793eaSopenharmony_ci
162275793eaSopenharmony_ci    /* clean up */
163275793eaSopenharmony_ci    free(source);
164275793eaSopenharmony_ci    return ret;
165275793eaSopenharmony_ci}
166