| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "bin/gzip.h" |
| |
| #include "platform/allocation.h" |
| #include "platform/assert.h" |
| #include "platform/globals.h" |
| #include "zlib/zlib.h" |
| |
| namespace dart { |
| namespace bin { |
| |
| void Decompress(const uint8_t* input, |
| intptr_t input_len, |
| uint8_t** output, |
| intptr_t* output_length) { |
| ASSERT(input != nullptr); |
| ASSERT(input_len > 0); |
| ASSERT(output != nullptr); |
| ASSERT(output_length != nullptr); |
| |
| const intptr_t kChunkSize = 256 * 1024; |
| |
| // Initialize output. |
| intptr_t output_capacity = input_len * 2; |
| if (output_capacity < kChunkSize) { |
| output_capacity = kChunkSize; |
| } |
| *output = reinterpret_cast<uint8_t*>(malloc(output_capacity)); |
| |
| uint8_t* chunk_out = reinterpret_cast<uint8_t*>(malloc(kChunkSize)); |
| z_stream strm; |
| strm.zalloc = Z_NULL; |
| strm.zfree = Z_NULL; |
| strm.opaque = Z_NULL; |
| strm.avail_in = 0; |
| strm.next_in = Z_NULL; |
| int ret = inflateInit2(&strm, 32 + MAX_WBITS); |
| ASSERT(ret == Z_OK); |
| |
| intptr_t input_cursor = 0; |
| intptr_t output_cursor = 0; |
| do { |
| // Setup input. |
| intptr_t size_in = input_len - input_cursor; |
| if (size_in > kChunkSize) { |
| size_in = kChunkSize; |
| } |
| strm.avail_in = size_in; |
| strm.next_in = const_cast<uint8_t*>(&input[input_cursor]); |
| |
| // Inflate until we've exhausted the current input chunk. |
| do { |
| // Setup output. |
| strm.avail_out = kChunkSize; |
| strm.next_out = &chunk_out[0]; |
| // Inflate. |
| ret = inflate(&strm, Z_SYNC_FLUSH); |
| // We either hit the end of the stream or made forward progress. |
| ASSERT((ret == Z_STREAM_END) || (ret == Z_OK)); |
| // Grow output buffer size. |
| intptr_t size_out = kChunkSize - strm.avail_out; |
| if (size_out > (output_capacity - output_cursor)) { |
| output_capacity *= 2; |
| ASSERT(size_out <= (output_capacity - output_cursor)); |
| *output = reinterpret_cast<uint8_t*>(realloc(*output, output_capacity)); |
| } |
| // Copy output. |
| memmove(&((*output)[output_cursor]), &chunk_out[0], size_out); |
| output_cursor += size_out; |
| } while (strm.avail_out == 0); |
| |
| // We've processed size_in bytes. |
| input_cursor += size_in; |
| |
| // We're finished decompressing when zlib tells us. |
| } while (ret != Z_STREAM_END); |
| |
| inflateEnd(&strm); |
| |
| *output_length = output_cursor; |
| free(chunk_out); |
| } |
| |
| } // namespace bin |
| } // namespace dart |