Home | History | Annotate | Line # | Download | only in examples
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