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