Decompress gzip data into a malloc'd buffer. Returns NULL on failure. * *out_total receives the decompressed size. Caller must free the result. */
| 6094 | /* Decompress gzip data into a malloc'd buffer. Returns NULL on failure. |
| 6095 | * *out_total receives the decompressed size. Caller must free the result. */ |
| 6096 | static unsigned char *gzip_decompress(const unsigned char *data, int data_len, size_t *out_total) { |
| 6097 | z_stream strm = {0}; |
| 6098 | unsigned char *mutable_data; |
| 6099 | memcpy(&mutable_data, &data, sizeof(data)); |
| 6100 | strm.next_in = mutable_data; |
| 6101 | strm.avail_in = (unsigned int)data_len; |
| 6102 | |
| 6103 | if (inflateInit2(&strm, 16 + MAX_WBITS) != Z_OK) { |
| 6104 | return NULL; |
| 6105 | } |
| 6106 | |
| 6107 | size_t buf_cap = (size_t)data_len * DECOMP_FACTOR; |
| 6108 | if (buf_cap < CLI_BUF_4K) { |
| 6109 | buf_cap = CLI_BUF_4K; |
| 6110 | } |
| 6111 | if (buf_cap > DECOMPRESS_MAX_BYTES) { |
| 6112 | buf_cap = DECOMPRESS_MAX_BYTES; |
| 6113 | } |
| 6114 | unsigned char *decompressed = malloc(buf_cap); |
| 6115 | if (!decompressed) { |
| 6116 | inflateEnd(&strm); |
| 6117 | return NULL; |
| 6118 | } |
| 6119 | |
| 6120 | size_t total = 0; |
| 6121 | int ret; |
| 6122 | do { |
| 6123 | if (total >= buf_cap) { |
| 6124 | size_t new_cap = buf_cap * GROWTH_FACTOR; |
| 6125 | if (new_cap > DECOMPRESS_MAX_BYTES) { |
| 6126 | free(decompressed); |
| 6127 | inflateEnd(&strm); |
| 6128 | return NULL; |
| 6129 | } |
| 6130 | unsigned char *nb = realloc(decompressed, new_cap); |
| 6131 | if (!nb) { |
| 6132 | free(decompressed); |
| 6133 | inflateEnd(&strm); |
| 6134 | return NULL; |
| 6135 | } |
| 6136 | decompressed = nb; |
| 6137 | buf_cap = new_cap; |
| 6138 | } |
| 6139 | strm.next_out = decompressed + total; |
| 6140 | strm.avail_out = (unsigned int)(buf_cap - total); |
| 6141 | ret = inflate(&strm, Z_NO_FLUSH); |
| 6142 | total = buf_cap - strm.avail_out; |
| 6143 | } while (ret == Z_OK); |
| 6144 | |
| 6145 | inflateEnd(&strm); |
| 6146 | |
| 6147 | if (ret != Z_STREAM_END) { |
| 6148 | free(decompressed); |
| 6149 | return NULL; |
| 6150 | } |
| 6151 | *out_total = total; |
| 6152 | return decompressed; |
| 6153 | } |
no outgoing calls
no test coverage detected