xref: /netbsd-src/external/gpl3/gdb/dist/zlib/contrib/puff/pufftest.c (revision ba340e457da88a40806d62ac0f140844ca1436e9)
1212397c6Schristos /*
2212397c6Schristos  * pufftest.c
3*ba340e45Schristos  * Copyright (C) 2002-2013 Mark Adler
4212397c6Schristos  * For conditions of distribution and use, see copyright notice in puff.h
5*ba340e45Schristos  * version 2.3, 21 Jan 2013
6212397c6Schristos  */
7212397c6Schristos 
8212397c6Schristos /* Example of how to use puff().
9212397c6Schristos 
10212397c6Schristos    Usage: puff [-w] [-f] [-nnn] file
11212397c6Schristos           ... | puff [-w] [-f] [-nnn]
12212397c6Schristos 
13212397c6Schristos    where file is the input file with deflate data, nnn is the number of bytes
14212397c6Schristos    of input to skip before inflating (e.g. to skip a zlib or gzip header), and
15212397c6Schristos    -w is used to write the decompressed data to stdout.  -f is for coverage
16212397c6Schristos    testing, and causes pufftest to fail with not enough output space (-f does
17212397c6Schristos    a write like -w, so -w is not required). */
18212397c6Schristos 
19212397c6Schristos #include <stdio.h>
20212397c6Schristos #include <stdlib.h>
21212397c6Schristos #include "puff.h"
22212397c6Schristos 
23212397c6Schristos #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
24212397c6Schristos #  include <fcntl.h>
25212397c6Schristos #  include <io.h>
26212397c6Schristos #  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
27212397c6Schristos #else
28212397c6Schristos #  define SET_BINARY_MODE(file)
29212397c6Schristos #endif
30212397c6Schristos 
31212397c6Schristos #define local static
32212397c6Schristos 
33212397c6Schristos /* Return size times approximately the cube root of 2, keeping the result as 1,
34212397c6Schristos    3, or 5 times a power of 2 -- the result is always > size, until the result
35212397c6Schristos    is the maximum value of an unsigned long, where it remains.  This is useful
36212397c6Schristos    to keep reallocations less than ~33% over the actual data. */
bythirds(size_t size)37212397c6Schristos local size_t bythirds(size_t size)
38212397c6Schristos {
39212397c6Schristos     int n;
40212397c6Schristos     size_t m;
41212397c6Schristos 
42212397c6Schristos     m = size;
43212397c6Schristos     for (n = 0; m; n++)
44212397c6Schristos         m >>= 1;
45212397c6Schristos     if (n < 3)
46212397c6Schristos         return size + 1;
47212397c6Schristos     n -= 3;
48212397c6Schristos     m = size >> n;
49212397c6Schristos     m += m == 6 ? 2 : 1;
50212397c6Schristos     m <<= n;
51212397c6Schristos     return m > size ? m : (size_t)(-1);
52212397c6Schristos }
53212397c6Schristos 
54212397c6Schristos /* Read the input file *name, or stdin if name is NULL, into allocated memory.
55212397c6Schristos    Reallocate to larger buffers until the entire file is read in.  Return a
56212397c6Schristos    pointer to the allocated data, or NULL if there was a memory allocation
57212397c6Schristos    failure.  *len is the number of bytes of data read from the input file (even
58212397c6Schristos    if load() returns NULL).  If the input file was empty or could not be opened
59212397c6Schristos    or read, *len is zero. */
load(const char * name,size_t * len)60212397c6Schristos local void *load(const char *name, size_t *len)
61212397c6Schristos {
62212397c6Schristos     size_t size;
63212397c6Schristos     void *buf, *swap;
64212397c6Schristos     FILE *in;
65212397c6Schristos 
66212397c6Schristos     *len = 0;
67212397c6Schristos     buf = malloc(size = 4096);
68212397c6Schristos     if (buf == NULL)
69212397c6Schristos         return NULL;
70212397c6Schristos     in = name == NULL ? stdin : fopen(name, "rb");
71212397c6Schristos     if (in != NULL) {
72212397c6Schristos         for (;;) {
73212397c6Schristos             *len += fread((char *)buf + *len, 1, size - *len, in);
74212397c6Schristos             if (*len < size) break;
75212397c6Schristos             size = bythirds(size);
76212397c6Schristos             if (size == *len || (swap = realloc(buf, size)) == NULL) {
77212397c6Schristos                 free(buf);
78212397c6Schristos                 buf = NULL;
79212397c6Schristos                 break;
80212397c6Schristos             }
81212397c6Schristos             buf = swap;
82212397c6Schristos         }
83212397c6Schristos         fclose(in);
84212397c6Schristos     }
85212397c6Schristos     return buf;
86212397c6Schristos }
87212397c6Schristos 
main(int argc,char ** argv)88212397c6Schristos int main(int argc, char **argv)
89212397c6Schristos {
90212397c6Schristos     int ret, put = 0, fail = 0;
91212397c6Schristos     unsigned skip = 0;
92212397c6Schristos     char *arg, *name = NULL;
93212397c6Schristos     unsigned char *source = NULL, *dest;
94212397c6Schristos     size_t len = 0;
95212397c6Schristos     unsigned long sourcelen, destlen;
96212397c6Schristos 
97212397c6Schristos     /* process arguments */
98212397c6Schristos     while (arg = *++argv, --argc)
99212397c6Schristos         if (arg[0] == '-') {
100212397c6Schristos             if (arg[1] == 'w' && arg[2] == 0)
101212397c6Schristos                 put = 1;
102212397c6Schristos             else if (arg[1] == 'f' && arg[2] == 0)
103212397c6Schristos                 fail = 1, put = 1;
104212397c6Schristos             else if (arg[1] >= '0' && arg[1] <= '9')
105212397c6Schristos                 skip = (unsigned)atoi(arg + 1);
106212397c6Schristos             else {
107212397c6Schristos                 fprintf(stderr, "invalid option %s\n", arg);
108212397c6Schristos                 return 3;
109212397c6Schristos             }
110212397c6Schristos         }
111212397c6Schristos         else if (name != NULL) {
112212397c6Schristos             fprintf(stderr, "only one file name allowed\n");
113212397c6Schristos             return 3;
114212397c6Schristos         }
115212397c6Schristos         else
116212397c6Schristos             name = arg;
117212397c6Schristos     source = load(name, &len);
118212397c6Schristos     if (source == NULL) {
119212397c6Schristos         fprintf(stderr, "memory allocation failure\n");
120212397c6Schristos         return 4;
121212397c6Schristos     }
122212397c6Schristos     if (len == 0) {
123212397c6Schristos         fprintf(stderr, "could not read %s, or it was empty\n",
124212397c6Schristos                 name == NULL ? "<stdin>" : name);
125212397c6Schristos         free(source);
126212397c6Schristos         return 3;
127212397c6Schristos     }
128212397c6Schristos     if (skip >= len) {
129212397c6Schristos         fprintf(stderr, "skip request of %d leaves no input\n", skip);
130212397c6Schristos         free(source);
131212397c6Schristos         return 3;
132212397c6Schristos     }
133212397c6Schristos 
134212397c6Schristos     /* test inflate data with offset skip */
135212397c6Schristos     len -= skip;
136212397c6Schristos     sourcelen = (unsigned long)len;
137212397c6Schristos     ret = puff(NIL, &destlen, source + skip, &sourcelen);
138212397c6Schristos     if (ret)
139212397c6Schristos         fprintf(stderr, "puff() failed with return code %d\n", ret);
140212397c6Schristos     else {
141212397c6Schristos         fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen);
142212397c6Schristos         if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n",
143212397c6Schristos                                      len - sourcelen);
144212397c6Schristos     }
145212397c6Schristos 
146212397c6Schristos     /* if requested, inflate again and write decompressd data to stdout */
147212397c6Schristos     if (put && ret == 0) {
148212397c6Schristos         if (fail)
149212397c6Schristos             destlen >>= 1;
150212397c6Schristos         dest = malloc(destlen);
151212397c6Schristos         if (dest == NULL) {
152212397c6Schristos             fprintf(stderr, "memory allocation failure\n");
153212397c6Schristos             free(source);
154212397c6Schristos             return 4;
155212397c6Schristos         }
156212397c6Schristos         puff(dest, &destlen, source + skip, &sourcelen);
157212397c6Schristos         SET_BINARY_MODE(stdout);
158212397c6Schristos         fwrite(dest, 1, destlen, stdout);
159212397c6Schristos         free(dest);
160212397c6Schristos     }
161212397c6Schristos 
162212397c6Schristos     /* clean up */
163212397c6Schristos     free(source);
164212397c6Schristos     return ret;
165212397c6Schristos }
166