127b27ec6Sopenharmony_ci// LZ4 HC streaming API example : ring buffer
227b27ec6Sopenharmony_ci// Based on a previous example by Takayuki Matsuoka
327b27ec6Sopenharmony_ci
427b27ec6Sopenharmony_ci
527b27ec6Sopenharmony_ci/**************************************
627b27ec6Sopenharmony_ci * Compiler Options
727b27ec6Sopenharmony_ci **************************************/
827b27ec6Sopenharmony_ci#if defined(_MSC_VER) && (_MSC_VER <= 1800)  /* Visual Studio <= 2013 */
927b27ec6Sopenharmony_ci#  define _CRT_SECURE_NO_WARNINGS
1027b27ec6Sopenharmony_ci#  define snprintf sprintf_s
1127b27ec6Sopenharmony_ci#endif
1227b27ec6Sopenharmony_ci
1327b27ec6Sopenharmony_ci#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
1427b27ec6Sopenharmony_ci#ifdef __GNUC__
1527b27ec6Sopenharmony_ci#  pragma GCC diagnostic ignored "-Wmissing-braces"   /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
1627b27ec6Sopenharmony_ci#endif
1727b27ec6Sopenharmony_ci
1827b27ec6Sopenharmony_ci
1927b27ec6Sopenharmony_ci/**************************************
2027b27ec6Sopenharmony_ci * Includes
2127b27ec6Sopenharmony_ci **************************************/
2227b27ec6Sopenharmony_ci#include "lz4hc.h"
2327b27ec6Sopenharmony_ci#include "lz4.h"
2427b27ec6Sopenharmony_ci
2527b27ec6Sopenharmony_ci#include <stdio.h>
2627b27ec6Sopenharmony_ci#include <stdint.h>
2727b27ec6Sopenharmony_ci#include <stdlib.h>
2827b27ec6Sopenharmony_ci#include <string.h>
2927b27ec6Sopenharmony_ci#include <assert.h>
3027b27ec6Sopenharmony_ci
3127b27ec6Sopenharmony_cienum {
3227b27ec6Sopenharmony_ci    MESSAGE_MAX_BYTES   = 1024,
3327b27ec6Sopenharmony_ci    RING_BUFFER_BYTES   = 1024 * 8 + MESSAGE_MAX_BYTES,
3427b27ec6Sopenharmony_ci    DEC_BUFFER_BYTES    = RING_BUFFER_BYTES + MESSAGE_MAX_BYTES   // Intentionally larger to test unsynchronized ring buffers
3527b27ec6Sopenharmony_ci};
3627b27ec6Sopenharmony_ci
3727b27ec6Sopenharmony_ci
3827b27ec6Sopenharmony_cisize_t write_int32(FILE* fp, int32_t i) {
3927b27ec6Sopenharmony_ci    return fwrite(&i, sizeof(i), 1, fp);
4027b27ec6Sopenharmony_ci}
4127b27ec6Sopenharmony_ci
4227b27ec6Sopenharmony_cisize_t write_bin(FILE* fp, const void* array, int arrayBytes) {
4327b27ec6Sopenharmony_ci    assert(arrayBytes >= 0);
4427b27ec6Sopenharmony_ci    return fwrite(array, 1, (size_t)arrayBytes, fp);
4527b27ec6Sopenharmony_ci}
4627b27ec6Sopenharmony_ci
4727b27ec6Sopenharmony_cisize_t read_int32(FILE* fp, int32_t* i) {
4827b27ec6Sopenharmony_ci    return fread(i, sizeof(*i), 1, fp);
4927b27ec6Sopenharmony_ci}
5027b27ec6Sopenharmony_ci
5127b27ec6Sopenharmony_cisize_t read_bin(FILE* fp, void* array, int arrayBytes) {
5227b27ec6Sopenharmony_ci    assert(arrayBytes >= 0);
5327b27ec6Sopenharmony_ci    return fread(array, 1, (size_t)arrayBytes, fp);
5427b27ec6Sopenharmony_ci}
5527b27ec6Sopenharmony_ci
5627b27ec6Sopenharmony_ci
5727b27ec6Sopenharmony_civoid test_compress(FILE* outFp, FILE* inpFp)
5827b27ec6Sopenharmony_ci{
5927b27ec6Sopenharmony_ci    LZ4_streamHC_t lz4Stream_body = { 0 };
6027b27ec6Sopenharmony_ci    LZ4_streamHC_t* lz4Stream = &lz4Stream_body;
6127b27ec6Sopenharmony_ci
6227b27ec6Sopenharmony_ci    static char inpBuf[RING_BUFFER_BYTES];
6327b27ec6Sopenharmony_ci    int inpOffset = 0;
6427b27ec6Sopenharmony_ci
6527b27ec6Sopenharmony_ci    for(;;) {
6627b27ec6Sopenharmony_ci        // Read random length ([1,MESSAGE_MAX_BYTES]) data to the ring buffer.
6727b27ec6Sopenharmony_ci        char* const inpPtr = &inpBuf[inpOffset];
6827b27ec6Sopenharmony_ci        const int randomLength = (rand() % MESSAGE_MAX_BYTES) + 1;
6927b27ec6Sopenharmony_ci        const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength);
7027b27ec6Sopenharmony_ci        if (0 == inpBytes) break;
7127b27ec6Sopenharmony_ci
7227b27ec6Sopenharmony_ci#define CMPBUFSIZE (LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES))
7327b27ec6Sopenharmony_ci        {   char cmpBuf[CMPBUFSIZE];
7427b27ec6Sopenharmony_ci            const int cmpBytes = LZ4_compress_HC_continue(lz4Stream, inpPtr, cmpBuf, inpBytes, CMPBUFSIZE);
7527b27ec6Sopenharmony_ci
7627b27ec6Sopenharmony_ci            if(cmpBytes <= 0) break;
7727b27ec6Sopenharmony_ci            write_int32(outFp, cmpBytes);
7827b27ec6Sopenharmony_ci            write_bin(outFp, cmpBuf, cmpBytes);
7927b27ec6Sopenharmony_ci
8027b27ec6Sopenharmony_ci            inpOffset += inpBytes;
8127b27ec6Sopenharmony_ci
8227b27ec6Sopenharmony_ci            // Wraparound the ringbuffer offset
8327b27ec6Sopenharmony_ci            if(inpOffset >= RING_BUFFER_BYTES - MESSAGE_MAX_BYTES)
8427b27ec6Sopenharmony_ci                inpOffset = 0;
8527b27ec6Sopenharmony_ci        }
8627b27ec6Sopenharmony_ci    }
8727b27ec6Sopenharmony_ci
8827b27ec6Sopenharmony_ci    write_int32(outFp, 0);
8927b27ec6Sopenharmony_ci}
9027b27ec6Sopenharmony_ci
9127b27ec6Sopenharmony_ci
9227b27ec6Sopenharmony_civoid test_decompress(FILE* outFp, FILE* inpFp)
9327b27ec6Sopenharmony_ci{
9427b27ec6Sopenharmony_ci    static char decBuf[DEC_BUFFER_BYTES];
9527b27ec6Sopenharmony_ci    int decOffset = 0;
9627b27ec6Sopenharmony_ci    LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
9727b27ec6Sopenharmony_ci    LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
9827b27ec6Sopenharmony_ci
9927b27ec6Sopenharmony_ci    for(;;) {
10027b27ec6Sopenharmony_ci        int  cmpBytes = 0;
10127b27ec6Sopenharmony_ci        char cmpBuf[CMPBUFSIZE];
10227b27ec6Sopenharmony_ci
10327b27ec6Sopenharmony_ci        {   const size_t r0 = read_int32(inpFp, &cmpBytes);
10427b27ec6Sopenharmony_ci            size_t r1;
10527b27ec6Sopenharmony_ci            if(r0 != 1 || cmpBytes <= 0)
10627b27ec6Sopenharmony_ci                break;
10727b27ec6Sopenharmony_ci
10827b27ec6Sopenharmony_ci            r1 = read_bin(inpFp, cmpBuf, cmpBytes);
10927b27ec6Sopenharmony_ci            if(r1 != (size_t) cmpBytes)
11027b27ec6Sopenharmony_ci                break;
11127b27ec6Sopenharmony_ci        }
11227b27ec6Sopenharmony_ci
11327b27ec6Sopenharmony_ci        {   char* const decPtr = &decBuf[decOffset];
11427b27ec6Sopenharmony_ci            const int decBytes = LZ4_decompress_safe_continue(
11527b27ec6Sopenharmony_ci                lz4StreamDecode, cmpBuf, decPtr, cmpBytes, MESSAGE_MAX_BYTES);
11627b27ec6Sopenharmony_ci            if(decBytes <= 0)
11727b27ec6Sopenharmony_ci                break;
11827b27ec6Sopenharmony_ci
11927b27ec6Sopenharmony_ci            decOffset += decBytes;
12027b27ec6Sopenharmony_ci            write_bin(outFp, decPtr, decBytes);
12127b27ec6Sopenharmony_ci
12227b27ec6Sopenharmony_ci            // Wraparound the ringbuffer offset
12327b27ec6Sopenharmony_ci            if(decOffset >= DEC_BUFFER_BYTES - MESSAGE_MAX_BYTES)
12427b27ec6Sopenharmony_ci                decOffset = 0;
12527b27ec6Sopenharmony_ci        }
12627b27ec6Sopenharmony_ci    }
12727b27ec6Sopenharmony_ci}
12827b27ec6Sopenharmony_ci
12927b27ec6Sopenharmony_ci
13027b27ec6Sopenharmony_ci// Compare 2 files content
13127b27ec6Sopenharmony_ci// return 0 if identical
13227b27ec6Sopenharmony_ci// return ByteNb>0 if different
13327b27ec6Sopenharmony_cisize_t compare(FILE* f0, FILE* f1)
13427b27ec6Sopenharmony_ci{
13527b27ec6Sopenharmony_ci    size_t result = 1;
13627b27ec6Sopenharmony_ci
13727b27ec6Sopenharmony_ci    for (;;) {
13827b27ec6Sopenharmony_ci        char b0[65536];
13927b27ec6Sopenharmony_ci        char b1[65536];
14027b27ec6Sopenharmony_ci        const size_t r0 = fread(b0, 1, sizeof(b0), f0);
14127b27ec6Sopenharmony_ci        const size_t r1 = fread(b1, 1, sizeof(b1), f1);
14227b27ec6Sopenharmony_ci
14327b27ec6Sopenharmony_ci        if ((r0==0) && (r1==0)) return 0;   // success
14427b27ec6Sopenharmony_ci
14527b27ec6Sopenharmony_ci        if (r0 != r1) {
14627b27ec6Sopenharmony_ci            size_t smallest = r0;
14727b27ec6Sopenharmony_ci            if (r1<r0) smallest = r1;
14827b27ec6Sopenharmony_ci            result += smallest;
14927b27ec6Sopenharmony_ci            break;
15027b27ec6Sopenharmony_ci        }
15127b27ec6Sopenharmony_ci
15227b27ec6Sopenharmony_ci        if (memcmp(b0, b1, r0)) {
15327b27ec6Sopenharmony_ci            unsigned errorPos = 0;
15427b27ec6Sopenharmony_ci            while ((errorPos < r0) && (b0[errorPos]==b1[errorPos])) errorPos++;
15527b27ec6Sopenharmony_ci            result += errorPos;
15627b27ec6Sopenharmony_ci            break;
15727b27ec6Sopenharmony_ci        }
15827b27ec6Sopenharmony_ci
15927b27ec6Sopenharmony_ci        result += sizeof(b0);
16027b27ec6Sopenharmony_ci    }
16127b27ec6Sopenharmony_ci
16227b27ec6Sopenharmony_ci    return result;
16327b27ec6Sopenharmony_ci}
16427b27ec6Sopenharmony_ci
16527b27ec6Sopenharmony_ci
16627b27ec6Sopenharmony_ciint main(int argc, const char** argv)
16727b27ec6Sopenharmony_ci{
16827b27ec6Sopenharmony_ci    char inpFilename[256] = { 0 };
16927b27ec6Sopenharmony_ci    char lz4Filename[256] = { 0 };
17027b27ec6Sopenharmony_ci    char decFilename[256] = { 0 };
17127b27ec6Sopenharmony_ci    unsigned fileID = 1;
17227b27ec6Sopenharmony_ci    unsigned pause = 0;
17327b27ec6Sopenharmony_ci
17427b27ec6Sopenharmony_ci
17527b27ec6Sopenharmony_ci    if(argc < 2) {
17627b27ec6Sopenharmony_ci        printf("Please specify input filename\n");
17727b27ec6Sopenharmony_ci        return 0;
17827b27ec6Sopenharmony_ci    }
17927b27ec6Sopenharmony_ci
18027b27ec6Sopenharmony_ci    if (!strcmp(argv[1], "-p")) { pause = 1; fileID = 2; }
18127b27ec6Sopenharmony_ci
18227b27ec6Sopenharmony_ci    snprintf(inpFilename, 256, "%s", argv[fileID]);
18327b27ec6Sopenharmony_ci    snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[fileID], 9);
18427b27ec6Sopenharmony_ci    snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[fileID], 9);
18527b27ec6Sopenharmony_ci
18627b27ec6Sopenharmony_ci    printf("input   = [%s]\n", inpFilename);
18727b27ec6Sopenharmony_ci    printf("lz4     = [%s]\n", lz4Filename);
18827b27ec6Sopenharmony_ci    printf("decoded = [%s]\n", decFilename);
18927b27ec6Sopenharmony_ci
19027b27ec6Sopenharmony_ci    // compress
19127b27ec6Sopenharmony_ci    {   FILE* const inpFp = fopen(inpFilename, "rb");
19227b27ec6Sopenharmony_ci        FILE* const outFp = fopen(lz4Filename, "wb");
19327b27ec6Sopenharmony_ci
19427b27ec6Sopenharmony_ci        test_compress(outFp, inpFp);
19527b27ec6Sopenharmony_ci
19627b27ec6Sopenharmony_ci        fclose(outFp);
19727b27ec6Sopenharmony_ci        fclose(inpFp);
19827b27ec6Sopenharmony_ci    }
19927b27ec6Sopenharmony_ci
20027b27ec6Sopenharmony_ci    // decompress
20127b27ec6Sopenharmony_ci    {   FILE* const inpFp = fopen(lz4Filename, "rb");
20227b27ec6Sopenharmony_ci        FILE* const outFp = fopen(decFilename, "wb");
20327b27ec6Sopenharmony_ci
20427b27ec6Sopenharmony_ci        test_decompress(outFp, inpFp);
20527b27ec6Sopenharmony_ci
20627b27ec6Sopenharmony_ci        fclose(outFp);
20727b27ec6Sopenharmony_ci        fclose(inpFp);
20827b27ec6Sopenharmony_ci    }
20927b27ec6Sopenharmony_ci
21027b27ec6Sopenharmony_ci    // verify
21127b27ec6Sopenharmony_ci    {   FILE* const inpFp = fopen(inpFilename, "rb");
21227b27ec6Sopenharmony_ci        FILE* const decFp = fopen(decFilename, "rb");
21327b27ec6Sopenharmony_ci
21427b27ec6Sopenharmony_ci        const size_t cmp = compare(inpFp, decFp);
21527b27ec6Sopenharmony_ci        if(0 == cmp) {
21627b27ec6Sopenharmony_ci            printf("Verify : OK\n");
21727b27ec6Sopenharmony_ci        } else {
21827b27ec6Sopenharmony_ci            printf("Verify : NG : error at pos %u\n", (unsigned)cmp-1);
21927b27ec6Sopenharmony_ci        }
22027b27ec6Sopenharmony_ci
22127b27ec6Sopenharmony_ci        fclose(decFp);
22227b27ec6Sopenharmony_ci        fclose(inpFp);
22327b27ec6Sopenharmony_ci    }
22427b27ec6Sopenharmony_ci
22527b27ec6Sopenharmony_ci    if (pause) {
22627b27ec6Sopenharmony_ci        int unused;
22727b27ec6Sopenharmony_ci        printf("Press enter to continue ...\n");
22827b27ec6Sopenharmony_ci        unused = getchar(); (void)unused;   /* silence static analyzer */
22927b27ec6Sopenharmony_ci    }
23027b27ec6Sopenharmony_ci
23127b27ec6Sopenharmony_ci    return 0;
23227b27ec6Sopenharmony_ci}
233