1*27162e4eSAndroid Build Coastguard Worker // LZ4 API example : Dictionary Random Access
2*27162e4eSAndroid Build Coastguard Worker
3*27162e4eSAndroid Build Coastguard Worker #if defined(_MSC_VER) && (_MSC_VER <= 1800) /* Visual Studio <= 2013 */
4*27162e4eSAndroid Build Coastguard Worker # define _CRT_SECURE_NO_WARNINGS
5*27162e4eSAndroid Build Coastguard Worker # define snprintf sprintf_s
6*27162e4eSAndroid Build Coastguard Worker #endif
7*27162e4eSAndroid Build Coastguard Worker #include "lz4.h"
8*27162e4eSAndroid Build Coastguard Worker
9*27162e4eSAndroid Build Coastguard Worker #include <stdio.h>
10*27162e4eSAndroid Build Coastguard Worker #include <stdint.h>
11*27162e4eSAndroid Build Coastguard Worker #include <stdlib.h>
12*27162e4eSAndroid Build Coastguard Worker #include <string.h>
13*27162e4eSAndroid Build Coastguard Worker
14*27162e4eSAndroid Build Coastguard Worker #define MIN(x, y) ((x) < (y) ? (x) : (y))
15*27162e4eSAndroid Build Coastguard Worker
16*27162e4eSAndroid Build Coastguard Worker enum {
17*27162e4eSAndroid Build Coastguard Worker BLOCK_BYTES = 1024, /* 1 KiB of uncompressed data in a block */
18*27162e4eSAndroid Build Coastguard Worker DICTIONARY_BYTES = 1024, /* Load a 1 KiB dictionary */
19*27162e4eSAndroid Build Coastguard Worker MAX_BLOCKS = 1024 /* For simplicity of implementation */
20*27162e4eSAndroid Build Coastguard Worker };
21*27162e4eSAndroid Build Coastguard Worker
22*27162e4eSAndroid Build Coastguard Worker /**
23*27162e4eSAndroid Build Coastguard Worker * Magic bytes for this test case.
24*27162e4eSAndroid Build Coastguard Worker * This is not a great magic number because it is a common word in ASCII.
25*27162e4eSAndroid Build Coastguard Worker * However, it is important to have some versioning system in your format.
26*27162e4eSAndroid Build Coastguard Worker */
27*27162e4eSAndroid Build Coastguard Worker const char kTestMagic[] = { 'T', 'E', 'S', 'T' };
28*27162e4eSAndroid Build Coastguard Worker
29*27162e4eSAndroid Build Coastguard Worker
write_int(FILE * fp,int i)30*27162e4eSAndroid Build Coastguard Worker void write_int(FILE* fp, int i) {
31*27162e4eSAndroid Build Coastguard Worker size_t written = fwrite(&i, sizeof(i), 1, fp);
32*27162e4eSAndroid Build Coastguard Worker if (written != 1) { exit(10); }
33*27162e4eSAndroid Build Coastguard Worker }
34*27162e4eSAndroid Build Coastguard Worker
write_bin(FILE * fp,const void * array,size_t arrayBytes)35*27162e4eSAndroid Build Coastguard Worker void write_bin(FILE* fp, const void* array, size_t arrayBytes) {
36*27162e4eSAndroid Build Coastguard Worker size_t written = fwrite(array, 1, arrayBytes, fp);
37*27162e4eSAndroid Build Coastguard Worker if (written != arrayBytes) { exit(11); }
38*27162e4eSAndroid Build Coastguard Worker }
39*27162e4eSAndroid Build Coastguard Worker
read_int(FILE * fp,int * i)40*27162e4eSAndroid Build Coastguard Worker void read_int(FILE* fp, int* i) {
41*27162e4eSAndroid Build Coastguard Worker size_t read = fread(i, sizeof(*i), 1, fp);
42*27162e4eSAndroid Build Coastguard Worker if (read != 1) { exit(12); }
43*27162e4eSAndroid Build Coastguard Worker }
44*27162e4eSAndroid Build Coastguard Worker
read_bin(FILE * fp,void * array,size_t arrayBytes)45*27162e4eSAndroid Build Coastguard Worker size_t read_bin(FILE* fp, void* array, size_t arrayBytes) {
46*27162e4eSAndroid Build Coastguard Worker size_t read = fread(array, 1, arrayBytes, fp);
47*27162e4eSAndroid Build Coastguard Worker if (ferror(fp)) { exit(12); }
48*27162e4eSAndroid Build Coastguard Worker return read;
49*27162e4eSAndroid Build Coastguard Worker }
50*27162e4eSAndroid Build Coastguard Worker
seek_bin(FILE * fp,long offset,int origin)51*27162e4eSAndroid Build Coastguard Worker void seek_bin(FILE* fp, long offset, int origin) {
52*27162e4eSAndroid Build Coastguard Worker if (fseek(fp, offset, origin)) { exit(14); }
53*27162e4eSAndroid Build Coastguard Worker }
54*27162e4eSAndroid Build Coastguard Worker
55*27162e4eSAndroid Build Coastguard Worker
test_compress(FILE * outFp,FILE * inpFp,void * dict,int dictSize)56*27162e4eSAndroid Build Coastguard Worker void test_compress(FILE* outFp, FILE* inpFp, void *dict, int dictSize)
57*27162e4eSAndroid Build Coastguard Worker {
58*27162e4eSAndroid Build Coastguard Worker LZ4_stream_t lz4Stream_body;
59*27162e4eSAndroid Build Coastguard Worker LZ4_stream_t* lz4Stream = &lz4Stream_body;
60*27162e4eSAndroid Build Coastguard Worker
61*27162e4eSAndroid Build Coastguard Worker char inpBuf[BLOCK_BYTES];
62*27162e4eSAndroid Build Coastguard Worker int offsets[MAX_BLOCKS];
63*27162e4eSAndroid Build Coastguard Worker int *offsetsEnd = offsets;
64*27162e4eSAndroid Build Coastguard Worker
65*27162e4eSAndroid Build Coastguard Worker
66*27162e4eSAndroid Build Coastguard Worker LZ4_initStream(lz4Stream, sizeof(*lz4Stream));
67*27162e4eSAndroid Build Coastguard Worker
68*27162e4eSAndroid Build Coastguard Worker /* Write header magic */
69*27162e4eSAndroid Build Coastguard Worker write_bin(outFp, kTestMagic, sizeof(kTestMagic));
70*27162e4eSAndroid Build Coastguard Worker
71*27162e4eSAndroid Build Coastguard Worker *offsetsEnd++ = sizeof(kTestMagic);
72*27162e4eSAndroid Build Coastguard Worker /* Write compressed data blocks. Each block contains BLOCK_BYTES of plain
73*27162e4eSAndroid Build Coastguard Worker data except possibly the last. */
74*27162e4eSAndroid Build Coastguard Worker for(;;) {
75*27162e4eSAndroid Build Coastguard Worker const int inpBytes = (int) read_bin(inpFp, inpBuf, BLOCK_BYTES);
76*27162e4eSAndroid Build Coastguard Worker if(0 == inpBytes) {
77*27162e4eSAndroid Build Coastguard Worker break;
78*27162e4eSAndroid Build Coastguard Worker }
79*27162e4eSAndroid Build Coastguard Worker
80*27162e4eSAndroid Build Coastguard Worker /* Forget previously compressed data and load the dictionary */
81*27162e4eSAndroid Build Coastguard Worker LZ4_loadDict(lz4Stream, (const char*) dict, dictSize);
82*27162e4eSAndroid Build Coastguard Worker {
83*27162e4eSAndroid Build Coastguard Worker char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)];
84*27162e4eSAndroid Build Coastguard Worker const int cmpBytes = LZ4_compress_fast_continue(
85*27162e4eSAndroid Build Coastguard Worker lz4Stream, inpBuf, cmpBuf, inpBytes, sizeof(cmpBuf), 1);
86*27162e4eSAndroid Build Coastguard Worker if(cmpBytes <= 0) { exit(1); }
87*27162e4eSAndroid Build Coastguard Worker write_bin(outFp, cmpBuf, (size_t)cmpBytes);
88*27162e4eSAndroid Build Coastguard Worker /* Keep track of the offsets */
89*27162e4eSAndroid Build Coastguard Worker *offsetsEnd = *(offsetsEnd - 1) + cmpBytes;
90*27162e4eSAndroid Build Coastguard Worker ++offsetsEnd;
91*27162e4eSAndroid Build Coastguard Worker }
92*27162e4eSAndroid Build Coastguard Worker if (offsetsEnd - offsets > MAX_BLOCKS) { exit(2); }
93*27162e4eSAndroid Build Coastguard Worker }
94*27162e4eSAndroid Build Coastguard Worker /* Write the tailing jump table */
95*27162e4eSAndroid Build Coastguard Worker {
96*27162e4eSAndroid Build Coastguard Worker int *ptr = offsets;
97*27162e4eSAndroid Build Coastguard Worker while (ptr != offsetsEnd) {
98*27162e4eSAndroid Build Coastguard Worker write_int(outFp, *ptr++);
99*27162e4eSAndroid Build Coastguard Worker }
100*27162e4eSAndroid Build Coastguard Worker write_int(outFp, (int) (offsetsEnd - offsets));
101*27162e4eSAndroid Build Coastguard Worker }
102*27162e4eSAndroid Build Coastguard Worker }
103*27162e4eSAndroid Build Coastguard Worker
104*27162e4eSAndroid Build Coastguard Worker
test_decompress(FILE * outFp,FILE * inpFp,void * dict,int dictSize,int offset,int length)105*27162e4eSAndroid Build Coastguard Worker void test_decompress(FILE* outFp, FILE* inpFp, void *dict, int dictSize, int offset, int length)
106*27162e4eSAndroid Build Coastguard Worker {
107*27162e4eSAndroid Build Coastguard Worker LZ4_streamDecode_t lz4StreamDecode_body;
108*27162e4eSAndroid Build Coastguard Worker LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
109*27162e4eSAndroid Build Coastguard Worker
110*27162e4eSAndroid Build Coastguard Worker /* The blocks [currentBlock, endBlock) contain the data we want */
111*27162e4eSAndroid Build Coastguard Worker int currentBlock = offset / BLOCK_BYTES;
112*27162e4eSAndroid Build Coastguard Worker int endBlock = ((offset + length - 1) / BLOCK_BYTES) + 1;
113*27162e4eSAndroid Build Coastguard Worker
114*27162e4eSAndroid Build Coastguard Worker char decBuf[BLOCK_BYTES];
115*27162e4eSAndroid Build Coastguard Worker int offsets[MAX_BLOCKS];
116*27162e4eSAndroid Build Coastguard Worker
117*27162e4eSAndroid Build Coastguard Worker /* Special cases */
118*27162e4eSAndroid Build Coastguard Worker if (length == 0) { return; }
119*27162e4eSAndroid Build Coastguard Worker
120*27162e4eSAndroid Build Coastguard Worker /* Read the magic bytes */
121*27162e4eSAndroid Build Coastguard Worker {
122*27162e4eSAndroid Build Coastguard Worker char magic[sizeof(kTestMagic)];
123*27162e4eSAndroid Build Coastguard Worker size_t read = read_bin(inpFp, magic, sizeof(magic));
124*27162e4eSAndroid Build Coastguard Worker if (read != sizeof(magic)) { exit(1); }
125*27162e4eSAndroid Build Coastguard Worker if (memcmp(kTestMagic, magic, sizeof(magic))) { exit(2); }
126*27162e4eSAndroid Build Coastguard Worker }
127*27162e4eSAndroid Build Coastguard Worker
128*27162e4eSAndroid Build Coastguard Worker /* Read the offsets tail */
129*27162e4eSAndroid Build Coastguard Worker {
130*27162e4eSAndroid Build Coastguard Worker int numOffsets;
131*27162e4eSAndroid Build Coastguard Worker int block;
132*27162e4eSAndroid Build Coastguard Worker int *offsetsPtr = offsets;
133*27162e4eSAndroid Build Coastguard Worker seek_bin(inpFp, -4, SEEK_END);
134*27162e4eSAndroid Build Coastguard Worker read_int(inpFp, &numOffsets);
135*27162e4eSAndroid Build Coastguard Worker if (numOffsets <= endBlock) { exit(3); }
136*27162e4eSAndroid Build Coastguard Worker seek_bin(inpFp, -4 * (numOffsets + 1), SEEK_END);
137*27162e4eSAndroid Build Coastguard Worker for (block = 0; block <= endBlock; ++block) {
138*27162e4eSAndroid Build Coastguard Worker read_int(inpFp, offsetsPtr++);
139*27162e4eSAndroid Build Coastguard Worker }
140*27162e4eSAndroid Build Coastguard Worker }
141*27162e4eSAndroid Build Coastguard Worker /* Seek to the first block to read */
142*27162e4eSAndroid Build Coastguard Worker seek_bin(inpFp, offsets[currentBlock], SEEK_SET);
143*27162e4eSAndroid Build Coastguard Worker offset = offset % BLOCK_BYTES;
144*27162e4eSAndroid Build Coastguard Worker
145*27162e4eSAndroid Build Coastguard Worker /* Start decoding */
146*27162e4eSAndroid Build Coastguard Worker for(; currentBlock < endBlock; ++currentBlock) {
147*27162e4eSAndroid Build Coastguard Worker char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)];
148*27162e4eSAndroid Build Coastguard Worker /* The difference in offsets is the size of the block */
149*27162e4eSAndroid Build Coastguard Worker int cmpBytes = offsets[currentBlock + 1] - offsets[currentBlock];
150*27162e4eSAndroid Build Coastguard Worker {
151*27162e4eSAndroid Build Coastguard Worker const size_t read = read_bin(inpFp, cmpBuf, (size_t)cmpBytes);
152*27162e4eSAndroid Build Coastguard Worker if(read != (size_t)cmpBytes) { exit(4); }
153*27162e4eSAndroid Build Coastguard Worker }
154*27162e4eSAndroid Build Coastguard Worker
155*27162e4eSAndroid Build Coastguard Worker /* Load the dictionary */
156*27162e4eSAndroid Build Coastguard Worker LZ4_setStreamDecode(lz4StreamDecode, (const char*) dict, dictSize);
157*27162e4eSAndroid Build Coastguard Worker {
158*27162e4eSAndroid Build Coastguard Worker const int decBytes = LZ4_decompress_safe_continue(
159*27162e4eSAndroid Build Coastguard Worker lz4StreamDecode, cmpBuf, decBuf, cmpBytes, BLOCK_BYTES);
160*27162e4eSAndroid Build Coastguard Worker if(decBytes <= 0) { exit(5); }
161*27162e4eSAndroid Build Coastguard Worker {
162*27162e4eSAndroid Build Coastguard Worker /* Write out the part of the data we care about */
163*27162e4eSAndroid Build Coastguard Worker int blockLength = MIN(length, (decBytes - offset));
164*27162e4eSAndroid Build Coastguard Worker write_bin(outFp, decBuf + offset, (size_t)blockLength);
165*27162e4eSAndroid Build Coastguard Worker offset = 0;
166*27162e4eSAndroid Build Coastguard Worker length -= blockLength;
167*27162e4eSAndroid Build Coastguard Worker }
168*27162e4eSAndroid Build Coastguard Worker }
169*27162e4eSAndroid Build Coastguard Worker }
170*27162e4eSAndroid Build Coastguard Worker }
171*27162e4eSAndroid Build Coastguard Worker
172*27162e4eSAndroid Build Coastguard Worker
compare(FILE * fp0,FILE * fp1,int length)173*27162e4eSAndroid Build Coastguard Worker int compare(FILE* fp0, FILE* fp1, int length)
174*27162e4eSAndroid Build Coastguard Worker {
175*27162e4eSAndroid Build Coastguard Worker int result = 0;
176*27162e4eSAndroid Build Coastguard Worker
177*27162e4eSAndroid Build Coastguard Worker while(0 == result) {
178*27162e4eSAndroid Build Coastguard Worker char b0[4096];
179*27162e4eSAndroid Build Coastguard Worker char b1[4096];
180*27162e4eSAndroid Build Coastguard Worker const size_t r0 = read_bin(fp0, b0, MIN(length, (int)sizeof(b0)));
181*27162e4eSAndroid Build Coastguard Worker const size_t r1 = read_bin(fp1, b1, MIN(length, (int)sizeof(b1)));
182*27162e4eSAndroid Build Coastguard Worker
183*27162e4eSAndroid Build Coastguard Worker result = (int) r0 - (int) r1;
184*27162e4eSAndroid Build Coastguard Worker
185*27162e4eSAndroid Build Coastguard Worker if(0 == r0 || 0 == r1) {
186*27162e4eSAndroid Build Coastguard Worker break;
187*27162e4eSAndroid Build Coastguard Worker }
188*27162e4eSAndroid Build Coastguard Worker if(0 == result) {
189*27162e4eSAndroid Build Coastguard Worker result = memcmp(b0, b1, r0);
190*27162e4eSAndroid Build Coastguard Worker }
191*27162e4eSAndroid Build Coastguard Worker length -= r0;
192*27162e4eSAndroid Build Coastguard Worker }
193*27162e4eSAndroid Build Coastguard Worker
194*27162e4eSAndroid Build Coastguard Worker return result;
195*27162e4eSAndroid Build Coastguard Worker }
196*27162e4eSAndroid Build Coastguard Worker
197*27162e4eSAndroid Build Coastguard Worker
main(int argc,char * argv[])198*27162e4eSAndroid Build Coastguard Worker int main(int argc, char* argv[])
199*27162e4eSAndroid Build Coastguard Worker {
200*27162e4eSAndroid Build Coastguard Worker char inpFilename[256] = { 0 };
201*27162e4eSAndroid Build Coastguard Worker char lz4Filename[256] = { 0 };
202*27162e4eSAndroid Build Coastguard Worker char decFilename[256] = { 0 };
203*27162e4eSAndroid Build Coastguard Worker char dictFilename[256] = { 0 };
204*27162e4eSAndroid Build Coastguard Worker int offset;
205*27162e4eSAndroid Build Coastguard Worker int length;
206*27162e4eSAndroid Build Coastguard Worker char dict[DICTIONARY_BYTES];
207*27162e4eSAndroid Build Coastguard Worker int dictSize;
208*27162e4eSAndroid Build Coastguard Worker
209*27162e4eSAndroid Build Coastguard Worker if(argc < 5) {
210*27162e4eSAndroid Build Coastguard Worker printf("Usage: %s input dictionary offset length", argv[0]);
211*27162e4eSAndroid Build Coastguard Worker return 0;
212*27162e4eSAndroid Build Coastguard Worker }
213*27162e4eSAndroid Build Coastguard Worker
214*27162e4eSAndroid Build Coastguard Worker snprintf(inpFilename, 256, "%s", argv[1]);
215*27162e4eSAndroid Build Coastguard Worker snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[1], BLOCK_BYTES);
216*27162e4eSAndroid Build Coastguard Worker snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[1], BLOCK_BYTES);
217*27162e4eSAndroid Build Coastguard Worker snprintf(dictFilename, 256, "%s", argv[2]);
218*27162e4eSAndroid Build Coastguard Worker offset = atoi(argv[3]);
219*27162e4eSAndroid Build Coastguard Worker length = atoi(argv[4]);
220*27162e4eSAndroid Build Coastguard Worker
221*27162e4eSAndroid Build Coastguard Worker printf("inp = [%s]\n", inpFilename);
222*27162e4eSAndroid Build Coastguard Worker printf("lz4 = [%s]\n", lz4Filename);
223*27162e4eSAndroid Build Coastguard Worker printf("dec = [%s]\n", decFilename);
224*27162e4eSAndroid Build Coastguard Worker printf("dict = [%s]\n", dictFilename);
225*27162e4eSAndroid Build Coastguard Worker printf("offset = [%d]\n", offset);
226*27162e4eSAndroid Build Coastguard Worker printf("length = [%d]\n", length);
227*27162e4eSAndroid Build Coastguard Worker
228*27162e4eSAndroid Build Coastguard Worker /* Load dictionary */
229*27162e4eSAndroid Build Coastguard Worker {
230*27162e4eSAndroid Build Coastguard Worker FILE* dictFp = fopen(dictFilename, "rb");
231*27162e4eSAndroid Build Coastguard Worker dictSize = (int)read_bin(dictFp, dict, DICTIONARY_BYTES);
232*27162e4eSAndroid Build Coastguard Worker fclose(dictFp);
233*27162e4eSAndroid Build Coastguard Worker }
234*27162e4eSAndroid Build Coastguard Worker
235*27162e4eSAndroid Build Coastguard Worker /* compress */
236*27162e4eSAndroid Build Coastguard Worker {
237*27162e4eSAndroid Build Coastguard Worker FILE* inpFp = fopen(inpFilename, "rb");
238*27162e4eSAndroid Build Coastguard Worker FILE* outFp = fopen(lz4Filename, "wb");
239*27162e4eSAndroid Build Coastguard Worker
240*27162e4eSAndroid Build Coastguard Worker printf("compress : %s -> %s\n", inpFilename, lz4Filename);
241*27162e4eSAndroid Build Coastguard Worker test_compress(outFp, inpFp, dict, dictSize);
242*27162e4eSAndroid Build Coastguard Worker printf("compress : done\n");
243*27162e4eSAndroid Build Coastguard Worker
244*27162e4eSAndroid Build Coastguard Worker fclose(outFp);
245*27162e4eSAndroid Build Coastguard Worker fclose(inpFp);
246*27162e4eSAndroid Build Coastguard Worker }
247*27162e4eSAndroid Build Coastguard Worker
248*27162e4eSAndroid Build Coastguard Worker /* decompress */
249*27162e4eSAndroid Build Coastguard Worker {
250*27162e4eSAndroid Build Coastguard Worker FILE* inpFp = fopen(lz4Filename, "rb");
251*27162e4eSAndroid Build Coastguard Worker FILE* outFp = fopen(decFilename, "wb");
252*27162e4eSAndroid Build Coastguard Worker
253*27162e4eSAndroid Build Coastguard Worker printf("decompress : %s -> %s\n", lz4Filename, decFilename);
254*27162e4eSAndroid Build Coastguard Worker test_decompress(outFp, inpFp, dict, DICTIONARY_BYTES, offset, length);
255*27162e4eSAndroid Build Coastguard Worker printf("decompress : done\n");
256*27162e4eSAndroid Build Coastguard Worker
257*27162e4eSAndroid Build Coastguard Worker fclose(outFp);
258*27162e4eSAndroid Build Coastguard Worker fclose(inpFp);
259*27162e4eSAndroid Build Coastguard Worker }
260*27162e4eSAndroid Build Coastguard Worker
261*27162e4eSAndroid Build Coastguard Worker /* verify */
262*27162e4eSAndroid Build Coastguard Worker {
263*27162e4eSAndroid Build Coastguard Worker FILE* inpFp = fopen(inpFilename, "rb");
264*27162e4eSAndroid Build Coastguard Worker FILE* decFp = fopen(decFilename, "rb");
265*27162e4eSAndroid Build Coastguard Worker seek_bin(inpFp, offset, SEEK_SET);
266*27162e4eSAndroid Build Coastguard Worker
267*27162e4eSAndroid Build Coastguard Worker printf("verify : %s <-> %s\n", inpFilename, decFilename);
268*27162e4eSAndroid Build Coastguard Worker const int cmp = compare(inpFp, decFp, length);
269*27162e4eSAndroid Build Coastguard Worker if(0 == cmp) {
270*27162e4eSAndroid Build Coastguard Worker printf("verify : OK\n");
271*27162e4eSAndroid Build Coastguard Worker } else {
272*27162e4eSAndroid Build Coastguard Worker printf("verify : NG\n");
273*27162e4eSAndroid Build Coastguard Worker }
274*27162e4eSAndroid Build Coastguard Worker
275*27162e4eSAndroid Build Coastguard Worker fclose(decFp);
276*27162e4eSAndroid Build Coastguard Worker fclose(inpFp);
277*27162e4eSAndroid Build Coastguard Worker }
278*27162e4eSAndroid Build Coastguard Worker
279*27162e4eSAndroid Build Coastguard Worker return 0;
280*27162e4eSAndroid Build Coastguard Worker }
281