diff options
author | Mark Adler <madler@alumni.caltech.edu> | 2016-12-04 17:09:33 -0800 |
---|---|---|
committer | Mark Adler <madler@alumni.caltech.edu> | 2016-12-04 18:35:41 -0800 |
commit | 44dfd831d24f9b627ab666cf0973b0dce98fabba (patch) | |
tree | 63d4dbb73dd292e96beb4e171c12a9a36399d6bc | |
parent | 3f8c768745e85d0e63ba306581710c6dc9db0d65 (diff) | |
download | zlib-44dfd831d24f9b627ab666cf0973b0dce98fabba.tar.gz zlib-44dfd831d24f9b627ab666cf0973b0dce98fabba.tar.bz2 zlib-44dfd831d24f9b627ab666cf0973b0dce98fabba.zip |
Add gzfread(), duplicating the interface of fread().
-rw-r--r-- | gzread.c | 136 | ||||
-rw-r--r-- | zlib.h | 30 |
2 files changed, 126 insertions, 40 deletions
@@ -12,6 +12,7 @@ local int gz_look OF((gz_statep)); | |||
12 | local int gz_decomp OF((gz_statep)); | 12 | local int gz_decomp OF((gz_statep)); |
13 | local int gz_fetch OF((gz_statep)); | 13 | local int gz_fetch OF((gz_statep)); |
14 | local int gz_skip OF((gz_statep, z_off64_t)); | 14 | local int gz_skip OF((gz_statep, z_off64_t)); |
15 | local z_size_t gz_read OF((gz_statep, voidp, z_size_t)); | ||
15 | 16 | ||
16 | /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from | 17 | /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from |
17 | state->fd, and update state->eof, state->err, and state->msg as appropriate. | 18 | state->fd, and update state->eof, state->err, and state->msg as appropriate. |
@@ -284,33 +285,17 @@ local int gz_skip(state, len) | |||
284 | return 0; | 285 | return 0; |
285 | } | 286 | } |
286 | 287 | ||
287 | /* -- see zlib.h -- */ | 288 | /* Read len bytes into buf from file, or less than len up to the end of the |
288 | int ZEXPORT gzread(file, buf, len) | 289 | input. Return the number of bytes read. If zero is returned, either the |
289 | gzFile file; | 290 | end of file was reached, or there was an error. state->err must be |
291 | consulted in that case to determine which. */ | ||
292 | local z_size_t gz_read(state, buf, len) | ||
293 | gz_statep state; | ||
290 | voidp buf; | 294 | voidp buf; |
291 | unsigned len; | 295 | z_size_t len; |
292 | { | 296 | { |
293 | unsigned got, n; | 297 | z_size_t got; |
294 | gz_statep state; | 298 | unsigned n; |
295 | z_streamp strm; | ||
296 | |||
297 | /* get internal structure */ | ||
298 | if (file == NULL) | ||
299 | return -1; | ||
300 | state = (gz_statep)file; | ||
301 | strm = &(state->strm); | ||
302 | |||
303 | /* check that we're reading and that there's no (serious) error */ | ||
304 | if (state->mode != GZ_READ || | ||
305 | (state->err != Z_OK && state->err != Z_BUF_ERROR)) | ||
306 | return -1; | ||
307 | |||
308 | /* since an int is returned, make sure len fits in one, otherwise return | ||
309 | with an error (this avoids the flaw in the interface) */ | ||
310 | if ((int)len < 0) { | ||
311 | gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); | ||
312 | return -1; | ||
313 | } | ||
314 | 299 | ||
315 | /* if len is zero, avoid unnecessary operations */ | 300 | /* if len is zero, avoid unnecessary operations */ |
316 | if (len == 0) | 301 | if (len == 0) |
@@ -320,32 +305,38 @@ int ZEXPORT gzread(file, buf, len) | |||
320 | if (state->seek) { | 305 | if (state->seek) { |
321 | state->seek = 0; | 306 | state->seek = 0; |
322 | if (gz_skip(state, state->skip) == -1) | 307 | if (gz_skip(state, state->skip) == -1) |
323 | return -1; | 308 | return 0; |
324 | } | 309 | } |
325 | 310 | ||
326 | /* get len bytes to buf, or less than len if at the end */ | 311 | /* get len bytes to buf, or less than len if at the end */ |
327 | got = 0; | 312 | got = 0; |
328 | do { | 313 | do { |
314 | /* set n to the maximum amount of len that fits in an unsigned int */ | ||
315 | n = -1; | ||
316 | if (n > len) | ||
317 | n = len; | ||
318 | |||
329 | /* first just try copying data from the output buffer */ | 319 | /* first just try copying data from the output buffer */ |
330 | if (state->x.have) { | 320 | if (state->x.have) { |
331 | n = state->x.have > len ? len : state->x.have; | 321 | if (state->x.have < n) |
322 | n = state->x.have; | ||
332 | memcpy(buf, state->x.next, n); | 323 | memcpy(buf, state->x.next, n); |
333 | state->x.next += n; | 324 | state->x.next += n; |
334 | state->x.have -= n; | 325 | state->x.have -= n; |
335 | } | 326 | } |
336 | 327 | ||
337 | /* output buffer empty -- return if we're at the end of the input */ | 328 | /* output buffer empty -- return if we're at the end of the input */ |
338 | else if (state->eof && strm->avail_in == 0) { | 329 | else if (state->eof && state->strm.avail_in == 0) { |
339 | state->past = 1; /* tried to read past end */ | 330 | state->past = 1; /* tried to read past end */ |
340 | break; | 331 | break; |
341 | } | 332 | } |
342 | 333 | ||
343 | /* need output data -- for small len or new stream load up our output | 334 | /* need output data -- for small len or new stream load up our output |
344 | buffer */ | 335 | buffer */ |
345 | else if (state->how == LOOK || len < (state->size << 1)) { | 336 | else if (state->how == LOOK || n < (state->size << 1)) { |
346 | /* get more output, looking for header if required */ | 337 | /* get more output, looking for header if required */ |
347 | if (gz_fetch(state) == -1) | 338 | if (gz_fetch(state) == -1) |
348 | return -1; | 339 | return 0; |
349 | continue; /* no progress yet -- go back to copy above */ | 340 | continue; /* no progress yet -- go back to copy above */ |
350 | /* the copy above assures that we will leave with space in the | 341 | /* the copy above assures that we will leave with space in the |
351 | output buffer, allowing at least one gzungetc() to succeed */ | 342 | output buffer, allowing at least one gzungetc() to succeed */ |
@@ -353,16 +344,16 @@ int ZEXPORT gzread(file, buf, len) | |||
353 | 344 | ||
354 | /* large len -- read directly into user buffer */ | 345 | /* large len -- read directly into user buffer */ |
355 | else if (state->how == COPY) { /* read directly */ | 346 | else if (state->how == COPY) { /* read directly */ |
356 | if (gz_load(state, (unsigned char *)buf, len, &n) == -1) | 347 | if (gz_load(state, (unsigned char *)buf, n, &n) == -1) |
357 | return -1; | 348 | return 0; |
358 | } | 349 | } |
359 | 350 | ||
360 | /* large len -- decompress directly into user buffer */ | 351 | /* large len -- decompress directly into user buffer */ |
361 | else { /* state->how == GZIP */ | 352 | else { /* state->how == GZIP */ |
362 | strm->avail_out = len; | 353 | state->strm.avail_out = n; |
363 | strm->next_out = (unsigned char *)buf; | 354 | state->strm.next_out = (unsigned char *)buf; |
364 | if (gz_decomp(state) == -1) | 355 | if (gz_decomp(state) == -1) |
365 | return -1; | 356 | return 0; |
366 | n = state->x.have; | 357 | n = state->x.have; |
367 | state->x.have = 0; | 358 | state->x.have = 0; |
368 | } | 359 | } |
@@ -374,8 +365,75 @@ int ZEXPORT gzread(file, buf, len) | |||
374 | state->x.pos += n; | 365 | state->x.pos += n; |
375 | } while (len); | 366 | } while (len); |
376 | 367 | ||
377 | /* return number of bytes read into user buffer (will fit in int) */ | 368 | /* return number of bytes read into user buffer */ |
378 | return (int)got; | 369 | return got; |
370 | } | ||
371 | |||
372 | /* -- see zlib.h -- */ | ||
373 | int ZEXPORT gzread(file, buf, len) | ||
374 | gzFile file; | ||
375 | voidp buf; | ||
376 | unsigned len; | ||
377 | { | ||
378 | gz_statep state; | ||
379 | |||
380 | /* get internal structure */ | ||
381 | if (file == NULL) | ||
382 | return -1; | ||
383 | state = (gz_statep)file; | ||
384 | |||
385 | /* check that we're reading and that there's no (serious) error */ | ||
386 | if (state->mode != GZ_READ || | ||
387 | (state->err != Z_OK && state->err != Z_BUF_ERROR)) | ||
388 | return -1; | ||
389 | |||
390 | /* since an int is returned, make sure len fits in one, otherwise return | ||
391 | with an error (this avoids a flaw in the interface) */ | ||
392 | if ((int)len < 0) { | ||
393 | gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); | ||
394 | return -1; | ||
395 | } | ||
396 | |||
397 | /* read len or fewer bytes to buf */ | ||
398 | len = gz_read(state, buf, len); | ||
399 | |||
400 | /* check for an error */ | ||
401 | if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) | ||
402 | return -1; | ||
403 | |||
404 | /* return the number of bytes read (this is assured to fit in an int) */ | ||
405 | return (int)len; | ||
406 | } | ||
407 | |||
408 | /* -- see zlib.h -- */ | ||
409 | z_size_t ZEXPORT gzfread(buf, size, nitems, file) | ||
410 | voidp buf; | ||
411 | z_size_t size; | ||
412 | z_size_t nitems; | ||
413 | gzFile file; | ||
414 | { | ||
415 | z_size_t len; | ||
416 | gz_statep state; | ||
417 | |||
418 | /* get internal structure */ | ||
419 | if (file == NULL) | ||
420 | return 0; | ||
421 | state = (gz_statep)file; | ||
422 | |||
423 | /* check that we're reading and that there's no (serious) error */ | ||
424 | if (state->mode != GZ_READ || | ||
425 | (state->err != Z_OK && state->err != Z_BUF_ERROR)) | ||
426 | return 0; | ||
427 | |||
428 | /* compute bytes to read -- error on overflow */ | ||
429 | len = nitems * size; | ||
430 | if (size && len / size != nitems) { | ||
431 | gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | /* read len or fewer bytes to buf, return the number of full items read */ | ||
436 | return len ? gz_read(state, buf, len) / size : 0; | ||
379 | } | 437 | } |
380 | 438 | ||
381 | /* -- see zlib.h -- */ | 439 | /* -- see zlib.h -- */ |
@@ -408,8 +466,8 @@ int ZEXPORT gzgetc(file) | |||
408 | return *(state->x.next)++; | 466 | return *(state->x.next)++; |
409 | } | 467 | } |
410 | 468 | ||
411 | /* nothing there -- try gzread() */ | 469 | /* nothing there -- try gz_read() */ |
412 | ret = gzread(file, buf, 1); | 470 | ret = gz_read(state, buf, 1); |
413 | return ret < 1 ? -1 : buf[0]; | 471 | return ret < 1 ? -1 : buf[0]; |
414 | } | 472 | } |
415 | 473 | ||
@@ -1388,7 +1388,35 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); | |||
1388 | case. | 1388 | case. |
1389 | 1389 | ||
1390 | gzread returns the number of uncompressed bytes actually read, less than | 1390 | gzread returns the number of uncompressed bytes actually read, less than |
1391 | len for end of file, or -1 for error. | 1391 | len for end of file, or -1 for error. If len is too large to fit in an int, |
1392 | then nothing is read, -1 is returned, and the error state is set to | ||
1393 | Z_STREAM_ERROR. | ||
1394 | */ | ||
1395 | |||
1396 | ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, | ||
1397 | gzFile file)); | ||
1398 | /* | ||
1399 | Read up to nitems items of size size from file to buf, otherwise operating | ||
1400 | as gzread() does. This duplicates the interface of stdio's fread(), with | ||
1401 | size_t request and return types. If the library defines size_t, then | ||
1402 | z_size_t is identical to size_t. If not, then z_size_t is an unsigned | ||
1403 | integer type that can contain a pointer. | ||
1404 | |||
1405 | gzfread() returns the number of full items read of size size, or zero if | ||
1406 | the end of the file was reached and a full item could not be read, or if | ||
1407 | there was an error. gzerror() must be consulted if zero is returned in | ||
1408 | order to determine if there was an error. If the multiplication of size and | ||
1409 | nitems overflows, i.e. the product does not fit in a z_size_t, then nothing | ||
1410 | is read, zero is returned, and the error state is set to Z_STREAM_ERROR. | ||
1411 | |||
1412 | In the event that the end of file is reached and only a partial item is | ||
1413 | available at the end, i.e. the remaining uncompressed data length is not a | ||
1414 | multiple of size, then the final partial item is nevetheless read into buf | ||
1415 | and the end-of-file flag is set. The length of the partial item read is not | ||
1416 | provided, but could be inferred from the result of gztell(). This behavior | ||
1417 | is the same as the behavior of fread() implementations in common libraries, | ||
1418 | but it prevents the direct use of gzfread() to read a concurrently written | ||
1419 | file, reseting and retrying on end-of-file, when size is not 1. | ||
1392 | */ | 1420 | */ |
1393 | 1421 | ||
1394 | ZEXTERN int ZEXPORT gzwrite OF((gzFile file, | 1422 | ZEXTERN int ZEXPORT gzwrite OF((gzFile file, |