• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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     {
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 
test_decompress(FILE * outFp,FILE * inpFp)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
compare(FILE * f0,FILE * f1)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 
main(int argc,char ** argv)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