Decompress gzip data into a malloc'd buffer. Returns NULL on failure. * *out_total receives the decompressed size. Caller must free the result. */
| 6032 | /* Decompress gzip data into a malloc'd buffer. Returns NULL on failure. |
| 6033 | * *out_total receives the decompressed size. Caller must free the result. */ |
| 6034 | static unsigned char *gzip_decompress(const unsigned char *data, int data_len, size_t *out_total) { |
| 6035 | z_stream strm = {0}; |
| 6036 | unsigned char *mutable_data; |
| 6037 | memcpy(&mutable_data, &data, sizeof(data)); |
| 6038 | strm.next_in = mutable_data; |
| 6039 | strm.avail_in = (unsigned int)data_len; |
| 6040 | |
| 6041 | if (inflateInit2(&strm, 16 + MAX_WBITS) != Z_OK) { |
| 6042 | return NULL; |
| 6043 | } |
| 6044 | |
| 6045 | size_t buf_cap = (size_t)data_len * DECOMP_FACTOR; |
| 6046 | if (buf_cap < CLI_BUF_4K) { |
| 6047 | buf_cap = CLI_BUF_4K; |
| 6048 | } |
| 6049 | if (buf_cap > DECOMPRESS_MAX_BYTES) { |
| 6050 | buf_cap = DECOMPRESS_MAX_BYTES; |
| 6051 | } |
| 6052 | unsigned char *decompressed = malloc(buf_cap); |
| 6053 | if (!decompressed) { |
| 6054 | inflateEnd(&strm); |
| 6055 | return NULL; |
| 6056 | } |
| 6057 | |
| 6058 | size_t total = 0; |
| 6059 | int ret; |
| 6060 | do { |
| 6061 | if (total >= buf_cap) { |
| 6062 | size_t new_cap = buf_cap * GROWTH_FACTOR; |
| 6063 | if (new_cap > DECOMPRESS_MAX_BYTES) { |
| 6064 | free(decompressed); |
| 6065 | inflateEnd(&strm); |
| 6066 | return NULL; |
| 6067 | } |
| 6068 | unsigned char *nb = realloc(decompressed, new_cap); |
| 6069 | if (!nb) { |
| 6070 | free(decompressed); |
| 6071 | inflateEnd(&strm); |
| 6072 | return NULL; |
| 6073 | } |
| 6074 | decompressed = nb; |
| 6075 | buf_cap = new_cap; |
| 6076 | } |
| 6077 | strm.next_out = decompressed + total; |
| 6078 | strm.avail_out = (unsigned int)(buf_cap - total); |
| 6079 | ret = inflate(&strm, Z_NO_FLUSH); |
| 6080 | total = buf_cap - strm.avail_out; |
| 6081 | } while (ret == Z_OK); |
| 6082 | |
| 6083 | inflateEnd(&strm); |
| 6084 | |
| 6085 | if (ret != Z_STREAM_END) { |
| 6086 | free(decompressed); |
| 6087 | return NULL; |
| 6088 | } |
| 6089 | *out_total = total; |
| 6090 | return decompressed; |
| 6091 | } |
no outgoing calls
no test coverage detected