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