zran.c revision 1.1.1.3.8.1 1 1.1.1.3.8.1 perseant /* zran.c -- example of deflate stream indexing and random access
2 1.1.1.3.8.1 perseant * Copyright (C) 2005, 2012, 2018, 2023 Mark Adler
3 1.1 christos * For conditions of distribution and use, see copyright notice in zlib.h
4 1.1.1.3.8.1 perseant * Version 1.4 13 Apr 2023 Mark Adler */
5 1.1.1.2 christos
6 1.1.1.2 christos /* Version History:
7 1.1.1.2 christos 1.0 29 May 2005 First version
8 1.1.1.2 christos 1.1 29 Sep 2012 Fix memory reallocation error
9 1.1.1.3 christos 1.2 14 Oct 2018 Handle gzip streams with multiple members
10 1.1.1.3 christos Add a header file to facilitate usage in applications
11 1.1.1.3.8.1 perseant 1.3 18 Feb 2023 Permit raw deflate streams as well as zlib and gzip
12 1.1.1.3.8.1 perseant Permit crossing gzip member boundaries when extracting
13 1.1.1.3.8.1 perseant Support a size_t size when extracting (was an int)
14 1.1.1.3.8.1 perseant Do a binary search over the index for an access point
15 1.1.1.3.8.1 perseant Expose the access point type to enable save and load
16 1.1.1.3.8.1 perseant 1.4 13 Apr 2023 Add a NOPRIME define to not use inflatePrime()
17 1.1.1.2 christos */
18 1.1 christos
19 1.1.1.3.8.1 perseant // Illustrate the use of Z_BLOCK, inflatePrime(), and inflateSetDictionary()
20 1.1.1.3.8.1 perseant // for random access of a compressed file. A file containing a raw deflate
21 1.1.1.3.8.1 perseant // stream is provided on the command line. The compressed stream is decoded in
22 1.1.1.3.8.1 perseant // its entirety, and an index built with access points about every SPAN bytes
23 1.1.1.3.8.1 perseant // in the uncompressed output. The compressed file is left open, and can then
24 1.1.1.3.8.1 perseant // be read randomly, having to decompress on the average SPAN/2 uncompressed
25 1.1.1.3.8.1 perseant // bytes before getting to the desired block of data.
26 1.1.1.3.8.1 perseant //
27 1.1.1.3.8.1 perseant // An access point can be created at the start of any deflate block, by saving
28 1.1.1.3.8.1 perseant // the starting file offset and bit of that block, and the 32K bytes of
29 1.1.1.3.8.1 perseant // uncompressed data that precede that block. Also the uncompressed offset of
30 1.1.1.3.8.1 perseant // that block is saved to provide a reference for locating a desired starting
31 1.1.1.3.8.1 perseant // point in the uncompressed stream. deflate_index_build() decompresses the
32 1.1.1.3.8.1 perseant // input raw deflate stream a block at a time, and at the end of each block
33 1.1.1.3.8.1 perseant // decides if enough uncompressed data has gone by to justify the creation of a
34 1.1.1.3.8.1 perseant // new access point. If so, that point is saved in a data structure that grows
35 1.1.1.3.8.1 perseant // as needed to accommodate the points.
36 1.1.1.3.8.1 perseant //
37 1.1.1.3.8.1 perseant // To use the index, an offset in the uncompressed data is provided, for which
38 1.1.1.3.8.1 perseant // the latest access point at or preceding that offset is located in the index.
39 1.1.1.3.8.1 perseant // The input file is positioned to the specified location in the index, and if
40 1.1.1.3.8.1 perseant // necessary the first few bits of the compressed data is read from the file.
41 1.1.1.3.8.1 perseant // inflate is initialized with those bits and the 32K of uncompressed data, and
42 1.1.1.3.8.1 perseant // decompression then proceeds until the desired offset in the file is reached.
43 1.1.1.3.8.1 perseant // Then decompression continues to read the requested uncompressed data from
44 1.1.1.3.8.1 perseant // the file.
45 1.1.1.3.8.1 perseant //
46 1.1.1.3.8.1 perseant // There is some fair bit of overhead to starting inflation for the random
47 1.1.1.3.8.1 perseant // access, mainly copying the 32K byte dictionary. If small pieces of the file
48 1.1.1.3.8.1 perseant // are being accessed, it would make sense to implement a cache to hold some
49 1.1.1.3.8.1 perseant // lookahead to avoid many calls to deflate_index_extract() for small lengths.
50 1.1.1.3.8.1 perseant //
51 1.1.1.3.8.1 perseant // Another way to build an index would be to use inflateCopy(). That would not
52 1.1.1.3.8.1 perseant // be constrained to have access points at block boundaries, but would require
53 1.1.1.3.8.1 perseant // more memory per access point, and could not be saved to a file due to the
54 1.1.1.3.8.1 perseant // use of pointers in the state. The approach here allows for storage of the
55 1.1.1.3.8.1 perseant // index in a file.
56 1.1 christos
57 1.1 christos #include <stdio.h>
58 1.1 christos #include <stdlib.h>
59 1.1 christos #include <string.h>
60 1.1.1.3.8.1 perseant #include <limits.h>
61 1.1 christos #include "zlib.h"
62 1.1.1.3 christos #include "zran.h"
63 1.1 christos
64 1.1.1.3.8.1 perseant #define WINSIZE 32768U // sliding window size
65 1.1.1.3.8.1 perseant #define CHUNK 16384 // file input buffer size
66 1.1 christos
67 1.1.1.3.8.1 perseant // See comments in zran.h.
68 1.1.1.3.8.1 perseant void deflate_index_free(struct deflate_index *index) {
69 1.1 christos if (index != NULL) {
70 1.1 christos free(index->list);
71 1.1 christos free(index);
72 1.1 christos }
73 1.1 christos }
74 1.1 christos
75 1.1.1.3.8.1 perseant // Add an access point to the list. If out of memory, deallocate the existing
76 1.1.1.3.8.1 perseant // list and return NULL. index->mode is temporarily the allocated number of
77 1.1.1.3.8.1 perseant // access points, until it is time for deflate_index_build() to return. Then
78 1.1.1.3.8.1 perseant // index->mode is set to the mode of inflation.
79 1.1.1.3.8.1 perseant static struct deflate_index *add_point(struct deflate_index *index, int bits,
80 1.1.1.3.8.1 perseant off_t in, off_t out, unsigned left,
81 1.1.1.3.8.1 perseant unsigned char *window) {
82 1.1 christos if (index == NULL) {
83 1.1.1.3.8.1 perseant // The list is empty. Create it, starting with eight access points.
84 1.1.1.3 christos index = malloc(sizeof(struct deflate_index));
85 1.1.1.3.8.1 perseant if (index == NULL)
86 1.1.1.3.8.1 perseant return NULL;
87 1.1.1.3.8.1 perseant index->have = 0;
88 1.1.1.3.8.1 perseant index->mode = 8;
89 1.1.1.3.8.1 perseant index->list = malloc(sizeof(point_t) * index->mode);
90 1.1 christos if (index->list == NULL) {
91 1.1 christos free(index);
92 1.1 christos return NULL;
93 1.1 christos }
94 1.1 christos }
95 1.1 christos
96 1.1.1.3.8.1 perseant else if (index->have == index->mode) {
97 1.1.1.3.8.1 perseant // The list is full. Make it bigger.
98 1.1.1.3.8.1 perseant index->mode <<= 1;
99 1.1.1.3.8.1 perseant point_t *next = realloc(index->list, sizeof(point_t) * index->mode);
100 1.1 christos if (next == NULL) {
101 1.1.1.3 christos deflate_index_free(index);
102 1.1 christos return NULL;
103 1.1 christos }
104 1.1 christos index->list = next;
105 1.1 christos }
106 1.1 christos
107 1.1.1.3.8.1 perseant // Fill in the access point and increment how many we have.
108 1.1.1.3.8.1 perseant point_t *next = (point_t *)(index->list) + index->have++;
109 1.1.1.3.8.1 perseant if (index->have < 0) {
110 1.1.1.3.8.1 perseant // Overflowed the int!
111 1.1.1.3.8.1 perseant deflate_index_free(index);
112 1.1.1.3.8.1 perseant return NULL;
113 1.1.1.3.8.1 perseant }
114 1.1 christos next->out = out;
115 1.1.1.3.8.1 perseant next->in = in;
116 1.1.1.3.8.1 perseant next->bits = bits;
117 1.1 christos if (left)
118 1.1 christos memcpy(next->window, window + WINSIZE - left, left);
119 1.1 christos if (left < WINSIZE)
120 1.1 christos memcpy(next->window + left, window, WINSIZE - left);
121 1.1 christos
122 1.1.1.3.8.1 perseant // Return the index, which may have been newly allocated or destroyed.
123 1.1 christos return index;
124 1.1 christos }
125 1.1 christos
126 1.1.1.3.8.1 perseant // Decompression modes. These are the inflateInit2() windowBits parameter.
127 1.1.1.3.8.1 perseant #define RAW -15
128 1.1.1.3.8.1 perseant #define ZLIB 15
129 1.1.1.3.8.1 perseant #define GZIP 31
130 1.1.1.3.8.1 perseant
131 1.1.1.3.8.1 perseant // See comments in zran.h.
132 1.1.1.3.8.1 perseant int deflate_index_build(FILE *in, off_t span, struct deflate_index **built) {
133 1.1.1.3.8.1 perseant // Set up inflation state.
134 1.1.1.3.8.1 perseant z_stream strm = {0}; // inflate engine (gets fired up later)
135 1.1.1.3.8.1 perseant unsigned char buf[CHUNK]; // input buffer
136 1.1.1.3.8.1 perseant unsigned char win[WINSIZE] = {0}; // output sliding window
137 1.1.1.3.8.1 perseant off_t totin = 0; // total bytes read from input
138 1.1.1.3.8.1 perseant off_t totout = 0; // total bytes uncompressed
139 1.1.1.3.8.1 perseant int mode = 0; // mode: RAW, ZLIB, or GZIP (0 => not set yet)
140 1.1.1.3.8.1 perseant
141 1.1.1.3.8.1 perseant // Decompress from in, generating access points along the way.
142 1.1.1.3.8.1 perseant int ret; // the return value from zlib, or Z_ERRNO
143 1.1.1.3.8.1 perseant off_t last; // last access point uncompressed offset
144 1.1.1.3.8.1 perseant struct deflate_index *index = NULL; // list of access points
145 1.1 christos do {
146 1.1.1.3.8.1 perseant // Assure available input, at least until reaching EOF.
147 1.1 christos if (strm.avail_in == 0) {
148 1.1.1.3.8.1 perseant strm.avail_in = fread(buf, 1, sizeof(buf), in);
149 1.1.1.3.8.1 perseant totin += strm.avail_in;
150 1.1.1.3.8.1 perseant strm.next_in = buf;
151 1.1.1.3.8.1 perseant if (strm.avail_in < sizeof(buf) && ferror(in)) {
152 1.1.1.3.8.1 perseant ret = Z_ERRNO;
153 1.1.1.3.8.1 perseant break;
154 1.1.1.3.8.1 perseant }
155 1.1 christos
156 1.1.1.3.8.1 perseant if (mode == 0) {
157 1.1.1.3.8.1 perseant // At the start of the input -- determine the type. Assume raw
158 1.1.1.3.8.1 perseant // if it is neither zlib nor gzip. This could in theory result
159 1.1.1.3.8.1 perseant // in a false positive for zlib, but in practice the fill bits
160 1.1.1.3.8.1 perseant // after a stored block are always zeros, so a raw stream won't
161 1.1.1.3.8.1 perseant // start with an 8 in the low nybble.
162 1.1.1.3.8.1 perseant mode = strm.avail_in == 0 ? RAW : // empty -- will fail
163 1.1.1.3.8.1 perseant (strm.next_in[0] & 0xf) == 8 ? ZLIB :
164 1.1.1.3.8.1 perseant strm.next_in[0] == 0x1f ? GZIP :
165 1.1.1.3.8.1 perseant /* else */ RAW;
166 1.1.1.3.8.1 perseant ret = inflateInit2(&strm, mode);
167 1.1.1.3.8.1 perseant if (ret != Z_OK)
168 1.1.1.3.8.1 perseant break;
169 1.1 christos }
170 1.1.1.3.8.1 perseant }
171 1.1 christos
172 1.1.1.3.8.1 perseant // Assure available output. This rotates the output through, for use as
173 1.1.1.3.8.1 perseant // a sliding window on the uncompressed data.
174 1.1.1.3.8.1 perseant if (strm.avail_out == 0) {
175 1.1.1.3.8.1 perseant strm.avail_out = sizeof(win);
176 1.1.1.3.8.1 perseant strm.next_out = win;
177 1.1.1.3.8.1 perseant }
178 1.1.1.3.8.1 perseant
179 1.1.1.3.8.1 perseant if (mode == RAW && index == NULL)
180 1.1.1.3.8.1 perseant // We skip the inflate() call at the start of raw deflate data in
181 1.1.1.3.8.1 perseant // order generate an access point there. Set data_type to imitate
182 1.1.1.3.8.1 perseant // the end of a header.
183 1.1.1.3.8.1 perseant strm.data_type = 0x80;
184 1.1.1.3.8.1 perseant else {
185 1.1.1.3.8.1 perseant // Inflate and update the number of uncompressed bytes.
186 1.1.1.3.8.1 perseant unsigned before = strm.avail_out;
187 1.1.1.3.8.1 perseant ret = inflate(&strm, Z_BLOCK);
188 1.1.1.3.8.1 perseant totout += before - strm.avail_out;
189 1.1.1.3.8.1 perseant }
190 1.1.1.3.8.1 perseant
191 1.1.1.3.8.1 perseant if ((strm.data_type & 0xc0) == 0x80 &&
192 1.1.1.3.8.1 perseant (index == NULL || totout - last >= span)) {
193 1.1.1.3.8.1 perseant // We are at the end of a header or a non-last deflate block, so we
194 1.1.1.3.8.1 perseant // can add an access point here. Furthermore, we are either at the
195 1.1.1.3.8.1 perseant // very start for the first access point, or there has been span or
196 1.1.1.3.8.1 perseant // more uncompressed bytes since the last access point, so we want
197 1.1.1.3.8.1 perseant // to add an access point here.
198 1.1.1.3.8.1 perseant index = add_point(index, strm.data_type & 7, totin - strm.avail_in,
199 1.1.1.3.8.1 perseant totout, strm.avail_out, win);
200 1.1.1.3.8.1 perseant if (index == NULL) {
201 1.1.1.3.8.1 perseant ret = Z_MEM_ERROR;
202 1.1 christos break;
203 1.1.1.3 christos }
204 1.1.1.3.8.1 perseant last = totout;
205 1.1.1.3.8.1 perseant }
206 1.1 christos
207 1.1.1.3.8.1 perseant if (ret == Z_STREAM_END && mode == GZIP &&
208 1.1.1.3.8.1 perseant (strm.avail_in || ungetc(getc(in), in) != EOF))
209 1.1.1.3.8.1 perseant // There is more input after the end of a gzip member. Reset the
210 1.1.1.3.8.1 perseant // inflate state to read another gzip member. On success, this will
211 1.1.1.3.8.1 perseant // set ret to Z_OK to continue decompressing.
212 1.1.1.3.8.1 perseant ret = inflateReset2(&strm, GZIP);
213 1.1.1.3.8.1 perseant
214 1.1.1.3.8.1 perseant // Keep going until Z_STREAM_END or error. If the compressed data ends
215 1.1.1.3.8.1 perseant // prematurely without a file read error, Z_BUF_ERROR is returned.
216 1.1.1.3.8.1 perseant } while (ret == Z_OK);
217 1.1.1.3.8.1 perseant inflateEnd(&strm);
218 1.1.1.3.8.1 perseant
219 1.1.1.3.8.1 perseant if (ret != Z_STREAM_END) {
220 1.1.1.3.8.1 perseant // An error was encountered. Discard the index and return a negative
221 1.1.1.3.8.1 perseant // error code.
222 1.1.1.3.8.1 perseant deflate_index_free(index);
223 1.1.1.3.8.1 perseant return ret == Z_NEED_DICT ? Z_DATA_ERROR : ret;
224 1.1.1.3.8.1 perseant }
225 1.1 christos
226 1.1.1.3.8.1 perseant // Shrink the index to only the occupied access points and return it.
227 1.1.1.3.8.1 perseant index->mode = mode;
228 1.1.1.3 christos index->length = totout;
229 1.1.1.3.8.1 perseant point_t *list = realloc(index->list, sizeof(point_t) * index->have);
230 1.1.1.3.8.1 perseant if (list == NULL) {
231 1.1.1.3.8.1 perseant // Seems like a realloc() to make something smaller should always work,
232 1.1.1.3.8.1 perseant // but just in case.
233 1.1.1.3.8.1 perseant deflate_index_free(index);
234 1.1.1.3.8.1 perseant return Z_MEM_ERROR;
235 1.1.1.3.8.1 perseant }
236 1.1.1.3.8.1 perseant index->list = list;
237 1.1 christos *built = index;
238 1.1.1.3 christos return index->have;
239 1.1.1.3.8.1 perseant }
240 1.1 christos
241 1.1.1.3.8.1 perseant #ifdef NOPRIME
242 1.1.1.3.8.1 perseant // Support zlib versions before 1.2.3 (July 2005), or incomplete zlib clones
243 1.1.1.3.8.1 perseant // that do not have inflatePrime().
244 1.1.1.3.8.1 perseant
245 1.1.1.3.8.1 perseant # define INFLATEPRIME inflatePreface
246 1.1.1.3.8.1 perseant
247 1.1.1.3.8.1 perseant // Append the low bits bits of value to in[] at bit position *have, updating
248 1.1.1.3.8.1 perseant // *have. value must be zero above its low bits bits. bits must be positive.
249 1.1.1.3.8.1 perseant // This assumes that any bits above the *have bits in the last byte are zeros.
250 1.1.1.3.8.1 perseant // That assumption is preserved on return, as any bits above *have + bits in
251 1.1.1.3.8.1 perseant // the last byte written will be set to zeros.
252 1.1.1.3.8.1 perseant static inline void append_bits(unsigned value, int bits,
253 1.1.1.3.8.1 perseant unsigned char *in, int *have) {
254 1.1.1.3.8.1 perseant in += *have >> 3; // where the first bits from value will go
255 1.1.1.3.8.1 perseant int k = *have & 7; // the number of bits already there
256 1.1.1.3.8.1 perseant *have += bits;
257 1.1.1.3.8.1 perseant if (k)
258 1.1.1.3.8.1 perseant *in |= value << k; // write value above the low k bits
259 1.1.1.3.8.1 perseant else
260 1.1.1.3.8.1 perseant *in = value;
261 1.1.1.3.8.1 perseant k = 8 - k; // the number of bits just appended
262 1.1.1.3.8.1 perseant while (bits > k) {
263 1.1.1.3.8.1 perseant value >>= k; // drop the bits appended
264 1.1.1.3.8.1 perseant bits -= k;
265 1.1.1.3.8.1 perseant k = 8; // now at a byte boundary
266 1.1.1.3.8.1 perseant *++in = value;
267 1.1.1.3.8.1 perseant }
268 1.1 christos }
269 1.1 christos
270 1.1.1.3.8.1 perseant // Insert enough bits in the form of empty deflate blocks in front of the
271 1.1.1.3.8.1 perseant // low bits bits of value, in order to bring the sequence to a byte boundary.
272 1.1.1.3.8.1 perseant // Then feed that to inflate(). This does what inflatePrime() does, except that
273 1.1.1.3.8.1 perseant // a negative value of bits is not supported. bits must be in 0..16. If the
274 1.1.1.3.8.1 perseant // arguments are invalid, Z_STREAM_ERROR is returned. Otherwise the return
275 1.1.1.3.8.1 perseant // value from inflate() is returned.
276 1.1.1.3.8.1 perseant static int inflatePreface(z_stream *strm, int bits, int value) {
277 1.1.1.3.8.1 perseant // Check input.
278 1.1.1.3.8.1 perseant if (strm == Z_NULL || bits < 0 || bits > 16)
279 1.1.1.3.8.1 perseant return Z_STREAM_ERROR;
280 1.1.1.3.8.1 perseant if (bits == 0)
281 1.1.1.3.8.1 perseant return Z_OK;
282 1.1.1.3.8.1 perseant value &= (2 << (bits - 1)) - 1;
283 1.1.1.3.8.1 perseant
284 1.1.1.3.8.1 perseant // An empty dynamic block with an odd number of bits (95). The high bit of
285 1.1.1.3.8.1 perseant // the last byte is unused.
286 1.1.1.3.8.1 perseant static const unsigned char dyn[] = {
287 1.1.1.3.8.1 perseant 4, 0xe0, 0x81, 8, 0, 0, 0, 0, 0x20, 0xa8, 0xab, 0x1f
288 1.1.1.3.8.1 perseant };
289 1.1.1.3.8.1 perseant const int dynlen = 95; // number of bits in the block
290 1.1.1.3.8.1 perseant
291 1.1.1.3.8.1 perseant // Build an input buffer for inflate that is a multiple of eight bits in
292 1.1.1.3.8.1 perseant // length, and that ends with the low bits bits of value.
293 1.1.1.3.8.1 perseant unsigned char in[(dynlen + 3 * 10 + 16 + 7) / 8];
294 1.1.1.3.8.1 perseant int have = 0;
295 1.1.1.3.8.1 perseant if (bits & 1) {
296 1.1.1.3.8.1 perseant // Insert an empty dynamic block to get to an odd number of bits, so
297 1.1.1.3.8.1 perseant // when bits bits from value are appended, we are at an even number of
298 1.1.1.3.8.1 perseant // bits.
299 1.1.1.3.8.1 perseant memcpy(in, dyn, sizeof(dyn));
300 1.1.1.3.8.1 perseant have = dynlen;
301 1.1.1.3.8.1 perseant }
302 1.1.1.3.8.1 perseant while ((have + bits) & 7)
303 1.1.1.3.8.1 perseant // Insert empty fixed blocks until appending bits bits would put us on
304 1.1.1.3.8.1 perseant // a byte boundary. This will insert at most three fixed blocks.
305 1.1.1.3.8.1 perseant append_bits(2, 10, in, &have);
306 1.1.1.3.8.1 perseant
307 1.1.1.3.8.1 perseant // Append the bits bits from value, which takes us to a byte boundary.
308 1.1.1.3.8.1 perseant append_bits(value, bits, in, &have);
309 1.1.1.3.8.1 perseant
310 1.1.1.3.8.1 perseant // Deliver the input to inflate(). There is no output space provided, but
311 1.1.1.3.8.1 perseant // inflate() can't get stuck waiting on output not ingesting all of the
312 1.1.1.3.8.1 perseant // provided input. The reason is that there will be at most 16 bits of
313 1.1.1.3.8.1 perseant // input from value after the empty deflate blocks (which themselves
314 1.1.1.3.8.1 perseant // generate no output). At least ten bits are needed to generate the first
315 1.1.1.3.8.1 perseant // output byte from a fixed block. The last two bytes of the buffer have to
316 1.1.1.3.8.1 perseant // be ingested in order to get ten bits, which is the most that value can
317 1.1.1.3.8.1 perseant // occupy.
318 1.1.1.3.8.1 perseant strm->avail_in = have >> 3;
319 1.1.1.3.8.1 perseant strm->next_in = in;
320 1.1.1.3.8.1 perseant strm->avail_out = 0;
321 1.1.1.3.8.1 perseant strm->next_out = in; // not used, but can't be NULL
322 1.1.1.3.8.1 perseant return inflate(strm, Z_NO_FLUSH);
323 1.1.1.3.8.1 perseant }
324 1.1.1.3.8.1 perseant
325 1.1.1.3.8.1 perseant #else
326 1.1.1.3.8.1 perseant # define INFLATEPRIME inflatePrime
327 1.1.1.3.8.1 perseant #endif
328 1.1 christos
329 1.1.1.3.8.1 perseant // See comments in zran.h.
330 1.1.1.3.8.1 perseant ptrdiff_t deflate_index_extract(FILE *in, struct deflate_index *index,
331 1.1.1.3.8.1 perseant off_t offset, unsigned char *buf, size_t len) {
332 1.1.1.3.8.1 perseant // Do a quick sanity check on the index.
333 1.1.1.3.8.1 perseant if (index == NULL || index->have < 1 || index->list[0].out != 0)
334 1.1.1.3.8.1 perseant return Z_STREAM_ERROR;
335 1.1.1.3.8.1 perseant
336 1.1.1.3.8.1 perseant // If nothing to extract, return zero bytes extracted.
337 1.1.1.3.8.1 perseant if (len == 0 || offset < 0 || offset >= index->length)
338 1.1 christos return 0;
339 1.1 christos
340 1.1.1.3.8.1 perseant // Find the access point closest to but not after offset.
341 1.1.1.3.8.1 perseant int lo = -1, hi = index->have;
342 1.1.1.3.8.1 perseant point_t *point = index->list;
343 1.1.1.3.8.1 perseant while (hi - lo > 1) {
344 1.1.1.3.8.1 perseant int mid = (lo + hi) >> 1;
345 1.1.1.3.8.1 perseant if (offset < point[mid].out)
346 1.1.1.3.8.1 perseant hi = mid;
347 1.1.1.3.8.1 perseant else
348 1.1.1.3.8.1 perseant lo = mid;
349 1.1.1.3.8.1 perseant }
350 1.1.1.3.8.1 perseant point += lo;
351 1.1.1.3.8.1 perseant
352 1.1.1.3.8.1 perseant // Initialize the input file and prime the inflate engine to start there.
353 1.1.1.3.8.1 perseant int ret = fseeko(in, point->in - (point->bits ? 1 : 0), SEEK_SET);
354 1.1.1.3.8.1 perseant if (ret == -1)
355 1.1.1.3.8.1 perseant return Z_ERRNO;
356 1.1.1.3.8.1 perseant int ch = 0;
357 1.1.1.3.8.1 perseant if (point->bits && (ch = getc(in)) == EOF)
358 1.1.1.3.8.1 perseant return ferror(in) ? Z_ERRNO : Z_BUF_ERROR;
359 1.1.1.3.8.1 perseant z_stream strm = {0};
360 1.1.1.3.8.1 perseant ret = inflateInit2(&strm, RAW);
361 1.1 christos if (ret != Z_OK)
362 1.1 christos return ret;
363 1.1.1.3.8.1 perseant if (point->bits)
364 1.1.1.3.8.1 perseant INFLATEPRIME(&strm, point->bits, ch >> (8 - point->bits));
365 1.1.1.3.8.1 perseant inflateSetDictionary(&strm, point->window, WINSIZE);
366 1.1.1.3.8.1 perseant
367 1.1.1.3.8.1 perseant // Skip uncompressed bytes until offset reached, then satisfy request.
368 1.1.1.3.8.1 perseant unsigned char input[CHUNK];
369 1.1.1.3.8.1 perseant unsigned char discard[WINSIZE];
370 1.1.1.3.8.1 perseant offset -= point->out; // number of bytes to skip to get to offset
371 1.1.1.3.8.1 perseant size_t left = len; // number of bytes left to read after offset
372 1.1 christos do {
373 1.1.1.3.8.1 perseant if (offset) {
374 1.1.1.3.8.1 perseant // Discard up to offset uncompressed bytes.
375 1.1.1.3.8.1 perseant strm.avail_out = offset < WINSIZE ? (unsigned)offset : WINSIZE;
376 1.1 christos strm.next_out = discard;
377 1.1 christos }
378 1.1.1.3.8.1 perseant else {
379 1.1.1.3.8.1 perseant // Uncompress up to left bytes into buf.
380 1.1.1.3.8.1 perseant strm.avail_out = left < UINT_MAX ? (unsigned)left : UINT_MAX;
381 1.1.1.3.8.1 perseant strm.next_out = buf + len - left;
382 1.1 christos }
383 1.1.1.3 christos
384 1.1.1.3.8.1 perseant // Uncompress, setting got to the number of bytes uncompressed.
385 1.1.1.3.8.1 perseant if (strm.avail_in == 0) {
386 1.1.1.3.8.1 perseant // Assure available input.
387 1.1.1.3.8.1 perseant strm.avail_in = fread(input, 1, CHUNK, in);
388 1.1.1.3.8.1 perseant if (strm.avail_in < CHUNK && ferror(in)) {
389 1.1.1.3.8.1 perseant ret = Z_ERRNO;
390 1.1.1.3.8.1 perseant break;
391 1.1.1.3.8.1 perseant }
392 1.1.1.3.8.1 perseant strm.next_in = input;
393 1.1.1.3.8.1 perseant }
394 1.1.1.3.8.1 perseant unsigned got = strm.avail_out;
395 1.1.1.3.8.1 perseant ret = inflate(&strm, Z_NO_FLUSH);
396 1.1.1.3.8.1 perseant got -= strm.avail_out;
397 1.1.1.3.8.1 perseant
398 1.1.1.3.8.1 perseant // Update the appropriate count.
399 1.1.1.3.8.1 perseant if (offset)
400 1.1.1.3.8.1 perseant offset -= got;
401 1.1.1.3.8.1 perseant else
402 1.1.1.3.8.1 perseant left -= got;
403 1.1.1.3.8.1 perseant
404 1.1.1.3.8.1 perseant // If we're at the end of a gzip member and there's more to read,
405 1.1.1.3.8.1 perseant // continue to the next gzip member.
406 1.1.1.3.8.1 perseant if (ret == Z_STREAM_END && index->mode == GZIP) {
407 1.1.1.3.8.1 perseant // Discard the gzip trailer.
408 1.1.1.3.8.1 perseant unsigned drop = 8; // length of gzip trailer
409 1.1.1.3.8.1 perseant if (strm.avail_in >= drop) {
410 1.1.1.3.8.1 perseant strm.avail_in -= drop;
411 1.1.1.3.8.1 perseant strm.next_in += drop;
412 1.1.1.3.8.1 perseant }
413 1.1.1.3.8.1 perseant else {
414 1.1.1.3.8.1 perseant // Read and discard the remainder of the gzip trailer.
415 1.1.1.3.8.1 perseant drop -= strm.avail_in;
416 1.1.1.3.8.1 perseant strm.avail_in = 0;
417 1.1.1.3.8.1 perseant do {
418 1.1.1.3.8.1 perseant if (getc(in) == EOF)
419 1.1.1.3.8.1 perseant // The input does not have a complete trailer.
420 1.1.1.3.8.1 perseant return ferror(in) ? Z_ERRNO : Z_BUF_ERROR;
421 1.1.1.3.8.1 perseant } while (--drop);
422 1.1.1.3.8.1 perseant }
423 1.1.1.3 christos
424 1.1.1.3.8.1 perseant if (strm.avail_in || ungetc(getc(in), in) != EOF) {
425 1.1.1.3.8.1 perseant // There's more after the gzip trailer. Use inflate to skip the
426 1.1.1.3.8.1 perseant // gzip header and resume the raw inflate there.
427 1.1.1.3.8.1 perseant inflateReset2(&strm, GZIP);
428 1.1.1.3 christos do {
429 1.1.1.3 christos if (strm.avail_in == 0) {
430 1.1.1.3 christos strm.avail_in = fread(input, 1, CHUNK, in);
431 1.1.1.3.8.1 perseant if (strm.avail_in < CHUNK && ferror(in)) {
432 1.1.1.3 christos ret = Z_ERRNO;
433 1.1.1.3.8.1 perseant break;
434 1.1.1.3 christos }
435 1.1.1.3 christos strm.next_in = input;
436 1.1.1.3 christos }
437 1.1.1.3.8.1 perseant strm.avail_out = WINSIZE;
438 1.1.1.3.8.1 perseant strm.next_out = discard;
439 1.1.1.3.8.1 perseant ret = inflate(&strm, Z_BLOCK); // stop at end of header
440 1.1.1.3.8.1 perseant } while (ret == Z_OK && (strm.data_type & 0x80) == 0);
441 1.1.1.3 christos if (ret != Z_OK)
442 1.1.1.3.8.1 perseant break;
443 1.1.1.3.8.1 perseant inflateReset2(&strm, RAW);
444 1.1.1.3 christos }
445 1.1.1.3.8.1 perseant }
446 1.1.1.3 christos
447 1.1.1.3.8.1 perseant // Continue until we have the requested data, the deflate data has
448 1.1.1.3.8.1 perseant // ended, or an error is encountered.
449 1.1.1.3.8.1 perseant } while (ret == Z_OK && left);
450 1.1.1.3.8.1 perseant inflateEnd(&strm);
451 1.1 christos
452 1.1.1.3.8.1 perseant // Return the number of uncompressed bytes read into buf, or the error.
453 1.1.1.3.8.1 perseant return ret == Z_OK || ret == Z_STREAM_END ? len - left : ret;
454 1.1 christos }
455 1.1 christos
456 1.1.1.3 christos #ifdef TEST
457 1.1.1.3 christos
458 1.1.1.3.8.1 perseant #define SPAN 1048576L // desired distance between access points
459 1.1.1.3.8.1 perseant #define LEN 16384 // number of bytes to extract
460 1.1 christos
461 1.1.1.3.8.1 perseant // Demonstrate the use of deflate_index_build() and deflate_index_extract() by
462 1.1.1.3.8.1 perseant // processing the file provided on the command line, and extracting LEN bytes
463 1.1.1.3.8.1 perseant // from 2/3rds of the way through the uncompressed output, writing that to
464 1.1.1.3.8.1 perseant // stdout. An offset can be provided as the second argument, in which case the
465 1.1.1.3.8.1 perseant // data is extracted from there instead.
466 1.1.1.3.8.1 perseant int main(int argc, char **argv) {
467 1.1.1.3.8.1 perseant // Open the input file.
468 1.1.1.3 christos if (argc < 2 || argc > 3) {
469 1.1.1.3.8.1 perseant fprintf(stderr, "usage: zran file.raw [offset]\n");
470 1.1 christos return 1;
471 1.1 christos }
472 1.1.1.3.8.1 perseant FILE *in = fopen(argv[1], "rb");
473 1.1 christos if (in == NULL) {
474 1.1 christos fprintf(stderr, "zran: could not open %s for reading\n", argv[1]);
475 1.1 christos return 1;
476 1.1 christos }
477 1.1 christos
478 1.1.1.3.8.1 perseant // Get optional offset.
479 1.1.1.3.8.1 perseant off_t offset = -1;
480 1.1.1.3 christos if (argc == 3) {
481 1.1.1.3 christos char *end;
482 1.1.1.3 christos offset = strtoll(argv[2], &end, 10);
483 1.1.1.3 christos if (*end || offset < 0) {
484 1.1.1.3 christos fprintf(stderr, "zran: %s is not a valid offset\n", argv[2]);
485 1.1.1.3 christos return 1;
486 1.1.1.3 christos }
487 1.1.1.3 christos }
488 1.1.1.3 christos
489 1.1.1.3.8.1 perseant // Build index.
490 1.1.1.3.8.1 perseant struct deflate_index *index = NULL;
491 1.1.1.3.8.1 perseant int len = deflate_index_build(in, SPAN, &index);
492 1.1 christos if (len < 0) {
493 1.1 christos fclose(in);
494 1.1 christos switch (len) {
495 1.1 christos case Z_MEM_ERROR:
496 1.1 christos fprintf(stderr, "zran: out of memory\n");
497 1.1 christos break;
498 1.1.1.3.8.1 perseant case Z_BUF_ERROR:
499 1.1.1.3.8.1 perseant fprintf(stderr, "zran: %s ended prematurely\n", argv[1]);
500 1.1.1.3.8.1 perseant break;
501 1.1 christos case Z_DATA_ERROR:
502 1.1 christos fprintf(stderr, "zran: compressed data error in %s\n", argv[1]);
503 1.1 christos break;
504 1.1 christos case Z_ERRNO:
505 1.1 christos fprintf(stderr, "zran: read error on %s\n", argv[1]);
506 1.1 christos break;
507 1.1 christos default:
508 1.1 christos fprintf(stderr, "zran: error %d while building index\n", len);
509 1.1 christos }
510 1.1 christos return 1;
511 1.1 christos }
512 1.1 christos fprintf(stderr, "zran: built index with %d access points\n", len);
513 1.1 christos
514 1.1.1.3.8.1 perseant // Use index by reading some bytes from an arbitrary offset.
515 1.1.1.3.8.1 perseant unsigned char buf[LEN];
516 1.1.1.3 christos if (offset == -1)
517 1.1.1.3.8.1 perseant offset = ((index->length + 1) << 1) / 3;
518 1.1.1.3.8.1 perseant ptrdiff_t got = deflate_index_extract(in, index, offset, buf, LEN);
519 1.1.1.3.8.1 perseant if (got < 0)
520 1.1 christos fprintf(stderr, "zran: extraction failed: %s error\n",
521 1.1.1.3.8.1 perseant got == Z_MEM_ERROR ? "out of memory" : "input corrupted");
522 1.1 christos else {
523 1.1.1.3.8.1 perseant fwrite(buf, 1, got, stdout);
524 1.1.1.3.8.1 perseant fprintf(stderr, "zran: extracted %ld bytes at %lld\n", got, offset);
525 1.1 christos }
526 1.1 christos
527 1.1.1.3.8.1 perseant // Clean up and exit.
528 1.1.1.3 christos deflate_index_free(index);
529 1.1 christos fclose(in);
530 1.1 christos return 0;
531 1.1 christos }
532 1.1.1.3 christos
533 1.1.1.3 christos #endif
534