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