Utility function to decompress snappy block compressed data. If size_only is true, this function does not decompress but only computes the output size and writes the result to *output_len. If size_only is false, output buffer size must be at least *output_len. *output_len is updated with the actual output size if the decompression succeeds, and is set to 0 otherwise. size_only is an O(1) operatio
| 441 | // otherwise. |
| 442 | // size_only is an O(1) operation (just reads a single varint for each snappy block). |
| 443 | static Status SnappyBlockDecompress(int64_t input_len, const uint8_t* input, |
| 444 | bool size_only, int64_t* output_len, char* output) { |
| 445 | int64_t buffer_size = *output_len; |
| 446 | *output_len = 0; |
| 447 | int64_t uncompressed_total_len = 0; |
| 448 | while (input_len > 0) { |
| 449 | uint32_t uncompressed_block_len = ReadWriteUtil::GetInt<uint32_t>(input); |
| 450 | input += sizeof(uint32_t); |
| 451 | input_len -= sizeof(uint32_t); |
| 452 | |
| 453 | if (!size_only) { |
| 454 | int64_t remaining_output_size = buffer_size - uncompressed_total_len; |
| 455 | if (remaining_output_size < uncompressed_block_len) { |
| 456 | return Status(TErrorCode::SNAPPY_DECOMPRESS_DECOMPRESS_SIZE_INCORRECT); |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | while (uncompressed_block_len > 0) { |
| 461 | // Check that input length should not be negative. |
| 462 | if (input_len < 0) { |
| 463 | stringstream ss; |
| 464 | ss << " Corruption snappy decomp input_len " << input_len; |
| 465 | return Status(ss.str()); |
| 466 | } |
| 467 | // Read the length of the next snappy compressed block. |
| 468 | size_t compressed_len = ReadWriteUtil::GetInt<uint32_t>(input); |
| 469 | input += sizeof(uint32_t); |
| 470 | input_len -= sizeof(uint32_t); |
| 471 | |
| 472 | if (compressed_len == 0 || compressed_len > input_len) { |
| 473 | return Status(TErrorCode::SNAPPY_DECOMPRESS_INVALID_COMPRESSED_LENGTH); |
| 474 | } |
| 475 | |
| 476 | // Read how big the output will be. |
| 477 | size_t uncompressed_len; |
| 478 | if (!snappy::GetUncompressedLength(reinterpret_cast<const char*>(input), |
| 479 | compressed_len, &uncompressed_len)) { |
| 480 | return Status(TErrorCode::SNAPPY_DECOMPRESS_UNCOMPRESSED_LENGTH_FAILED); |
| 481 | } |
| 482 | // Check that uncompressed length should be greater than 0. |
| 483 | if (uncompressed_len <= 0) { |
| 484 | return Status(TErrorCode::SNAPPY_DECOMPRESS_UNCOMPRESSED_LENGTH_FAILED); |
| 485 | } |
| 486 | DCHECK_GT(uncompressed_len, 0); |
| 487 | |
| 488 | if (!size_only) { |
| 489 | // Check output bounds |
| 490 | int64_t remaining_output_size = buffer_size - uncompressed_total_len; |
| 491 | if (remaining_output_size < uncompressed_len) { |
| 492 | return Status(TErrorCode::SNAPPY_DECOMPRESS_DECOMPRESS_SIZE_INCORRECT); |
| 493 | } |
| 494 | // Decompress this snappy block |
| 495 | if (!snappy::RawUncompress(reinterpret_cast<const char*>(input), |
| 496 | compressed_len, output)) { |
| 497 | return Status(TErrorCode::SNAPPY_DECOMPRESS_RAW_UNCOMPRESS_FAILED); |
| 498 | } |
| 499 | output += uncompressed_len; |
| 500 | } |
no test coverage detected