1*27162e4eSAndroid Build Coastguard Worker /*
2*27162e4eSAndroid Build Coastguard Worker * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
3*27162e4eSAndroid Build Coastguard Worker * All rights reserved.
4*27162e4eSAndroid Build Coastguard Worker *
5*27162e4eSAndroid Build Coastguard Worker * This source code is licensed under both the BSD-style license (found in the
6*27162e4eSAndroid Build Coastguard Worker * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*27162e4eSAndroid Build Coastguard Worker * in the COPYING file in the root directory of this source tree),
8*27162e4eSAndroid Build Coastguard Worker * meaning you may select, at your option, one of the above-listed licenses.
9*27162e4eSAndroid Build Coastguard Worker */
10*27162e4eSAndroid Build Coastguard Worker
11*27162e4eSAndroid Build Coastguard Worker /*
12*27162e4eSAndroid Build Coastguard Worker * abiTest :
13*27162e4eSAndroid Build Coastguard Worker * ensure ABI stability expectations are not broken by a new version
14*27162e4eSAndroid Build Coastguard Worker **/
15*27162e4eSAndroid Build Coastguard Worker
16*27162e4eSAndroid Build Coastguard Worker
17*27162e4eSAndroid Build Coastguard Worker /*===========================================
18*27162e4eSAndroid Build Coastguard Worker * Dependencies
19*27162e4eSAndroid Build Coastguard Worker *==========================================*/
20*27162e4eSAndroid Build Coastguard Worker #include <stddef.h> /* size_t */
21*27162e4eSAndroid Build Coastguard Worker #include <stdlib.h> /* malloc, free, exit */
22*27162e4eSAndroid Build Coastguard Worker #include <stdio.h> /* fprintf */
23*27162e4eSAndroid Build Coastguard Worker #include <string.h> /* strcmp */
24*27162e4eSAndroid Build Coastguard Worker #include <assert.h>
25*27162e4eSAndroid Build Coastguard Worker #include <sys/types.h> /* stat */
26*27162e4eSAndroid Build Coastguard Worker #include <sys/stat.h> /* stat */
27*27162e4eSAndroid Build Coastguard Worker #include "xxhash.h"
28*27162e4eSAndroid Build Coastguard Worker
29*27162e4eSAndroid Build Coastguard Worker #include "lz4.h"
30*27162e4eSAndroid Build Coastguard Worker #include "lz4frame.h"
31*27162e4eSAndroid Build Coastguard Worker
32*27162e4eSAndroid Build Coastguard Worker
33*27162e4eSAndroid Build Coastguard Worker /*===========================================
34*27162e4eSAndroid Build Coastguard Worker * Macros
35*27162e4eSAndroid Build Coastguard Worker *==========================================*/
36*27162e4eSAndroid Build Coastguard Worker #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
37*27162e4eSAndroid Build Coastguard Worker
38*27162e4eSAndroid Build Coastguard Worker #define MSG(...) fprintf(stderr, __VA_ARGS__)
39*27162e4eSAndroid Build Coastguard Worker
40*27162e4eSAndroid Build Coastguard Worker #define CONTROL_MSG(c, ...) { \
41*27162e4eSAndroid Build Coastguard Worker if ((c)) { \
42*27162e4eSAndroid Build Coastguard Worker MSG(__VA_ARGS__); \
43*27162e4eSAndroid Build Coastguard Worker MSG(" \n"); \
44*27162e4eSAndroid Build Coastguard Worker abort(); \
45*27162e4eSAndroid Build Coastguard Worker } \
46*27162e4eSAndroid Build Coastguard Worker }
47*27162e4eSAndroid Build Coastguard Worker
48*27162e4eSAndroid Build Coastguard Worker
checkBuffers(const void * buff1,const void * buff2,size_t buffSize)49*27162e4eSAndroid Build Coastguard Worker static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize)
50*27162e4eSAndroid Build Coastguard Worker {
51*27162e4eSAndroid Build Coastguard Worker const char* const ip1 = (const char*)buff1;
52*27162e4eSAndroid Build Coastguard Worker const char* const ip2 = (const char*)buff2;
53*27162e4eSAndroid Build Coastguard Worker size_t pos;
54*27162e4eSAndroid Build Coastguard Worker
55*27162e4eSAndroid Build Coastguard Worker for (pos=0; pos<buffSize; pos++)
56*27162e4eSAndroid Build Coastguard Worker if (ip1[pos]!=ip2[pos])
57*27162e4eSAndroid Build Coastguard Worker break;
58*27162e4eSAndroid Build Coastguard Worker
59*27162e4eSAndroid Build Coastguard Worker return pos;
60*27162e4eSAndroid Build Coastguard Worker }
61*27162e4eSAndroid Build Coastguard Worker
62*27162e4eSAndroid Build Coastguard Worker
63*27162e4eSAndroid Build Coastguard Worker LZ4_stream_t LZ4_cState;
64*27162e4eSAndroid Build Coastguard Worker LZ4_streamDecode_t LZ4_dState;
65*27162e4eSAndroid Build Coastguard Worker
66*27162e4eSAndroid Build Coastguard Worker /** roundTripTest() :
67*27162e4eSAndroid Build Coastguard Worker * Compresses `srcBuff` into `compressedBuff`,
68*27162e4eSAndroid Build Coastguard Worker * then decompresses `compressedBuff` into `resultBuff`.
69*27162e4eSAndroid Build Coastguard Worker * If clevel==0, compression level is derived from srcBuff's content head bytes.
70*27162e4eSAndroid Build Coastguard Worker * This function abort() if it detects any round-trip error.
71*27162e4eSAndroid Build Coastguard Worker * Therefore, if it returns, round trip is considered successfully validated.
72*27162e4eSAndroid Build Coastguard Worker * Note : `compressedBuffCapacity` should be `>= LZ4_compressBound(srcSize)`
73*27162e4eSAndroid Build Coastguard Worker * for compression to be guaranteed to work */
roundTripTest(void * resultBuff,size_t resultBuffCapacity,void * compressedBuff,size_t compressedBuffCapacity,const void * srcBuff,size_t srcSize)74*27162e4eSAndroid Build Coastguard Worker static void roundTripTest(void* resultBuff, size_t resultBuffCapacity,
75*27162e4eSAndroid Build Coastguard Worker void* compressedBuff, size_t compressedBuffCapacity,
76*27162e4eSAndroid Build Coastguard Worker const void* srcBuff, size_t srcSize)
77*27162e4eSAndroid Build Coastguard Worker {
78*27162e4eSAndroid Build Coastguard Worker int const acceleration = 1;
79*27162e4eSAndroid Build Coastguard Worker // Note : can't use LZ4_initStream(), because it's only present since v1.9.0
80*27162e4eSAndroid Build Coastguard Worker memset(&LZ4_cState, 0, sizeof(LZ4_cState));
81*27162e4eSAndroid Build Coastguard Worker { int const cSize = LZ4_compress_fast_continue(&LZ4_cState, (const char*)srcBuff, (char*)compressedBuff, (int)srcSize, (int)compressedBuffCapacity, acceleration);
82*27162e4eSAndroid Build Coastguard Worker CONTROL_MSG(cSize == 0, "Compression error !");
83*27162e4eSAndroid Build Coastguard Worker { int const dInit = LZ4_setStreamDecode(&LZ4_dState, NULL, 0);
84*27162e4eSAndroid Build Coastguard Worker CONTROL_MSG(dInit == 0, "LZ4_setStreamDecode error !");
85*27162e4eSAndroid Build Coastguard Worker }
86*27162e4eSAndroid Build Coastguard Worker { int const dSize = LZ4_decompress_safe_continue (&LZ4_dState, (const char*)compressedBuff, (char*)resultBuff, cSize, (int)resultBuffCapacity);
87*27162e4eSAndroid Build Coastguard Worker CONTROL_MSG(dSize < 0, "Decompression detected an error !");
88*27162e4eSAndroid Build Coastguard Worker CONTROL_MSG(dSize != (int)srcSize, "Decompression corruption error : wrong decompressed size !");
89*27162e4eSAndroid Build Coastguard Worker } }
90*27162e4eSAndroid Build Coastguard Worker
91*27162e4eSAndroid Build Coastguard Worker /* check potential content corruption error */
92*27162e4eSAndroid Build Coastguard Worker assert(resultBuffCapacity >= srcSize);
93*27162e4eSAndroid Build Coastguard Worker { size_t const errorPos = checkBuffers(srcBuff, resultBuff, srcSize);
94*27162e4eSAndroid Build Coastguard Worker CONTROL_MSG(errorPos != srcSize,
95*27162e4eSAndroid Build Coastguard Worker "Silent decoding corruption, at pos %u !!!",
96*27162e4eSAndroid Build Coastguard Worker (unsigned)errorPos);
97*27162e4eSAndroid Build Coastguard Worker }
98*27162e4eSAndroid Build Coastguard Worker }
99*27162e4eSAndroid Build Coastguard Worker
roundTripCheck(const void * srcBuff,size_t srcSize)100*27162e4eSAndroid Build Coastguard Worker static void roundTripCheck(const void* srcBuff, size_t srcSize)
101*27162e4eSAndroid Build Coastguard Worker {
102*27162e4eSAndroid Build Coastguard Worker size_t const cBuffSize = LZ4_COMPRESSBOUND(srcSize);
103*27162e4eSAndroid Build Coastguard Worker void* const cBuff = malloc(cBuffSize);
104*27162e4eSAndroid Build Coastguard Worker void* const rBuff = malloc(cBuffSize);
105*27162e4eSAndroid Build Coastguard Worker
106*27162e4eSAndroid Build Coastguard Worker if (!cBuff || !rBuff) {
107*27162e4eSAndroid Build Coastguard Worker fprintf(stderr, "not enough memory ! \n");
108*27162e4eSAndroid Build Coastguard Worker exit(1);
109*27162e4eSAndroid Build Coastguard Worker }
110*27162e4eSAndroid Build Coastguard Worker
111*27162e4eSAndroid Build Coastguard Worker roundTripTest(rBuff, cBuffSize,
112*27162e4eSAndroid Build Coastguard Worker cBuff, cBuffSize,
113*27162e4eSAndroid Build Coastguard Worker srcBuff, srcSize);
114*27162e4eSAndroid Build Coastguard Worker
115*27162e4eSAndroid Build Coastguard Worker free(rBuff);
116*27162e4eSAndroid Build Coastguard Worker free(cBuff);
117*27162e4eSAndroid Build Coastguard Worker }
118*27162e4eSAndroid Build Coastguard Worker
119*27162e4eSAndroid Build Coastguard Worker
getFileSize(const char * infilename)120*27162e4eSAndroid Build Coastguard Worker static size_t getFileSize(const char* infilename)
121*27162e4eSAndroid Build Coastguard Worker {
122*27162e4eSAndroid Build Coastguard Worker int r;
123*27162e4eSAndroid Build Coastguard Worker #if defined(_MSC_VER)
124*27162e4eSAndroid Build Coastguard Worker struct _stat64 statbuf;
125*27162e4eSAndroid Build Coastguard Worker r = _stat64(infilename, &statbuf);
126*27162e4eSAndroid Build Coastguard Worker if (r || !(statbuf.st_mode & S_IFREG)) return 0; /* No good... */
127*27162e4eSAndroid Build Coastguard Worker #else
128*27162e4eSAndroid Build Coastguard Worker struct stat statbuf;
129*27162e4eSAndroid Build Coastguard Worker r = stat(infilename, &statbuf);
130*27162e4eSAndroid Build Coastguard Worker if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */
131*27162e4eSAndroid Build Coastguard Worker #endif
132*27162e4eSAndroid Build Coastguard Worker return (size_t)statbuf.st_size;
133*27162e4eSAndroid Build Coastguard Worker }
134*27162e4eSAndroid Build Coastguard Worker
135*27162e4eSAndroid Build Coastguard Worker
isDirectory(const char * infilename)136*27162e4eSAndroid Build Coastguard Worker static int isDirectory(const char* infilename)
137*27162e4eSAndroid Build Coastguard Worker {
138*27162e4eSAndroid Build Coastguard Worker int r;
139*27162e4eSAndroid Build Coastguard Worker #if defined(_MSC_VER)
140*27162e4eSAndroid Build Coastguard Worker struct _stat64 statbuf;
141*27162e4eSAndroid Build Coastguard Worker r = _stat64(infilename, &statbuf);
142*27162e4eSAndroid Build Coastguard Worker if (!r && (statbuf.st_mode & _S_IFDIR)) return 1;
143*27162e4eSAndroid Build Coastguard Worker #else
144*27162e4eSAndroid Build Coastguard Worker struct stat statbuf;
145*27162e4eSAndroid Build Coastguard Worker r = stat(infilename, &statbuf);
146*27162e4eSAndroid Build Coastguard Worker if (!r && S_ISDIR(statbuf.st_mode)) return 1;
147*27162e4eSAndroid Build Coastguard Worker #endif
148*27162e4eSAndroid Build Coastguard Worker return 0;
149*27162e4eSAndroid Build Coastguard Worker }
150*27162e4eSAndroid Build Coastguard Worker
151*27162e4eSAndroid Build Coastguard Worker
152*27162e4eSAndroid Build Coastguard Worker /** loadFile() :
153*27162e4eSAndroid Build Coastguard Worker * requirement : `buffer` size >= `fileSize` */
loadFile(void * buffer,const char * fileName,size_t fileSize)154*27162e4eSAndroid Build Coastguard Worker static void loadFile(void* buffer, const char* fileName, size_t fileSize)
155*27162e4eSAndroid Build Coastguard Worker {
156*27162e4eSAndroid Build Coastguard Worker FILE* const f = fopen(fileName, "rb");
157*27162e4eSAndroid Build Coastguard Worker if (isDirectory(fileName)) {
158*27162e4eSAndroid Build Coastguard Worker MSG("Ignoring %s directory \n", fileName);
159*27162e4eSAndroid Build Coastguard Worker exit(2);
160*27162e4eSAndroid Build Coastguard Worker }
161*27162e4eSAndroid Build Coastguard Worker if (f==NULL) {
162*27162e4eSAndroid Build Coastguard Worker MSG("Impossible to open %s \n", fileName);
163*27162e4eSAndroid Build Coastguard Worker exit(3);
164*27162e4eSAndroid Build Coastguard Worker }
165*27162e4eSAndroid Build Coastguard Worker { size_t const readSize = fread(buffer, 1, fileSize, f);
166*27162e4eSAndroid Build Coastguard Worker if (readSize != fileSize) {
167*27162e4eSAndroid Build Coastguard Worker MSG("Error reading %s \n", fileName);
168*27162e4eSAndroid Build Coastguard Worker exit(5);
169*27162e4eSAndroid Build Coastguard Worker } }
170*27162e4eSAndroid Build Coastguard Worker fclose(f);
171*27162e4eSAndroid Build Coastguard Worker }
172*27162e4eSAndroid Build Coastguard Worker
173*27162e4eSAndroid Build Coastguard Worker
fileCheck(const char * fileName)174*27162e4eSAndroid Build Coastguard Worker static void fileCheck(const char* fileName)
175*27162e4eSAndroid Build Coastguard Worker {
176*27162e4eSAndroid Build Coastguard Worker size_t const fileSize = getFileSize(fileName);
177*27162e4eSAndroid Build Coastguard Worker void* const buffer = malloc(fileSize + !fileSize /* avoid 0 */);
178*27162e4eSAndroid Build Coastguard Worker if (!buffer) {
179*27162e4eSAndroid Build Coastguard Worker MSG("not enough memory \n");
180*27162e4eSAndroid Build Coastguard Worker exit(4);
181*27162e4eSAndroid Build Coastguard Worker }
182*27162e4eSAndroid Build Coastguard Worker loadFile(buffer, fileName, fileSize);
183*27162e4eSAndroid Build Coastguard Worker roundTripCheck(buffer, fileSize);
184*27162e4eSAndroid Build Coastguard Worker free (buffer);
185*27162e4eSAndroid Build Coastguard Worker }
186*27162e4eSAndroid Build Coastguard Worker
187*27162e4eSAndroid Build Coastguard Worker
bad_usage(const char * exeName)188*27162e4eSAndroid Build Coastguard Worker int bad_usage(const char* exeName)
189*27162e4eSAndroid Build Coastguard Worker {
190*27162e4eSAndroid Build Coastguard Worker MSG(" \n");
191*27162e4eSAndroid Build Coastguard Worker MSG("bad usage: \n");
192*27162e4eSAndroid Build Coastguard Worker MSG(" \n");
193*27162e4eSAndroid Build Coastguard Worker MSG("%s [Options] fileName \n", exeName);
194*27162e4eSAndroid Build Coastguard Worker MSG(" \n");
195*27162e4eSAndroid Build Coastguard Worker MSG("Options: \n");
196*27162e4eSAndroid Build Coastguard Worker MSG("-# : use #=[0-9] compression level (default:0 == random) \n");
197*27162e4eSAndroid Build Coastguard Worker return 1;
198*27162e4eSAndroid Build Coastguard Worker }
199*27162e4eSAndroid Build Coastguard Worker
200*27162e4eSAndroid Build Coastguard Worker
main(int argCount,const char ** argv)201*27162e4eSAndroid Build Coastguard Worker int main(int argCount, const char** argv)
202*27162e4eSAndroid Build Coastguard Worker {
203*27162e4eSAndroid Build Coastguard Worker const char* const exeName = argv[0];
204*27162e4eSAndroid Build Coastguard Worker int argNb = 1;
205*27162e4eSAndroid Build Coastguard Worker // Note : LZ4_VERSION_STRING requires >= v1.7.3+
206*27162e4eSAndroid Build Coastguard Worker MSG("abiTest, built binary based on API %s \n", LZ4_VERSION_STRING);
207*27162e4eSAndroid Build Coastguard Worker // Note : LZ4_versionString() requires >= v1.7.5+
208*27162e4eSAndroid Build Coastguard Worker MSG("currently linked to dll %s \n", LZ4_versionString());
209*27162e4eSAndroid Build Coastguard Worker
210*27162e4eSAndroid Build Coastguard Worker assert(argCount >= 1);
211*27162e4eSAndroid Build Coastguard Worker if (argCount < 2) return bad_usage(exeName);
212*27162e4eSAndroid Build Coastguard Worker
213*27162e4eSAndroid Build Coastguard Worker if (argNb >= argCount) return bad_usage(exeName);
214*27162e4eSAndroid Build Coastguard Worker
215*27162e4eSAndroid Build Coastguard Worker fileCheck(argv[argNb]);
216*27162e4eSAndroid Build Coastguard Worker MSG("no pb detected \n");
217*27162e4eSAndroid Build Coastguard Worker return 0;
218*27162e4eSAndroid Build Coastguard Worker }
219