127b27ec6Sopenharmony_ci/* LZ4frame API example : compress a file
227b27ec6Sopenharmony_ci * Modified from an example code by Zbigniew Jędrzejewski-Szmek
327b27ec6Sopenharmony_ci *
427b27ec6Sopenharmony_ci * This example streams an input file into an output file
527b27ec6Sopenharmony_ci * using a bounded memory budget.
627b27ec6Sopenharmony_ci * Input is read in chunks of IN_CHUNK_SIZE */
727b27ec6Sopenharmony_ci
827b27ec6Sopenharmony_ci#include <stdio.h>
927b27ec6Sopenharmony_ci#include <stdlib.h>
1027b27ec6Sopenharmony_ci#include <string.h>
1127b27ec6Sopenharmony_ci#include <errno.h>
1227b27ec6Sopenharmony_ci#include <assert.h>
1327b27ec6Sopenharmony_ci
1427b27ec6Sopenharmony_ci#include <getopt.h>
1527b27ec6Sopenharmony_ci#include <lz4frame.h>
1627b27ec6Sopenharmony_ci#include <lz4frame_static.h>
1727b27ec6Sopenharmony_ci
1827b27ec6Sopenharmony_ci#define IN_CHUNK_SIZE  (16*1024)
1927b27ec6Sopenharmony_ci
2027b27ec6Sopenharmony_cistatic const LZ4F_preferences_t kPrefs = {
2127b27ec6Sopenharmony_ci    { LZ4F_max256KB, LZ4F_blockLinked, LZ4F_noContentChecksum, LZ4F_frame,
2227b27ec6Sopenharmony_ci      0 /* unknown content size */, 0 /* no dictID */ , LZ4F_noBlockChecksum },
2327b27ec6Sopenharmony_ci    0,   /* compression level; 0 == default */
2427b27ec6Sopenharmony_ci    0,   /* autoflush */
2527b27ec6Sopenharmony_ci    0,   /* favor decompression speed */
2627b27ec6Sopenharmony_ci    { 0, 0, 0 },  /* reserved, must be set to 0 */
2727b27ec6Sopenharmony_ci};
2827b27ec6Sopenharmony_ci
2927b27ec6Sopenharmony_ci
3027b27ec6Sopenharmony_ci/* safe_fwrite() :
3127b27ec6Sopenharmony_ci * performs fwrite(), ensure operation success, or immediately exit() */
3227b27ec6Sopenharmony_cistatic void safe_fwrite(void* buf, size_t eltSize, size_t nbElt, FILE* f)
3327b27ec6Sopenharmony_ci{
3427b27ec6Sopenharmony_ci    size_t const writtenSize = fwrite(buf, eltSize, nbElt, f);
3527b27ec6Sopenharmony_ci    size_t const expectedSize = eltSize * nbElt;
3627b27ec6Sopenharmony_ci    if (nbElt>0) assert(expectedSize / nbElt == eltSize);  /* check overflow */
3727b27ec6Sopenharmony_ci    if (writtenSize < expectedSize) {
3827b27ec6Sopenharmony_ci        if (ferror(f))  /* note : ferror() must follow fwrite */
3927b27ec6Sopenharmony_ci            fprintf(stderr, "Write failed \n");
4027b27ec6Sopenharmony_ci        else
4127b27ec6Sopenharmony_ci            fprintf(stderr, "Write too short \n");
4227b27ec6Sopenharmony_ci        exit(1);
4327b27ec6Sopenharmony_ci    }
4427b27ec6Sopenharmony_ci}
4527b27ec6Sopenharmony_ci
4627b27ec6Sopenharmony_ci
4727b27ec6Sopenharmony_ci/* ================================================= */
4827b27ec6Sopenharmony_ci/*     Streaming Compression example               */
4927b27ec6Sopenharmony_ci/* ================================================= */
5027b27ec6Sopenharmony_ci
5127b27ec6Sopenharmony_citypedef struct {
5227b27ec6Sopenharmony_ci    int error;
5327b27ec6Sopenharmony_ci    unsigned long long size_in;
5427b27ec6Sopenharmony_ci    unsigned long long size_out;
5527b27ec6Sopenharmony_ci} compressResult_t;
5627b27ec6Sopenharmony_ci
5727b27ec6Sopenharmony_cistatic compressResult_t
5827b27ec6Sopenharmony_cicompress_file_internal(FILE* f_in, FILE* f_out,
5927b27ec6Sopenharmony_ci                       LZ4F_compressionContext_t ctx,
6027b27ec6Sopenharmony_ci                       void* inBuff,  size_t inChunkSize,
6127b27ec6Sopenharmony_ci                       void* outBuff, size_t outCapacity,
6227b27ec6Sopenharmony_ci                       FILE* f_unc, long uncOffset)
6327b27ec6Sopenharmony_ci{
6427b27ec6Sopenharmony_ci    compressResult_t result = { 1, 0, 0 };  /* result for an error */
6527b27ec6Sopenharmony_ci    long long count_in = 0, count_out, bytesToOffset = -1;
6627b27ec6Sopenharmony_ci
6727b27ec6Sopenharmony_ci    assert(f_in != NULL); assert(f_out != NULL);
6827b27ec6Sopenharmony_ci    assert(ctx != NULL);
6927b27ec6Sopenharmony_ci    assert(outCapacity >= LZ4F_HEADER_SIZE_MAX);
7027b27ec6Sopenharmony_ci    assert(outCapacity >= LZ4F_compressBound(inChunkSize, &kPrefs));
7127b27ec6Sopenharmony_ci
7227b27ec6Sopenharmony_ci    /* write frame header */
7327b27ec6Sopenharmony_ci    {   size_t const headerSize = LZ4F_compressBegin(ctx, outBuff, outCapacity, &kPrefs);
7427b27ec6Sopenharmony_ci        if (LZ4F_isError(headerSize)) {
7527b27ec6Sopenharmony_ci            printf("Failed to start compression: error %u \n", (unsigned)headerSize);
7627b27ec6Sopenharmony_ci            return result;
7727b27ec6Sopenharmony_ci        }
7827b27ec6Sopenharmony_ci        count_out = headerSize;
7927b27ec6Sopenharmony_ci        printf("Buffer size is %u bytes, header size %u bytes \n",
8027b27ec6Sopenharmony_ci                (unsigned)outCapacity, (unsigned)headerSize);
8127b27ec6Sopenharmony_ci        safe_fwrite(outBuff, 1, headerSize, f_out);
8227b27ec6Sopenharmony_ci    }
8327b27ec6Sopenharmony_ci
8427b27ec6Sopenharmony_ci    /* stream file */
8527b27ec6Sopenharmony_ci    for (;;) {
8627b27ec6Sopenharmony_ci      size_t compressedSize;
8727b27ec6Sopenharmony_ci      long long inSize = IN_CHUNK_SIZE;
8827b27ec6Sopenharmony_ci      if (uncOffset >= 0) {
8927b27ec6Sopenharmony_ci        bytesToOffset = uncOffset - count_in;
9027b27ec6Sopenharmony_ci
9127b27ec6Sopenharmony_ci        /* read only remaining bytes to offset position */
9227b27ec6Sopenharmony_ci        if (bytesToOffset < IN_CHUNK_SIZE && bytesToOffset > 0) {
9327b27ec6Sopenharmony_ci          inSize = bytesToOffset;
9427b27ec6Sopenharmony_ci        }
9527b27ec6Sopenharmony_ci      }
9627b27ec6Sopenharmony_ci
9727b27ec6Sopenharmony_ci      /* input data is at uncompressed data offset */
9827b27ec6Sopenharmony_ci      if (bytesToOffset <= 0 && uncOffset >= 0 && f_unc) {
9927b27ec6Sopenharmony_ci        size_t const readSize = fread(inBuff, 1, inSize, f_unc);
10027b27ec6Sopenharmony_ci        if (readSize == 0) {
10127b27ec6Sopenharmony_ci          uncOffset = -1;
10227b27ec6Sopenharmony_ci          continue;
10327b27ec6Sopenharmony_ci        }
10427b27ec6Sopenharmony_ci        count_in += readSize;
10527b27ec6Sopenharmony_ci        compressedSize = LZ4F_uncompressedUpdate(ctx,
10627b27ec6Sopenharmony_ci                                             outBuff, outCapacity,
10727b27ec6Sopenharmony_ci                                             inBuff, readSize,
10827b27ec6Sopenharmony_ci                                             NULL);
10927b27ec6Sopenharmony_ci      } else {
11027b27ec6Sopenharmony_ci        size_t const readSize = fread(inBuff, 1, inSize, f_in);
11127b27ec6Sopenharmony_ci        if (readSize == 0) break; /* nothing left to read from input file */
11227b27ec6Sopenharmony_ci        count_in += readSize;
11327b27ec6Sopenharmony_ci        compressedSize = LZ4F_compressUpdate(ctx,
11427b27ec6Sopenharmony_ci                                                outBuff, outCapacity,
11527b27ec6Sopenharmony_ci                                                inBuff, readSize,
11627b27ec6Sopenharmony_ci                                                NULL);
11727b27ec6Sopenharmony_ci
11827b27ec6Sopenharmony_ci      }
11927b27ec6Sopenharmony_ci
12027b27ec6Sopenharmony_ci      if (LZ4F_isError(compressedSize)) {
12127b27ec6Sopenharmony_ci        printf("Compression failed: error %u \n", (unsigned)compressedSize);
12227b27ec6Sopenharmony_ci        return result;
12327b27ec6Sopenharmony_ci      }
12427b27ec6Sopenharmony_ci
12527b27ec6Sopenharmony_ci      printf("Writing %u bytes\n", (unsigned)compressedSize);
12627b27ec6Sopenharmony_ci      safe_fwrite(outBuff, 1, compressedSize, f_out);
12727b27ec6Sopenharmony_ci      count_out += compressedSize;
12827b27ec6Sopenharmony_ci    }
12927b27ec6Sopenharmony_ci
13027b27ec6Sopenharmony_ci    /* flush whatever remains within internal buffers */
13127b27ec6Sopenharmony_ci    {   size_t const compressedSize = LZ4F_compressEnd(ctx,
13227b27ec6Sopenharmony_ci                                                outBuff, outCapacity,
13327b27ec6Sopenharmony_ci                                                NULL);
13427b27ec6Sopenharmony_ci        if (LZ4F_isError(compressedSize)) {
13527b27ec6Sopenharmony_ci            printf("Failed to end compression: error %u \n", (unsigned)compressedSize);
13627b27ec6Sopenharmony_ci            return result;
13727b27ec6Sopenharmony_ci        }
13827b27ec6Sopenharmony_ci
13927b27ec6Sopenharmony_ci        printf("Writing %u bytes \n", (unsigned)compressedSize);
14027b27ec6Sopenharmony_ci        safe_fwrite(outBuff, 1, compressedSize, f_out);
14127b27ec6Sopenharmony_ci        count_out += compressedSize;
14227b27ec6Sopenharmony_ci    }
14327b27ec6Sopenharmony_ci
14427b27ec6Sopenharmony_ci    result.size_in = count_in;
14527b27ec6Sopenharmony_ci    result.size_out = count_out;
14627b27ec6Sopenharmony_ci    result.error = 0;
14727b27ec6Sopenharmony_ci    return result;
14827b27ec6Sopenharmony_ci}
14927b27ec6Sopenharmony_ci
15027b27ec6Sopenharmony_cistatic compressResult_t
15127b27ec6Sopenharmony_cicompress_file(FILE* f_in, FILE* f_out,
15227b27ec6Sopenharmony_ci              FILE* f_unc, int uncOffset)
15327b27ec6Sopenharmony_ci{
15427b27ec6Sopenharmony_ci    assert(f_in != NULL);
15527b27ec6Sopenharmony_ci    assert(f_out != NULL);
15627b27ec6Sopenharmony_ci
15727b27ec6Sopenharmony_ci    /* resource allocation */
15827b27ec6Sopenharmony_ci    LZ4F_compressionContext_t ctx;
15927b27ec6Sopenharmony_ci    size_t const ctxCreation = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
16027b27ec6Sopenharmony_ci    void* const src = malloc(IN_CHUNK_SIZE);
16127b27ec6Sopenharmony_ci    size_t const outbufCapacity = LZ4F_compressBound(IN_CHUNK_SIZE, &kPrefs);   /* large enough for any input <= IN_CHUNK_SIZE */
16227b27ec6Sopenharmony_ci    void* const outbuff = malloc(outbufCapacity);
16327b27ec6Sopenharmony_ci
16427b27ec6Sopenharmony_ci    compressResult_t result = { 1, 0, 0 };  /* == error (default) */
16527b27ec6Sopenharmony_ci    if (!LZ4F_isError(ctxCreation) && src && outbuff) {
16627b27ec6Sopenharmony_ci        result = compress_file_internal(f_in, f_out,
16727b27ec6Sopenharmony_ci                                        ctx,
16827b27ec6Sopenharmony_ci                                        src, IN_CHUNK_SIZE,
16927b27ec6Sopenharmony_ci                                        outbuff, outbufCapacity,
17027b27ec6Sopenharmony_ci                                        f_unc, uncOffset);
17127b27ec6Sopenharmony_ci    } else {
17227b27ec6Sopenharmony_ci        printf("error : resource allocation failed \n");
17327b27ec6Sopenharmony_ci    }
17427b27ec6Sopenharmony_ci
17527b27ec6Sopenharmony_ci    LZ4F_freeCompressionContext(ctx);   /* supports free on NULL */
17627b27ec6Sopenharmony_ci    free(src);
17727b27ec6Sopenharmony_ci    free(outbuff);
17827b27ec6Sopenharmony_ci    return result;
17927b27ec6Sopenharmony_ci}
18027b27ec6Sopenharmony_ci
18127b27ec6Sopenharmony_ci
18227b27ec6Sopenharmony_ci/* ================================================= */
18327b27ec6Sopenharmony_ci/*     Streaming decompression example               */
18427b27ec6Sopenharmony_ci/* ================================================= */
18527b27ec6Sopenharmony_ci
18627b27ec6Sopenharmony_cistatic size_t get_block_size(const LZ4F_frameInfo_t* info) {
18727b27ec6Sopenharmony_ci    switch (info->blockSizeID) {
18827b27ec6Sopenharmony_ci        case LZ4F_default:
18927b27ec6Sopenharmony_ci        case LZ4F_max64KB:  return 1 << 16;
19027b27ec6Sopenharmony_ci        case LZ4F_max256KB: return 1 << 18;
19127b27ec6Sopenharmony_ci        case LZ4F_max1MB:   return 1 << 20;
19227b27ec6Sopenharmony_ci        case LZ4F_max4MB:   return 1 << 22;
19327b27ec6Sopenharmony_ci        default:
19427b27ec6Sopenharmony_ci            printf("Impossible with expected frame specification (<=v1.6.1)\n");
19527b27ec6Sopenharmony_ci            exit(1);
19627b27ec6Sopenharmony_ci    }
19727b27ec6Sopenharmony_ci}
19827b27ec6Sopenharmony_ci
19927b27ec6Sopenharmony_ci/* @return : 1==error, 0==success */
20027b27ec6Sopenharmony_cistatic int
20127b27ec6Sopenharmony_cidecompress_file_internal(FILE* f_in, FILE* f_out,
20227b27ec6Sopenharmony_ci                         LZ4F_dctx* dctx,
20327b27ec6Sopenharmony_ci                         void* src, size_t srcCapacity, size_t filled, size_t alreadyConsumed,
20427b27ec6Sopenharmony_ci                         void* dst, size_t dstCapacity)
20527b27ec6Sopenharmony_ci{
20627b27ec6Sopenharmony_ci    int firstChunk = 1;
20727b27ec6Sopenharmony_ci    size_t ret = 1;
20827b27ec6Sopenharmony_ci
20927b27ec6Sopenharmony_ci    assert(f_in != NULL); assert(f_out != NULL);
21027b27ec6Sopenharmony_ci    assert(dctx != NULL);
21127b27ec6Sopenharmony_ci    assert(src != NULL); assert(srcCapacity > 0); assert(filled <= srcCapacity); assert(alreadyConsumed <= filled);
21227b27ec6Sopenharmony_ci    assert(dst != NULL); assert(dstCapacity > 0);
21327b27ec6Sopenharmony_ci
21427b27ec6Sopenharmony_ci    /* Decompression */
21527b27ec6Sopenharmony_ci    while (ret != 0) {
21627b27ec6Sopenharmony_ci        /* Load more input */
21727b27ec6Sopenharmony_ci        size_t readSize = firstChunk ? filled : fread(src, 1, srcCapacity, f_in); firstChunk=0;
21827b27ec6Sopenharmony_ci        const void* srcPtr = (const char*)src + alreadyConsumed; alreadyConsumed=0;
21927b27ec6Sopenharmony_ci        const void* const srcEnd = (const char*)srcPtr + readSize;
22027b27ec6Sopenharmony_ci        if (readSize == 0 || ferror(f_in)) {
22127b27ec6Sopenharmony_ci            printf("Decompress: not enough input or error reading file\n");
22227b27ec6Sopenharmony_ci            return 1;
22327b27ec6Sopenharmony_ci        }
22427b27ec6Sopenharmony_ci
22527b27ec6Sopenharmony_ci        /* Decompress:
22627b27ec6Sopenharmony_ci         * Continue while there is more input to read (srcPtr != srcEnd)
22727b27ec6Sopenharmony_ci         * and the frame isn't over (ret != 0)
22827b27ec6Sopenharmony_ci         */
22927b27ec6Sopenharmony_ci        while (srcPtr < srcEnd && ret != 0) {
23027b27ec6Sopenharmony_ci            /* Any data within dst has been flushed at this stage */
23127b27ec6Sopenharmony_ci            size_t dstSize = dstCapacity;
23227b27ec6Sopenharmony_ci            size_t srcSize = (const char*)srcEnd - (const char*)srcPtr;
23327b27ec6Sopenharmony_ci            ret = LZ4F_decompress(dctx, dst, &dstSize, srcPtr, &srcSize, /* LZ4F_decompressOptions_t */ NULL);
23427b27ec6Sopenharmony_ci            if (LZ4F_isError(ret)) {
23527b27ec6Sopenharmony_ci                printf("Decompression error: %s\n", LZ4F_getErrorName(ret));
23627b27ec6Sopenharmony_ci                return 1;
23727b27ec6Sopenharmony_ci            }
23827b27ec6Sopenharmony_ci            /* Flush output */
23927b27ec6Sopenharmony_ci            if (dstSize != 0) safe_fwrite(dst, 1, dstSize, f_out);
24027b27ec6Sopenharmony_ci            /* Update input */
24127b27ec6Sopenharmony_ci            srcPtr = (const char*)srcPtr + srcSize;
24227b27ec6Sopenharmony_ci        }
24327b27ec6Sopenharmony_ci
24427b27ec6Sopenharmony_ci        assert(srcPtr <= srcEnd);
24527b27ec6Sopenharmony_ci
24627b27ec6Sopenharmony_ci        /* Ensure all input data has been consumed.
24727b27ec6Sopenharmony_ci         * It is valid to have multiple frames in the same file,
24827b27ec6Sopenharmony_ci         * but this example only supports one frame.
24927b27ec6Sopenharmony_ci         */
25027b27ec6Sopenharmony_ci        if (srcPtr < srcEnd) {
25127b27ec6Sopenharmony_ci            printf("Decompress: Trailing data left in file after frame\n");
25227b27ec6Sopenharmony_ci            return 1;
25327b27ec6Sopenharmony_ci        }
25427b27ec6Sopenharmony_ci    }
25527b27ec6Sopenharmony_ci
25627b27ec6Sopenharmony_ci    /* Check that there isn't trailing data in the file after the frame.
25727b27ec6Sopenharmony_ci     * It is valid to have multiple frames in the same file,
25827b27ec6Sopenharmony_ci     * but this example only supports one frame.
25927b27ec6Sopenharmony_ci     */
26027b27ec6Sopenharmony_ci    {   size_t const readSize = fread(src, 1, 1, f_in);
26127b27ec6Sopenharmony_ci        if (readSize != 0 || !feof(f_in)) {
26227b27ec6Sopenharmony_ci            printf("Decompress: Trailing data left in file after frame\n");
26327b27ec6Sopenharmony_ci            return 1;
26427b27ec6Sopenharmony_ci    }   }
26527b27ec6Sopenharmony_ci
26627b27ec6Sopenharmony_ci    return 0;
26727b27ec6Sopenharmony_ci}
26827b27ec6Sopenharmony_ci
26927b27ec6Sopenharmony_ci
27027b27ec6Sopenharmony_ci/* @return : 1==error, 0==completed */
27127b27ec6Sopenharmony_cistatic int
27227b27ec6Sopenharmony_cidecompress_file_allocDst(FILE* f_in, FILE* f_out,
27327b27ec6Sopenharmony_ci                        LZ4F_dctx* dctx,
27427b27ec6Sopenharmony_ci                        void* src, size_t srcCapacity)
27527b27ec6Sopenharmony_ci{
27627b27ec6Sopenharmony_ci    assert(f_in != NULL); assert(f_out != NULL);
27727b27ec6Sopenharmony_ci    assert(dctx != NULL);
27827b27ec6Sopenharmony_ci    assert(src != NULL);
27927b27ec6Sopenharmony_ci    assert(srcCapacity >= LZ4F_HEADER_SIZE_MAX);  /* ensure LZ4F_getFrameInfo() can read enough data */
28027b27ec6Sopenharmony_ci
28127b27ec6Sopenharmony_ci    /* Read Frame header */
28227b27ec6Sopenharmony_ci    size_t const readSize = fread(src, 1, srcCapacity, f_in);
28327b27ec6Sopenharmony_ci    if (readSize == 0 || ferror(f_in)) {
28427b27ec6Sopenharmony_ci        printf("Decompress: not enough input or error reading file\n");
28527b27ec6Sopenharmony_ci        return 1;
28627b27ec6Sopenharmony_ci    }
28727b27ec6Sopenharmony_ci
28827b27ec6Sopenharmony_ci    LZ4F_frameInfo_t info;
28927b27ec6Sopenharmony_ci    size_t consumedSize = readSize;
29027b27ec6Sopenharmony_ci    {   size_t const fires = LZ4F_getFrameInfo(dctx, &info, src, &consumedSize);
29127b27ec6Sopenharmony_ci        if (LZ4F_isError(fires)) {
29227b27ec6Sopenharmony_ci            printf("LZ4F_getFrameInfo error: %s\n", LZ4F_getErrorName(fires));
29327b27ec6Sopenharmony_ci            return 1;
29427b27ec6Sopenharmony_ci    }   }
29527b27ec6Sopenharmony_ci
29627b27ec6Sopenharmony_ci    /* Allocating enough space for an entire block isn't necessary for
29727b27ec6Sopenharmony_ci     * correctness, but it allows some memcpy's to be elided.
29827b27ec6Sopenharmony_ci     */
29927b27ec6Sopenharmony_ci    size_t const dstCapacity = get_block_size(&info);
30027b27ec6Sopenharmony_ci    void* const dst = malloc(dstCapacity);
30127b27ec6Sopenharmony_ci    if (!dst) { perror("decompress_file(dst)"); return 1; }
30227b27ec6Sopenharmony_ci
30327b27ec6Sopenharmony_ci    int const decompressionResult = decompress_file_internal(
30427b27ec6Sopenharmony_ci                        f_in, f_out,
30527b27ec6Sopenharmony_ci                        dctx,
30627b27ec6Sopenharmony_ci                        src, srcCapacity, readSize-consumedSize, consumedSize,
30727b27ec6Sopenharmony_ci                        dst, dstCapacity);
30827b27ec6Sopenharmony_ci
30927b27ec6Sopenharmony_ci    free(dst);
31027b27ec6Sopenharmony_ci    return decompressionResult;
31127b27ec6Sopenharmony_ci}
31227b27ec6Sopenharmony_ci
31327b27ec6Sopenharmony_ci
31427b27ec6Sopenharmony_ci/* @result : 1==error, 0==success */
31527b27ec6Sopenharmony_cistatic int decompress_file(FILE* f_in, FILE* f_out)
31627b27ec6Sopenharmony_ci{
31727b27ec6Sopenharmony_ci    assert(f_in != NULL); assert(f_out != NULL);
31827b27ec6Sopenharmony_ci
31927b27ec6Sopenharmony_ci    /* Resource allocation */
32027b27ec6Sopenharmony_ci    void* const src = malloc(IN_CHUNK_SIZE);
32127b27ec6Sopenharmony_ci    if (!src) { perror("decompress_file(src)"); return 1; }
32227b27ec6Sopenharmony_ci
32327b27ec6Sopenharmony_ci    LZ4F_dctx* dctx;
32427b27ec6Sopenharmony_ci    {   size_t const dctxStatus = LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
32527b27ec6Sopenharmony_ci        if (LZ4F_isError(dctxStatus)) {
32627b27ec6Sopenharmony_ci            printf("LZ4F_dctx creation error: %s\n", LZ4F_getErrorName(dctxStatus));
32727b27ec6Sopenharmony_ci    }   }
32827b27ec6Sopenharmony_ci
32927b27ec6Sopenharmony_ci    int const result = !dctx ? 1 /* error */ :
33027b27ec6Sopenharmony_ci                       decompress_file_allocDst(f_in, f_out, dctx, src, IN_CHUNK_SIZE);
33127b27ec6Sopenharmony_ci
33227b27ec6Sopenharmony_ci    free(src);
33327b27ec6Sopenharmony_ci    LZ4F_freeDecompressionContext(dctx);   /* note : free works on NULL */
33427b27ec6Sopenharmony_ci    return result;
33527b27ec6Sopenharmony_ci}
33627b27ec6Sopenharmony_ci
33727b27ec6Sopenharmony_ci
33827b27ec6Sopenharmony_ciint compareFiles(FILE* fp0, FILE* fp1, FILE* fpUnc, long uncOffset)
33927b27ec6Sopenharmony_ci{
34027b27ec6Sopenharmony_ci    int result = 0;
34127b27ec6Sopenharmony_ci    long bytesRead = 0;
34227b27ec6Sopenharmony_ci    long bytesToOffset = -1;
34327b27ec6Sopenharmony_ci    long b1Size = 1024;
34427b27ec6Sopenharmony_ci
34527b27ec6Sopenharmony_ci    while (result==0) {
34627b27ec6Sopenharmony_ci        char b1[b1Size];
34727b27ec6Sopenharmony_ci        size_t r1;
34827b27ec6Sopenharmony_ci        size_t bytesToRead = sizeof b1;
34927b27ec6Sopenharmony_ci        if (uncOffset >= 0) {
35027b27ec6Sopenharmony_ci          bytesToOffset = uncOffset - bytesRead;
35127b27ec6Sopenharmony_ci
35227b27ec6Sopenharmony_ci          /* read remainder to offset */
35327b27ec6Sopenharmony_ci          if (bytesToOffset < b1Size) {
35427b27ec6Sopenharmony_ci            bytesToRead = bytesToOffset;
35527b27ec6Sopenharmony_ci          }
35627b27ec6Sopenharmony_ci        }
35727b27ec6Sopenharmony_ci
35827b27ec6Sopenharmony_ci        char b0[1024];
35927b27ec6Sopenharmony_ci        size_t r0;
36027b27ec6Sopenharmony_ci        if (bytesToOffset <= 0 && fpUnc) {
36127b27ec6Sopenharmony_ci          bytesToRead = sizeof b1;
36227b27ec6Sopenharmony_ci          r0 = fread(b0, 1,bytesToRead, fpUnc);
36327b27ec6Sopenharmony_ci        } else {
36427b27ec6Sopenharmony_ci          r0 = fread(b0, 1, bytesToRead, fp0);
36527b27ec6Sopenharmony_ci        }
36627b27ec6Sopenharmony_ci
36727b27ec6Sopenharmony_ci        r1 = fread(b1, 1, r0, fp1);
36827b27ec6Sopenharmony_ci
36927b27ec6Sopenharmony_ci        result = (r0 != r1);
37027b27ec6Sopenharmony_ci        if (!r0 || !r1) break;
37127b27ec6Sopenharmony_ci        if (!result) result = memcmp(b0, b1, r0);
37227b27ec6Sopenharmony_ci
37327b27ec6Sopenharmony_ci        bytesRead += r1;
37427b27ec6Sopenharmony_ci    }
37527b27ec6Sopenharmony_ci
37627b27ec6Sopenharmony_ci    return result;
37727b27ec6Sopenharmony_ci}
37827b27ec6Sopenharmony_ci
37927b27ec6Sopenharmony_ci
38027b27ec6Sopenharmony_ciint main(int argc, char **argv) {
38127b27ec6Sopenharmony_ci    char inpFilename[256] = { 0 };
38227b27ec6Sopenharmony_ci    char lz4Filename[256] = { 0 };
38327b27ec6Sopenharmony_ci    char decFilename[256] = { 0 };
38427b27ec6Sopenharmony_ci
38527b27ec6Sopenharmony_ci    int uncOffset = -1;
38627b27ec6Sopenharmony_ci    char uncFilename[256] = { 0 };
38727b27ec6Sopenharmony_ci    int opt;
38827b27ec6Sopenharmony_ci
38927b27ec6Sopenharmony_ci    if (argc < 2) {
39027b27ec6Sopenharmony_ci        printf("Please specify input filename\n");
39127b27ec6Sopenharmony_ci        return EXIT_FAILURE;
39227b27ec6Sopenharmony_ci    }
39327b27ec6Sopenharmony_ci
39427b27ec6Sopenharmony_ci    snprintf(inpFilename, 256, "%s", argv[1]);
39527b27ec6Sopenharmony_ci    snprintf(lz4Filename, 256, "%s.lz4", argv[1]);
39627b27ec6Sopenharmony_ci    snprintf(decFilename, 256, "%s.lz4.dec", argv[1]);
39727b27ec6Sopenharmony_ci
39827b27ec6Sopenharmony_ci    while ((opt = getopt(argc, argv, "o:d:")) != -1) {
39927b27ec6Sopenharmony_ci      switch (opt) {
40027b27ec6Sopenharmony_ci      case 'd':
40127b27ec6Sopenharmony_ci        snprintf(uncFilename, 256, "%s", optarg);
40227b27ec6Sopenharmony_ci        break;
40327b27ec6Sopenharmony_ci      case 'o':
40427b27ec6Sopenharmony_ci        uncOffset = atoi(optarg);
40527b27ec6Sopenharmony_ci        break;
40627b27ec6Sopenharmony_ci      default:
40727b27ec6Sopenharmony_ci        printf("usage: %s <input file> [-o <offset> -d <file>]\n", argv[0]);
40827b27ec6Sopenharmony_ci        printf("-o uncompressed data offset\n");
40927b27ec6Sopenharmony_ci        printf("   inject uncompressed data at this offset into the lz4 file\n");
41027b27ec6Sopenharmony_ci        printf("-d uncompressed file\n");
41127b27ec6Sopenharmony_ci        printf("   file to inject without compression into the lz4 file\n");
41227b27ec6Sopenharmony_ci        return EXIT_FAILURE;
41327b27ec6Sopenharmony_ci      }
41427b27ec6Sopenharmony_ci    }
41527b27ec6Sopenharmony_ci
41627b27ec6Sopenharmony_ci    printf("inp = [%s]\n", inpFilename);
41727b27ec6Sopenharmony_ci    printf("lz4 = [%s]\n", lz4Filename);
41827b27ec6Sopenharmony_ci    printf("dec = [%s]\n", decFilename);
41927b27ec6Sopenharmony_ci    if (uncOffset > 0) {
42027b27ec6Sopenharmony_ci      printf("unc = [%s]\n", uncFilename);
42127b27ec6Sopenharmony_ci      printf("ofs = [%i]\n", uncOffset);
42227b27ec6Sopenharmony_ci    }
42327b27ec6Sopenharmony_ci
42427b27ec6Sopenharmony_ci    /* compress */
42527b27ec6Sopenharmony_ci    {   FILE* const inpFp = fopen(inpFilename, "rb");
42627b27ec6Sopenharmony_ci        FILE* const outFp = fopen(lz4Filename, "wb");
42727b27ec6Sopenharmony_ci        FILE* const uncFp = fopen(uncFilename, "rb");
42827b27ec6Sopenharmony_ci
42927b27ec6Sopenharmony_ci        printf("compress : %s -> %s\n", inpFilename, lz4Filename);
43027b27ec6Sopenharmony_ci        compressResult_t const ret = compress_file(
43127b27ec6Sopenharmony_ci            inpFp, outFp,
43227b27ec6Sopenharmony_ci            uncFp, uncOffset);
43327b27ec6Sopenharmony_ci
43427b27ec6Sopenharmony_ci        fclose(outFp);
43527b27ec6Sopenharmony_ci        fclose(inpFp);
43627b27ec6Sopenharmony_ci        if (uncFp)
43727b27ec6Sopenharmony_ci          fclose(uncFp);
43827b27ec6Sopenharmony_ci
43927b27ec6Sopenharmony_ci        if (ret.error) {
44027b27ec6Sopenharmony_ci            printf("compress : failed with code %i\n", ret.error);
44127b27ec6Sopenharmony_ci            return ret.error;
44227b27ec6Sopenharmony_ci        }
44327b27ec6Sopenharmony_ci        printf("%s: %zu → %zu bytes, %.1f%%\n",
44427b27ec6Sopenharmony_ci            inpFilename,
44527b27ec6Sopenharmony_ci            (size_t)ret.size_in, (size_t)ret.size_out,  /* might overflow is size_t is 32 bits and size_{in,out} > 4 GB */
44627b27ec6Sopenharmony_ci            (double)ret.size_out / ret.size_in * 100);
44727b27ec6Sopenharmony_ci        printf("compress : done\n");
44827b27ec6Sopenharmony_ci    }
44927b27ec6Sopenharmony_ci
45027b27ec6Sopenharmony_ci    /* decompress */
45127b27ec6Sopenharmony_ci    {   FILE* const inpFp = fopen(lz4Filename, "rb");
45227b27ec6Sopenharmony_ci        FILE* const outFp = fopen(decFilename, "wb");
45327b27ec6Sopenharmony_ci
45427b27ec6Sopenharmony_ci        printf("decompress : %s -> %s\n", lz4Filename, decFilename);
45527b27ec6Sopenharmony_ci        int const ret = decompress_file(inpFp, outFp);
45627b27ec6Sopenharmony_ci
45727b27ec6Sopenharmony_ci        fclose(outFp);
45827b27ec6Sopenharmony_ci        fclose(inpFp);
45927b27ec6Sopenharmony_ci
46027b27ec6Sopenharmony_ci        if (ret) {
46127b27ec6Sopenharmony_ci            printf("decompress : failed with code %i\n", ret);
46227b27ec6Sopenharmony_ci            return ret;
46327b27ec6Sopenharmony_ci        }
46427b27ec6Sopenharmony_ci        printf("decompress : done\n");
46527b27ec6Sopenharmony_ci    }
46627b27ec6Sopenharmony_ci
46727b27ec6Sopenharmony_ci    /* verify */
46827b27ec6Sopenharmony_ci    {   FILE* const inpFp = fopen(inpFilename, "rb");
46927b27ec6Sopenharmony_ci        FILE* const decFp = fopen(decFilename, "rb");
47027b27ec6Sopenharmony_ci        FILE* const uncFp = fopen(uncFilename, "rb");
47127b27ec6Sopenharmony_ci
47227b27ec6Sopenharmony_ci        printf("verify : %s <-> %s\n", inpFilename, decFilename);
47327b27ec6Sopenharmony_ci        int const cmp = compareFiles(inpFp, decFp,
47427b27ec6Sopenharmony_ci                                     uncFp, uncOffset);
47527b27ec6Sopenharmony_ci
47627b27ec6Sopenharmony_ci        fclose(decFp);
47727b27ec6Sopenharmony_ci        fclose(inpFp);
47827b27ec6Sopenharmony_ci        if (uncFp)
47927b27ec6Sopenharmony_ci          fclose(uncFp);
48027b27ec6Sopenharmony_ci
48127b27ec6Sopenharmony_ci        if (cmp) {
48227b27ec6Sopenharmony_ci            printf("corruption detected : decompressed file differs from original\n");
48327b27ec6Sopenharmony_ci            return cmp;
48427b27ec6Sopenharmony_ci        }
48527b27ec6Sopenharmony_ci        printf("verify : OK\n");
48627b27ec6Sopenharmony_ci    }
48727b27ec6Sopenharmony_ci
48827b27ec6Sopenharmony_ci    return 0;
48927b27ec6Sopenharmony_ci}
490