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