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