00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052 #include <string.h>
00053 #include "zlib.h"
00054
00055 #define local static
00056
00057 #define SPAN 1048576L
00058 #define WINSIZE 32768U
00059 #define CHUNK 16384
00060
00061
00062 struct point {
00063 off_t out;
00064 off_t in;
00065 int bits;
00066 unsigned char window[WINSIZE];
00067 };
00068
00069
00070 struct access {
00071 int have;
00072 int size;
00073 struct point *list;
00074 };
00075
00076
00077 local void free_index(struct access *index)
00078 {
00079 if (index != NULL) {
00080 free(index->list);
00081 free(index);
00082 }
00083 }
00084
00085
00086
00087 local struct access *addpoint(struct access *index, int bits,
00088 off_t in, off_t out, unsigned left, unsigned char *window)
00089 {
00090 struct point *next;
00091
00092
00093 if (index == NULL) {
00094 index = malloc(sizeof(struct access));
00095 if (index == NULL) return NULL;
00096 index->list = malloc(sizeof(struct point) << 3);
00097 if (index->list == NULL) {
00098 free(index);
00099 return NULL;
00100 }
00101 index->size = 8;
00102 index->have = 0;
00103 }
00104
00105
00106 else if (index->have == index->size) {
00107 index->size <<= 1;
00108 next = realloc(index->list, sizeof(struct point) * index->size);
00109 if (next == NULL) {
00110 free_index(index);
00111 return NULL;
00112 }
00113 index->list = next;
00114 }
00115
00116
00117 next = index->list + index->have;
00118 next->bits = bits;
00119 next->in = in;
00120 next->out = out;
00121 if (left)
00122 memcpy(next->window, window + WINSIZE - left, left);
00123 if (left < WINSIZE)
00124 memcpy(next->window + left, window, WINSIZE - left);
00125 index->have++;
00126
00127
00128 return index;
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 local int build_index(FILE *in, off_t span, struct access **built)
00140 {
00141 int ret;
00142 off_t totin, totout;
00143 off_t last;
00144 struct access *index;
00145 z_stream strm;
00146 unsigned char input[CHUNK];
00147 unsigned char window[WINSIZE];
00148
00149
00150 strm.zalloc = Z_NULL;
00151 strm.zfree = Z_NULL;
00152 strm.opaque = Z_NULL;
00153 strm.avail_in = 0;
00154 strm.next_in = Z_NULL;
00155 ret = inflateInit2(&strm, 47);
00156 if (ret != Z_OK)
00157 return ret;
00158
00159
00160
00161
00162 totin = totout = last = 0;
00163 index = NULL;
00164 strm.avail_out = 0;
00165 do {
00166
00167 strm.avail_in = fread(input, 1, CHUNK, in);
00168 if (ferror(in)) {
00169 ret = Z_ERRNO;
00170 goto build_index_error;
00171 }
00172 if (strm.avail_in == 0) {
00173 ret = Z_DATA_ERROR;
00174 goto build_index_error;
00175 }
00176 strm.next_in = input;
00177
00178
00179 do {
00180
00181 if (strm.avail_out == 0) {
00182 strm.avail_out = WINSIZE;
00183 strm.next_out = window;
00184 }
00185
00186
00187
00188 totin += strm.avail_in;
00189 totout += strm.avail_out;
00190 ret = inflate(&strm, Z_BLOCK);
00191 totin -= strm.avail_in;
00192 totout -= strm.avail_out;
00193 if (ret == Z_NEED_DICT)
00194 ret = Z_DATA_ERROR;
00195 if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR)
00196 goto build_index_error;
00197 if (ret == Z_STREAM_END)
00198 break;
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 if ((strm.data_type & 128) && !(strm.data_type & 64) &&
00210 (totout == 0 || totout - last > span)) {
00211 index = addpoint(index, strm.data_type & 7, totin,
00212 totout, strm.avail_out, window);
00213 if (index == NULL) {
00214 ret = Z_MEM_ERROR;
00215 goto build_index_error;
00216 }
00217 last = totout;
00218 }
00219 } while (strm.avail_in != 0);
00220 } while (ret != Z_STREAM_END);
00221
00222
00223 (void)inflateEnd(&strm);
00224 index = realloc(index, sizeof(struct point) * index->have);
00225 index->size = index->have;
00226 *built = index;
00227 return index->size;
00228
00229
00230 build_index_error:
00231 (void)inflateEnd(&strm);
00232 if (index != NULL)
00233 free_index(index);
00234 return ret;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244 local int extract(FILE *in, struct access *index, off_t offset,
00245 unsigned char *buf, int len)
00246 {
00247 int ret, skip;
00248 z_stream strm;
00249 struct point *here;
00250 unsigned char input[CHUNK];
00251 unsigned char discard[WINSIZE];
00252
00253
00254 if (len < 0)
00255 return 0;
00256
00257
00258 here = index->list;
00259 ret = index->have;
00260 while (--ret && here[1].out <= offset)
00261 here++;
00262
00263
00264 strm.zalloc = Z_NULL;
00265 strm.zfree = Z_NULL;
00266 strm.opaque = Z_NULL;
00267 strm.avail_in = 0;
00268 strm.next_in = Z_NULL;
00269 ret = inflateInit2(&strm, -15);
00270 if (ret != Z_OK)
00271 return ret;
00272 ret = fseeko(in, here->in - (here->bits ? 1 : 0), SEEK_SET);
00273 if (ret == -1)
00274 goto extract_ret;
00275 if (here->bits) {
00276 ret = getc(in);
00277 if (ret == -1) {
00278 ret = ferror(in) ? Z_ERRNO : Z_DATA_ERROR;
00279 goto extract_ret;
00280 }
00281 (void)inflatePrime(&strm, here->bits, ret >> (8 - here->bits));
00282 }
00283 (void)inflateSetDictionary(&strm, here->window, WINSIZE);
00284
00285
00286 offset -= here->out;
00287 strm.avail_in = 0;
00288 skip = 1;
00289 do {
00290
00291 if (offset == 0 && skip) {
00292 strm.avail_out = len;
00293 strm.next_out = buf;
00294 skip = 0;
00295 }
00296 if (offset > WINSIZE) {
00297 strm.avail_out = WINSIZE;
00298 strm.next_out = discard;
00299 offset -= WINSIZE;
00300 }
00301 else if (offset != 0) {
00302 strm.avail_out = (unsigned)offset;
00303 strm.next_out = discard;
00304 offset = 0;
00305 }
00306
00307
00308 do {
00309 if (strm.avail_in == 0) {
00310 strm.avail_in = fread(input, 1, CHUNK, in);
00311 if (ferror(in)) {
00312 ret = Z_ERRNO;
00313 goto extract_ret;
00314 }
00315 if (strm.avail_in == 0) {
00316 ret = Z_DATA_ERROR;
00317 goto extract_ret;
00318 }
00319 strm.next_in = input;
00320 }
00321 ret = inflate(&strm, Z_NO_FLUSH);
00322 if (ret == Z_NEED_DICT)
00323 ret = Z_DATA_ERROR;
00324 if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR)
00325 goto extract_ret;
00326 if (ret == Z_STREAM_END)
00327 break;
00328 } while (strm.avail_out != 0);
00329
00330
00331 if (ret == Z_STREAM_END)
00332 break;
00333
00334
00335 } while (skip);
00336
00337
00338 ret = skip ? 0 : len - strm.avail_out;
00339
00340
00341 extract_ret:
00342 (void)inflateEnd(&strm);
00343 return ret;
00344 }
00345
00346
00347
00348
00349 int main(int argc, char **argv)
00350 {
00351 int len;
00352 off_t offset;
00353 FILE *in;
00354 struct access *index = NULL;
00355 unsigned char buf[CHUNK];
00356
00357
00358 if (argc != 2) {
00359 fprintf(stderr, "usage: zran file.gz\n");
00360 return 1;
00361 }
00362 in = fopen(argv[1], "rb");
00363 if (in == NULL) {
00364 fprintf(stderr, "zran: could not open %s for reading\n", argv[1]);
00365 return 1;
00366 }
00367
00368
00369 len = build_index(in, SPAN, &index);
00370 if (len < 0) {
00371 fclose(in);
00372 switch (len) {
00373 case Z_MEM_ERROR:
00374 fprintf(stderr, "zran: out of memory\n");
00375 break;
00376 case Z_DATA_ERROR:
00377 fprintf(stderr, "zran: compressed data error in %s\n", argv[1]);
00378 break;
00379 case Z_ERRNO:
00380 fprintf(stderr, "zran: read error on %s\n", argv[1]);
00381 break;
00382 default:
00383 fprintf(stderr, "zran: error %d while building index\n", len);
00384 }
00385 return 1;
00386 }
00387 fprintf(stderr, "zran: built index with %d access points\n", len);
00388
00389
00390 offset = (index->list[index->have - 1].out << 1) / 3;
00391 len = extract(in, index, offset, buf, CHUNK);
00392 if (len < 0)
00393 fprintf(stderr, "zran: extraction failed: %s error\n",
00394 len == Z_MEM_ERROR ? "out of memory" : "input corrupted");
00395 else {
00396 fwrite(buf, 1, len, stdout);
00397 fprintf(stderr, "zran: extracted %d bytes at %llu\n", len, offset);
00398 }
00399
00400
00401 free_index(index);
00402 fclose(in);
00403 return 0;
00404 }