Home | History | Annotate | Download | only in examples
      1 // LZ4 streaming API example : line-by-line logfile compression
      2 // Copyright : Takayuki Matsuoka
      3 
      4 
      5 #define _CRT_SECURE_NO_WARNINGS // for MSVC
      6 #include "lz4.h"
      7 
      8 #include <stdio.h>
      9 #include <stdint.h>
     10 #include <stdlib.h>
     11 #include <string.h>
     12 
     13 static size_t write_uint16(FILE* fp, uint16_t i)
     14 {
     15     return fwrite(&i, sizeof(i), 1, fp);
     16 }
     17 
     18 static size_t write_bin(FILE* fp, const void* array, int arrayBytes)
     19 {
     20     return fwrite(array, 1, arrayBytes, fp);
     21 }
     22 
     23 static size_t read_uint16(FILE* fp, uint16_t* i)
     24 {
     25     return fread(i, sizeof(*i), 1, fp);
     26 }
     27 
     28 static size_t read_bin(FILE* fp, void* array, int arrayBytes)
     29 {
     30     return fread(array, 1, arrayBytes, fp);
     31 }
     32 
     33 
     34 static void test_compress(
     35     FILE* outFp,
     36     FILE* inpFp,
     37     size_t messageMaxBytes,
     38     size_t ringBufferBytes)
     39 {
     40     LZ4_stream_t* const lz4Stream = LZ4_createStream();
     41     char* const cmpBuf = malloc(LZ4_COMPRESSBOUND(messageMaxBytes));
     42     char* const inpBuf = malloc(ringBufferBytes);
     43     int inpOffset = 0;
     44 
     45     for ( ; ; )
     46     {
     47         char* const inpPtr = &inpBuf[inpOffset];
     48 
     49 #if 0
     50         // Read random length data to the ring buffer.
     51         const int randomLength = (rand() % messageMaxBytes) + 1;
     52         const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength);
     53         if (0 == inpBytes) break;
     54 #else
     55         // Read line to the ring buffer.
     56         int inpBytes = 0;
     57         if (!fgets(inpPtr, (int) messageMaxBytes, inpFp))
     58             break;
     59         inpBytes = (int) strlen(inpPtr);
     60 #endif
     61 
     62         {
     63             const int cmpBytes = LZ4_compress_continue(
     64                 lz4Stream, inpPtr, cmpBuf, inpBytes);
     65             if (cmpBytes <= 0) break;
     66             write_uint16(outFp, (uint16_t) cmpBytes);
     67             write_bin(outFp, cmpBuf, cmpBytes);
     68 
     69             // Add and wraparound the ringbuffer offset
     70             inpOffset += inpBytes;
     71             if ((size_t)inpOffset >= ringBufferBytes - messageMaxBytes) inpOffset = 0;
     72         }
     73     }
     74     write_uint16(outFp, 0);
     75 
     76     free(inpBuf);
     77     free(cmpBuf);
     78     LZ4_freeStream(lz4Stream);
     79 }
     80 
     81 
     82 static void test_decompress(
     83     FILE* outFp,
     84     FILE* inpFp,
     85     size_t messageMaxBytes,
     86     size_t ringBufferBytes)
     87 {
     88     LZ4_streamDecode_t* const lz4StreamDecode = LZ4_createStreamDecode();
     89     char* const cmpBuf = malloc(LZ4_COMPRESSBOUND(messageMaxBytes));
     90     char* const decBuf = malloc(ringBufferBytes);
     91     int decOffset = 0;
     92 
     93     for ( ; ; )
     94     {
     95         uint16_t cmpBytes = 0;
     96 
     97         if (read_uint16(inpFp, &cmpBytes) != 1) break;
     98         if (cmpBytes <= 0) break;
     99         if (read_bin(inpFp, cmpBuf, cmpBytes) != cmpBytes) break;
    100 
    101         {
    102             char* const decPtr = &decBuf[decOffset];
    103             const int decBytes = LZ4_decompress_safe_continue(
    104                 lz4StreamDecode, cmpBuf, decPtr, cmpBytes, (int) messageMaxBytes);
    105             if (decBytes <= 0) break;
    106             write_bin(outFp, decPtr, decBytes);
    107 
    108             // Add and wraparound the ringbuffer offset
    109             decOffset += decBytes;
    110             if ((size_t)decOffset >= ringBufferBytes - messageMaxBytes) decOffset = 0;
    111         }
    112     }
    113 
    114     free(decBuf);
    115     free(cmpBuf);
    116     LZ4_freeStreamDecode(lz4StreamDecode);
    117 }
    118 
    119 
    120 static int compare(FILE* f0, FILE* f1)
    121 {
    122     int result = 0;
    123     const size_t tempBufferBytes = 65536;
    124     char* const b0 = malloc(tempBufferBytes);
    125     char* const b1 = malloc(tempBufferBytes);
    126 
    127     while(0 == result)
    128     {
    129         const size_t r0 = fread(b0, 1, tempBufferBytes, f0);
    130         const size_t r1 = fread(b1, 1, tempBufferBytes, f1);
    131 
    132         result = (int) r0 - (int) r1;
    133 
    134         if (0 == r0 || 0 == r1) break;
    135         if (0 == result) result = memcmp(b0, b1, r0);
    136     }
    137 
    138     free(b1);
    139     free(b0);
    140     return result;
    141 }
    142 
    143 
    144 int main(int argc, char* argv[])
    145 {
    146     enum {
    147         MESSAGE_MAX_BYTES   = 1024,
    148         RING_BUFFER_BYTES   = 1024 * 256 + MESSAGE_MAX_BYTES,
    149     };
    150 
    151     char inpFilename[256] = { 0 };
    152     char lz4Filename[256] = { 0 };
    153     char decFilename[256] = { 0 };
    154 
    155     if (argc < 2)
    156     {
    157         printf("Please specify input filename\n");
    158         return 0;
    159     }
    160 
    161     snprintf(inpFilename, 256, "%s", argv[1]);
    162     snprintf(lz4Filename, 256, "%s.lz4s", argv[1]);
    163     snprintf(decFilename, 256, "%s.lz4s.dec", argv[1]);
    164 
    165     printf("inp = [%s]\n", inpFilename);
    166     printf("lz4 = [%s]\n", lz4Filename);
    167     printf("dec = [%s]\n", decFilename);
    168 
    169     // compress
    170     {
    171         FILE* inpFp = fopen(inpFilename, "rb");
    172         FILE* outFp = fopen(lz4Filename, "wb");
    173 
    174         test_compress(outFp, inpFp, MESSAGE_MAX_BYTES, RING_BUFFER_BYTES);
    175 
    176         fclose(outFp);
    177         fclose(inpFp);
    178     }
    179 
    180     // decompress
    181     {
    182         FILE* inpFp = fopen(lz4Filename, "rb");
    183         FILE* outFp = fopen(decFilename, "wb");
    184 
    185         test_decompress(outFp, inpFp, MESSAGE_MAX_BYTES, RING_BUFFER_BYTES);
    186 
    187         fclose(outFp);
    188         fclose(inpFp);
    189     }
    190 
    191     // verify
    192     {
    193         FILE* inpFp = fopen(inpFilename, "rb");
    194         FILE* decFp = fopen(decFilename, "rb");
    195 
    196         const int cmp = compare(inpFp, decFp);
    197         if (0 == cmp)
    198             printf("Verify : OK\n");
    199         else
    200             printf("Verify : NG\n");
    201 
    202         fclose(decFp);
    203         fclose(inpFp);
    204     }
    205 
    206     return 0;
    207 }
    208