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, |
