• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // LZ4 HC streaming API example : ring buffer
2 // Based on a previous example by Takayuki Matsuoka
3 
4 
5 /**************************************
6  * Compiler Options
7  **************************************/
8 #if defined(_MSC_VER) && (_MSC_VER <= 1800)  /* Visual Studio <= 2013 */
9 #  define _CRT_SECURE_NO_WARNINGS
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 
write_int32(FILE * fp,int32_t i)37 size_t write_int32(FILE* fp, int32_t i) {
38     return fwrite(&i, sizeof(i), 1, fp);
39 }
40 
write_bin(FILE * fp,const void * array,int arrayBytes)41 size_t write_bin(FILE* fp, const void* array, int arrayBytes) {
42     return fwrite(array, 1, arrayBytes, fp);
43 }
44 
read_int32(FILE * fp,int32_t * i)45 size_t read_int32(FILE* fp, int32_t* i) {
46     return fread(i, sizeof(*i), 1, fp);
47 }
48 
read_bin(FILE * fp,void * array,int arrayBytes)49 size_t read_bin(FILE* fp, void* array, int arrayBytes) {
50     return fread(array, 1, arrayBytes, fp);
51 }
52 
53 
test_compress(FILE * outFp,FILE * inpFp)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         // Read random length ([1,MESSAGE_MAX_BYTES]) data to the ring buffer.
64         char* const inpPtr = &inpBuf[inpOffset];
65         const int randomLength = (rand() % MESSAGE_MAX_BYTES) + 1;
66         const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength);
67         if (0 == inpBytes) break;
68 
69 #define CMPBUFSIZE (LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES))
70         {   char cmpBuf[CMPBUFSIZE];
71             const int cmpBytes = LZ4_compress_HC_continue(lz4Stream, inpPtr, cmpBuf, inpBytes, CMPBUFSIZE);
72 
73             if(cmpBytes <= 0) break;
74             write_int32(outFp, cmpBytes);
75             write_bin(outFp, cmpBuf, cmpBytes);
76 
77             inpOffset += inpBytes;
78 
79             // Wraparound the ringbuffer offset
80             if(inpOffset >= RING_BUFFER_BYTES - MESSAGE_MAX_BYTES)
81                 inpOffset = 0;
82         }
83     }
84 
85     write_int32(outFp, 0);
86 }
87 
88 
test_decompress(FILE * outFp,FILE * inpFp)89 void test_decompress(FILE* outFp, FILE* inpFp)
90 {
91     static char decBuf[DEC_BUFFER_BYTES];
92     int decOffset = 0;
93     LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
94     LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
95 
96     for(;;) {
97         int  cmpBytes = 0;
98         char cmpBuf[CMPBUFSIZE];
99 
100         {   const size_t r0 = read_int32(inpFp, &cmpBytes);
101             size_t r1;
102             if(r0 != 1 || cmpBytes <= 0)
103                 break;
104 
105             r1 = read_bin(inpFp, cmpBuf, cmpBytes);
106             if(r1 != (size_t) cmpBytes)
107                 break;
108         }
109 
110         {   char* const decPtr = &decBuf[decOffset];
111             const int decBytes = LZ4_decompress_safe_continue(
112                 lz4StreamDecode, cmpBuf, decPtr, cmpBytes, MESSAGE_MAX_BYTES);
113             if(decBytes <= 0)
114                 break;
115 
116             decOffset += decBytes;
117             write_bin(outFp, decPtr, decBytes);
118 
119             // Wraparound the ringbuffer offset
120             if(decOffset >= DEC_BUFFER_BYTES - MESSAGE_MAX_BYTES)
121                 decOffset = 0;
122         }
123     }
124 }
125 
126 
127 // Compare 2 files content
128 // return 0 if identical
129 // return ByteNb>0 if different
compare(FILE * f0,FILE * f1)130 size_t compare(FILE* f0, FILE* f1)
131 {
132     size_t result = 1;
133 
134     for (;;) {
135         char b0[65536];
136         char b1[65536];
137         const size_t r0 = fread(b0, 1, sizeof(b0), f0);
138         const size_t r1 = fread(b1, 1, sizeof(b1), f1);
139 
140         if ((r0==0) && (r1==0)) return 0;   // success
141 
142         if (r0 != r1) {
143             size_t smallest = r0;
144             if (r1<r0) smallest = r1;
145             result += smallest;
146             break;
147         }
148 
149         if (memcmp(b0, b1, r0)) {
150             unsigned errorPos = 0;
151             while ((errorPos < r0) && (b0[errorPos]==b1[errorPos])) errorPos++;
152             result += errorPos;
153             break;
154         }
155 
156         result += sizeof(b0);
157     }
158 
159     return result;
160 }
161 
162 
main(int argc,const char ** argv)163 int main(int argc, const char** argv)
164 {
165     char inpFilename[256] = { 0 };
166     char lz4Filename[256] = { 0 };
167     char decFilename[256] = { 0 };
168     unsigned fileID = 1;
169     unsigned pause = 0;
170 
171 
172     if(argc < 2) {
173         printf("Please specify input filename\n");
174         return 0;
175     }
176 
177     if (!strcmp(argv[1], "-p")) pause = 1, fileID = 2;
178 
179     snprintf(inpFilename, 256, "%s", argv[fileID]);
180     snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[fileID], 9);
181     snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[fileID], 9);
182 
183     printf("input   = [%s]\n", inpFilename);
184     printf("lz4     = [%s]\n", lz4Filename);
185     printf("decoded = [%s]\n", decFilename);
186 
187     // compress
188     {   FILE* const inpFp = fopen(inpFilename, "rb");
189         FILE* const outFp = fopen(lz4Filename, "wb");
190 
191         test_compress(outFp, inpFp);
192 
193         fclose(outFp);
194         fclose(inpFp);
195     }
196 
197     // decompress
198     {   FILE* const inpFp = fopen(lz4Filename, "rb");
199         FILE* const outFp = fopen(decFilename, "wb");
200 
201         test_decompress(outFp, inpFp);
202 
203         fclose(outFp);
204         fclose(inpFp);
205     }
206 
207     // verify
208     {   FILE* const inpFp = fopen(inpFilename, "rb");
209         FILE* const decFp = fopen(decFilename, "rb");
210 
211         const size_t cmp = compare(inpFp, decFp);
212         if(0 == cmp) {
213             printf("Verify : OK\n");
214         } else {
215             printf("Verify : NG : error at pos %u\n", (unsigned)cmp-1);
216         }
217 
218         fclose(decFp);
219         fclose(inpFp);
220     }
221 
222     if (pause) {
223         int unused;
224         printf("Press enter to continue ...\n");
225         unused = getchar(); (void)unused;   /* silence static analyzer */
226     }
227 
228     return 0;
229 }
230