cl_error_t cli_egg_lzma_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;

    struct CLI_LZMA stream;
    int lzmastat;

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

    *decompressed      = NULL;
    *decompressed_size = 0;

    if (!(decoded = (uint8_t*)cli_calloc(BUFSIZ, sizeof(char)))) {
        cli_errmsg("cli_egg_lzma_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;

    lzmastat = cli_LzmaInit(&stream, 0);
    if (lzmastat != LZMA_RESULT_OK) {
        cli_warnmsg("cli_egg_lzma_decompress: inflateInit failed\n");
        status = CL_EMEM;
        goto done;
    }

    /* initial inflate */
    lzmastat = cli_LzmaDecode(&stream);

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

    while (lzmastat == LZMA_RESULT_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_lzma_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 */
        lzmastat = cli_LzmaDecode(&stream);
    }

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

    /* error handling */
    switch (lzmastat) {
        case LZMA_RESULT_OK:
            cli_dbgmsg("cli_egg_lzma_decompress: Z_OK on stream decompression\n");
            /* intentional fall-through */
        case LZMA_STREAM_END:
            cli_dbgmsg("cli_egg_lzma_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 */
        case LZMA_RESULT_DATA_ERROR:
        default:
            cli_dbgmsg("cli_egg_lzma_decompress: after decompressing %lu bytes, got error %d\n",
                       (unsigned long)declen, lzmastat);

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

                status = CL_EPARSE;
            }
            break;
    }

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

    status = CL_SUCCESS;

done:

    (void)cli_LzmaShutdown(&stream);

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

    return status;
}