| 390 | } |
| 391 | |
| 392 | Result<int64_t> Decompress(int64_t input_length, const uint8_t* input, |
| 393 | int64_t output_buffer_length, uint8_t* output) override { |
| 394 | int64_t read_input_bytes = 0; |
| 395 | int64_t decompressed_bytes = 0; |
| 396 | |
| 397 | if (!decompressor_initialized_) { |
| 398 | RETURN_NOT_OK(InitDecompressor()); |
| 399 | } |
| 400 | if (output_buffer_length == 0) { |
| 401 | // The zlib library does not allow *output to be NULL, even when |
| 402 | // output_buffer_length is 0 (inflate() will return Z_STREAM_ERROR). We don't |
| 403 | // consider this an error, so bail early if no output is expected. Note that we |
| 404 | // don't signal an error if the input actually contains compressed data. |
| 405 | return 0; |
| 406 | } |
| 407 | |
| 408 | // inflate() will not automatically decode concatenated gzip members, keep calling |
| 409 | // inflate until reading all input data (GH-38271). |
| 410 | while (read_input_bytes < input_length) { |
| 411 | // Reset the stream for this block |
| 412 | if (inflateReset(&stream_) != Z_OK) { |
| 413 | return ZlibErrorPrefix("zlib inflateReset failed: ", stream_.msg); |
| 414 | } |
| 415 | |
| 416 | int ret = 0; |
| 417 | // gzip can run in streaming mode or non-streaming mode. We only |
| 418 | // support the non-streaming use case where we present it the entire |
| 419 | // compressed input and a buffer big enough to contain the entire |
| 420 | // compressed output. In the case where we don't know the output, |
| 421 | // we just make a bigger buffer and try the non-streaming mode |
| 422 | // from the beginning again. |
| 423 | stream_.next_in = |
| 424 | const_cast<Bytef*>(reinterpret_cast<const Bytef*>(input + read_input_bytes)); |
| 425 | stream_.avail_in = static_cast<uInt>(input_length - read_input_bytes); |
| 426 | stream_.next_out = reinterpret_cast<Bytef*>(output + decompressed_bytes); |
| 427 | stream_.avail_out = static_cast<uInt>(output_buffer_length - decompressed_bytes); |
| 428 | |
| 429 | // We know the output size. In this case, we can use Z_FINISH |
| 430 | // which is more efficient. |
| 431 | ret = inflate(&stream_, Z_FINISH); |
| 432 | if (ret == Z_OK) { |
| 433 | // Failure, buffer was too small |
| 434 | return Status::IOError("Too small a buffer passed to GZipCodec. InputLength=", |
| 435 | input_length, " OutputLength=", output_buffer_length); |
| 436 | } |
| 437 | |
| 438 | // Failure for some other reason |
| 439 | if (ret != Z_STREAM_END) { |
| 440 | return ZlibErrorPrefix("GZipCodec failed: ", stream_.msg); |
| 441 | } |
| 442 | |
| 443 | read_input_bytes += stream_.total_in; |
| 444 | decompressed_bytes += stream_.total_out; |
| 445 | } |
| 446 | |
| 447 | return decompressed_bytes; |
| 448 | } |
| 449 |
nothing calls this directly
no test coverage detected