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