cl_error_t cli_egg_deflate_decompress(char* compressed, size_t compressed_size, char** decompressed, size_t* decompressed_size)
{
    cl_error_t status = CL_EPARSE;

    uint8_t* decoded_tmp;
    uint8_t* decoded = NULL;
    uint32_t declen = 0, capacity = 0;

    z_stream stream;
    int zstat;

    if (NULL == compressed || compressed_size == 0 || NULL == decompressed || NULL == decompressed_size) {
        cli_errmsg("cli_egg_deflate_decompress: Invalid args!\n");
        status = CL_EARG;
        goto done;
    }

    *decompressed      = NULL;
    *decompressed_size = 0;

    if (!(decoded = (uint8_t*)cli_calloc(BUFSIZ, sizeof(uint8_t)))) {
        cli_errmsg("cli_egg_deflate_decompress: cannot allocate memory for decompressed output\n");
        status = CL_EMEM;
        goto done;
    }

    capacity = BUFSIZ;

    memset(&stream, 0, sizeof(stream));
    stream.next_in   = (Bytef*)compressed;
    stream.avail_in  = compressed_size;
    stream.next_out  = (Bytef*)decoded;
    stream.avail_out = BUFSIZ;

    zstat = inflateInit2(&stream, -15);
    if (zstat != Z_OK) {
        cli_warnmsg("cli_egg_deflate_decompress: inflateInit failed\n");
        status = CL_EMEM;
        goto done;
    }

    /* initial inflate */
    zstat = inflate(&stream, Z_NO_FLUSH);

    /* check if nothing written whatsoever */
    if ((zstat != Z_OK) && (stream.avail_out == BUFSIZ)) {
        /* Inflation failed */
        cli_errmsg("cli_egg_deflate_decompress: failed to decompress data\n");
        status = CL_EPARSE;
        goto done;
    }

    while (zstat == Z_OK && stream.avail_in) {
        /* extend output capacity if needed,*/
        if (stream.avail_out == 0) {
            if (!(decoded_tmp = cli_realloc(decoded, capacity + BUFSIZ))) {
                cli_errmsg("cli_egg_deflate_decompress: cannot reallocate memory for decompressed output\n");
                status = CL_EMEM;
                goto done;
            }
            decoded          = decoded_tmp;
            stream.next_out  = decoded + capacity;
            stream.avail_out = BUFSIZ;
            declen += BUFSIZ;
            capacity += BUFSIZ;
        }

        /* continue inflation */
        zstat = inflate(&stream, Z_NO_FLUSH);
    }

    /* add end fragment to decoded length */
    declen += (BUFSIZ - stream.avail_out);

    /* error handling */
    switch (zstat) {
        case Z_OK:
            cli_dbgmsg("cli_egg_deflate_decompress: Z_OK on stream decompression\n");
            /* intentional fall-through */
        case Z_STREAM_END:
            cli_dbgmsg("cli_egg_deflate_decompress: decompressed %lu bytes from %lu total bytes (%lu bytes remaining)\n",
                       (unsigned long)declen, (unsigned long)(compressed_size), (unsigned long)(stream.avail_in));
            break;

        /* potentially fatal - *mostly* ignored as per older version */
        case Z_STREAM_ERROR:
        case Z_NEED_DICT:
        case Z_DATA_ERROR:
        case Z_MEM_ERROR:
        default:
            if (stream.msg)
                cli_dbgmsg("cli_egg_deflate_decompress: after decompressing %lu bytes, got error \"%s\"\n",
                           (unsigned long)declen, stream.msg);
            else
                cli_dbgmsg("cli_egg_deflate_decompress: after decompressing %lu bytes, got error %d\n",
                           (unsigned long)declen, zstat);

            if (declen == 0) {
                cli_dbgmsg("cli_egg_deflate_decompress: no bytes were decompressed.\n");

                status = CL_EPARSE;
            }
            break;
    }

    *decompressed      = (char*)decoded;
    *decompressed_size = declen;

    status = CL_SUCCESS;

done:

    (void)inflateEnd(&stream);

    if (CL_SUCCESS != status) {
        free(decoded);
    }

    return status;
}