Decompress gzip data into a malloc'd buffer. Returns NULL on failure. * *out_total receives the decompressed size. Caller must free the result. */
| 2347 | /* Decompress gzip data into a malloc'd buffer. Returns NULL on failure. |
| 2348 | * *out_total receives the decompressed size. Caller must free the result. */ |
| 2349 | static unsigned char *gzip_decompress(const unsigned char *data, int data_len, size_t *out_total) { |
| 2350 | z_stream strm = {0}; |
| 2351 | unsigned char *mutable_data; |
| 2352 | memcpy(&mutable_data, &data, sizeof(data)); |
| 2353 | strm.next_in = mutable_data; |
| 2354 | strm.avail_in = (unsigned int)data_len; |
| 2355 | |
| 2356 | if (inflateInit2(&strm, 16 + MAX_WBITS) != Z_OK) { |
| 2357 | return NULL; |
| 2358 | } |
| 2359 | |
| 2360 | size_t buf_cap = (size_t)data_len * DECOMP_FACTOR; |
| 2361 | if (buf_cap < CLI_BUF_4K) { |
| 2362 | buf_cap = CLI_BUF_4K; |
| 2363 | } |
| 2364 | if (buf_cap > DECOMPRESS_MAX_BYTES) { |
| 2365 | buf_cap = DECOMPRESS_MAX_BYTES; |
| 2366 | } |
| 2367 | unsigned char *decompressed = malloc(buf_cap); |
| 2368 | if (!decompressed) { |
| 2369 | inflateEnd(&strm); |
| 2370 | return NULL; |
| 2371 | } |
| 2372 | |
| 2373 | size_t total = 0; |
| 2374 | int ret; |
| 2375 | do { |
| 2376 | if (total >= buf_cap) { |
| 2377 | size_t new_cap = buf_cap * GROWTH_FACTOR; |
| 2378 | if (new_cap > DECOMPRESS_MAX_BYTES) { |
| 2379 | free(decompressed); |
| 2380 | inflateEnd(&strm); |
| 2381 | return NULL; |
| 2382 | } |
| 2383 | unsigned char *nb = realloc(decompressed, new_cap); |
| 2384 | if (!nb) { |
| 2385 | free(decompressed); |
| 2386 | inflateEnd(&strm); |
| 2387 | return NULL; |
| 2388 | } |
| 2389 | decompressed = nb; |
| 2390 | buf_cap = new_cap; |
| 2391 | } |
| 2392 | strm.next_out = decompressed + total; |
| 2393 | strm.avail_out = (unsigned int)(buf_cap - total); |
| 2394 | ret = inflate(&strm, Z_NO_FLUSH); |
| 2395 | total = buf_cap - strm.avail_out; |
| 2396 | } while (ret == Z_OK); |
| 2397 | |
| 2398 | inflateEnd(&strm); |
| 2399 | |
| 2400 | if (ret != Z_STREAM_END) { |
| 2401 | free(decompressed); |
| 2402 | return NULL; |
| 2403 | } |
| 2404 | *out_total = total; |
| 2405 | return decompressed; |
| 2406 | } |
no outgoing calls
no test coverage detected