1 // LZ4 streaming API example : double buffer
2 // Copyright : Takayuki Matsuoka
3 
4 
5 #if defined(_MSC_VER) && (_MSC_VER <= 1800)  /* Visual Studio <= 2013 */
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 enum {
17     BLOCK_BYTES = 1024 * 8,
18 //  BLOCK_BYTES = 1024 * 64,
19 };
20 
21 
write_int(FILE * fp,int i)22 size_t write_int(FILE* fp, int i) {
23     return fwrite(&i, sizeof(i), 1, fp);
24 }
25 
write_bin(FILE * fp,const void * array,size_t arrayBytes)26 size_t write_bin(FILE* fp, const void* array, size_t arrayBytes) {
27     return fwrite(array, 1, arrayBytes, fp);
28 }
29 
read_int(FILE * fp,int * i)30 size_t read_int(FILE* fp, int* i) {
31     return fread(i, sizeof(*i), 1, fp);
32 }
33 
read_bin(FILE * fp,void * array,size_t arrayBytes)34 size_t read_bin(FILE* fp, void* array, size_t arrayBytes) {
35     return fread(array, 1, arrayBytes, fp);
36 }
37 
38 
test_compress(FILE * outFp,FILE * inpFp)39 void test_compress(FILE* outFp, FILE* inpFp)
40 {
41     LZ4_stream_t lz4Stream_body;
42     LZ4_stream_t* lz4Stream = &lz4Stream_body;
43 
44     char inpBuf[2][BLOCK_BYTES];
45     int  inpBufIndex = 0;
46 
47     LZ4_initStream(lz4Stream, sizeof (*lz4Stream));
48 
49     for(;;) {
50         char* const inpPtr = inpBuf[inpBufIndex];
51         const int inpBytes = (int) read_bin(inpFp, inpPtr, BLOCK_BYTES);
52         if(0 == inpBytes) {
53             break;
54         }
55 
56         {
57             char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)];
58             const int cmpBytes = LZ4_compress_fast_continue(
59                 lz4Stream, inpPtr, cmpBuf, inpBytes, sizeof(cmpBuf), 1);
60             if(cmpBytes <= 0) {
61                 break;
62             }
63             write_int(outFp, cmpBytes);
64             write_bin(outFp, cmpBuf, (size_t) cmpBytes);
65         }
66 
67         inpBufIndex = (inpBufIndex + 1) % 2;
68     }
69 
70     write_int(outFp, 0);
71 }
72 
73 
test_decompress(FILE * outFp,FILE * inpFp)74 void test_decompress(FILE* outFp, FILE* inpFp)
75 {
76     LZ4_streamDecode_t lz4StreamDecode_body;
77     LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
78 
79     char decBuf[2][BLOCK_BYTES];
80     int  decBufIndex = 0;
81 
82     LZ4_setStreamDecode(lz4StreamDecode, NULL, 0);
83 
84     for(;;) {
85         char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)];
86         int  cmpBytes = 0;
87 
88         {
89             const size_t readCount0 = read_int(inpFp, &cmpBytes);
90             if(readCount0 != 1 || cmpBytes <= 0) {
91                 break;
92             }
93 
94             const size_t readCount1 = read_bin(inpFp, cmpBuf, (size_t) cmpBytes);
95             if(readCount1 != (size_t) cmpBytes) {
96                 break;
97             }
98         }
99 
100         {
101             char* const decPtr = decBuf[decBufIndex];
102             const int decBytes = LZ4_decompress_safe_continue(
103                 lz4StreamDecode, cmpBuf, decPtr, cmpBytes, BLOCK_BYTES);
104             if(decBytes <= 0) {
105                 break;
106             }
107             write_bin(outFp, decPtr, (size_t) decBytes);
108         }
109 
110         decBufIndex = (decBufIndex + 1) % 2;
111     }
112 }
113 
114 
compare(FILE * fp0,FILE * fp1)115 int compare(FILE* fp0, FILE* fp1)
116 {
117     int result = 0;
118 
119     while(0 == result) {
120         char b0[65536];
121         char b1[65536];
122         const size_t r0 = read_bin(fp0, b0, sizeof(b0));
123         const size_t r1 = read_bin(fp1, b1, sizeof(b1));
124 
125         result = (int) r0 - (int) r1;
126 
127         if(0 == r0 || 0 == r1) {
128             break;
129         }
130         if(0 == result) {
131             result = memcmp(b0, b1, r0);
132         }
133     }
134 
135     return result;
136 }
137 
138 
main(int argc,char * argv[])139 int main(int argc, char* argv[])
140 {
141     char inpFilename[256] = { 0 };
142     char lz4Filename[256] = { 0 };
143     char decFilename[256] = { 0 };
144 
145     if(argc < 2) {
146         printf("Please specify input filename\n");
147         return 0;
148     }
149 
150     snprintf(inpFilename, 256, "%s", argv[1]);
151     snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[1], BLOCK_BYTES);
152     snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[1], BLOCK_BYTES);
153 
154     printf("inp = [%s]\n", inpFilename);
155     printf("lz4 = [%s]\n", lz4Filename);
156     printf("dec = [%s]\n", decFilename);
157 
158     // compress
159     {
160         FILE* inpFp = fopen(inpFilename, "rb");
161         FILE* outFp = fopen(lz4Filename, "wb");
162 
163         printf("compress : %s -> %s\n", inpFilename, lz4Filename);
164         test_compress(outFp, inpFp);
165         printf("compress : done\n");
166 
167         fclose(outFp);
168         fclose(inpFp);
169     }
170 
171     // decompress
172     {
173         FILE* inpFp = fopen(lz4Filename, "rb");
174         FILE* outFp = fopen(decFilename, "wb");
175 
176         printf("decompress : %s -> %s\n", lz4Filename, decFilename);
177         test_decompress(outFp, inpFp);
178         printf("decompress : done\n");
179 
180         fclose(outFp);
181         fclose(inpFp);
182     }
183 
184     // verify
185     {
186         FILE* inpFp = fopen(inpFilename, "rb");
187         FILE* decFp = fopen(decFilename, "rb");
188 
189         printf("verify : %s <-> %s\n", inpFilename, decFilename);
190         const int cmp = compare(inpFp, decFp);
191         if(0 == cmp) {
192             printf("verify : OK\n");
193         } else {
194             printf("verify : NG\n");
195         }
196 
197         fclose(decFp);
198         fclose(inpFp);
199     }
200 
201     return 0;
202 }
203