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