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