Home | History | Annotate | Download | only in examples
      1 // LZ4 HC streaming API example : ring buffer
      2 // Based on previous work from Takayuki Matsuoka
      3 
      4 
      5 /**************************************
      6  * Compiler Options
      7  **************************************/
      8 #ifdef _MSC_VER    /* Visual Studio */
      9 #  define _CRT_SECURE_NO_WARNINGS // for MSVC
     10 #  define snprintf sprintf_s
     11 #endif
     12 
     13 #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
     14 #ifdef __GNUC__
     15 #  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) */
     16 #endif
     17 
     18 
     19 /**************************************
     20  * Includes
     21  **************************************/
     22 #include "lz4hc.h"
     23 #include "lz4.h"
     24 
     25 #include <stdio.h>
     26 #include <stdint.h>
     27 #include <stdlib.h>
     28 #include <string.h>
     29 
     30 enum {
     31     MESSAGE_MAX_BYTES   = 1024,
     32     RING_BUFFER_BYTES   = 1024 * 8 + MESSAGE_MAX_BYTES,
     33     DEC_BUFFER_BYTES    = RING_BUFFER_BYTES + MESSAGE_MAX_BYTES   // Intentionally larger to test unsynchronized ring buffers
     34 };
     35 
     36 
     37 size_t write_int32(FILE* fp, int32_t i) {
     38     return fwrite(&i, sizeof(i), 1, fp);
     39 }
     40 
     41 size_t write_bin(FILE* fp, const void* array, int arrayBytes) {
     42     return fwrite(array, 1, arrayBytes, fp);
     43 }
     44 
     45 size_t read_int32(FILE* fp, int32_t* i) {
     46     return fread(i, sizeof(*i), 1, fp);
     47 }
     48 
     49 size_t read_bin(FILE* fp, void* array, int arrayBytes) {
     50     return fread(array, 1, arrayBytes, fp);
     51 }
     52 
     53 
     54 void test_compress(FILE* outFp, FILE* inpFp)
     55 {
     56     LZ4_streamHC_t lz4Stream_body = { 0 };
     57     LZ4_streamHC_t* lz4Stream = &lz4Stream_body;
     58 
     59     static char inpBuf[RING_BUFFER_BYTES];
     60     int inpOffset = 0;
     61 
     62     for(;;)
     63     {
     64         // Read random length ([1,MESSAGE_MAX_BYTES]) data to the ring buffer.
     65         char* const inpPtr = &inpBuf[inpOffset];
     66         const int randomLength = (rand() % MESSAGE_MAX_BYTES) + 1;
     67         const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength);
     68         if (0 == inpBytes) break;
     69 
     70         {
     71             char cmpBuf[LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)];
     72             const int cmpBytes = LZ4_compressHC_continue(lz4Stream, inpPtr, cmpBuf, inpBytes);
     73 
     74             if(cmpBytes <= 0) break;
     75             write_int32(outFp, cmpBytes);
     76             write_bin(outFp, cmpBuf, cmpBytes);
     77 
     78             inpOffset += inpBytes;
     79 
     80             // Wraparound the ringbuffer offset
     81             if(inpOffset >= RING_BUFFER_BYTES - MESSAGE_MAX_BYTES)
     82                 inpOffset = 0;
     83         }
     84     }
     85 
     86     write_int32(outFp, 0);
     87 }
     88 
     89 
     90 void test_decompress(FILE* outFp, FILE* inpFp)
     91 {
     92     static char decBuf[DEC_BUFFER_BYTES];
     93     int decOffset = 0;
     94     LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
     95     LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
     96 
     97     for(;;)
     98     {
     99         int  cmpBytes = 0;
    100         char cmpBuf[LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)];
    101 
    102         {
    103             const size_t r0 = read_int32(inpFp, &cmpBytes);
    104             size_t r1;
    105             if(r0 != 1 || cmpBytes <= 0)
    106                 break;
    107 
    108             r1 = read_bin(inpFp, cmpBuf, cmpBytes);
    109             if(r1 != (size_t) cmpBytes)
    110                 break;
    111         }
    112 
    113         {
    114             char* const decPtr = &decBuf[decOffset];
    115             const int decBytes = LZ4_decompress_safe_continue(
    116                 lz4StreamDecode, cmpBuf, decPtr, cmpBytes, MESSAGE_MAX_BYTES);
    117             if(decBytes <= 0)
    118                 break;
    119 
    120             decOffset += decBytes;
    121             write_bin(outFp, decPtr, decBytes);
    122 
    123             // Wraparound the ringbuffer offset
    124             if(decOffset >= DEC_BUFFER_BYTES - MESSAGE_MAX_BYTES)
    125                 decOffset = 0;
    126         }
    127     }
    128 }
    129 
    130 
    131 // Compare 2 files content
    132 // return 0 if identical
    133 // return ByteNb>0 if different
    134 size_t compare(FILE* f0, FILE* f1)
    135 {
    136     size_t result = 1;
    137 
    138     for (;;)
    139     {
    140         char b0[65536];
    141         char b1[65536];
    142         const size_t r0 = fread(b0, 1, sizeof(b0), f0);
    143         const size_t r1 = fread(b1, 1, sizeof(b1), f1);
    144 
    145         if ((r0==0) && (r1==0)) return 0;   // success
    146 
    147         if (r0 != r1)
    148         {
    149             size_t smallest = r0;
    150             if (r1<r0) smallest = r1;
    151             result += smallest;
    152             break;
    153         }
    154 
    155         if (memcmp(b0, b1, r0))
    156         {
    157             unsigned errorPos = 0;
    158             while ((errorPos < r0) && (b0[errorPos]==b1[errorPos])) errorPos++;
    159             result += errorPos;
    160             break;
    161         }
    162 
    163         result += sizeof(b0);
    164     }
    165 
    166     return result;
    167 }
    168 
    169 
    170 int main(int argc, char** argv)
    171 {
    172     char inpFilename[256] = { 0 };
    173     char lz4Filename[256] = { 0 };
    174     char decFilename[256] = { 0 };
    175     unsigned fileID = 1;
    176     unsigned pause = 0;
    177 
    178 
    179     if(argc < 2) {
    180         printf("Please specify input filename\n");
    181         return 0;
    182     }
    183 
    184     if (!strcmp(argv[1], "-p")) pause = 1, fileID = 2;
    185 
    186     snprintf(inpFilename, 256, "%s", argv[fileID]);
    187     snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[fileID], 9);
    188     snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[fileID], 9);
    189 
    190     printf("input   = [%s]\n", inpFilename);
    191     printf("lz4     = [%s]\n", lz4Filename);
    192     printf("decoded = [%s]\n", decFilename);
    193 
    194     // compress
    195     {
    196         FILE* inpFp = fopen(inpFilename, "rb");
    197         FILE* outFp = fopen(lz4Filename, "wb");
    198 
    199         test_compress(outFp, inpFp);
    200 
    201         fclose(outFp);
    202         fclose(inpFp);
    203     }
    204 
    205     // decompress
    206     {
    207         FILE* inpFp = fopen(lz4Filename, "rb");
    208         FILE* outFp = fopen(decFilename, "wb");
    209 
    210         test_decompress(outFp, inpFp);
    211 
    212         fclose(outFp);
    213         fclose(inpFp);
    214     }
    215 
    216     // verify
    217     {
    218         FILE* inpFp = fopen(inpFilename, "rb");
    219         FILE* decFp = fopen(decFilename, "rb");
    220 
    221         const size_t cmp = compare(inpFp, decFp);
    222         if(0 == cmp) {
    223             printf("Verify : OK\n");
    224         } else {
    225             printf("Verify : NG : error at pos %u\n", (unsigned)cmp-1);
    226         }
    227 
    228         fclose(decFp);
    229         fclose(inpFp);
    230     }
    231 
    232     if (pause)
    233     {
    234         printf("Press enter to continue ...\n");
    235         getchar();
    236     }
    237 
    238     return 0;
    239 }
    240