Decompress gzip data into a malloc'd buffer. Returns NULL on failure. * *out_total receives the decompressed size. Caller must free the result. */
| 6258 | /* Decompress gzip data into a malloc'd buffer. Returns NULL on failure. |
| 6259 | * *out_total receives the decompressed size. Caller must free the result. */ |
| 6260 | static unsigned char *gzip_decompress(const unsigned char *data, int data_len, size_t *out_total) { |
| 6261 | z_stream strm = {0}; |
| 6262 | unsigned char *mutable_data; |
| 6263 | memcpy(&mutable_data, &data, sizeof(data)); |
| 6264 | strm.next_in = mutable_data; |
| 6265 | strm.avail_in = (unsigned int)data_len; |
| 6266 | |
| 6267 | if (inflateInit2(&strm, 16 + MAX_WBITS) != Z_OK) { |
| 6268 | return NULL; |
| 6269 | } |
| 6270 | |
| 6271 | size_t buf_cap = (size_t)data_len * DECOMP_FACTOR; |
| 6272 | if (buf_cap < CLI_BUF_4K) { |
| 6273 | buf_cap = CLI_BUF_4K; |
| 6274 | } |
| 6275 | if (buf_cap > DECOMPRESS_MAX_BYTES) { |
| 6276 | buf_cap = DECOMPRESS_MAX_BYTES; |
| 6277 | } |
| 6278 | unsigned char *decompressed = malloc(buf_cap); |
| 6279 | if (!decompressed) { |
| 6280 | inflateEnd(&strm); |
| 6281 | return NULL; |
| 6282 | } |
| 6283 | |
| 6284 | size_t total = 0; |
| 6285 | int ret; |
| 6286 | do { |
| 6287 | if (total >= buf_cap) { |
| 6288 | size_t new_cap = buf_cap * GROWTH_FACTOR; |
| 6289 | if (new_cap > DECOMPRESS_MAX_BYTES) { |
| 6290 | free(decompressed); |
| 6291 | inflateEnd(&strm); |
| 6292 | return NULL; |
| 6293 | } |
| 6294 | unsigned char *nb = realloc(decompressed, new_cap); |
| 6295 | if (!nb) { |
| 6296 | free(decompressed); |
| 6297 | inflateEnd(&strm); |
| 6298 | return NULL; |
| 6299 | } |
| 6300 | decompressed = nb; |
| 6301 | buf_cap = new_cap; |
| 6302 | } |
| 6303 | strm.next_out = decompressed + total; |
| 6304 | strm.avail_out = (unsigned int)(buf_cap - total); |
| 6305 | ret = inflate(&strm, Z_NO_FLUSH); |
| 6306 | total = buf_cap - strm.avail_out; |
| 6307 | } while (ret == Z_OK); |
| 6308 | |
| 6309 | inflateEnd(&strm); |
| 6310 | |
| 6311 | if (ret != Z_STREAM_END) { |
| 6312 | free(decompressed); |
| 6313 | return NULL; |
| 6314 | } |
| 6315 | *out_total = total; |
| 6316 | return decompressed; |
| 6317 | } |
no outgoing calls
no test coverage detected