1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
---|---|
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "bin/gzip.h" |
6 | |
7 | #include "platform/assert.h" |
8 | #include "platform/globals.h" |
9 | #include "zlib/zlib.h" |
10 | |
11 | namespace dart { |
12 | namespace bin { |
13 | |
14 | void Decompress(const uint8_t* input, |
15 | intptr_t input_len, |
16 | uint8_t** output, |
17 | intptr_t* output_length) { |
18 | ASSERT(input != NULL); |
19 | ASSERT(input_len > 0); |
20 | ASSERT(output != NULL); |
21 | ASSERT(output_length != NULL); |
22 | |
23 | const intptr_t kChunkSize = 256 * 1024; |
24 | |
25 | // Initialize output. |
26 | intptr_t output_capacity = input_len * 2; |
27 | if (output_capacity < kChunkSize) { |
28 | output_capacity = kChunkSize; |
29 | } |
30 | *output = reinterpret_cast<uint8_t*>(malloc(output_capacity)); |
31 | |
32 | uint8_t* chunk_out = reinterpret_cast<uint8_t*>(malloc(kChunkSize)); |
33 | z_stream strm; |
34 | strm.zalloc = Z_NULL; |
35 | strm.zfree = Z_NULL; |
36 | strm.opaque = Z_NULL; |
37 | strm.avail_in = 0; |
38 | strm.next_in = 0; |
39 | int ret = inflateInit2(&strm, 32 + MAX_WBITS); |
40 | ASSERT(ret == Z_OK); |
41 | |
42 | intptr_t input_cursor = 0; |
43 | intptr_t output_cursor = 0; |
44 | do { |
45 | // Setup input. |
46 | intptr_t size_in = input_len - input_cursor; |
47 | if (size_in > kChunkSize) { |
48 | size_in = kChunkSize; |
49 | } |
50 | strm.avail_in = size_in; |
51 | strm.next_in = const_cast<uint8_t*>(&input[input_cursor]); |
52 | |
53 | // Inflate until we've exhausted the current input chunk. |
54 | do { |
55 | // Setup output. |
56 | strm.avail_out = kChunkSize; |
57 | strm.next_out = &chunk_out[0]; |
58 | // Inflate. |
59 | ret = inflate(&strm, Z_SYNC_FLUSH); |
60 | // We either hit the end of the stream or made forward progress. |
61 | ASSERT((ret == Z_STREAM_END) || (ret == Z_OK)); |
62 | // Grow output buffer size. |
63 | intptr_t size_out = kChunkSize - strm.avail_out; |
64 | if (size_out > (output_capacity - output_cursor)) { |
65 | output_capacity *= 2; |
66 | ASSERT(size_out <= (output_capacity - output_cursor)); |
67 | *output = reinterpret_cast<uint8_t*>(realloc(*output, output_capacity)); |
68 | } |
69 | // Copy output. |
70 | memmove(&((*output)[output_cursor]), &chunk_out[0], size_out); |
71 | output_cursor += size_out; |
72 | } while (strm.avail_out == 0); |
73 | |
74 | // We've processed size_in bytes. |
75 | input_cursor += size_in; |
76 | |
77 | // We're finished decompressing when zlib tells us. |
78 | } while (ret != Z_STREAM_END); |
79 | |
80 | inflateEnd(&strm); |
81 | |
82 | *output_length = output_cursor; |
83 | free(chunk_out); |
84 | } |
85 | |
86 | } // namespace bin |
87 | } // namespace dart |
88 |