1*27162e4eSAndroid Build Coastguard Worker /*
2*27162e4eSAndroid Build Coastguard Worker LZ4io.c - LZ4 File/Stream Interface
3*27162e4eSAndroid Build Coastguard Worker Copyright (C) Yann Collet 2011-2024
4*27162e4eSAndroid Build Coastguard Worker
5*27162e4eSAndroid Build Coastguard Worker GPL v2 License
6*27162e4eSAndroid Build Coastguard Worker
7*27162e4eSAndroid Build Coastguard Worker This program is free software; you can redistribute it and/or modify
8*27162e4eSAndroid Build Coastguard Worker it under the terms of the GNU General Public License as published by
9*27162e4eSAndroid Build Coastguard Worker the Free Software Foundation; either version 2 of the License, or
10*27162e4eSAndroid Build Coastguard Worker (at your option) any later version.
11*27162e4eSAndroid Build Coastguard Worker
12*27162e4eSAndroid Build Coastguard Worker This program is distributed in the hope that it will be useful,
13*27162e4eSAndroid Build Coastguard Worker but WITHOUT ANY WARRANTY; without even the implied warranty of
14*27162e4eSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*27162e4eSAndroid Build Coastguard Worker GNU General Public License for more details.
16*27162e4eSAndroid Build Coastguard Worker
17*27162e4eSAndroid Build Coastguard Worker You should have received a copy of the GNU General Public License along
18*27162e4eSAndroid Build Coastguard Worker with this program; if not, write to the Free Software Foundation, Inc.,
19*27162e4eSAndroid Build Coastguard Worker 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20*27162e4eSAndroid Build Coastguard Worker
21*27162e4eSAndroid Build Coastguard Worker You can contact the author at :
22*27162e4eSAndroid Build Coastguard Worker - LZ4 source repository : https://github.com/lz4/lz4
23*27162e4eSAndroid Build Coastguard Worker - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
24*27162e4eSAndroid Build Coastguard Worker */
25*27162e4eSAndroid Build Coastguard Worker /*
26*27162e4eSAndroid Build Coastguard Worker Note : this is stand-alone program.
27*27162e4eSAndroid Build Coastguard Worker It is not part of LZ4 compression library, it is a user code of the LZ4 library.
28*27162e4eSAndroid Build Coastguard Worker - The license of LZ4 library is BSD.
29*27162e4eSAndroid Build Coastguard Worker - The license of xxHash library is BSD.
30*27162e4eSAndroid Build Coastguard Worker - The license of this source file is GPLv2.
31*27162e4eSAndroid Build Coastguard Worker */
32*27162e4eSAndroid Build Coastguard Worker
33*27162e4eSAndroid Build Coastguard Worker
34*27162e4eSAndroid Build Coastguard Worker /*-************************************
35*27162e4eSAndroid Build Coastguard Worker * Compiler options
36*27162e4eSAndroid Build Coastguard Worker **************************************/
37*27162e4eSAndroid Build Coastguard Worker #ifdef _MSC_VER /* Visual Studio */
38*27162e4eSAndroid Build Coastguard Worker # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
39*27162e4eSAndroid Build Coastguard Worker #endif
40*27162e4eSAndroid Build Coastguard Worker #if defined(__MINGW32__) && !defined(_POSIX_SOURCE)
41*27162e4eSAndroid Build Coastguard Worker # define _POSIX_SOURCE 1 /* disable %llu warnings with MinGW on Windows */
42*27162e4eSAndroid Build Coastguard Worker #endif
43*27162e4eSAndroid Build Coastguard Worker
44*27162e4eSAndroid Build Coastguard Worker
45*27162e4eSAndroid Build Coastguard Worker /*****************************
46*27162e4eSAndroid Build Coastguard Worker * Includes
47*27162e4eSAndroid Build Coastguard Worker *****************************/
48*27162e4eSAndroid Build Coastguard Worker #include "platform.h" /* Large File Support, SET_BINARY_MODE, SET_SPARSE_FILE_MODE, PLATFORM_POSIX_VERSION, __64BIT__ */
49*27162e4eSAndroid Build Coastguard Worker #include "timefn.h" /* TIME_ */
50*27162e4eSAndroid Build Coastguard Worker #include "util.h" /* UTIL_getFileStat, UTIL_setFileStat */
51*27162e4eSAndroid Build Coastguard Worker #include <stdio.h> /* fprintf, fopen, fread, stdin, stdout, fflush, getchar */
52*27162e4eSAndroid Build Coastguard Worker #include <stdlib.h> /* malloc, free */
53*27162e4eSAndroid Build Coastguard Worker #include <string.h> /* strerror, strcmp, strlen */
54*27162e4eSAndroid Build Coastguard Worker #include <time.h> /* clock_t, for cpu-time */
55*27162e4eSAndroid Build Coastguard Worker #include <sys/types.h> /* stat64 */
56*27162e4eSAndroid Build Coastguard Worker #include <sys/stat.h> /* stat64 */
57*27162e4eSAndroid Build Coastguard Worker #include "lz4conf.h" /* compile-time constants */
58*27162e4eSAndroid Build Coastguard Worker #include "lz4io.h"
59*27162e4eSAndroid Build Coastguard Worker #include "lz4.h" /* required for legacy format */
60*27162e4eSAndroid Build Coastguard Worker #include "lz4hc.h" /* required for legacy format */
61*27162e4eSAndroid Build Coastguard Worker #define LZ4F_STATIC_LINKING_ONLY
62*27162e4eSAndroid Build Coastguard Worker #include "lz4frame.h" /* LZ4F_* */
63*27162e4eSAndroid Build Coastguard Worker #include "xxhash.h" /* frame checksum (MT mode) */
64*27162e4eSAndroid Build Coastguard Worker
65*27162e4eSAndroid Build Coastguard Worker
66*27162e4eSAndroid Build Coastguard Worker /*****************************
67*27162e4eSAndroid Build Coastguard Worker * Constants
68*27162e4eSAndroid Build Coastguard Worker *****************************/
69*27162e4eSAndroid Build Coastguard Worker #define KB *(1 <<10)
70*27162e4eSAndroid Build Coastguard Worker #define MB *(1 <<20)
71*27162e4eSAndroid Build Coastguard Worker #define GB *(1U<<30)
72*27162e4eSAndroid Build Coastguard Worker
73*27162e4eSAndroid Build Coastguard Worker #define _1BIT 0x01
74*27162e4eSAndroid Build Coastguard Worker #define _2BITS 0x03
75*27162e4eSAndroid Build Coastguard Worker #define _3BITS 0x07
76*27162e4eSAndroid Build Coastguard Worker #define _4BITS 0x0F
77*27162e4eSAndroid Build Coastguard Worker #define _8BITS 0xFF
78*27162e4eSAndroid Build Coastguard Worker
79*27162e4eSAndroid Build Coastguard Worker #define MAGICNUMBER_SIZE 4
80*27162e4eSAndroid Build Coastguard Worker #define LZ4IO_MAGICNUMBER 0x184D2204
81*27162e4eSAndroid Build Coastguard Worker #define LZ4IO_SKIPPABLE0 0x184D2A50
82*27162e4eSAndroid Build Coastguard Worker #define LZ4IO_SKIPPABLEMASK 0xFFFFFFF0
83*27162e4eSAndroid Build Coastguard Worker #define LEGACY_MAGICNUMBER 0x184C2102
84*27162e4eSAndroid Build Coastguard Worker
85*27162e4eSAndroid Build Coastguard Worker #define CACHELINE 64
86*27162e4eSAndroid Build Coastguard Worker #define LEGACY_BLOCKSIZE (8 MB)
87*27162e4eSAndroid Build Coastguard Worker #define MIN_STREAM_BUFSIZE (192 KB)
88*27162e4eSAndroid Build Coastguard Worker #define LZ4IO_BLOCKSIZEID_DEFAULT 7
89*27162e4eSAndroid Build Coastguard Worker #define LZ4_MAX_DICT_SIZE (64 KB)
90*27162e4eSAndroid Build Coastguard Worker
91*27162e4eSAndroid Build Coastguard Worker #undef MIN
92*27162e4eSAndroid Build Coastguard Worker #define MIN(a,b) ((a)<(b)?(a):(b))
93*27162e4eSAndroid Build Coastguard Worker
94*27162e4eSAndroid Build Coastguard Worker /**************************************
95*27162e4eSAndroid Build Coastguard Worker * Time and Display
96*27162e4eSAndroid Build Coastguard Worker **************************************/
97*27162e4eSAndroid Build Coastguard Worker #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
98*27162e4eSAndroid Build Coastguard Worker #define DISPLAYOUT(...) fprintf(stdout, __VA_ARGS__)
99*27162e4eSAndroid Build Coastguard Worker #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); if (g_displayLevel>=4) fflush(stderr); }
100*27162e4eSAndroid Build Coastguard Worker static int g_displayLevel = 0; /* 0 : no display ; 1: errors ; 2 : + result + interaction + warnings ; 3 : + progression; 4 : + information */
101*27162e4eSAndroid Build Coastguard Worker
102*27162e4eSAndroid Build Coastguard Worker #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
103*27162e4eSAndroid Build Coastguard Worker if ( (TIME_clockSpan_ns(g_time) > refreshRate) \
104*27162e4eSAndroid Build Coastguard Worker || (g_displayLevel>=4) ) { \
105*27162e4eSAndroid Build Coastguard Worker g_time = TIME_getTime(); \
106*27162e4eSAndroid Build Coastguard Worker DISPLAY(__VA_ARGS__); \
107*27162e4eSAndroid Build Coastguard Worker if (g_displayLevel>=4) fflush(stderr); \
108*27162e4eSAndroid Build Coastguard Worker } }
109*27162e4eSAndroid Build Coastguard Worker static const Duration_ns refreshRate = 200000000;
110*27162e4eSAndroid Build Coastguard Worker static TIME_t g_time = { 0 };
111*27162e4eSAndroid Build Coastguard Worker
cpuLoad_sec(clock_t cpuStart)112*27162e4eSAndroid Build Coastguard Worker static double cpuLoad_sec(clock_t cpuStart)
113*27162e4eSAndroid Build Coastguard Worker {
114*27162e4eSAndroid Build Coastguard Worker #ifdef _WIN32
115*27162e4eSAndroid Build Coastguard Worker FILETIME creationTime, exitTime, kernelTime, userTime;
116*27162e4eSAndroid Build Coastguard Worker (void)cpuStart;
117*27162e4eSAndroid Build Coastguard Worker GetProcessTimes(GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime);
118*27162e4eSAndroid Build Coastguard Worker assert(kernelTime.dwHighDateTime == 0);
119*27162e4eSAndroid Build Coastguard Worker assert(userTime.dwHighDateTime == 0);
120*27162e4eSAndroid Build Coastguard Worker return ((double)kernelTime.dwLowDateTime + (double)userTime.dwLowDateTime) * 100. / 1000000000.;
121*27162e4eSAndroid Build Coastguard Worker #else
122*27162e4eSAndroid Build Coastguard Worker return (double)(clock() - cpuStart) / CLOCKS_PER_SEC;
123*27162e4eSAndroid Build Coastguard Worker #endif
124*27162e4eSAndroid Build Coastguard Worker }
125*27162e4eSAndroid Build Coastguard Worker
LZ4IO_finalTimeDisplay(TIME_t timeStart,clock_t cpuStart,unsigned long long size)126*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_finalTimeDisplay(TIME_t timeStart, clock_t cpuStart, unsigned long long size)
127*27162e4eSAndroid Build Coastguard Worker {
128*27162e4eSAndroid Build Coastguard Worker #if LZ4IO_MULTITHREAD
129*27162e4eSAndroid Build Coastguard Worker if (!TIME_support_MT_measurements()) {
130*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(5, "time measurements not compatible with multithreading \n");
131*27162e4eSAndroid Build Coastguard Worker } else
132*27162e4eSAndroid Build Coastguard Worker #endif
133*27162e4eSAndroid Build Coastguard Worker {
134*27162e4eSAndroid Build Coastguard Worker Duration_ns duration_ns = TIME_clockSpan_ns(timeStart);
135*27162e4eSAndroid Build Coastguard Worker double const seconds = (double)(duration_ns + !duration_ns) / (double)1000000000.;
136*27162e4eSAndroid Build Coastguard Worker double const cpuLoad_s = cpuLoad_sec(cpuStart);
137*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(3,"Done in %.2f s ==> %.2f MiB/s (cpu load : %.0f%%)\n", seconds,
138*27162e4eSAndroid Build Coastguard Worker (double)size / seconds / 1024. / 1024.,
139*27162e4eSAndroid Build Coastguard Worker (cpuLoad_s / seconds) * 100.);
140*27162e4eSAndroid Build Coastguard Worker }
141*27162e4eSAndroid Build Coastguard Worker }
142*27162e4eSAndroid Build Coastguard Worker
143*27162e4eSAndroid Build Coastguard Worker /**************************************
144*27162e4eSAndroid Build Coastguard Worker * Exceptions
145*27162e4eSAndroid Build Coastguard Worker ***************************************/
146*27162e4eSAndroid Build Coastguard Worker #ifndef DEBUG
147*27162e4eSAndroid Build Coastguard Worker # define DEBUG 0
148*27162e4eSAndroid Build Coastguard Worker #endif
149*27162e4eSAndroid Build Coastguard Worker #define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);
150*27162e4eSAndroid Build Coastguard Worker #define END_PROCESS(error, ...) \
151*27162e4eSAndroid Build Coastguard Worker { \
152*27162e4eSAndroid Build Coastguard Worker DEBUGOUTPUT("Error in %s, line %i : \n", __FILE__, __LINE__); \
153*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(1, "Error %i : ", error); \
154*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(1, __VA_ARGS__); \
155*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(1, " \n"); \
156*27162e4eSAndroid Build Coastguard Worker fflush(NULL); \
157*27162e4eSAndroid Build Coastguard Worker exit(error); \
158*27162e4eSAndroid Build Coastguard Worker }
159*27162e4eSAndroid Build Coastguard Worker
160*27162e4eSAndroid Build Coastguard Worker #define LZ4IO_STATIC_ASSERT(c) { enum { LZ4IO_static_assert = 1/(int)(!!(c)) }; } /* use after variable declarations */
161*27162e4eSAndroid Build Coastguard Worker
162*27162e4eSAndroid Build Coastguard Worker
163*27162e4eSAndroid Build Coastguard Worker /* ************************************************** */
164*27162e4eSAndroid Build Coastguard Worker /* ****************** Init functions ******************** */
165*27162e4eSAndroid Build Coastguard Worker /* ************************************************** */
166*27162e4eSAndroid Build Coastguard Worker
LZ4IO_defaultNbWorkers(void)167*27162e4eSAndroid Build Coastguard Worker int LZ4IO_defaultNbWorkers(void)
168*27162e4eSAndroid Build Coastguard Worker {
169*27162e4eSAndroid Build Coastguard Worker #if LZ4IO_MULTITHREAD
170*27162e4eSAndroid Build Coastguard Worker int const nbCores = UTIL_countCores();
171*27162e4eSAndroid Build Coastguard Worker int const spared = 1 + ((unsigned)nbCores >> 3);
172*27162e4eSAndroid Build Coastguard Worker if (nbCores <= spared) return 1;
173*27162e4eSAndroid Build Coastguard Worker return nbCores - spared;
174*27162e4eSAndroid Build Coastguard Worker #else
175*27162e4eSAndroid Build Coastguard Worker return 1;
176*27162e4eSAndroid Build Coastguard Worker #endif
177*27162e4eSAndroid Build Coastguard Worker }
178*27162e4eSAndroid Build Coastguard Worker
179*27162e4eSAndroid Build Coastguard Worker /* ************************************************** */
180*27162e4eSAndroid Build Coastguard Worker /* ****************** Parameters ******************** */
181*27162e4eSAndroid Build Coastguard Worker /* ************************************************** */
182*27162e4eSAndroid Build Coastguard Worker
183*27162e4eSAndroid Build Coastguard Worker struct LZ4IO_prefs_s {
184*27162e4eSAndroid Build Coastguard Worker int passThrough;
185*27162e4eSAndroid Build Coastguard Worker int overwrite;
186*27162e4eSAndroid Build Coastguard Worker int testMode;
187*27162e4eSAndroid Build Coastguard Worker int blockSizeId;
188*27162e4eSAndroid Build Coastguard Worker size_t blockSize;
189*27162e4eSAndroid Build Coastguard Worker int blockChecksum;
190*27162e4eSAndroid Build Coastguard Worker int streamChecksum;
191*27162e4eSAndroid Build Coastguard Worker int blockIndependence;
192*27162e4eSAndroid Build Coastguard Worker int sparseFileSupport;
193*27162e4eSAndroid Build Coastguard Worker int contentSizeFlag;
194*27162e4eSAndroid Build Coastguard Worker int useDictionary;
195*27162e4eSAndroid Build Coastguard Worker unsigned favorDecSpeed;
196*27162e4eSAndroid Build Coastguard Worker const char* dictionaryFilename;
197*27162e4eSAndroid Build Coastguard Worker int removeSrcFile;
198*27162e4eSAndroid Build Coastguard Worker int nbWorkers;
199*27162e4eSAndroid Build Coastguard Worker };
200*27162e4eSAndroid Build Coastguard Worker
LZ4IO_freePreferences(LZ4IO_prefs_t * prefs)201*27162e4eSAndroid Build Coastguard Worker void LZ4IO_freePreferences(LZ4IO_prefs_t* prefs)
202*27162e4eSAndroid Build Coastguard Worker {
203*27162e4eSAndroid Build Coastguard Worker free(prefs);
204*27162e4eSAndroid Build Coastguard Worker }
205*27162e4eSAndroid Build Coastguard Worker
LZ4IO_defaultPreferences(void)206*27162e4eSAndroid Build Coastguard Worker LZ4IO_prefs_t* LZ4IO_defaultPreferences(void)
207*27162e4eSAndroid Build Coastguard Worker {
208*27162e4eSAndroid Build Coastguard Worker LZ4IO_prefs_t* const prefs = (LZ4IO_prefs_t*)malloc(sizeof(*prefs));
209*27162e4eSAndroid Build Coastguard Worker if (!prefs) END_PROCESS(11, "Can't even allocate LZ4IO preferences");
210*27162e4eSAndroid Build Coastguard Worker prefs->passThrough = 0;
211*27162e4eSAndroid Build Coastguard Worker prefs->overwrite = 1;
212*27162e4eSAndroid Build Coastguard Worker prefs->testMode = 0;
213*27162e4eSAndroid Build Coastguard Worker prefs->blockSizeId = LZ4IO_BLOCKSIZEID_DEFAULT;
214*27162e4eSAndroid Build Coastguard Worker prefs->blockSize = 0;
215*27162e4eSAndroid Build Coastguard Worker prefs->blockChecksum = 0;
216*27162e4eSAndroid Build Coastguard Worker prefs->streamChecksum = 1;
217*27162e4eSAndroid Build Coastguard Worker prefs->blockIndependence = 1;
218*27162e4eSAndroid Build Coastguard Worker prefs->sparseFileSupport = 1;
219*27162e4eSAndroid Build Coastguard Worker prefs->contentSizeFlag = 0;
220*27162e4eSAndroid Build Coastguard Worker prefs->useDictionary = 0;
221*27162e4eSAndroid Build Coastguard Worker prefs->favorDecSpeed = 0;
222*27162e4eSAndroid Build Coastguard Worker prefs->dictionaryFilename = NULL;
223*27162e4eSAndroid Build Coastguard Worker prefs->removeSrcFile = 0;
224*27162e4eSAndroid Build Coastguard Worker prefs->nbWorkers = LZ4IO_defaultNbWorkers();
225*27162e4eSAndroid Build Coastguard Worker return prefs;
226*27162e4eSAndroid Build Coastguard Worker }
227*27162e4eSAndroid Build Coastguard Worker
LZ4IO_setNbWorkers(LZ4IO_prefs_t * const prefs,int nbWorkers)228*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setNbWorkers(LZ4IO_prefs_t* const prefs, int nbWorkers)
229*27162e4eSAndroid Build Coastguard Worker {
230*27162e4eSAndroid Build Coastguard Worker if (nbWorkers < 1 ) nbWorkers = 1;
231*27162e4eSAndroid Build Coastguard Worker nbWorkers = MIN(nbWorkers, LZ4_NBWORKERS_MAX);
232*27162e4eSAndroid Build Coastguard Worker prefs->nbWorkers = nbWorkers;
233*27162e4eSAndroid Build Coastguard Worker return nbWorkers;
234*27162e4eSAndroid Build Coastguard Worker }
235*27162e4eSAndroid Build Coastguard Worker
LZ4IO_setDictionaryFilename(LZ4IO_prefs_t * const prefs,const char * dictionaryFilename)236*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setDictionaryFilename(LZ4IO_prefs_t* const prefs, const char* dictionaryFilename)
237*27162e4eSAndroid Build Coastguard Worker {
238*27162e4eSAndroid Build Coastguard Worker prefs->dictionaryFilename = dictionaryFilename;
239*27162e4eSAndroid Build Coastguard Worker prefs->useDictionary = dictionaryFilename != NULL;
240*27162e4eSAndroid Build Coastguard Worker return prefs->useDictionary;
241*27162e4eSAndroid Build Coastguard Worker }
242*27162e4eSAndroid Build Coastguard Worker
243*27162e4eSAndroid Build Coastguard Worker /* Default setting : passThrough = 0; return : passThrough mode (0/1) */
LZ4IO_setPassThrough(LZ4IO_prefs_t * const prefs,int yes)244*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setPassThrough(LZ4IO_prefs_t* const prefs, int yes)
245*27162e4eSAndroid Build Coastguard Worker {
246*27162e4eSAndroid Build Coastguard Worker prefs->passThrough = (yes!=0);
247*27162e4eSAndroid Build Coastguard Worker return prefs->passThrough;
248*27162e4eSAndroid Build Coastguard Worker }
249*27162e4eSAndroid Build Coastguard Worker
250*27162e4eSAndroid Build Coastguard Worker /* Default setting : overwrite = 1; return : overwrite mode (0/1) */
LZ4IO_setOverwrite(LZ4IO_prefs_t * const prefs,int yes)251*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setOverwrite(LZ4IO_prefs_t* const prefs, int yes)
252*27162e4eSAndroid Build Coastguard Worker {
253*27162e4eSAndroid Build Coastguard Worker prefs->overwrite = (yes!=0);
254*27162e4eSAndroid Build Coastguard Worker return prefs->overwrite;
255*27162e4eSAndroid Build Coastguard Worker }
256*27162e4eSAndroid Build Coastguard Worker
257*27162e4eSAndroid Build Coastguard Worker /* Default setting : testMode = 0; return : testMode (0/1) */
LZ4IO_setTestMode(LZ4IO_prefs_t * const prefs,int yes)258*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setTestMode(LZ4IO_prefs_t* const prefs, int yes)
259*27162e4eSAndroid Build Coastguard Worker {
260*27162e4eSAndroid Build Coastguard Worker prefs->testMode = (yes!=0);
261*27162e4eSAndroid Build Coastguard Worker return prefs->testMode;
262*27162e4eSAndroid Build Coastguard Worker }
263*27162e4eSAndroid Build Coastguard Worker
264*27162e4eSAndroid Build Coastguard Worker /* blockSizeID : valid values : 4-5-6-7 */
LZ4IO_setBlockSizeID(LZ4IO_prefs_t * const prefs,unsigned bsid)265*27162e4eSAndroid Build Coastguard Worker size_t LZ4IO_setBlockSizeID(LZ4IO_prefs_t* const prefs, unsigned bsid)
266*27162e4eSAndroid Build Coastguard Worker {
267*27162e4eSAndroid Build Coastguard Worker static const size_t blockSizeTable[] = { 64 KB, 256 KB, 1 MB, 4 MB };
268*27162e4eSAndroid Build Coastguard Worker static const unsigned minBlockSizeID = 4;
269*27162e4eSAndroid Build Coastguard Worker static const unsigned maxBlockSizeID = 7;
270*27162e4eSAndroid Build Coastguard Worker if ((bsid < minBlockSizeID) || (bsid > maxBlockSizeID)) return 0;
271*27162e4eSAndroid Build Coastguard Worker prefs->blockSizeId = (int)bsid;
272*27162e4eSAndroid Build Coastguard Worker prefs->blockSize = blockSizeTable[(unsigned)prefs->blockSizeId-minBlockSizeID];
273*27162e4eSAndroid Build Coastguard Worker return prefs->blockSize;
274*27162e4eSAndroid Build Coastguard Worker }
275*27162e4eSAndroid Build Coastguard Worker
LZ4IO_setBlockSize(LZ4IO_prefs_t * const prefs,size_t blockSize)276*27162e4eSAndroid Build Coastguard Worker size_t LZ4IO_setBlockSize(LZ4IO_prefs_t* const prefs, size_t blockSize)
277*27162e4eSAndroid Build Coastguard Worker {
278*27162e4eSAndroid Build Coastguard Worker static const size_t minBlockSize = 32;
279*27162e4eSAndroid Build Coastguard Worker static const size_t maxBlockSize = 4 MB;
280*27162e4eSAndroid Build Coastguard Worker unsigned bsid = 0;
281*27162e4eSAndroid Build Coastguard Worker if (blockSize < minBlockSize) blockSize = minBlockSize;
282*27162e4eSAndroid Build Coastguard Worker if (blockSize > maxBlockSize) blockSize = maxBlockSize;
283*27162e4eSAndroid Build Coastguard Worker prefs->blockSize = blockSize;
284*27162e4eSAndroid Build Coastguard Worker blockSize--;
285*27162e4eSAndroid Build Coastguard Worker /* find which of { 64k, 256k, 1MB, 4MB } is closest to blockSize */
286*27162e4eSAndroid Build Coastguard Worker while (blockSize >>= 2)
287*27162e4eSAndroid Build Coastguard Worker bsid++;
288*27162e4eSAndroid Build Coastguard Worker if (bsid < 7) bsid = 7;
289*27162e4eSAndroid Build Coastguard Worker prefs->blockSizeId = (int)(bsid-3);
290*27162e4eSAndroid Build Coastguard Worker return prefs->blockSize;
291*27162e4eSAndroid Build Coastguard Worker }
292*27162e4eSAndroid Build Coastguard Worker
293*27162e4eSAndroid Build Coastguard Worker /* Default setting : 1 == independent blocks */
LZ4IO_setBlockMode(LZ4IO_prefs_t * const prefs,LZ4IO_blockMode_t blockMode)294*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setBlockMode(LZ4IO_prefs_t* const prefs, LZ4IO_blockMode_t blockMode)
295*27162e4eSAndroid Build Coastguard Worker {
296*27162e4eSAndroid Build Coastguard Worker prefs->blockIndependence = (blockMode == LZ4IO_blockIndependent);
297*27162e4eSAndroid Build Coastguard Worker return prefs->blockIndependence;
298*27162e4eSAndroid Build Coastguard Worker }
299*27162e4eSAndroid Build Coastguard Worker
300*27162e4eSAndroid Build Coastguard Worker /* Default setting : 0 == no block checksum */
LZ4IO_setBlockChecksumMode(LZ4IO_prefs_t * const prefs,int enable)301*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setBlockChecksumMode(LZ4IO_prefs_t* const prefs, int enable)
302*27162e4eSAndroid Build Coastguard Worker {
303*27162e4eSAndroid Build Coastguard Worker prefs->blockChecksum = (enable != 0);
304*27162e4eSAndroid Build Coastguard Worker return prefs->blockChecksum;
305*27162e4eSAndroid Build Coastguard Worker }
306*27162e4eSAndroid Build Coastguard Worker
307*27162e4eSAndroid Build Coastguard Worker /* Default setting : 1 == checksum enabled */
LZ4IO_setStreamChecksumMode(LZ4IO_prefs_t * const prefs,int enable)308*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setStreamChecksumMode(LZ4IO_prefs_t* const prefs, int enable)
309*27162e4eSAndroid Build Coastguard Worker {
310*27162e4eSAndroid Build Coastguard Worker prefs->streamChecksum = (enable != 0);
311*27162e4eSAndroid Build Coastguard Worker return prefs->streamChecksum;
312*27162e4eSAndroid Build Coastguard Worker }
313*27162e4eSAndroid Build Coastguard Worker
314*27162e4eSAndroid Build Coastguard Worker /* Default setting : 0 (no notification) */
LZ4IO_setNotificationLevel(int level)315*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setNotificationLevel(int level)
316*27162e4eSAndroid Build Coastguard Worker {
317*27162e4eSAndroid Build Coastguard Worker g_displayLevel = level;
318*27162e4eSAndroid Build Coastguard Worker return g_displayLevel;
319*27162e4eSAndroid Build Coastguard Worker }
320*27162e4eSAndroid Build Coastguard Worker
321*27162e4eSAndroid Build Coastguard Worker /* Default setting : 1 (auto: enabled on file, disabled on stdout) */
LZ4IO_setSparseFile(LZ4IO_prefs_t * const prefs,int enable)322*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setSparseFile(LZ4IO_prefs_t* const prefs, int enable)
323*27162e4eSAndroid Build Coastguard Worker {
324*27162e4eSAndroid Build Coastguard Worker prefs->sparseFileSupport = 2*(enable!=0); /* 2==force enable */
325*27162e4eSAndroid Build Coastguard Worker return prefs->sparseFileSupport;
326*27162e4eSAndroid Build Coastguard Worker }
327*27162e4eSAndroid Build Coastguard Worker
328*27162e4eSAndroid Build Coastguard Worker /* Default setting : 0 (disabled) */
LZ4IO_setContentSize(LZ4IO_prefs_t * const prefs,int enable)329*27162e4eSAndroid Build Coastguard Worker int LZ4IO_setContentSize(LZ4IO_prefs_t* const prefs, int enable)
330*27162e4eSAndroid Build Coastguard Worker {
331*27162e4eSAndroid Build Coastguard Worker prefs->contentSizeFlag = (enable!=0);
332*27162e4eSAndroid Build Coastguard Worker return prefs->contentSizeFlag;
333*27162e4eSAndroid Build Coastguard Worker }
334*27162e4eSAndroid Build Coastguard Worker
335*27162e4eSAndroid Build Coastguard Worker /* Default setting : 0 (disabled) */
LZ4IO_favorDecSpeed(LZ4IO_prefs_t * const prefs,int favor)336*27162e4eSAndroid Build Coastguard Worker void LZ4IO_favorDecSpeed(LZ4IO_prefs_t* const prefs, int favor)
337*27162e4eSAndroid Build Coastguard Worker {
338*27162e4eSAndroid Build Coastguard Worker prefs->favorDecSpeed = (favor!=0);
339*27162e4eSAndroid Build Coastguard Worker }
340*27162e4eSAndroid Build Coastguard Worker
LZ4IO_setRemoveSrcFile(LZ4IO_prefs_t * const prefs,unsigned flag)341*27162e4eSAndroid Build Coastguard Worker void LZ4IO_setRemoveSrcFile(LZ4IO_prefs_t* const prefs, unsigned flag)
342*27162e4eSAndroid Build Coastguard Worker {
343*27162e4eSAndroid Build Coastguard Worker prefs->removeSrcFile = (flag>0);
344*27162e4eSAndroid Build Coastguard Worker }
345*27162e4eSAndroid Build Coastguard Worker
346*27162e4eSAndroid Build Coastguard Worker
347*27162e4eSAndroid Build Coastguard Worker /* ************************************************************************ **
348*27162e4eSAndroid Build Coastguard Worker ** ********************** String functions ********************* **
349*27162e4eSAndroid Build Coastguard Worker ** ************************************************************************ */
350*27162e4eSAndroid Build Coastguard Worker
LZ4IO_isDevNull(const char * s)351*27162e4eSAndroid Build Coastguard Worker static int LZ4IO_isDevNull(const char* s)
352*27162e4eSAndroid Build Coastguard Worker {
353*27162e4eSAndroid Build Coastguard Worker return UTIL_sameString(s, nulmark);
354*27162e4eSAndroid Build Coastguard Worker }
355*27162e4eSAndroid Build Coastguard Worker
LZ4IO_isStdin(const char * s)356*27162e4eSAndroid Build Coastguard Worker static int LZ4IO_isStdin(const char* s)
357*27162e4eSAndroid Build Coastguard Worker {
358*27162e4eSAndroid Build Coastguard Worker return UTIL_sameString(s, stdinmark);
359*27162e4eSAndroid Build Coastguard Worker }
360*27162e4eSAndroid Build Coastguard Worker
LZ4IO_isStdout(const char * s)361*27162e4eSAndroid Build Coastguard Worker static int LZ4IO_isStdout(const char* s)
362*27162e4eSAndroid Build Coastguard Worker {
363*27162e4eSAndroid Build Coastguard Worker return UTIL_sameString(s, stdoutmark);
364*27162e4eSAndroid Build Coastguard Worker }
365*27162e4eSAndroid Build Coastguard Worker
366*27162e4eSAndroid Build Coastguard Worker
367*27162e4eSAndroid Build Coastguard Worker /* ************************************************************************ **
368*27162e4eSAndroid Build Coastguard Worker ** ********************** LZ4 File / Pipe compression ********************* **
369*27162e4eSAndroid Build Coastguard Worker ** ************************************************************************ */
370*27162e4eSAndroid Build Coastguard Worker
LZ4IO_isSkippableMagicNumber(unsigned int magic)371*27162e4eSAndroid Build Coastguard Worker static int LZ4IO_isSkippableMagicNumber(unsigned int magic) {
372*27162e4eSAndroid Build Coastguard Worker return (magic & LZ4IO_SKIPPABLEMASK) == LZ4IO_SKIPPABLE0;
373*27162e4eSAndroid Build Coastguard Worker }
374*27162e4eSAndroid Build Coastguard Worker
375*27162e4eSAndroid Build Coastguard Worker
376*27162e4eSAndroid Build Coastguard Worker /** LZ4IO_openSrcFile() :
377*27162e4eSAndroid Build Coastguard Worker * condition : `srcFileName` must be non-NULL.
378*27162e4eSAndroid Build Coastguard Worker * @result : FILE* to `dstFileName`, or NULL if it fails */
LZ4IO_openSrcFile(const char * srcFileName)379*27162e4eSAndroid Build Coastguard Worker static FILE* LZ4IO_openSrcFile(const char* srcFileName)
380*27162e4eSAndroid Build Coastguard Worker {
381*27162e4eSAndroid Build Coastguard Worker FILE* f;
382*27162e4eSAndroid Build Coastguard Worker
383*27162e4eSAndroid Build Coastguard Worker if (LZ4IO_isStdin(srcFileName)) {
384*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(4,"Using stdin for input \n");
385*27162e4eSAndroid Build Coastguard Worker f = stdin;
386*27162e4eSAndroid Build Coastguard Worker SET_BINARY_MODE(stdin);
387*27162e4eSAndroid Build Coastguard Worker return f;
388*27162e4eSAndroid Build Coastguard Worker }
389*27162e4eSAndroid Build Coastguard Worker
390*27162e4eSAndroid Build Coastguard Worker if (UTIL_isDirectory(srcFileName)) {
391*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(1, "lz4: %s is a directory -- ignored \n", srcFileName);
392*27162e4eSAndroid Build Coastguard Worker return NULL;
393*27162e4eSAndroid Build Coastguard Worker }
394*27162e4eSAndroid Build Coastguard Worker
395*27162e4eSAndroid Build Coastguard Worker f = fopen(srcFileName, "rb");
396*27162e4eSAndroid Build Coastguard Worker if (f==NULL) DISPLAYLEVEL(1, "%s: %s \n", srcFileName, strerror(errno));
397*27162e4eSAndroid Build Coastguard Worker return f;
398*27162e4eSAndroid Build Coastguard Worker }
399*27162e4eSAndroid Build Coastguard Worker
400*27162e4eSAndroid Build Coastguard Worker /** FIO_openDstFile() :
401*27162e4eSAndroid Build Coastguard Worker * prefs is writable, because sparseFileSupport might be updated.
402*27162e4eSAndroid Build Coastguard Worker * condition : `dstFileName` must be non-NULL.
403*27162e4eSAndroid Build Coastguard Worker * @result : FILE* to `dstFileName`, or NULL if it fails */
404*27162e4eSAndroid Build Coastguard Worker static FILE*
LZ4IO_openDstFile(const char * dstFileName,const LZ4IO_prefs_t * const prefs)405*27162e4eSAndroid Build Coastguard Worker LZ4IO_openDstFile(const char* dstFileName, const LZ4IO_prefs_t* const prefs)
406*27162e4eSAndroid Build Coastguard Worker {
407*27162e4eSAndroid Build Coastguard Worker FILE* f;
408*27162e4eSAndroid Build Coastguard Worker assert(dstFileName != NULL);
409*27162e4eSAndroid Build Coastguard Worker
410*27162e4eSAndroid Build Coastguard Worker if (LZ4IO_isStdout(dstFileName)) {
411*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(4, "Using stdout for output \n");
412*27162e4eSAndroid Build Coastguard Worker f = stdout;
413*27162e4eSAndroid Build Coastguard Worker SET_BINARY_MODE(stdout);
414*27162e4eSAndroid Build Coastguard Worker if (prefs->sparseFileSupport==1) {
415*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(4, "Sparse File Support automatically disabled on stdout ;"
416*27162e4eSAndroid Build Coastguard Worker " to force-enable it, add --sparse command \n");
417*27162e4eSAndroid Build Coastguard Worker }
418*27162e4eSAndroid Build Coastguard Worker } else {
419*27162e4eSAndroid Build Coastguard Worker if (!prefs->overwrite && !LZ4IO_isDevNull(dstFileName)) {
420*27162e4eSAndroid Build Coastguard Worker /* Check if destination file already exists */
421*27162e4eSAndroid Build Coastguard Worker FILE* const testf = fopen( dstFileName, "rb" );
422*27162e4eSAndroid Build Coastguard Worker if (testf != NULL) { /* dest exists, prompt for overwrite authorization */
423*27162e4eSAndroid Build Coastguard Worker fclose(testf);
424*27162e4eSAndroid Build Coastguard Worker if (g_displayLevel <= 1) { /* No interaction possible */
425*27162e4eSAndroid Build Coastguard Worker DISPLAY("%s already exists; not overwritten \n", dstFileName);
426*27162e4eSAndroid Build Coastguard Worker return NULL;
427*27162e4eSAndroid Build Coastguard Worker }
428*27162e4eSAndroid Build Coastguard Worker DISPLAY("%s already exists; do you want to overwrite (y/N) ? ", dstFileName);
429*27162e4eSAndroid Build Coastguard Worker { int ch = getchar();
430*27162e4eSAndroid Build Coastguard Worker if ((ch!='Y') && (ch!='y')) {
431*27162e4eSAndroid Build Coastguard Worker DISPLAY(" not overwritten \n");
432*27162e4eSAndroid Build Coastguard Worker return NULL;
433*27162e4eSAndroid Build Coastguard Worker }
434*27162e4eSAndroid Build Coastguard Worker while ((ch!=EOF) && (ch!='\n')) ch = getchar(); /* flush rest of input line */
435*27162e4eSAndroid Build Coastguard Worker } } }
436*27162e4eSAndroid Build Coastguard Worker f = fopen( dstFileName, "wb" );
437*27162e4eSAndroid Build Coastguard Worker if (f==NULL) DISPLAYLEVEL(1, "%s: %s\n", dstFileName, strerror(errno));
438*27162e4eSAndroid Build Coastguard Worker }
439*27162e4eSAndroid Build Coastguard Worker
440*27162e4eSAndroid Build Coastguard Worker /* sparse file */
441*27162e4eSAndroid Build Coastguard Worker { int const sparseMode = (prefs->sparseFileSupport - (f==stdout)) > 0;
442*27162e4eSAndroid Build Coastguard Worker if (f && sparseMode) { SET_SPARSE_FILE_MODE(f); }
443*27162e4eSAndroid Build Coastguard Worker }
444*27162e4eSAndroid Build Coastguard Worker
445*27162e4eSAndroid Build Coastguard Worker return f;
446*27162e4eSAndroid Build Coastguard Worker }
447*27162e4eSAndroid Build Coastguard Worker
448*27162e4eSAndroid Build Coastguard Worker
449*27162e4eSAndroid Build Coastguard Worker /***************************************
450*27162e4eSAndroid Build Coastguard Worker * MT I/O
451*27162e4eSAndroid Build Coastguard Worker ***************************************/
452*27162e4eSAndroid Build Coastguard Worker
453*27162e4eSAndroid Build Coastguard Worker #include "threadpool.h"
454*27162e4eSAndroid Build Coastguard Worker
455*27162e4eSAndroid Build Coastguard Worker typedef struct {
456*27162e4eSAndroid Build Coastguard Worker void* buf;
457*27162e4eSAndroid Build Coastguard Worker size_t size;
458*27162e4eSAndroid Build Coastguard Worker unsigned long long rank;
459*27162e4eSAndroid Build Coastguard Worker } BufferDesc;
460*27162e4eSAndroid Build Coastguard Worker
461*27162e4eSAndroid Build Coastguard Worker typedef struct {
462*27162e4eSAndroid Build Coastguard Worker unsigned long long expectedRank;
463*27162e4eSAndroid Build Coastguard Worker BufferDesc* buffers;
464*27162e4eSAndroid Build Coastguard Worker size_t capacity;
465*27162e4eSAndroid Build Coastguard Worker size_t blockSize;
466*27162e4eSAndroid Build Coastguard Worker unsigned long long totalCSize;
467*27162e4eSAndroid Build Coastguard Worker } WriteRegister;
468*27162e4eSAndroid Build Coastguard Worker
WR_destroy(WriteRegister * wr)469*27162e4eSAndroid Build Coastguard Worker static void WR_destroy(WriteRegister* wr)
470*27162e4eSAndroid Build Coastguard Worker {
471*27162e4eSAndroid Build Coastguard Worker free(wr->buffers);
472*27162e4eSAndroid Build Coastguard Worker }
473*27162e4eSAndroid Build Coastguard Worker
474*27162e4eSAndroid Build Coastguard Worker #define WR_INITIAL_BUFFER_POOL_SIZE 16
475*27162e4eSAndroid Build Coastguard Worker /* Note: WR_init() can fail (allocation)
476*27162e4eSAndroid Build Coastguard Worker * check that wr->buffers!= NULL for success */
WR_init(size_t blockSize)477*27162e4eSAndroid Build Coastguard Worker static WriteRegister WR_init(size_t blockSize)
478*27162e4eSAndroid Build Coastguard Worker {
479*27162e4eSAndroid Build Coastguard Worker WriteRegister wr = { 0, NULL, WR_INITIAL_BUFFER_POOL_SIZE, 0, 0 };
480*27162e4eSAndroid Build Coastguard Worker wr.buffers = (BufferDesc*)calloc(1, WR_INITIAL_BUFFER_POOL_SIZE * sizeof(BufferDesc));
481*27162e4eSAndroid Build Coastguard Worker wr.blockSize = blockSize;
482*27162e4eSAndroid Build Coastguard Worker return wr;
483*27162e4eSAndroid Build Coastguard Worker }
484*27162e4eSAndroid Build Coastguard Worker
WR_addBufDesc(WriteRegister * wr,const BufferDesc * bd)485*27162e4eSAndroid Build Coastguard Worker static void WR_addBufDesc(WriteRegister* wr, const BufferDesc* bd)
486*27162e4eSAndroid Build Coastguard Worker {
487*27162e4eSAndroid Build Coastguard Worker if (wr->buffers[wr->capacity-1].buf != NULL) {
488*27162e4eSAndroid Build Coastguard Worker /* buffer capacity is full : extend it */
489*27162e4eSAndroid Build Coastguard Worker size_t const oldCapacity = wr->capacity;
490*27162e4eSAndroid Build Coastguard Worker size_t const addedCapacity = MIN(oldCapacity, 256);
491*27162e4eSAndroid Build Coastguard Worker size_t const newCapacity = oldCapacity + addedCapacity;
492*27162e4eSAndroid Build Coastguard Worker size_t const newSize = newCapacity * sizeof(BufferDesc);
493*27162e4eSAndroid Build Coastguard Worker void* const newBuf = realloc(wr->buffers, newSize);
494*27162e4eSAndroid Build Coastguard Worker if (newBuf == NULL) {
495*27162e4eSAndroid Build Coastguard Worker END_PROCESS(39, "cannot extend register of buffers")
496*27162e4eSAndroid Build Coastguard Worker }
497*27162e4eSAndroid Build Coastguard Worker wr->buffers = (BufferDesc*)newBuf;
498*27162e4eSAndroid Build Coastguard Worker memset(wr->buffers + oldCapacity, 0, addedCapacity * sizeof(BufferDesc));
499*27162e4eSAndroid Build Coastguard Worker wr->buffers[oldCapacity] = bd[0];
500*27162e4eSAndroid Build Coastguard Worker wr->capacity = newCapacity;
501*27162e4eSAndroid Build Coastguard Worker } else {
502*27162e4eSAndroid Build Coastguard Worker /* at least one position (the last one) is free, i.e. buffer==NULL */
503*27162e4eSAndroid Build Coastguard Worker size_t n;
504*27162e4eSAndroid Build Coastguard Worker for (n=0; n<wr->capacity; n++) {
505*27162e4eSAndroid Build Coastguard Worker if (wr->buffers[n].buf == NULL) {
506*27162e4eSAndroid Build Coastguard Worker wr->buffers[n] = bd[0];
507*27162e4eSAndroid Build Coastguard Worker break;
508*27162e4eSAndroid Build Coastguard Worker }
509*27162e4eSAndroid Build Coastguard Worker }
510*27162e4eSAndroid Build Coastguard Worker assert(n != wr->capacity);
511*27162e4eSAndroid Build Coastguard Worker }
512*27162e4eSAndroid Build Coastguard Worker }
513*27162e4eSAndroid Build Coastguard Worker
WR_isPresent(WriteRegister * wr,unsigned long long id)514*27162e4eSAndroid Build Coastguard Worker static int WR_isPresent(WriteRegister* wr, unsigned long long id)
515*27162e4eSAndroid Build Coastguard Worker {
516*27162e4eSAndroid Build Coastguard Worker size_t n;
517*27162e4eSAndroid Build Coastguard Worker for (n=0; n<wr->capacity; n++) {
518*27162e4eSAndroid Build Coastguard Worker if (wr->buffers[n].buf == NULL) {
519*27162e4eSAndroid Build Coastguard Worker /* no more buffers stored */
520*27162e4eSAndroid Build Coastguard Worker return 0;
521*27162e4eSAndroid Build Coastguard Worker }
522*27162e4eSAndroid Build Coastguard Worker if (wr->buffers[n].rank == id)
523*27162e4eSAndroid Build Coastguard Worker return 1;
524*27162e4eSAndroid Build Coastguard Worker }
525*27162e4eSAndroid Build Coastguard Worker return 0;
526*27162e4eSAndroid Build Coastguard Worker }
527*27162e4eSAndroid Build Coastguard Worker
528*27162e4eSAndroid Build Coastguard Worker /* Note: requires @id to exist! */
WR_getBufID(WriteRegister * wr,unsigned long long id)529*27162e4eSAndroid Build Coastguard Worker static BufferDesc WR_getBufID(WriteRegister* wr, unsigned long long id)
530*27162e4eSAndroid Build Coastguard Worker {
531*27162e4eSAndroid Build Coastguard Worker size_t n;
532*27162e4eSAndroid Build Coastguard Worker for (n=0; n<wr->capacity; n++) {
533*27162e4eSAndroid Build Coastguard Worker if (wr->buffers[n].buf == NULL) {
534*27162e4eSAndroid Build Coastguard Worker /* no more buffers stored */
535*27162e4eSAndroid Build Coastguard Worker break;
536*27162e4eSAndroid Build Coastguard Worker }
537*27162e4eSAndroid Build Coastguard Worker if (wr->buffers[n].rank == id)
538*27162e4eSAndroid Build Coastguard Worker return wr->buffers[n];
539*27162e4eSAndroid Build Coastguard Worker }
540*27162e4eSAndroid Build Coastguard Worker END_PROCESS(41, "buffer ID not found");
541*27162e4eSAndroid Build Coastguard Worker }
542*27162e4eSAndroid Build Coastguard Worker
WR_removeBuffID(WriteRegister * wr,unsigned long long id)543*27162e4eSAndroid Build Coastguard Worker static void WR_removeBuffID(WriteRegister* wr, unsigned long long id)
544*27162e4eSAndroid Build Coastguard Worker {
545*27162e4eSAndroid Build Coastguard Worker size_t n;
546*27162e4eSAndroid Build Coastguard Worker for (n=0; n<wr->capacity; n++) {
547*27162e4eSAndroid Build Coastguard Worker if (wr->buffers[n].buf == NULL) {
548*27162e4eSAndroid Build Coastguard Worker /* no more buffers stored */
549*27162e4eSAndroid Build Coastguard Worker return;
550*27162e4eSAndroid Build Coastguard Worker }
551*27162e4eSAndroid Build Coastguard Worker if (wr->buffers[n].rank == id) {
552*27162e4eSAndroid Build Coastguard Worker free(wr->buffers[n].buf);
553*27162e4eSAndroid Build Coastguard Worker break;
554*27162e4eSAndroid Build Coastguard Worker }
555*27162e4eSAndroid Build Coastguard Worker }
556*27162e4eSAndroid Build Coastguard Worker /* overwrite buffer descriptor, scale others down*/
557*27162e4eSAndroid Build Coastguard Worker n++;
558*27162e4eSAndroid Build Coastguard Worker for (; n < wr->capacity; n++) {
559*27162e4eSAndroid Build Coastguard Worker wr->buffers[n-1] = wr->buffers[n];
560*27162e4eSAndroid Build Coastguard Worker if (wr->buffers[n].buf == NULL)
561*27162e4eSAndroid Build Coastguard Worker return;
562*27162e4eSAndroid Build Coastguard Worker }
563*27162e4eSAndroid Build Coastguard Worker { BufferDesc const nullBd = { NULL, 0, 0 };
564*27162e4eSAndroid Build Coastguard Worker wr->buffers[wr->capacity-1] = nullBd;
565*27162e4eSAndroid Build Coastguard Worker }
566*27162e4eSAndroid Build Coastguard Worker }
567*27162e4eSAndroid Build Coastguard Worker
568*27162e4eSAndroid Build Coastguard Worker typedef struct {
569*27162e4eSAndroid Build Coastguard Worker WriteRegister* wr;
570*27162e4eSAndroid Build Coastguard Worker void* cBuf;
571*27162e4eSAndroid Build Coastguard Worker size_t cSize;
572*27162e4eSAndroid Build Coastguard Worker unsigned long long blockNb;
573*27162e4eSAndroid Build Coastguard Worker FILE* out;
574*27162e4eSAndroid Build Coastguard Worker } WriteJobDesc;
575*27162e4eSAndroid Build Coastguard Worker
LZ4IO_writeBuffer(BufferDesc bufDesc,FILE * out)576*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_writeBuffer(BufferDesc bufDesc, FILE* out)
577*27162e4eSAndroid Build Coastguard Worker {
578*27162e4eSAndroid Build Coastguard Worker size_t const size = bufDesc.size;
579*27162e4eSAndroid Build Coastguard Worker if (fwrite(bufDesc.buf, 1, size, out) != size) {
580*27162e4eSAndroid Build Coastguard Worker END_PROCESS(38, "Write error : cannot write compressed block");
581*27162e4eSAndroid Build Coastguard Worker }
582*27162e4eSAndroid Build Coastguard Worker }
583*27162e4eSAndroid Build Coastguard Worker
LZ4IO_checkWriteOrder(void * arg)584*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_checkWriteOrder(void* arg)
585*27162e4eSAndroid Build Coastguard Worker {
586*27162e4eSAndroid Build Coastguard Worker WriteJobDesc* const wjd = (WriteJobDesc*)arg;
587*27162e4eSAndroid Build Coastguard Worker size_t const cSize = wjd->cSize;
588*27162e4eSAndroid Build Coastguard Worker WriteRegister* const wr = wjd->wr;
589*27162e4eSAndroid Build Coastguard Worker
590*27162e4eSAndroid Build Coastguard Worker if (wjd->blockNb != wr->expectedRank) {
591*27162e4eSAndroid Build Coastguard Worker /* incorrect order : let's store this buffer for later write */
592*27162e4eSAndroid Build Coastguard Worker BufferDesc bd;
593*27162e4eSAndroid Build Coastguard Worker bd.buf = wjd->cBuf;
594*27162e4eSAndroid Build Coastguard Worker bd.size = wjd->cSize;
595*27162e4eSAndroid Build Coastguard Worker bd.rank = wjd->blockNb;
596*27162e4eSAndroid Build Coastguard Worker WR_addBufDesc(wr, &bd);
597*27162e4eSAndroid Build Coastguard Worker free(wjd); /* because wjd is pod */
598*27162e4eSAndroid Build Coastguard Worker return;
599*27162e4eSAndroid Build Coastguard Worker }
600*27162e4eSAndroid Build Coastguard Worker
601*27162e4eSAndroid Build Coastguard Worker /* expected block ID : let's write this block */
602*27162e4eSAndroid Build Coastguard Worker { BufferDesc bd;
603*27162e4eSAndroid Build Coastguard Worker bd.buf = wjd->cBuf;
604*27162e4eSAndroid Build Coastguard Worker bd.size = wjd->cSize;
605*27162e4eSAndroid Build Coastguard Worker bd.rank = wjd->blockNb;
606*27162e4eSAndroid Build Coastguard Worker LZ4IO_writeBuffer(bd, wjd->out);
607*27162e4eSAndroid Build Coastguard Worker }
608*27162e4eSAndroid Build Coastguard Worker wr->expectedRank++;
609*27162e4eSAndroid Build Coastguard Worker wr->totalCSize += cSize;
610*27162e4eSAndroid Build Coastguard Worker free(wjd->cBuf);
611*27162e4eSAndroid Build Coastguard Worker /* and check for more blocks, previously saved */
612*27162e4eSAndroid Build Coastguard Worker while (WR_isPresent(wr, wr->expectedRank)) {
613*27162e4eSAndroid Build Coastguard Worker BufferDesc const bd = WR_getBufID(wr, wr->expectedRank);
614*27162e4eSAndroid Build Coastguard Worker LZ4IO_writeBuffer(bd, wjd->out);
615*27162e4eSAndroid Build Coastguard Worker wr->totalCSize += bd.size;
616*27162e4eSAndroid Build Coastguard Worker WR_removeBuffID(wr, wr->expectedRank);
617*27162e4eSAndroid Build Coastguard Worker wr->expectedRank++;
618*27162e4eSAndroid Build Coastguard Worker }
619*27162e4eSAndroid Build Coastguard Worker free(wjd); /* because wjd is pod */
620*27162e4eSAndroid Build Coastguard Worker { unsigned long long const processedSize = (unsigned long long)(wr->expectedRank-1) * wr->blockSize;
621*27162e4eSAndroid Build Coastguard Worker DISPLAYUPDATE(2, "\rRead : %u MiB ==> %.2f%% ",
622*27162e4eSAndroid Build Coastguard Worker (unsigned)(processedSize >> 20),
623*27162e4eSAndroid Build Coastguard Worker (double)wr->totalCSize / (double)processedSize * 100.);
624*27162e4eSAndroid Build Coastguard Worker }
625*27162e4eSAndroid Build Coastguard Worker }
626*27162e4eSAndroid Build Coastguard Worker
627*27162e4eSAndroid Build Coastguard Worker typedef size_t (*compress_f)(
628*27162e4eSAndroid Build Coastguard Worker const void* parameters,
629*27162e4eSAndroid Build Coastguard Worker void* dst,
630*27162e4eSAndroid Build Coastguard Worker size_t dstCapacity,
631*27162e4eSAndroid Build Coastguard Worker const void* src,
632*27162e4eSAndroid Build Coastguard Worker size_t srcSize,
633*27162e4eSAndroid Build Coastguard Worker size_t prefixSize);
634*27162e4eSAndroid Build Coastguard Worker
635*27162e4eSAndroid Build Coastguard Worker typedef struct {
636*27162e4eSAndroid Build Coastguard Worker TPool* wpool;
637*27162e4eSAndroid Build Coastguard Worker void* buffer;
638*27162e4eSAndroid Build Coastguard Worker size_t prefixSize;
639*27162e4eSAndroid Build Coastguard Worker size_t inSize;
640*27162e4eSAndroid Build Coastguard Worker unsigned long long blockNb;
641*27162e4eSAndroid Build Coastguard Worker compress_f compress;
642*27162e4eSAndroid Build Coastguard Worker const void* compressParameters;
643*27162e4eSAndroid Build Coastguard Worker FILE* fout;
644*27162e4eSAndroid Build Coastguard Worker WriteRegister* wr;
645*27162e4eSAndroid Build Coastguard Worker size_t maxCBlockSize;
646*27162e4eSAndroid Build Coastguard Worker int lastBlock;
647*27162e4eSAndroid Build Coastguard Worker } CompressJobDesc;
648*27162e4eSAndroid Build Coastguard Worker
LZ4IO_compressChunk(void * arg)649*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_compressChunk(void* arg)
650*27162e4eSAndroid Build Coastguard Worker {
651*27162e4eSAndroid Build Coastguard Worker CompressJobDesc* const cjd = (CompressJobDesc*)arg;
652*27162e4eSAndroid Build Coastguard Worker size_t const outCapacity = cjd->maxCBlockSize;
653*27162e4eSAndroid Build Coastguard Worker void* const out_buff = malloc(outCapacity);
654*27162e4eSAndroid Build Coastguard Worker if (!out_buff)
655*27162e4eSAndroid Build Coastguard Worker END_PROCESS(33, "Allocation error : can't allocate output buffer to compress new chunk");
656*27162e4eSAndroid Build Coastguard Worker { char* const inBuff = (char*)cjd->buffer + cjd->prefixSize;
657*27162e4eSAndroid Build Coastguard Worker size_t const cSize = cjd->compress(cjd->compressParameters, out_buff, outCapacity, inBuff, cjd->inSize, cjd->prefixSize);
658*27162e4eSAndroid Build Coastguard Worker
659*27162e4eSAndroid Build Coastguard Worker /* check for write */
660*27162e4eSAndroid Build Coastguard Worker { WriteJobDesc* const wjd = (WriteJobDesc*)malloc(sizeof(*wjd));
661*27162e4eSAndroid Build Coastguard Worker if (wjd == NULL) {
662*27162e4eSAndroid Build Coastguard Worker END_PROCESS(35, "Allocation error : can't describe new write job");
663*27162e4eSAndroid Build Coastguard Worker }
664*27162e4eSAndroid Build Coastguard Worker wjd->cBuf = out_buff;
665*27162e4eSAndroid Build Coastguard Worker wjd->cSize = (size_t)cSize;
666*27162e4eSAndroid Build Coastguard Worker wjd->blockNb = cjd->blockNb;
667*27162e4eSAndroid Build Coastguard Worker wjd->out = cjd->fout;
668*27162e4eSAndroid Build Coastguard Worker wjd->wr = cjd->wr;
669*27162e4eSAndroid Build Coastguard Worker TPool_submitJob(cjd->wpool, LZ4IO_checkWriteOrder, wjd);
670*27162e4eSAndroid Build Coastguard Worker } }
671*27162e4eSAndroid Build Coastguard Worker }
672*27162e4eSAndroid Build Coastguard Worker
LZ4IO_compressAndFreeChunk(void * arg)673*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_compressAndFreeChunk(void* arg)
674*27162e4eSAndroid Build Coastguard Worker {
675*27162e4eSAndroid Build Coastguard Worker CompressJobDesc* const cjd = (CompressJobDesc*)arg;
676*27162e4eSAndroid Build Coastguard Worker LZ4IO_compressChunk(arg);
677*27162e4eSAndroid Build Coastguard Worker /* clean up */
678*27162e4eSAndroid Build Coastguard Worker free(cjd->buffer);
679*27162e4eSAndroid Build Coastguard Worker free(cjd); /* because cjd is pod */
680*27162e4eSAndroid Build Coastguard Worker }
681*27162e4eSAndroid Build Coastguard Worker
682*27162e4eSAndroid Build Coastguard Worker /* one ReadTracker per file to compress */
683*27162e4eSAndroid Build Coastguard Worker typedef struct {
684*27162e4eSAndroid Build Coastguard Worker TPool* tPool;
685*27162e4eSAndroid Build Coastguard Worker TPool* wpool;
686*27162e4eSAndroid Build Coastguard Worker FILE* fin;
687*27162e4eSAndroid Build Coastguard Worker size_t chunkSize;
688*27162e4eSAndroid Build Coastguard Worker unsigned long long totalReadSize;
689*27162e4eSAndroid Build Coastguard Worker unsigned long long blockNb;
690*27162e4eSAndroid Build Coastguard Worker XXH32_state_t* xxh32;
691*27162e4eSAndroid Build Coastguard Worker compress_f compress;
692*27162e4eSAndroid Build Coastguard Worker const void* compressParameters;
693*27162e4eSAndroid Build Coastguard Worker void* prefix; /* if it exists, assumed to be filled with 64 KB */
694*27162e4eSAndroid Build Coastguard Worker FILE* fout;
695*27162e4eSAndroid Build Coastguard Worker WriteRegister* wr;
696*27162e4eSAndroid Build Coastguard Worker size_t maxCBlockSize;
697*27162e4eSAndroid Build Coastguard Worker } ReadTracker;
698*27162e4eSAndroid Build Coastguard Worker
LZ4IO_readAndProcess(void * arg)699*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_readAndProcess(void* arg)
700*27162e4eSAndroid Build Coastguard Worker {
701*27162e4eSAndroid Build Coastguard Worker ReadTracker* const rjd = (ReadTracker*)arg;
702*27162e4eSAndroid Build Coastguard Worker size_t const chunkSize = rjd->chunkSize;
703*27162e4eSAndroid Build Coastguard Worker size_t const prefixSize = (rjd->prefix != NULL) * 64 KB;
704*27162e4eSAndroid Build Coastguard Worker size_t const bufferSize = chunkSize + prefixSize;
705*27162e4eSAndroid Build Coastguard Worker void* const buffer = malloc(bufferSize);
706*27162e4eSAndroid Build Coastguard Worker if (!buffer)
707*27162e4eSAndroid Build Coastguard Worker END_PROCESS(31, "Allocation error : can't allocate buffer to read new chunk");
708*27162e4eSAndroid Build Coastguard Worker if (prefixSize) {
709*27162e4eSAndroid Build Coastguard Worker assert(prefixSize == 64 KB);
710*27162e4eSAndroid Build Coastguard Worker memcpy(buffer, rjd->prefix, prefixSize);
711*27162e4eSAndroid Build Coastguard Worker }
712*27162e4eSAndroid Build Coastguard Worker { char* const in_buff = (char*)buffer + prefixSize;
713*27162e4eSAndroid Build Coastguard Worker size_t const inSize = fread(in_buff, (size_t)1, chunkSize, rjd->fin);
714*27162e4eSAndroid Build Coastguard Worker if (inSize > chunkSize) {
715*27162e4eSAndroid Build Coastguard Worker END_PROCESS(32, "Read error (read %u > %u [chunk size])", (unsigned)inSize, (unsigned)chunkSize);
716*27162e4eSAndroid Build Coastguard Worker }
717*27162e4eSAndroid Build Coastguard Worker rjd->totalReadSize += inSize;
718*27162e4eSAndroid Build Coastguard Worker /* special case: nothing left: stop read operation */
719*27162e4eSAndroid Build Coastguard Worker if (inSize == 0) {
720*27162e4eSAndroid Build Coastguard Worker free(buffer);
721*27162e4eSAndroid Build Coastguard Worker return;
722*27162e4eSAndroid Build Coastguard Worker }
723*27162e4eSAndroid Build Coastguard Worker /* process read input */
724*27162e4eSAndroid Build Coastguard Worker { CompressJobDesc* const cjd = (CompressJobDesc*)malloc(sizeof(*cjd));
725*27162e4eSAndroid Build Coastguard Worker if (cjd==NULL) {
726*27162e4eSAndroid Build Coastguard Worker END_PROCESS(33, "Allocation error : can't describe new compression job");
727*27162e4eSAndroid Build Coastguard Worker }
728*27162e4eSAndroid Build Coastguard Worker if (rjd->xxh32) {
729*27162e4eSAndroid Build Coastguard Worker XXH32_update(rjd->xxh32, in_buff, inSize);
730*27162e4eSAndroid Build Coastguard Worker }
731*27162e4eSAndroid Build Coastguard Worker if (rjd->prefix) {
732*27162e4eSAndroid Build Coastguard Worker /* dependent blocks mode */
733*27162e4eSAndroid Build Coastguard Worker memcpy(rjd->prefix, in_buff + inSize - 64 KB, 64 KB);
734*27162e4eSAndroid Build Coastguard Worker }
735*27162e4eSAndroid Build Coastguard Worker cjd->wpool = rjd->wpool;
736*27162e4eSAndroid Build Coastguard Worker cjd->buffer = buffer; /* transfer ownership */
737*27162e4eSAndroid Build Coastguard Worker cjd->prefixSize = prefixSize;
738*27162e4eSAndroid Build Coastguard Worker cjd->inSize = inSize;
739*27162e4eSAndroid Build Coastguard Worker cjd->blockNb = rjd->blockNb;
740*27162e4eSAndroid Build Coastguard Worker cjd->compress = rjd->compress;
741*27162e4eSAndroid Build Coastguard Worker cjd->compressParameters = rjd->compressParameters;
742*27162e4eSAndroid Build Coastguard Worker cjd->fout = rjd->fout;
743*27162e4eSAndroid Build Coastguard Worker cjd->wr = rjd->wr;
744*27162e4eSAndroid Build Coastguard Worker cjd->maxCBlockSize = rjd->maxCBlockSize;
745*27162e4eSAndroid Build Coastguard Worker cjd->lastBlock = inSize < chunkSize;
746*27162e4eSAndroid Build Coastguard Worker TPool_submitJob(rjd->tPool, LZ4IO_compressAndFreeChunk, cjd);
747*27162e4eSAndroid Build Coastguard Worker if (inSize == chunkSize) {
748*27162e4eSAndroid Build Coastguard Worker /* likely more => read another chunk */
749*27162e4eSAndroid Build Coastguard Worker rjd->blockNb++;
750*27162e4eSAndroid Build Coastguard Worker TPool_submitJob(rjd->tPool, LZ4IO_readAndProcess, rjd);
751*27162e4eSAndroid Build Coastguard Worker } } }
752*27162e4eSAndroid Build Coastguard Worker }
753*27162e4eSAndroid Build Coastguard Worker
754*27162e4eSAndroid Build Coastguard Worker
755*27162e4eSAndroid Build Coastguard Worker /***************************************
756*27162e4eSAndroid Build Coastguard Worker * Legacy Compression
757*27162e4eSAndroid Build Coastguard Worker ***************************************/
758*27162e4eSAndroid Build Coastguard Worker
759*27162e4eSAndroid Build Coastguard Worker /* Size in bytes of a legacy block header in little-endian format */
760*27162e4eSAndroid Build Coastguard Worker #define LZ4IO_LEGACY_BLOCK_HEADER_SIZE 4
761*27162e4eSAndroid Build Coastguard Worker #define LZ4IO_LEGACY_BLOCK_SIZE_MAX (8 MB)
762*27162e4eSAndroid Build Coastguard Worker
763*27162e4eSAndroid Build Coastguard Worker /* unoptimized version; solves endianness & alignment issues */
LZ4IO_writeLE32(void * p,unsigned value32)764*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_writeLE32 (void* p, unsigned value32)
765*27162e4eSAndroid Build Coastguard Worker {
766*27162e4eSAndroid Build Coastguard Worker unsigned char* const dstPtr = (unsigned char*)p;
767*27162e4eSAndroid Build Coastguard Worker dstPtr[0] = (unsigned char)value32;
768*27162e4eSAndroid Build Coastguard Worker dstPtr[1] = (unsigned char)(value32 >> 8);
769*27162e4eSAndroid Build Coastguard Worker dstPtr[2] = (unsigned char)(value32 >> 16);
770*27162e4eSAndroid Build Coastguard Worker dstPtr[3] = (unsigned char)(value32 >> 24);
771*27162e4eSAndroid Build Coastguard Worker }
772*27162e4eSAndroid Build Coastguard Worker
773*27162e4eSAndroid Build Coastguard Worker
774*27162e4eSAndroid Build Coastguard Worker typedef struct {
775*27162e4eSAndroid Build Coastguard Worker int cLevel;
776*27162e4eSAndroid Build Coastguard Worker } CompressLegacyState;
777*27162e4eSAndroid Build Coastguard Worker
LZ4IO_compressBlockLegacy_fast(const void * params,void * dst,size_t dstCapacity,const void * src,size_t srcSize,size_t prefixSize)778*27162e4eSAndroid Build Coastguard Worker static size_t LZ4IO_compressBlockLegacy_fast(
779*27162e4eSAndroid Build Coastguard Worker const void* params,
780*27162e4eSAndroid Build Coastguard Worker void* dst,
781*27162e4eSAndroid Build Coastguard Worker size_t dstCapacity,
782*27162e4eSAndroid Build Coastguard Worker const void* src,
783*27162e4eSAndroid Build Coastguard Worker size_t srcSize,
784*27162e4eSAndroid Build Coastguard Worker size_t prefixSize
785*27162e4eSAndroid Build Coastguard Worker )
786*27162e4eSAndroid Build Coastguard Worker {
787*27162e4eSAndroid Build Coastguard Worker const CompressLegacyState* const clevel = (const CompressLegacyState*)params;
788*27162e4eSAndroid Build Coastguard Worker int const acceleration = (clevel->cLevel < 0) ? -clevel->cLevel : 0;
789*27162e4eSAndroid Build Coastguard Worker int const cSize = LZ4_compress_fast((const char*)src, (char*)dst + LZ4IO_LEGACY_BLOCK_HEADER_SIZE, (int)srcSize, (int)dstCapacity, acceleration);
790*27162e4eSAndroid Build Coastguard Worker if (cSize < 0)
791*27162e4eSAndroid Build Coastguard Worker END_PROCESS(51, "fast compression failed");
792*27162e4eSAndroid Build Coastguard Worker LZ4IO_writeLE32(dst, (unsigned)cSize);
793*27162e4eSAndroid Build Coastguard Worker assert(prefixSize == 0); (void)prefixSize;
794*27162e4eSAndroid Build Coastguard Worker return (size_t) cSize + LZ4IO_LEGACY_BLOCK_HEADER_SIZE;
795*27162e4eSAndroid Build Coastguard Worker }
796*27162e4eSAndroid Build Coastguard Worker
LZ4IO_compressBlockLegacy_HC(const void * params,void * dst,size_t dstCapacity,const void * src,size_t srcSize,size_t prefixSize)797*27162e4eSAndroid Build Coastguard Worker static size_t LZ4IO_compressBlockLegacy_HC(
798*27162e4eSAndroid Build Coastguard Worker const void* params,
799*27162e4eSAndroid Build Coastguard Worker void* dst,
800*27162e4eSAndroid Build Coastguard Worker size_t dstCapacity,
801*27162e4eSAndroid Build Coastguard Worker const void* src,
802*27162e4eSAndroid Build Coastguard Worker size_t srcSize,
803*27162e4eSAndroid Build Coastguard Worker size_t prefixSize
804*27162e4eSAndroid Build Coastguard Worker )
805*27162e4eSAndroid Build Coastguard Worker {
806*27162e4eSAndroid Build Coastguard Worker const CompressLegacyState* const cs = (const CompressLegacyState*)params;
807*27162e4eSAndroid Build Coastguard Worker int const clevel = cs->cLevel;
808*27162e4eSAndroid Build Coastguard Worker int const cSize = LZ4_compress_HC((const char*)src, (char*)dst + LZ4IO_LEGACY_BLOCK_HEADER_SIZE, (int)srcSize, (int)dstCapacity, clevel);
809*27162e4eSAndroid Build Coastguard Worker if (cSize < 0)
810*27162e4eSAndroid Build Coastguard Worker END_PROCESS(52, "HC compression failed");
811*27162e4eSAndroid Build Coastguard Worker LZ4IO_writeLE32(dst, (unsigned)cSize);
812*27162e4eSAndroid Build Coastguard Worker assert(prefixSize == 0); (void)prefixSize;
813*27162e4eSAndroid Build Coastguard Worker return (size_t) cSize + LZ4IO_LEGACY_BLOCK_HEADER_SIZE;
814*27162e4eSAndroid Build Coastguard Worker }
815*27162e4eSAndroid Build Coastguard Worker
816*27162e4eSAndroid Build Coastguard Worker /* LZ4IO_compressLegacy_internal :
817*27162e4eSAndroid Build Coastguard Worker * Implementation of LZ4IO_compressFilename_Legacy.
818*27162e4eSAndroid Build Coastguard Worker * @return: 0 if success, !0 if error
819*27162e4eSAndroid Build Coastguard Worker */
LZ4IO_compressLegacy_internal(unsigned long long * readSize,const char * input_filename,const char * output_filename,int compressionlevel,const LZ4IO_prefs_t * prefs)820*27162e4eSAndroid Build Coastguard Worker static int LZ4IO_compressLegacy_internal(unsigned long long* readSize,
821*27162e4eSAndroid Build Coastguard Worker const char* input_filename,
822*27162e4eSAndroid Build Coastguard Worker const char* output_filename,
823*27162e4eSAndroid Build Coastguard Worker int compressionlevel,
824*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* prefs)
825*27162e4eSAndroid Build Coastguard Worker {
826*27162e4eSAndroid Build Coastguard Worker int clResult = 0;
827*27162e4eSAndroid Build Coastguard Worker compress_f const compressionFunction = (compressionlevel < 3) ? LZ4IO_compressBlockLegacy_fast : LZ4IO_compressBlockLegacy_HC;
828*27162e4eSAndroid Build Coastguard Worker FILE* const finput = LZ4IO_openSrcFile(input_filename);
829*27162e4eSAndroid Build Coastguard Worker FILE* foutput = NULL;
830*27162e4eSAndroid Build Coastguard Worker TPool* const tPool = TPool_create(prefs->nbWorkers, 4);
831*27162e4eSAndroid Build Coastguard Worker TPool* const wPool = TPool_create(1, 4);
832*27162e4eSAndroid Build Coastguard Worker WriteRegister wr = WR_init(LEGACY_BLOCKSIZE);
833*27162e4eSAndroid Build Coastguard Worker
834*27162e4eSAndroid Build Coastguard Worker /* Init & checks */
835*27162e4eSAndroid Build Coastguard Worker *readSize = 0;
836*27162e4eSAndroid Build Coastguard Worker if (finput == NULL) {
837*27162e4eSAndroid Build Coastguard Worker /* read file error : recoverable */
838*27162e4eSAndroid Build Coastguard Worker clResult = 1;
839*27162e4eSAndroid Build Coastguard Worker goto _cfl_clean;
840*27162e4eSAndroid Build Coastguard Worker }
841*27162e4eSAndroid Build Coastguard Worker foutput = LZ4IO_openDstFile(output_filename, prefs);
842*27162e4eSAndroid Build Coastguard Worker if (foutput == NULL) {
843*27162e4eSAndroid Build Coastguard Worker /* write file error : recoverable */
844*27162e4eSAndroid Build Coastguard Worker clResult = 1;
845*27162e4eSAndroid Build Coastguard Worker goto _cfl_clean;
846*27162e4eSAndroid Build Coastguard Worker }
847*27162e4eSAndroid Build Coastguard Worker if (tPool == NULL || wPool == NULL)
848*27162e4eSAndroid Build Coastguard Worker END_PROCESS(21, "threadpool creation error ");
849*27162e4eSAndroid Build Coastguard Worker if (wr.buffers == NULL)
850*27162e4eSAndroid Build Coastguard Worker END_PROCESS(22, "can't allocate write register");
851*27162e4eSAndroid Build Coastguard Worker
852*27162e4eSAndroid Build Coastguard Worker
853*27162e4eSAndroid Build Coastguard Worker /* Write Archive Header */
854*27162e4eSAndroid Build Coastguard Worker { char outHeader[MAGICNUMBER_SIZE];
855*27162e4eSAndroid Build Coastguard Worker LZ4IO_writeLE32(outHeader, LEGACY_MAGICNUMBER);
856*27162e4eSAndroid Build Coastguard Worker if (fwrite(outHeader, 1, MAGICNUMBER_SIZE, foutput) != MAGICNUMBER_SIZE)
857*27162e4eSAndroid Build Coastguard Worker END_PROCESS(23, "Write error : cannot write header");
858*27162e4eSAndroid Build Coastguard Worker }
859*27162e4eSAndroid Build Coastguard Worker wr.totalCSize = MAGICNUMBER_SIZE;
860*27162e4eSAndroid Build Coastguard Worker
861*27162e4eSAndroid Build Coastguard Worker { CompressLegacyState cls;
862*27162e4eSAndroid Build Coastguard Worker ReadTracker rjd;
863*27162e4eSAndroid Build Coastguard Worker cls.cLevel = compressionlevel;
864*27162e4eSAndroid Build Coastguard Worker rjd.tPool = tPool;
865*27162e4eSAndroid Build Coastguard Worker rjd.wpool = wPool;
866*27162e4eSAndroid Build Coastguard Worker rjd.fin = finput;
867*27162e4eSAndroid Build Coastguard Worker rjd.chunkSize = LEGACY_BLOCKSIZE;
868*27162e4eSAndroid Build Coastguard Worker rjd.totalReadSize = 0;
869*27162e4eSAndroid Build Coastguard Worker rjd.blockNb = 0;
870*27162e4eSAndroid Build Coastguard Worker rjd.xxh32 = NULL;
871*27162e4eSAndroid Build Coastguard Worker rjd.compress = compressionFunction;
872*27162e4eSAndroid Build Coastguard Worker rjd.compressParameters = &cls;
873*27162e4eSAndroid Build Coastguard Worker rjd.prefix = NULL;
874*27162e4eSAndroid Build Coastguard Worker rjd.fout = foutput;
875*27162e4eSAndroid Build Coastguard Worker rjd.wr = ≀
876*27162e4eSAndroid Build Coastguard Worker rjd.maxCBlockSize = (size_t)LZ4_compressBound(LEGACY_BLOCKSIZE) + LZ4IO_LEGACY_BLOCK_HEADER_SIZE;
877*27162e4eSAndroid Build Coastguard Worker /* Ignite the job chain */
878*27162e4eSAndroid Build Coastguard Worker TPool_submitJob(tPool, LZ4IO_readAndProcess, &rjd);
879*27162e4eSAndroid Build Coastguard Worker /* Wait for all completion */
880*27162e4eSAndroid Build Coastguard Worker TPool_jobsCompleted(tPool);
881*27162e4eSAndroid Build Coastguard Worker TPool_jobsCompleted(wPool);
882*27162e4eSAndroid Build Coastguard Worker
883*27162e4eSAndroid Build Coastguard Worker /* Status */
884*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2, "\r%79s\r", ""); /* blank line */
885*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2,"Compressed %llu bytes into %llu bytes ==> %.2f%% \n",
886*27162e4eSAndroid Build Coastguard Worker rjd.totalReadSize, wr.totalCSize,
887*27162e4eSAndroid Build Coastguard Worker (double)wr.totalCSize / (double)(rjd.totalReadSize + !rjd.totalReadSize) * 100.);
888*27162e4eSAndroid Build Coastguard Worker *readSize = rjd.totalReadSize;
889*27162e4eSAndroid Build Coastguard Worker }
890*27162e4eSAndroid Build Coastguard Worker
891*27162e4eSAndroid Build Coastguard Worker /* Close & Free */
892*27162e4eSAndroid Build Coastguard Worker _cfl_clean:
893*27162e4eSAndroid Build Coastguard Worker WR_destroy(&wr);
894*27162e4eSAndroid Build Coastguard Worker TPool_free(wPool);
895*27162e4eSAndroid Build Coastguard Worker TPool_free(tPool);
896*27162e4eSAndroid Build Coastguard Worker if (finput) fclose(finput);
897*27162e4eSAndroid Build Coastguard Worker if (foutput && !LZ4IO_isStdout(output_filename)) fclose(foutput); /* do not close stdout */
898*27162e4eSAndroid Build Coastguard Worker
899*27162e4eSAndroid Build Coastguard Worker return clResult;
900*27162e4eSAndroid Build Coastguard Worker }
901*27162e4eSAndroid Build Coastguard Worker
902*27162e4eSAndroid Build Coastguard Worker /* LZ4IO_compressFilename_Legacy :
903*27162e4eSAndroid Build Coastguard Worker * This function is intentionally "hidden" (not published in .h)
904*27162e4eSAndroid Build Coastguard Worker * It generates compressed streams using the old 'legacy' format
905*27162e4eSAndroid Build Coastguard Worker * @return: 0 if success, !0 if error
906*27162e4eSAndroid Build Coastguard Worker */
LZ4IO_compressFilename_Legacy(const char * input_filename,const char * output_filename,int compressionlevel,const LZ4IO_prefs_t * prefs)907*27162e4eSAndroid Build Coastguard Worker int LZ4IO_compressFilename_Legacy(const char* input_filename,
908*27162e4eSAndroid Build Coastguard Worker const char* output_filename,
909*27162e4eSAndroid Build Coastguard Worker int compressionlevel,
910*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* prefs)
911*27162e4eSAndroid Build Coastguard Worker {
912*27162e4eSAndroid Build Coastguard Worker TIME_t const timeStart = TIME_getTime();
913*27162e4eSAndroid Build Coastguard Worker clock_t const cpuStart = clock();
914*27162e4eSAndroid Build Coastguard Worker unsigned long long processed = 0;
915*27162e4eSAndroid Build Coastguard Worker int r = LZ4IO_compressLegacy_internal(&processed, input_filename, output_filename, compressionlevel, prefs);
916*27162e4eSAndroid Build Coastguard Worker LZ4IO_finalTimeDisplay(timeStart, cpuStart, processed);
917*27162e4eSAndroid Build Coastguard Worker return r;
918*27162e4eSAndroid Build Coastguard Worker }
919*27162e4eSAndroid Build Coastguard Worker
920*27162e4eSAndroid Build Coastguard Worker #define FNSPACE 30
921*27162e4eSAndroid Build Coastguard Worker /* LZ4IO_compressMultipleFilenames_Legacy :
922*27162e4eSAndroid Build Coastguard Worker * This function is intentionally "hidden" (not published in .h)
923*27162e4eSAndroid Build Coastguard Worker * It generates multiple compressed streams using the old 'legacy' format */
LZ4IO_compressMultipleFilenames_Legacy(const char ** inFileNamesTable,int ifntSize,const char * suffix,int compressionLevel,const LZ4IO_prefs_t * prefs)924*27162e4eSAndroid Build Coastguard Worker int LZ4IO_compressMultipleFilenames_Legacy(
925*27162e4eSAndroid Build Coastguard Worker const char** inFileNamesTable, int ifntSize,
926*27162e4eSAndroid Build Coastguard Worker const char* suffix,
927*27162e4eSAndroid Build Coastguard Worker int compressionLevel, const LZ4IO_prefs_t* prefs)
928*27162e4eSAndroid Build Coastguard Worker {
929*27162e4eSAndroid Build Coastguard Worker TIME_t const timeStart = TIME_getTime();
930*27162e4eSAndroid Build Coastguard Worker clock_t const cpuStart = clock();
931*27162e4eSAndroid Build Coastguard Worker unsigned long long totalProcessed = 0;
932*27162e4eSAndroid Build Coastguard Worker int i;
933*27162e4eSAndroid Build Coastguard Worker int missed_files = 0;
934*27162e4eSAndroid Build Coastguard Worker char* dstFileName = (char*)malloc(FNSPACE);
935*27162e4eSAndroid Build Coastguard Worker size_t ofnSize = FNSPACE;
936*27162e4eSAndroid Build Coastguard Worker const size_t suffixSize = strlen(suffix);
937*27162e4eSAndroid Build Coastguard Worker
938*27162e4eSAndroid Build Coastguard Worker if (dstFileName == NULL) return ifntSize; /* not enough memory */
939*27162e4eSAndroid Build Coastguard Worker
940*27162e4eSAndroid Build Coastguard Worker /* loop on each file */
941*27162e4eSAndroid Build Coastguard Worker for (i=0; i<ifntSize; i++) {
942*27162e4eSAndroid Build Coastguard Worker unsigned long long processed = 0;
943*27162e4eSAndroid Build Coastguard Worker size_t const ifnSize = strlen(inFileNamesTable[i]);
944*27162e4eSAndroid Build Coastguard Worker if (LZ4IO_isStdout(suffix)) {
945*27162e4eSAndroid Build Coastguard Worker missed_files += LZ4IO_compressLegacy_internal(&processed,
946*27162e4eSAndroid Build Coastguard Worker inFileNamesTable[i], stdoutmark,
947*27162e4eSAndroid Build Coastguard Worker compressionLevel, prefs);
948*27162e4eSAndroid Build Coastguard Worker totalProcessed += processed;
949*27162e4eSAndroid Build Coastguard Worker continue;
950*27162e4eSAndroid Build Coastguard Worker }
951*27162e4eSAndroid Build Coastguard Worker
952*27162e4eSAndroid Build Coastguard Worker if (ofnSize <= ifnSize+suffixSize+1) {
953*27162e4eSAndroid Build Coastguard Worker free(dstFileName);
954*27162e4eSAndroid Build Coastguard Worker ofnSize = ifnSize + 20;
955*27162e4eSAndroid Build Coastguard Worker dstFileName = (char*)malloc(ofnSize);
956*27162e4eSAndroid Build Coastguard Worker if (dstFileName==NULL) {
957*27162e4eSAndroid Build Coastguard Worker return ifntSize;
958*27162e4eSAndroid Build Coastguard Worker } }
959*27162e4eSAndroid Build Coastguard Worker strcpy(dstFileName, inFileNamesTable[i]);
960*27162e4eSAndroid Build Coastguard Worker strcat(dstFileName, suffix);
961*27162e4eSAndroid Build Coastguard Worker
962*27162e4eSAndroid Build Coastguard Worker missed_files += LZ4IO_compressLegacy_internal(&processed,
963*27162e4eSAndroid Build Coastguard Worker inFileNamesTable[i], dstFileName,
964*27162e4eSAndroid Build Coastguard Worker compressionLevel, prefs);
965*27162e4eSAndroid Build Coastguard Worker totalProcessed += processed;
966*27162e4eSAndroid Build Coastguard Worker }
967*27162e4eSAndroid Build Coastguard Worker
968*27162e4eSAndroid Build Coastguard Worker /* Close & Free */
969*27162e4eSAndroid Build Coastguard Worker LZ4IO_finalTimeDisplay(timeStart, cpuStart, totalProcessed);
970*27162e4eSAndroid Build Coastguard Worker free(dstFileName);
971*27162e4eSAndroid Build Coastguard Worker
972*27162e4eSAndroid Build Coastguard Worker return missed_files;
973*27162e4eSAndroid Build Coastguard Worker }
974*27162e4eSAndroid Build Coastguard Worker
975*27162e4eSAndroid Build Coastguard Worker /*********************************************
976*27162e4eSAndroid Build Coastguard Worker * Compression using Frame format
977*27162e4eSAndroid Build Coastguard Worker *********************************************/
978*27162e4eSAndroid Build Coastguard Worker typedef struct {
979*27162e4eSAndroid Build Coastguard Worker void* srcBuffer;
980*27162e4eSAndroid Build Coastguard Worker size_t srcBufferSize;
981*27162e4eSAndroid Build Coastguard Worker void* dstBuffer;
982*27162e4eSAndroid Build Coastguard Worker size_t dstBufferSize;
983*27162e4eSAndroid Build Coastguard Worker LZ4F_compressionContext_t ctx;
984*27162e4eSAndroid Build Coastguard Worker LZ4F_preferences_t preparedPrefs;
985*27162e4eSAndroid Build Coastguard Worker LZ4F_CDict* cdict;
986*27162e4eSAndroid Build Coastguard Worker TPool* tPool;
987*27162e4eSAndroid Build Coastguard Worker TPool* wPool; /* writer thread */
988*27162e4eSAndroid Build Coastguard Worker } cRess_t;
989*27162e4eSAndroid Build Coastguard Worker
LZ4IO_freeCResources(cRess_t ress)990*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_freeCResources(cRess_t ress)
991*27162e4eSAndroid Build Coastguard Worker {
992*27162e4eSAndroid Build Coastguard Worker TPool_free(ress.tPool);
993*27162e4eSAndroid Build Coastguard Worker TPool_free(ress.wPool);
994*27162e4eSAndroid Build Coastguard Worker
995*27162e4eSAndroid Build Coastguard Worker free(ress.srcBuffer);
996*27162e4eSAndroid Build Coastguard Worker free(ress.dstBuffer);
997*27162e4eSAndroid Build Coastguard Worker
998*27162e4eSAndroid Build Coastguard Worker LZ4F_freeCDict(ress.cdict);
999*27162e4eSAndroid Build Coastguard Worker ress.cdict = NULL;
1000*27162e4eSAndroid Build Coastguard Worker
1001*27162e4eSAndroid Build Coastguard Worker { LZ4F_errorCode_t const errorCode = LZ4F_freeCompressionContext(ress.ctx);
1002*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(errorCode)) END_PROCESS(35, "Error : can't free LZ4F context resource : %s", LZ4F_getErrorName(errorCode)); }
1003*27162e4eSAndroid Build Coastguard Worker }
1004*27162e4eSAndroid Build Coastguard Worker
LZ4IO_createDict(size_t * dictSize,const char * dictFilename)1005*27162e4eSAndroid Build Coastguard Worker static void* LZ4IO_createDict(size_t* dictSize, const char* dictFilename)
1006*27162e4eSAndroid Build Coastguard Worker {
1007*27162e4eSAndroid Build Coastguard Worker size_t readSize;
1008*27162e4eSAndroid Build Coastguard Worker size_t dictEnd = 0;
1009*27162e4eSAndroid Build Coastguard Worker size_t dictLen = 0;
1010*27162e4eSAndroid Build Coastguard Worker size_t dictStart;
1011*27162e4eSAndroid Build Coastguard Worker size_t circularBufSize = LZ4_MAX_DICT_SIZE;
1012*27162e4eSAndroid Build Coastguard Worker char* circularBuf = (char*)malloc(circularBufSize);
1013*27162e4eSAndroid Build Coastguard Worker char* dictBuf;
1014*27162e4eSAndroid Build Coastguard Worker FILE* dictFile;
1015*27162e4eSAndroid Build Coastguard Worker
1016*27162e4eSAndroid Build Coastguard Worker if (!dictFilename)
1017*27162e4eSAndroid Build Coastguard Worker END_PROCESS(26, "Dictionary error : no filename provided");
1018*27162e4eSAndroid Build Coastguard Worker if (!circularBuf)
1019*27162e4eSAndroid Build Coastguard Worker END_PROCESS(25, "Allocation error : not enough memory for circular buffer");
1020*27162e4eSAndroid Build Coastguard Worker
1021*27162e4eSAndroid Build Coastguard Worker dictFile = LZ4IO_openSrcFile(dictFilename);
1022*27162e4eSAndroid Build Coastguard Worker if (!dictFile)
1023*27162e4eSAndroid Build Coastguard Worker END_PROCESS(27, "Dictionary error : could not open dictionary file");
1024*27162e4eSAndroid Build Coastguard Worker
1025*27162e4eSAndroid Build Coastguard Worker /* opportunistically seek to the part of the file we care about.
1026*27162e4eSAndroid Build Coastguard Worker * If this fails it's not a problem since we'll just read everything anyways. */
1027*27162e4eSAndroid Build Coastguard Worker if (!LZ4IO_isStdin(dictFilename)) {
1028*27162e4eSAndroid Build Coastguard Worker (void)UTIL_fseek(dictFile, -LZ4_MAX_DICT_SIZE, SEEK_END);
1029*27162e4eSAndroid Build Coastguard Worker }
1030*27162e4eSAndroid Build Coastguard Worker
1031*27162e4eSAndroid Build Coastguard Worker do {
1032*27162e4eSAndroid Build Coastguard Worker readSize = fread(circularBuf + dictEnd, 1, circularBufSize - dictEnd, dictFile);
1033*27162e4eSAndroid Build Coastguard Worker dictEnd = (dictEnd + readSize) % circularBufSize;
1034*27162e4eSAndroid Build Coastguard Worker dictLen += readSize;
1035*27162e4eSAndroid Build Coastguard Worker } while (readSize>0);
1036*27162e4eSAndroid Build Coastguard Worker
1037*27162e4eSAndroid Build Coastguard Worker if (dictLen > LZ4_MAX_DICT_SIZE) {
1038*27162e4eSAndroid Build Coastguard Worker dictLen = LZ4_MAX_DICT_SIZE;
1039*27162e4eSAndroid Build Coastguard Worker }
1040*27162e4eSAndroid Build Coastguard Worker
1041*27162e4eSAndroid Build Coastguard Worker *dictSize = dictLen;
1042*27162e4eSAndroid Build Coastguard Worker
1043*27162e4eSAndroid Build Coastguard Worker dictStart = (circularBufSize + dictEnd - dictLen) % circularBufSize;
1044*27162e4eSAndroid Build Coastguard Worker
1045*27162e4eSAndroid Build Coastguard Worker if (dictStart == 0) {
1046*27162e4eSAndroid Build Coastguard Worker /* We're in the simple case where the dict starts at the beginning of our circular buffer. */
1047*27162e4eSAndroid Build Coastguard Worker dictBuf = circularBuf;
1048*27162e4eSAndroid Build Coastguard Worker circularBuf = NULL;
1049*27162e4eSAndroid Build Coastguard Worker } else {
1050*27162e4eSAndroid Build Coastguard Worker /* Otherwise, we will alloc a new buffer and copy our dict into that. */
1051*27162e4eSAndroid Build Coastguard Worker dictBuf = (char *)malloc(dictLen ? dictLen : 1);
1052*27162e4eSAndroid Build Coastguard Worker if (!dictBuf) END_PROCESS(28, "Allocation error : not enough memory");
1053*27162e4eSAndroid Build Coastguard Worker
1054*27162e4eSAndroid Build Coastguard Worker memcpy(dictBuf, circularBuf + dictStart, circularBufSize - dictStart);
1055*27162e4eSAndroid Build Coastguard Worker memcpy(dictBuf + circularBufSize - dictStart, circularBuf, dictLen - (circularBufSize - dictStart));
1056*27162e4eSAndroid Build Coastguard Worker }
1057*27162e4eSAndroid Build Coastguard Worker
1058*27162e4eSAndroid Build Coastguard Worker fclose(dictFile);
1059*27162e4eSAndroid Build Coastguard Worker free(circularBuf);
1060*27162e4eSAndroid Build Coastguard Worker
1061*27162e4eSAndroid Build Coastguard Worker return dictBuf;
1062*27162e4eSAndroid Build Coastguard Worker }
1063*27162e4eSAndroid Build Coastguard Worker
LZ4IO_createCDict(const LZ4IO_prefs_t * io_prefs)1064*27162e4eSAndroid Build Coastguard Worker static LZ4F_CDict* LZ4IO_createCDict(const LZ4IO_prefs_t* io_prefs)
1065*27162e4eSAndroid Build Coastguard Worker {
1066*27162e4eSAndroid Build Coastguard Worker size_t dictionarySize;
1067*27162e4eSAndroid Build Coastguard Worker void* dictionaryBuffer;
1068*27162e4eSAndroid Build Coastguard Worker LZ4F_CDict* cdict;
1069*27162e4eSAndroid Build Coastguard Worker if (!io_prefs->useDictionary) return NULL;
1070*27162e4eSAndroid Build Coastguard Worker dictionaryBuffer = LZ4IO_createDict(&dictionarySize, io_prefs->dictionaryFilename);
1071*27162e4eSAndroid Build Coastguard Worker if (!dictionaryBuffer) END_PROCESS(29, "Dictionary error : could not create dictionary");
1072*27162e4eSAndroid Build Coastguard Worker cdict = LZ4F_createCDict(dictionaryBuffer, dictionarySize);
1073*27162e4eSAndroid Build Coastguard Worker free(dictionaryBuffer);
1074*27162e4eSAndroid Build Coastguard Worker return cdict;
1075*27162e4eSAndroid Build Coastguard Worker }
1076*27162e4eSAndroid Build Coastguard Worker
LZ4IO_createCResources(const LZ4IO_prefs_t * io_prefs)1077*27162e4eSAndroid Build Coastguard Worker static cRess_t LZ4IO_createCResources(const LZ4IO_prefs_t* io_prefs)
1078*27162e4eSAndroid Build Coastguard Worker {
1079*27162e4eSAndroid Build Coastguard Worker const size_t chunkSize = 4 MB;
1080*27162e4eSAndroid Build Coastguard Worker cRess_t ress;
1081*27162e4eSAndroid Build Coastguard Worker memset(&ress, 0, sizeof(ress));
1082*27162e4eSAndroid Build Coastguard Worker
1083*27162e4eSAndroid Build Coastguard Worker /* set compression advanced parameters */
1084*27162e4eSAndroid Build Coastguard Worker ress.preparedPrefs.autoFlush = 1;
1085*27162e4eSAndroid Build Coastguard Worker ress.preparedPrefs.frameInfo.blockMode = (LZ4F_blockMode_t)io_prefs->blockIndependence;
1086*27162e4eSAndroid Build Coastguard Worker ress.preparedPrefs.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)io_prefs->blockSizeId;
1087*27162e4eSAndroid Build Coastguard Worker ress.preparedPrefs.frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)io_prefs->blockChecksum;
1088*27162e4eSAndroid Build Coastguard Worker ress.preparedPrefs.frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)io_prefs->streamChecksum;
1089*27162e4eSAndroid Build Coastguard Worker ress.preparedPrefs.favorDecSpeed = io_prefs->favorDecSpeed;
1090*27162e4eSAndroid Build Coastguard Worker
1091*27162e4eSAndroid Build Coastguard Worker /* Allocate compression state */
1092*27162e4eSAndroid Build Coastguard Worker { LZ4F_errorCode_t const errorCode = LZ4F_createCompressionContext(&(ress.ctx), LZ4F_VERSION);
1093*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(errorCode))
1094*27162e4eSAndroid Build Coastguard Worker END_PROCESS(30, "Allocation error : can't create LZ4F context : %s", LZ4F_getErrorName(errorCode));
1095*27162e4eSAndroid Build Coastguard Worker }
1096*27162e4eSAndroid Build Coastguard Worker assert(ress.ctx != NULL);
1097*27162e4eSAndroid Build Coastguard Worker
1098*27162e4eSAndroid Build Coastguard Worker /* Allocate Buffers */
1099*27162e4eSAndroid Build Coastguard Worker ress.srcBuffer = malloc(chunkSize);
1100*27162e4eSAndroid Build Coastguard Worker ress.srcBufferSize = chunkSize;
1101*27162e4eSAndroid Build Coastguard Worker ress.dstBufferSize = LZ4F_compressFrameBound(chunkSize, &ress.preparedPrefs);
1102*27162e4eSAndroid Build Coastguard Worker ress.dstBuffer = malloc(ress.dstBufferSize);
1103*27162e4eSAndroid Build Coastguard Worker if (!ress.srcBuffer || !ress.dstBuffer)
1104*27162e4eSAndroid Build Coastguard Worker END_PROCESS(31, "Allocation error : can't allocate buffers");
1105*27162e4eSAndroid Build Coastguard Worker
1106*27162e4eSAndroid Build Coastguard Worker ress.cdict = LZ4IO_createCDict(io_prefs);
1107*27162e4eSAndroid Build Coastguard Worker
1108*27162e4eSAndroid Build Coastguard Worker /* will be created it needed */
1109*27162e4eSAndroid Build Coastguard Worker ress.tPool = NULL;
1110*27162e4eSAndroid Build Coastguard Worker ress.wPool = NULL;
1111*27162e4eSAndroid Build Coastguard Worker
1112*27162e4eSAndroid Build Coastguard Worker return ress;
1113*27162e4eSAndroid Build Coastguard Worker }
1114*27162e4eSAndroid Build Coastguard Worker
1115*27162e4eSAndroid Build Coastguard Worker typedef struct {
1116*27162e4eSAndroid Build Coastguard Worker const LZ4F_preferences_t* prefs;
1117*27162e4eSAndroid Build Coastguard Worker const LZ4F_CDict* cdict;
1118*27162e4eSAndroid Build Coastguard Worker } LZ4IO_CfcParameters;
1119*27162e4eSAndroid Build Coastguard Worker
LZ4IO_compressFrameChunk(const void * params,void * dst,size_t dstCapacity,const void * src,size_t srcSize,size_t prefixSize)1120*27162e4eSAndroid Build Coastguard Worker static size_t LZ4IO_compressFrameChunk(const void* params,
1121*27162e4eSAndroid Build Coastguard Worker void* dst, size_t dstCapacity,
1122*27162e4eSAndroid Build Coastguard Worker const void* src, size_t srcSize,
1123*27162e4eSAndroid Build Coastguard Worker size_t prefixSize)
1124*27162e4eSAndroid Build Coastguard Worker {
1125*27162e4eSAndroid Build Coastguard Worker const LZ4IO_CfcParameters* const cfcp = (const LZ4IO_CfcParameters*)params;
1126*27162e4eSAndroid Build Coastguard Worker LZ4F_cctx* cctx = NULL;
1127*27162e4eSAndroid Build Coastguard Worker { LZ4F_errorCode_t const ccr = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION);
1128*27162e4eSAndroid Build Coastguard Worker if (cctx==NULL || LZ4F_isError(ccr))
1129*27162e4eSAndroid Build Coastguard Worker END_PROCESS(51, "unable to create a LZ4F compression context");
1130*27162e4eSAndroid Build Coastguard Worker }
1131*27162e4eSAndroid Build Coastguard Worker /* init state, and writes frame header, will be overwritten at next stage. */
1132*27162e4eSAndroid Build Coastguard Worker if (prefixSize) {
1133*27162e4eSAndroid Build Coastguard Worker size_t const whr = LZ4F_compressBegin_usingDict(cctx, dst, dstCapacity, (const char*)src - prefixSize, prefixSize, cfcp->prefs);
1134*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(whr))
1135*27162e4eSAndroid Build Coastguard Worker END_PROCESS(52, "error initializing LZ4F compression context with prefix");
1136*27162e4eSAndroid Build Coastguard Worker assert(prefixSize == 64 KB);
1137*27162e4eSAndroid Build Coastguard Worker } else {
1138*27162e4eSAndroid Build Coastguard Worker size_t const whr = LZ4F_compressBegin_usingCDict(cctx, dst, dstCapacity, cfcp->cdict, cfcp->prefs);
1139*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(whr))
1140*27162e4eSAndroid Build Coastguard Worker END_PROCESS(53, "error initializing LZ4F compression context");
1141*27162e4eSAndroid Build Coastguard Worker }
1142*27162e4eSAndroid Build Coastguard Worker /* let's now compress, overwriting unused header */
1143*27162e4eSAndroid Build Coastguard Worker { size_t const cSize = LZ4F_compressUpdate(cctx, dst, dstCapacity, src, srcSize, NULL);
1144*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(cSize))
1145*27162e4eSAndroid Build Coastguard Worker END_PROCESS(55, "error compressing with LZ4F_compressUpdate");
1146*27162e4eSAndroid Build Coastguard Worker
1147*27162e4eSAndroid Build Coastguard Worker LZ4F_freeCompressionContext(cctx);
1148*27162e4eSAndroid Build Coastguard Worker return (size_t) cSize;
1149*27162e4eSAndroid Build Coastguard Worker }
1150*27162e4eSAndroid Build Coastguard Worker }
1151*27162e4eSAndroid Build Coastguard Worker
1152*27162e4eSAndroid Build Coastguard Worker /*
1153*27162e4eSAndroid Build Coastguard Worker * LZ4IO_compressFilename_extRess()
1154*27162e4eSAndroid Build Coastguard Worker * result : 0 : compression completed correctly
1155*27162e4eSAndroid Build Coastguard Worker * 1 : missing or pb opening srcFileName
1156*27162e4eSAndroid Build Coastguard Worker */
1157*27162e4eSAndroid Build Coastguard Worker int
LZ4IO_compressFilename_extRess_MT(unsigned long long * inStreamSize,cRess_t * ress,const char * srcFileName,const char * dstFileName,int compressionLevel,const LZ4IO_prefs_t * const io_prefs)1158*27162e4eSAndroid Build Coastguard Worker LZ4IO_compressFilename_extRess_MT(unsigned long long* inStreamSize,
1159*27162e4eSAndroid Build Coastguard Worker cRess_t* ress,
1160*27162e4eSAndroid Build Coastguard Worker const char* srcFileName, const char* dstFileName,
1161*27162e4eSAndroid Build Coastguard Worker int compressionLevel,
1162*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* const io_prefs)
1163*27162e4eSAndroid Build Coastguard Worker {
1164*27162e4eSAndroid Build Coastguard Worker unsigned long long filesize = 0;
1165*27162e4eSAndroid Build Coastguard Worker unsigned long long compressedfilesize = 0;
1166*27162e4eSAndroid Build Coastguard Worker FILE* dstFile;
1167*27162e4eSAndroid Build Coastguard Worker void* const srcBuffer = ress->srcBuffer;
1168*27162e4eSAndroid Build Coastguard Worker void* const dstBuffer = ress->dstBuffer;
1169*27162e4eSAndroid Build Coastguard Worker const size_t dstBufferSize = ress->dstBufferSize;
1170*27162e4eSAndroid Build Coastguard Worker const size_t chunkSize = 4 MB; /* each job should be "sufficiently large" */
1171*27162e4eSAndroid Build Coastguard Worker size_t readSize;
1172*27162e4eSAndroid Build Coastguard Worker LZ4F_compressionContext_t ctx = ress->ctx; /* just a pointer */
1173*27162e4eSAndroid Build Coastguard Worker LZ4F_preferences_t prefs;
1174*27162e4eSAndroid Build Coastguard Worker
1175*27162e4eSAndroid Build Coastguard Worker /* Init */
1176*27162e4eSAndroid Build Coastguard Worker FILE* const srcFile = LZ4IO_openSrcFile(srcFileName);
1177*27162e4eSAndroid Build Coastguard Worker if (srcFile == NULL) return 1;
1178*27162e4eSAndroid Build Coastguard Worker dstFile = LZ4IO_openDstFile(dstFileName, io_prefs);
1179*27162e4eSAndroid Build Coastguard Worker if (dstFile == NULL) { fclose(srcFile); return 1; }
1180*27162e4eSAndroid Build Coastguard Worker
1181*27162e4eSAndroid Build Coastguard Worker /* Adjust compression parameters */
1182*27162e4eSAndroid Build Coastguard Worker prefs = ress->preparedPrefs;
1183*27162e4eSAndroid Build Coastguard Worker prefs.compressionLevel = compressionLevel;
1184*27162e4eSAndroid Build Coastguard Worker if (io_prefs->contentSizeFlag) {
1185*27162e4eSAndroid Build Coastguard Worker U64 const fileSize = UTIL_getOpenFileSize(srcFile);
1186*27162e4eSAndroid Build Coastguard Worker prefs.frameInfo.contentSize = fileSize; /* == 0 if input == stdin */
1187*27162e4eSAndroid Build Coastguard Worker if (fileSize==0)
1188*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(3, "Warning : cannot determine input content size \n");
1189*27162e4eSAndroid Build Coastguard Worker }
1190*27162e4eSAndroid Build Coastguard Worker
1191*27162e4eSAndroid Build Coastguard Worker /* read first chunk */
1192*27162e4eSAndroid Build Coastguard Worker assert(chunkSize <= ress->srcBufferSize);
1193*27162e4eSAndroid Build Coastguard Worker readSize = fread(srcBuffer, (size_t)1, chunkSize, srcFile);
1194*27162e4eSAndroid Build Coastguard Worker if (ferror(srcFile))
1195*27162e4eSAndroid Build Coastguard Worker END_PROCESS(40, "Error reading first chunk (%u bytes) of '%s' ", (unsigned)chunkSize, srcFileName);
1196*27162e4eSAndroid Build Coastguard Worker filesize += readSize;
1197*27162e4eSAndroid Build Coastguard Worker
1198*27162e4eSAndroid Build Coastguard Worker /* single-block file */
1199*27162e4eSAndroid Build Coastguard Worker if (readSize < chunkSize) {
1200*27162e4eSAndroid Build Coastguard Worker /* Compress in single pass */
1201*27162e4eSAndroid Build Coastguard Worker size_t const cSize = LZ4F_compressFrame_usingCDict(ctx, dstBuffer, dstBufferSize, srcBuffer, readSize, ress->cdict, &prefs);
1202*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(cSize))
1203*27162e4eSAndroid Build Coastguard Worker END_PROCESS(41, "Compression failed : %s", LZ4F_getErrorName(cSize));
1204*27162e4eSAndroid Build Coastguard Worker compressedfilesize = cSize;
1205*27162e4eSAndroid Build Coastguard Worker DISPLAYUPDATE(2, "\rRead : %u MiB ==> %.2f%% ",
1206*27162e4eSAndroid Build Coastguard Worker (unsigned)(filesize>>20), (double)compressedfilesize/(double)(filesize+!filesize)*100); /* avoid division by zero */
1207*27162e4eSAndroid Build Coastguard Worker
1208*27162e4eSAndroid Build Coastguard Worker /* Write Block */
1209*27162e4eSAndroid Build Coastguard Worker if (fwrite(dstBuffer, 1, cSize, dstFile) != cSize) {
1210*27162e4eSAndroid Build Coastguard Worker END_PROCESS(42, "Write error : failed writing single-block compressed frame");
1211*27162e4eSAndroid Build Coastguard Worker } }
1212*27162e4eSAndroid Build Coastguard Worker
1213*27162e4eSAndroid Build Coastguard Worker else
1214*27162e4eSAndroid Build Coastguard Worker
1215*27162e4eSAndroid Build Coastguard Worker /* multiple-blocks file */
1216*27162e4eSAndroid Build Coastguard Worker { WriteRegister wr = WR_init(chunkSize);
1217*27162e4eSAndroid Build Coastguard Worker void* prefixBuffer = NULL;
1218*27162e4eSAndroid Build Coastguard Worker
1219*27162e4eSAndroid Build Coastguard Worker int checksum = (int)prefs.frameInfo.contentChecksumFlag;
1220*27162e4eSAndroid Build Coastguard Worker XXH32_state_t* xxh32 = NULL;
1221*27162e4eSAndroid Build Coastguard Worker
1222*27162e4eSAndroid Build Coastguard Worker LZ4IO_CfcParameters cfcp;
1223*27162e4eSAndroid Build Coastguard Worker ReadTracker rjd;
1224*27162e4eSAndroid Build Coastguard Worker
1225*27162e4eSAndroid Build Coastguard Worker if (ress->tPool == NULL) {
1226*27162e4eSAndroid Build Coastguard Worker ress->tPool = TPool_create(io_prefs->nbWorkers, 4);
1227*27162e4eSAndroid Build Coastguard Worker assert(ress->wPool == NULL);
1228*27162e4eSAndroid Build Coastguard Worker ress->wPool = TPool_create(1, 4);
1229*27162e4eSAndroid Build Coastguard Worker if (ress->tPool == NULL || ress->wPool == NULL)
1230*27162e4eSAndroid Build Coastguard Worker END_PROCESS(43, "can't create threadpools");
1231*27162e4eSAndroid Build Coastguard Worker }
1232*27162e4eSAndroid Build Coastguard Worker cfcp.prefs = &prefs;
1233*27162e4eSAndroid Build Coastguard Worker cfcp.cdict = ress->cdict;
1234*27162e4eSAndroid Build Coastguard Worker rjd.tPool = ress->tPool;
1235*27162e4eSAndroid Build Coastguard Worker rjd.wpool = ress->wPool;
1236*27162e4eSAndroid Build Coastguard Worker rjd.fin = srcFile;
1237*27162e4eSAndroid Build Coastguard Worker rjd.chunkSize = chunkSize;
1238*27162e4eSAndroid Build Coastguard Worker rjd.totalReadSize = 0;
1239*27162e4eSAndroid Build Coastguard Worker rjd.blockNb = 0;
1240*27162e4eSAndroid Build Coastguard Worker rjd.xxh32 = xxh32;
1241*27162e4eSAndroid Build Coastguard Worker rjd.compress = LZ4IO_compressFrameChunk;
1242*27162e4eSAndroid Build Coastguard Worker rjd.compressParameters = &cfcp;
1243*27162e4eSAndroid Build Coastguard Worker rjd.prefix = NULL;
1244*27162e4eSAndroid Build Coastguard Worker rjd.fout = dstFile;
1245*27162e4eSAndroid Build Coastguard Worker rjd.wr = ≀
1246*27162e4eSAndroid Build Coastguard Worker rjd.maxCBlockSize = LZ4F_compressFrameBound(chunkSize, &prefs);
1247*27162e4eSAndroid Build Coastguard Worker
1248*27162e4eSAndroid Build Coastguard Worker /* process frame checksum externally */
1249*27162e4eSAndroid Build Coastguard Worker if (checksum) {
1250*27162e4eSAndroid Build Coastguard Worker xxh32 = XXH32_createState();
1251*27162e4eSAndroid Build Coastguard Worker if (xxh32==NULL)
1252*27162e4eSAndroid Build Coastguard Worker END_PROCESS(42, "could not init checksum");
1253*27162e4eSAndroid Build Coastguard Worker XXH32_reset(xxh32, 0);
1254*27162e4eSAndroid Build Coastguard Worker XXH32_update(xxh32, srcBuffer, readSize);
1255*27162e4eSAndroid Build Coastguard Worker rjd.xxh32 = xxh32;
1256*27162e4eSAndroid Build Coastguard Worker }
1257*27162e4eSAndroid Build Coastguard Worker
1258*27162e4eSAndroid Build Coastguard Worker /* block dependency */
1259*27162e4eSAndroid Build Coastguard Worker if (prefs.frameInfo.blockMode == LZ4F_blockLinked) {
1260*27162e4eSAndroid Build Coastguard Worker prefixBuffer = malloc(64 KB);
1261*27162e4eSAndroid Build Coastguard Worker if (prefixBuffer==NULL)
1262*27162e4eSAndroid Build Coastguard Worker END_PROCESS(43, "cannot allocate small dictionary buffer");
1263*27162e4eSAndroid Build Coastguard Worker rjd.prefix = prefixBuffer;
1264*27162e4eSAndroid Build Coastguard Worker }
1265*27162e4eSAndroid Build Coastguard Worker
1266*27162e4eSAndroid Build Coastguard Worker /* Write Frame Header */
1267*27162e4eSAndroid Build Coastguard Worker /* note: simplification: do not employ dictionary when input size >= 4 MB,
1268*27162e4eSAndroid Build Coastguard Worker * the benefit is very limited anyway, and is not worth the dependency cost */
1269*27162e4eSAndroid Build Coastguard Worker { size_t const headerSize = LZ4F_compressBegin(ctx, dstBuffer, dstBufferSize, &prefs);
1270*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(headerSize))
1271*27162e4eSAndroid Build Coastguard Worker END_PROCESS(44, "File header generation failed : %s", LZ4F_getErrorName(headerSize));
1272*27162e4eSAndroid Build Coastguard Worker if (fwrite(dstBuffer, 1, headerSize, dstFile) != headerSize)
1273*27162e4eSAndroid Build Coastguard Worker END_PROCESS(45, "Write error : cannot write header");
1274*27162e4eSAndroid Build Coastguard Worker compressedfilesize = headerSize;
1275*27162e4eSAndroid Build Coastguard Worker }
1276*27162e4eSAndroid Build Coastguard Worker /* avoid duplicating effort to process content checksum (done externally) */
1277*27162e4eSAndroid Build Coastguard Worker prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
1278*27162e4eSAndroid Build Coastguard Worker
1279*27162e4eSAndroid Build Coastguard Worker /* process first block */
1280*27162e4eSAndroid Build Coastguard Worker { CompressJobDesc cjd;
1281*27162e4eSAndroid Build Coastguard Worker cjd.wpool = ress->wPool;
1282*27162e4eSAndroid Build Coastguard Worker cjd.buffer = srcBuffer;
1283*27162e4eSAndroid Build Coastguard Worker cjd.prefixSize = 0;
1284*27162e4eSAndroid Build Coastguard Worker cjd.inSize = readSize;
1285*27162e4eSAndroid Build Coastguard Worker cjd.blockNb = 0;
1286*27162e4eSAndroid Build Coastguard Worker cjd.compress = LZ4IO_compressFrameChunk;
1287*27162e4eSAndroid Build Coastguard Worker cjd.compressParameters = &cfcp;
1288*27162e4eSAndroid Build Coastguard Worker cjd.fout = dstFile;
1289*27162e4eSAndroid Build Coastguard Worker cjd.wr = ≀
1290*27162e4eSAndroid Build Coastguard Worker cjd.maxCBlockSize = rjd.maxCBlockSize;
1291*27162e4eSAndroid Build Coastguard Worker cjd.lastBlock = 0;
1292*27162e4eSAndroid Build Coastguard Worker TPool_submitJob(ress->tPool, LZ4IO_compressChunk, &cjd);
1293*27162e4eSAndroid Build Coastguard Worker rjd.totalReadSize = readSize;
1294*27162e4eSAndroid Build Coastguard Worker rjd.blockNb = 1;
1295*27162e4eSAndroid Build Coastguard Worker if (prefixBuffer) {
1296*27162e4eSAndroid Build Coastguard Worker assert(readSize >= 64 KB);
1297*27162e4eSAndroid Build Coastguard Worker memcpy(prefixBuffer, (char*)srcBuffer + readSize - 64 KB, 64 KB);
1298*27162e4eSAndroid Build Coastguard Worker }
1299*27162e4eSAndroid Build Coastguard Worker
1300*27162e4eSAndroid Build Coastguard Worker /* Start the job chain */
1301*27162e4eSAndroid Build Coastguard Worker TPool_submitJob(ress->tPool, LZ4IO_readAndProcess, &rjd);
1302*27162e4eSAndroid Build Coastguard Worker
1303*27162e4eSAndroid Build Coastguard Worker /* Wait for all completion */
1304*27162e4eSAndroid Build Coastguard Worker TPool_jobsCompleted(ress->tPool);
1305*27162e4eSAndroid Build Coastguard Worker TPool_jobsCompleted(ress->wPool);
1306*27162e4eSAndroid Build Coastguard Worker compressedfilesize += wr.totalCSize;
1307*27162e4eSAndroid Build Coastguard Worker }
1308*27162e4eSAndroid Build Coastguard Worker
1309*27162e4eSAndroid Build Coastguard Worker /* End of Frame mark */
1310*27162e4eSAndroid Build Coastguard Worker { size_t endSize = 4;
1311*27162e4eSAndroid Build Coastguard Worker assert(dstBufferSize >= 8);
1312*27162e4eSAndroid Build Coastguard Worker memset(dstBuffer, 0, 4);
1313*27162e4eSAndroid Build Coastguard Worker if (checksum) {
1314*27162e4eSAndroid Build Coastguard Worker /* handle frame checksum externally
1315*27162e4eSAndroid Build Coastguard Worker * note: LZ4F_compressEnd already wrote a (bogus) checksum */
1316*27162e4eSAndroid Build Coastguard Worker U32 const crc = XXH32_digest(xxh32);
1317*27162e4eSAndroid Build Coastguard Worker LZ4IO_writeLE32( (char*)dstBuffer + 4, crc);
1318*27162e4eSAndroid Build Coastguard Worker endSize = 8;
1319*27162e4eSAndroid Build Coastguard Worker }
1320*27162e4eSAndroid Build Coastguard Worker if (fwrite(dstBuffer, 1, endSize, dstFile) != endSize)
1321*27162e4eSAndroid Build Coastguard Worker END_PROCESS(49, "Write error : cannot write end of frame");
1322*27162e4eSAndroid Build Coastguard Worker compressedfilesize += endSize;
1323*27162e4eSAndroid Build Coastguard Worker filesize = rjd.totalReadSize;
1324*27162e4eSAndroid Build Coastguard Worker }
1325*27162e4eSAndroid Build Coastguard Worker
1326*27162e4eSAndroid Build Coastguard Worker /* clean up*/
1327*27162e4eSAndroid Build Coastguard Worker free(prefixBuffer);
1328*27162e4eSAndroid Build Coastguard Worker XXH32_freeState(xxh32);
1329*27162e4eSAndroid Build Coastguard Worker WR_destroy(&wr);
1330*27162e4eSAndroid Build Coastguard Worker }
1331*27162e4eSAndroid Build Coastguard Worker
1332*27162e4eSAndroid Build Coastguard Worker /* Release file handlers */
1333*27162e4eSAndroid Build Coastguard Worker fclose (srcFile);
1334*27162e4eSAndroid Build Coastguard Worker if (!LZ4IO_isStdout(dstFileName)) fclose(dstFile); /* do not close stdout */
1335*27162e4eSAndroid Build Coastguard Worker
1336*27162e4eSAndroid Build Coastguard Worker /* Copy owner, file permissions and modification time */
1337*27162e4eSAndroid Build Coastguard Worker { stat_t statbuf;
1338*27162e4eSAndroid Build Coastguard Worker if (!LZ4IO_isStdin(srcFileName)
1339*27162e4eSAndroid Build Coastguard Worker && !LZ4IO_isStdout(dstFileName)
1340*27162e4eSAndroid Build Coastguard Worker && !LZ4IO_isDevNull(dstFileName)
1341*27162e4eSAndroid Build Coastguard Worker && UTIL_getFileStat(srcFileName, &statbuf)) {
1342*27162e4eSAndroid Build Coastguard Worker UTIL_setFileStat(dstFileName, &statbuf);
1343*27162e4eSAndroid Build Coastguard Worker } }
1344*27162e4eSAndroid Build Coastguard Worker
1345*27162e4eSAndroid Build Coastguard Worker if (io_prefs->removeSrcFile) { /* remove source file : --rm */
1346*27162e4eSAndroid Build Coastguard Worker if (remove(srcFileName))
1347*27162e4eSAndroid Build Coastguard Worker END_PROCESS(50, "Remove error : %s: %s", srcFileName, strerror(errno));
1348*27162e4eSAndroid Build Coastguard Worker }
1349*27162e4eSAndroid Build Coastguard Worker
1350*27162e4eSAndroid Build Coastguard Worker /* Final Status */
1351*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2, "\r%79s\r", "");
1352*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2, "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",
1353*27162e4eSAndroid Build Coastguard Worker filesize, compressedfilesize,
1354*27162e4eSAndroid Build Coastguard Worker (double)compressedfilesize / (double)(filesize + !filesize /* avoid division by zero */ ) * 100.);
1355*27162e4eSAndroid Build Coastguard Worker *inStreamSize = filesize;
1356*27162e4eSAndroid Build Coastguard Worker
1357*27162e4eSAndroid Build Coastguard Worker return 0;
1358*27162e4eSAndroid Build Coastguard Worker }
1359*27162e4eSAndroid Build Coastguard Worker
1360*27162e4eSAndroid Build Coastguard Worker /*
1361*27162e4eSAndroid Build Coastguard Worker * LZ4IO_compressFilename_extRess()
1362*27162e4eSAndroid Build Coastguard Worker * result : 0 : compression completed correctly
1363*27162e4eSAndroid Build Coastguard Worker * 1 : missing or pb opening srcFileName
1364*27162e4eSAndroid Build Coastguard Worker */
1365*27162e4eSAndroid Build Coastguard Worker int
LZ4IO_compressFilename_extRess_ST(unsigned long long * inStreamSize,const cRess_t * ress,const char * srcFileName,const char * dstFileName,int compressionLevel,const LZ4IO_prefs_t * const io_prefs)1366*27162e4eSAndroid Build Coastguard Worker LZ4IO_compressFilename_extRess_ST(unsigned long long* inStreamSize,
1367*27162e4eSAndroid Build Coastguard Worker const cRess_t* ress,
1368*27162e4eSAndroid Build Coastguard Worker const char* srcFileName, const char* dstFileName,
1369*27162e4eSAndroid Build Coastguard Worker int compressionLevel,
1370*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* const io_prefs)
1371*27162e4eSAndroid Build Coastguard Worker {
1372*27162e4eSAndroid Build Coastguard Worker unsigned long long filesize = 0;
1373*27162e4eSAndroid Build Coastguard Worker unsigned long long compressedfilesize = 0;
1374*27162e4eSAndroid Build Coastguard Worker FILE* dstFile;
1375*27162e4eSAndroid Build Coastguard Worker void* const srcBuffer = ress->srcBuffer;
1376*27162e4eSAndroid Build Coastguard Worker void* const dstBuffer = ress->dstBuffer;
1377*27162e4eSAndroid Build Coastguard Worker const size_t dstBufferSize = ress->dstBufferSize;
1378*27162e4eSAndroid Build Coastguard Worker const size_t blockSize = io_prefs->blockSize;
1379*27162e4eSAndroid Build Coastguard Worker size_t readSize;
1380*27162e4eSAndroid Build Coastguard Worker LZ4F_compressionContext_t ctx = ress->ctx; /* just a pointer */
1381*27162e4eSAndroid Build Coastguard Worker LZ4F_preferences_t prefs;
1382*27162e4eSAndroid Build Coastguard Worker
1383*27162e4eSAndroid Build Coastguard Worker /* Init */
1384*27162e4eSAndroid Build Coastguard Worker FILE* const srcFile = LZ4IO_openSrcFile(srcFileName);
1385*27162e4eSAndroid Build Coastguard Worker if (srcFile == NULL) return 1;
1386*27162e4eSAndroid Build Coastguard Worker dstFile = LZ4IO_openDstFile(dstFileName, io_prefs);
1387*27162e4eSAndroid Build Coastguard Worker if (dstFile == NULL) { fclose(srcFile); return 1; }
1388*27162e4eSAndroid Build Coastguard Worker memset(&prefs, 0, sizeof(prefs));
1389*27162e4eSAndroid Build Coastguard Worker
1390*27162e4eSAndroid Build Coastguard Worker /* Adjust compression parameters */
1391*27162e4eSAndroid Build Coastguard Worker prefs = ress->preparedPrefs;
1392*27162e4eSAndroid Build Coastguard Worker prefs.compressionLevel = compressionLevel;
1393*27162e4eSAndroid Build Coastguard Worker if (io_prefs->contentSizeFlag) {
1394*27162e4eSAndroid Build Coastguard Worker U64 const fileSize = UTIL_getOpenFileSize(srcFile);
1395*27162e4eSAndroid Build Coastguard Worker prefs.frameInfo.contentSize = fileSize; /* == 0 if input == stdin */
1396*27162e4eSAndroid Build Coastguard Worker if (fileSize==0)
1397*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(3, "Warning : cannot determine input content size \n");
1398*27162e4eSAndroid Build Coastguard Worker }
1399*27162e4eSAndroid Build Coastguard Worker
1400*27162e4eSAndroid Build Coastguard Worker /* read first block */
1401*27162e4eSAndroid Build Coastguard Worker readSize = fread(srcBuffer, (size_t)1, blockSize, srcFile);
1402*27162e4eSAndroid Build Coastguard Worker if (ferror(srcFile)) END_PROCESS(40, "Error reading %s ", srcFileName);
1403*27162e4eSAndroid Build Coastguard Worker filesize += readSize;
1404*27162e4eSAndroid Build Coastguard Worker
1405*27162e4eSAndroid Build Coastguard Worker /* single-block file */
1406*27162e4eSAndroid Build Coastguard Worker if (readSize < blockSize) {
1407*27162e4eSAndroid Build Coastguard Worker /* Compress in single pass */
1408*27162e4eSAndroid Build Coastguard Worker size_t const cSize = LZ4F_compressFrame_usingCDict(ctx, dstBuffer, dstBufferSize, srcBuffer, readSize, ress->cdict, &prefs);
1409*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(cSize))
1410*27162e4eSAndroid Build Coastguard Worker END_PROCESS(41, "Compression failed : %s", LZ4F_getErrorName(cSize));
1411*27162e4eSAndroid Build Coastguard Worker compressedfilesize = cSize;
1412*27162e4eSAndroid Build Coastguard Worker DISPLAYUPDATE(2, "\rRead : %u MiB ==> %.2f%% ",
1413*27162e4eSAndroid Build Coastguard Worker (unsigned)(filesize>>20), (double)compressedfilesize/(double)(filesize+!filesize)*100); /* avoid division by zero */
1414*27162e4eSAndroid Build Coastguard Worker
1415*27162e4eSAndroid Build Coastguard Worker /* Write Block */
1416*27162e4eSAndroid Build Coastguard Worker if (fwrite(dstBuffer, 1, cSize, dstFile) != cSize) {
1417*27162e4eSAndroid Build Coastguard Worker END_PROCESS(42, "Write error : failed writing single-block compressed frame");
1418*27162e4eSAndroid Build Coastguard Worker } }
1419*27162e4eSAndroid Build Coastguard Worker
1420*27162e4eSAndroid Build Coastguard Worker else
1421*27162e4eSAndroid Build Coastguard Worker
1422*27162e4eSAndroid Build Coastguard Worker /* multiple-blocks file */
1423*27162e4eSAndroid Build Coastguard Worker {
1424*27162e4eSAndroid Build Coastguard Worker /* Write Frame Header */
1425*27162e4eSAndroid Build Coastguard Worker size_t const headerSize = LZ4F_compressBegin_usingCDict(ctx, dstBuffer, dstBufferSize, ress->cdict, &prefs);
1426*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(headerSize))
1427*27162e4eSAndroid Build Coastguard Worker END_PROCESS(43, "File header generation failed : %s", LZ4F_getErrorName(headerSize));
1428*27162e4eSAndroid Build Coastguard Worker if (fwrite(dstBuffer, 1, headerSize, dstFile) != headerSize)
1429*27162e4eSAndroid Build Coastguard Worker END_PROCESS(44, "Write error : cannot write header");
1430*27162e4eSAndroid Build Coastguard Worker compressedfilesize += headerSize;
1431*27162e4eSAndroid Build Coastguard Worker
1432*27162e4eSAndroid Build Coastguard Worker /* Main Loop - one block at a time */
1433*27162e4eSAndroid Build Coastguard Worker while (readSize>0) {
1434*27162e4eSAndroid Build Coastguard Worker size_t const outSize = LZ4F_compressUpdate(ctx, dstBuffer, dstBufferSize, srcBuffer, readSize, NULL);
1435*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(outSize))
1436*27162e4eSAndroid Build Coastguard Worker END_PROCESS(45, "Compression failed : %s", LZ4F_getErrorName(outSize));
1437*27162e4eSAndroid Build Coastguard Worker compressedfilesize += outSize;
1438*27162e4eSAndroid Build Coastguard Worker DISPLAYUPDATE(2, "\rRead : %u MiB ==> %.2f%% ",
1439*27162e4eSAndroid Build Coastguard Worker (unsigned)(filesize>>20),
1440*27162e4eSAndroid Build Coastguard Worker (double)compressedfilesize / (double)filesize * 100.);
1441*27162e4eSAndroid Build Coastguard Worker
1442*27162e4eSAndroid Build Coastguard Worker /* Write Block */
1443*27162e4eSAndroid Build Coastguard Worker if (fwrite(dstBuffer, 1, outSize, dstFile) != outSize)
1444*27162e4eSAndroid Build Coastguard Worker END_PROCESS(46, "Write error : cannot write compressed block");
1445*27162e4eSAndroid Build Coastguard Worker
1446*27162e4eSAndroid Build Coastguard Worker /* Read next block */
1447*27162e4eSAndroid Build Coastguard Worker readSize = fread(srcBuffer, (size_t)1, (size_t)blockSize, srcFile);
1448*27162e4eSAndroid Build Coastguard Worker filesize += readSize;
1449*27162e4eSAndroid Build Coastguard Worker }
1450*27162e4eSAndroid Build Coastguard Worker if (ferror(srcFile)) END_PROCESS(47, "Error reading %s ", srcFileName);
1451*27162e4eSAndroid Build Coastguard Worker
1452*27162e4eSAndroid Build Coastguard Worker /* End of Frame mark */
1453*27162e4eSAndroid Build Coastguard Worker { size_t const endSize = LZ4F_compressEnd(ctx, dstBuffer, dstBufferSize, NULL);
1454*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(endSize))
1455*27162e4eSAndroid Build Coastguard Worker END_PROCESS(48, "End of frame error : %s", LZ4F_getErrorName(endSize));
1456*27162e4eSAndroid Build Coastguard Worker if (fwrite(dstBuffer, 1, endSize, dstFile) != endSize)
1457*27162e4eSAndroid Build Coastguard Worker END_PROCESS(49, "Write error : cannot write end of frame");
1458*27162e4eSAndroid Build Coastguard Worker compressedfilesize += endSize;
1459*27162e4eSAndroid Build Coastguard Worker }
1460*27162e4eSAndroid Build Coastguard Worker }
1461*27162e4eSAndroid Build Coastguard Worker
1462*27162e4eSAndroid Build Coastguard Worker /* Release file handlers */
1463*27162e4eSAndroid Build Coastguard Worker fclose (srcFile);
1464*27162e4eSAndroid Build Coastguard Worker if (!LZ4IO_isStdout(dstFileName)) fclose(dstFile); /* do not close stdout */
1465*27162e4eSAndroid Build Coastguard Worker
1466*27162e4eSAndroid Build Coastguard Worker /* Copy owner, file permissions and modification time */
1467*27162e4eSAndroid Build Coastguard Worker { stat_t statbuf;
1468*27162e4eSAndroid Build Coastguard Worker if (!LZ4IO_isStdin(srcFileName)
1469*27162e4eSAndroid Build Coastguard Worker && !LZ4IO_isStdout(dstFileName)
1470*27162e4eSAndroid Build Coastguard Worker && !LZ4IO_isDevNull(dstFileName)
1471*27162e4eSAndroid Build Coastguard Worker && UTIL_getFileStat(srcFileName, &statbuf)) {
1472*27162e4eSAndroid Build Coastguard Worker UTIL_setFileStat(dstFileName, &statbuf);
1473*27162e4eSAndroid Build Coastguard Worker } }
1474*27162e4eSAndroid Build Coastguard Worker
1475*27162e4eSAndroid Build Coastguard Worker if (io_prefs->removeSrcFile) { /* remove source file : --rm */
1476*27162e4eSAndroid Build Coastguard Worker if (remove(srcFileName))
1477*27162e4eSAndroid Build Coastguard Worker END_PROCESS(50, "Remove error : %s: %s", srcFileName, strerror(errno));
1478*27162e4eSAndroid Build Coastguard Worker }
1479*27162e4eSAndroid Build Coastguard Worker
1480*27162e4eSAndroid Build Coastguard Worker /* Final Status */
1481*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2, "\r%79s\r", "");
1482*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2, "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",
1483*27162e4eSAndroid Build Coastguard Worker filesize, compressedfilesize,
1484*27162e4eSAndroid Build Coastguard Worker (double)compressedfilesize / (double)(filesize + !filesize /* avoid division by zero */ ) * 100.);
1485*27162e4eSAndroid Build Coastguard Worker *inStreamSize = filesize;
1486*27162e4eSAndroid Build Coastguard Worker
1487*27162e4eSAndroid Build Coastguard Worker return 0;
1488*27162e4eSAndroid Build Coastguard Worker }
1489*27162e4eSAndroid Build Coastguard Worker
1490*27162e4eSAndroid Build Coastguard Worker static int
LZ4IO_compressFilename_extRess(unsigned long long * inStreamSize,cRess_t * ress,const char * srcFileName,const char * dstFileName,int compressionLevel,const LZ4IO_prefs_t * const io_prefs)1491*27162e4eSAndroid Build Coastguard Worker LZ4IO_compressFilename_extRess(unsigned long long* inStreamSize,
1492*27162e4eSAndroid Build Coastguard Worker cRess_t* ress,
1493*27162e4eSAndroid Build Coastguard Worker const char* srcFileName, const char* dstFileName,
1494*27162e4eSAndroid Build Coastguard Worker int compressionLevel,
1495*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* const io_prefs)
1496*27162e4eSAndroid Build Coastguard Worker {
1497*27162e4eSAndroid Build Coastguard Worker if (LZ4IO_MULTITHREAD)
1498*27162e4eSAndroid Build Coastguard Worker return LZ4IO_compressFilename_extRess_MT(inStreamSize, ress, srcFileName, dstFileName, compressionLevel, io_prefs);
1499*27162e4eSAndroid Build Coastguard Worker /* Only single-thread available */
1500*27162e4eSAndroid Build Coastguard Worker return LZ4IO_compressFilename_extRess_ST(inStreamSize, ress, srcFileName, dstFileName, compressionLevel, io_prefs);
1501*27162e4eSAndroid Build Coastguard Worker }
1502*27162e4eSAndroid Build Coastguard Worker
LZ4IO_compressFilename(const char * srcFileName,const char * dstFileName,int compressionLevel,const LZ4IO_prefs_t * prefs)1503*27162e4eSAndroid Build Coastguard Worker int LZ4IO_compressFilename(const char* srcFileName, const char* dstFileName, int compressionLevel, const LZ4IO_prefs_t* prefs)
1504*27162e4eSAndroid Build Coastguard Worker {
1505*27162e4eSAndroid Build Coastguard Worker TIME_t const timeStart = TIME_getTime();
1506*27162e4eSAndroid Build Coastguard Worker clock_t const cpuStart = clock();
1507*27162e4eSAndroid Build Coastguard Worker cRess_t ress = LZ4IO_createCResources(prefs);
1508*27162e4eSAndroid Build Coastguard Worker unsigned long long processed;
1509*27162e4eSAndroid Build Coastguard Worker
1510*27162e4eSAndroid Build Coastguard Worker int const result = LZ4IO_compressFilename_extRess(&processed, &ress, srcFileName, dstFileName, compressionLevel, prefs);
1511*27162e4eSAndroid Build Coastguard Worker
1512*27162e4eSAndroid Build Coastguard Worker /* Free resources */
1513*27162e4eSAndroid Build Coastguard Worker LZ4IO_freeCResources(ress);
1514*27162e4eSAndroid Build Coastguard Worker
1515*27162e4eSAndroid Build Coastguard Worker /* Final Status */
1516*27162e4eSAndroid Build Coastguard Worker LZ4IO_finalTimeDisplay(timeStart, cpuStart, processed);
1517*27162e4eSAndroid Build Coastguard Worker
1518*27162e4eSAndroid Build Coastguard Worker return result;
1519*27162e4eSAndroid Build Coastguard Worker }
1520*27162e4eSAndroid Build Coastguard Worker
LZ4IO_compressMultipleFilenames(const char ** inFileNamesTable,int ifntSize,const char * suffix,int compressionLevel,const LZ4IO_prefs_t * prefs)1521*27162e4eSAndroid Build Coastguard Worker int LZ4IO_compressMultipleFilenames(
1522*27162e4eSAndroid Build Coastguard Worker const char** inFileNamesTable, int ifntSize,
1523*27162e4eSAndroid Build Coastguard Worker const char* suffix,
1524*27162e4eSAndroid Build Coastguard Worker int compressionLevel,
1525*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* prefs)
1526*27162e4eSAndroid Build Coastguard Worker {
1527*27162e4eSAndroid Build Coastguard Worker int i;
1528*27162e4eSAndroid Build Coastguard Worker int missed_files = 0;
1529*27162e4eSAndroid Build Coastguard Worker char* dstFileName = (char*)malloc(FNSPACE);
1530*27162e4eSAndroid Build Coastguard Worker size_t ofnSize = FNSPACE;
1531*27162e4eSAndroid Build Coastguard Worker const size_t suffixSize = strlen(suffix);
1532*27162e4eSAndroid Build Coastguard Worker cRess_t ress;
1533*27162e4eSAndroid Build Coastguard Worker unsigned long long totalProcessed = 0;
1534*27162e4eSAndroid Build Coastguard Worker TIME_t timeStart = TIME_getTime();
1535*27162e4eSAndroid Build Coastguard Worker clock_t cpuStart = clock();
1536*27162e4eSAndroid Build Coastguard Worker
1537*27162e4eSAndroid Build Coastguard Worker if (dstFileName == NULL) return ifntSize; /* not enough memory */
1538*27162e4eSAndroid Build Coastguard Worker ress = LZ4IO_createCResources(prefs);
1539*27162e4eSAndroid Build Coastguard Worker
1540*27162e4eSAndroid Build Coastguard Worker /* loop on each file */
1541*27162e4eSAndroid Build Coastguard Worker for (i=0; i<ifntSize; i++) {
1542*27162e4eSAndroid Build Coastguard Worker unsigned long long processed;
1543*27162e4eSAndroid Build Coastguard Worker size_t const ifnSize = strlen(inFileNamesTable[i]);
1544*27162e4eSAndroid Build Coastguard Worker if (LZ4IO_isStdout(suffix)) {
1545*27162e4eSAndroid Build Coastguard Worker missed_files += LZ4IO_compressFilename_extRess(&processed, &ress,
1546*27162e4eSAndroid Build Coastguard Worker inFileNamesTable[i], stdoutmark,
1547*27162e4eSAndroid Build Coastguard Worker compressionLevel, prefs);
1548*27162e4eSAndroid Build Coastguard Worker totalProcessed += processed;
1549*27162e4eSAndroid Build Coastguard Worker continue;
1550*27162e4eSAndroid Build Coastguard Worker }
1551*27162e4eSAndroid Build Coastguard Worker /* suffix != stdout => compress into a file => generate its name */
1552*27162e4eSAndroid Build Coastguard Worker if (ofnSize <= ifnSize+suffixSize+1) {
1553*27162e4eSAndroid Build Coastguard Worker free(dstFileName);
1554*27162e4eSAndroid Build Coastguard Worker ofnSize = ifnSize + 20;
1555*27162e4eSAndroid Build Coastguard Worker dstFileName = (char*)malloc(ofnSize);
1556*27162e4eSAndroid Build Coastguard Worker if (dstFileName==NULL) {
1557*27162e4eSAndroid Build Coastguard Worker LZ4IO_freeCResources(ress);
1558*27162e4eSAndroid Build Coastguard Worker return ifntSize;
1559*27162e4eSAndroid Build Coastguard Worker } }
1560*27162e4eSAndroid Build Coastguard Worker strcpy(dstFileName, inFileNamesTable[i]);
1561*27162e4eSAndroid Build Coastguard Worker strcat(dstFileName, suffix);
1562*27162e4eSAndroid Build Coastguard Worker
1563*27162e4eSAndroid Build Coastguard Worker missed_files += LZ4IO_compressFilename_extRess(&processed, &ress,
1564*27162e4eSAndroid Build Coastguard Worker inFileNamesTable[i], dstFileName,
1565*27162e4eSAndroid Build Coastguard Worker compressionLevel, prefs);
1566*27162e4eSAndroid Build Coastguard Worker totalProcessed += processed;
1567*27162e4eSAndroid Build Coastguard Worker }
1568*27162e4eSAndroid Build Coastguard Worker
1569*27162e4eSAndroid Build Coastguard Worker /* Close & Free */
1570*27162e4eSAndroid Build Coastguard Worker LZ4IO_freeCResources(ress);
1571*27162e4eSAndroid Build Coastguard Worker free(dstFileName);
1572*27162e4eSAndroid Build Coastguard Worker LZ4IO_finalTimeDisplay(timeStart, cpuStart, totalProcessed);
1573*27162e4eSAndroid Build Coastguard Worker
1574*27162e4eSAndroid Build Coastguard Worker return missed_files;
1575*27162e4eSAndroid Build Coastguard Worker }
1576*27162e4eSAndroid Build Coastguard Worker
1577*27162e4eSAndroid Build Coastguard Worker
1578*27162e4eSAndroid Build Coastguard Worker /* ********************************************************************* */
1579*27162e4eSAndroid Build Coastguard Worker /* ********************** LZ4 file-stream Decompression **************** */
1580*27162e4eSAndroid Build Coastguard Worker /* ********************************************************************* */
1581*27162e4eSAndroid Build Coastguard Worker
1582*27162e4eSAndroid Build Coastguard Worker /* It's presumed that @p points to a memory space of size >= 4 */
LZ4IO_readLE32(const void * p)1583*27162e4eSAndroid Build Coastguard Worker static unsigned LZ4IO_readLE32 (const void* p)
1584*27162e4eSAndroid Build Coastguard Worker {
1585*27162e4eSAndroid Build Coastguard Worker const unsigned char* const srcPtr = (const unsigned char*)p;
1586*27162e4eSAndroid Build Coastguard Worker unsigned value32 = srcPtr[0];
1587*27162e4eSAndroid Build Coastguard Worker value32 += (unsigned)srcPtr[1] << 8;
1588*27162e4eSAndroid Build Coastguard Worker value32 += (unsigned)srcPtr[2] << 16;
1589*27162e4eSAndroid Build Coastguard Worker value32 += (unsigned)srcPtr[3] << 24;
1590*27162e4eSAndroid Build Coastguard Worker return value32;
1591*27162e4eSAndroid Build Coastguard Worker }
1592*27162e4eSAndroid Build Coastguard Worker
1593*27162e4eSAndroid Build Coastguard Worker
1594*27162e4eSAndroid Build Coastguard Worker static unsigned
LZ4IO_fwriteSparse(FILE * file,const void * buffer,size_t bufferSize,int sparseFileSupport,unsigned storedSkips)1595*27162e4eSAndroid Build Coastguard Worker LZ4IO_fwriteSparse(FILE* file,
1596*27162e4eSAndroid Build Coastguard Worker const void* buffer, size_t bufferSize,
1597*27162e4eSAndroid Build Coastguard Worker int sparseFileSupport,
1598*27162e4eSAndroid Build Coastguard Worker unsigned storedSkips)
1599*27162e4eSAndroid Build Coastguard Worker {
1600*27162e4eSAndroid Build Coastguard Worker const size_t sizeT = sizeof(size_t);
1601*27162e4eSAndroid Build Coastguard Worker const size_t maskT = sizeT -1 ;
1602*27162e4eSAndroid Build Coastguard Worker const size_t* const bufferT = (const size_t*)buffer; /* Buffer is supposed malloc'ed, hence aligned on size_t */
1603*27162e4eSAndroid Build Coastguard Worker const size_t* ptrT = bufferT;
1604*27162e4eSAndroid Build Coastguard Worker size_t bufferSizeT = bufferSize / sizeT;
1605*27162e4eSAndroid Build Coastguard Worker const size_t* const bufferTEnd = bufferT + bufferSizeT;
1606*27162e4eSAndroid Build Coastguard Worker const size_t segmentSizeT = (32 KB) / sizeT;
1607*27162e4eSAndroid Build Coastguard Worker int const sparseMode = (sparseFileSupport - (file==stdout)) > 0;
1608*27162e4eSAndroid Build Coastguard Worker
1609*27162e4eSAndroid Build Coastguard Worker if (!sparseMode) { /* normal write */
1610*27162e4eSAndroid Build Coastguard Worker size_t const sizeCheck = fwrite(buffer, 1, bufferSize, file);
1611*27162e4eSAndroid Build Coastguard Worker if (sizeCheck != bufferSize) END_PROCESS(70, "Write error : cannot write decoded block");
1612*27162e4eSAndroid Build Coastguard Worker return 0;
1613*27162e4eSAndroid Build Coastguard Worker }
1614*27162e4eSAndroid Build Coastguard Worker
1615*27162e4eSAndroid Build Coastguard Worker /* avoid int overflow */
1616*27162e4eSAndroid Build Coastguard Worker if (storedSkips > 1 GB) {
1617*27162e4eSAndroid Build Coastguard Worker int const seekResult = UTIL_fseek(file, 1 GB, SEEK_CUR);
1618*27162e4eSAndroid Build Coastguard Worker if (seekResult != 0) END_PROCESS(71, "1 GB skip error (sparse file support)");
1619*27162e4eSAndroid Build Coastguard Worker storedSkips -= 1 GB;
1620*27162e4eSAndroid Build Coastguard Worker }
1621*27162e4eSAndroid Build Coastguard Worker
1622*27162e4eSAndroid Build Coastguard Worker while (ptrT < bufferTEnd) {
1623*27162e4eSAndroid Build Coastguard Worker size_t seg0SizeT = segmentSizeT;
1624*27162e4eSAndroid Build Coastguard Worker size_t nb0T;
1625*27162e4eSAndroid Build Coastguard Worker
1626*27162e4eSAndroid Build Coastguard Worker /* count leading zeros */
1627*27162e4eSAndroid Build Coastguard Worker if (seg0SizeT > bufferSizeT) seg0SizeT = bufferSizeT;
1628*27162e4eSAndroid Build Coastguard Worker bufferSizeT -= seg0SizeT;
1629*27162e4eSAndroid Build Coastguard Worker for (nb0T=0; (nb0T < seg0SizeT) && (ptrT[nb0T] == 0); nb0T++) ;
1630*27162e4eSAndroid Build Coastguard Worker storedSkips += (unsigned)(nb0T * sizeT);
1631*27162e4eSAndroid Build Coastguard Worker
1632*27162e4eSAndroid Build Coastguard Worker if (nb0T != seg0SizeT) { /* not all 0s */
1633*27162e4eSAndroid Build Coastguard Worker errno = 0;
1634*27162e4eSAndroid Build Coastguard Worker { int const seekResult = UTIL_fseek(file, storedSkips, SEEK_CUR);
1635*27162e4eSAndroid Build Coastguard Worker if (seekResult) END_PROCESS(72, "Sparse skip error(%d): %s ; try --no-sparse", (int)errno, strerror(errno));
1636*27162e4eSAndroid Build Coastguard Worker }
1637*27162e4eSAndroid Build Coastguard Worker storedSkips = 0;
1638*27162e4eSAndroid Build Coastguard Worker seg0SizeT -= nb0T;
1639*27162e4eSAndroid Build Coastguard Worker ptrT += nb0T;
1640*27162e4eSAndroid Build Coastguard Worker { size_t const sizeCheck = fwrite(ptrT, sizeT, seg0SizeT, file);
1641*27162e4eSAndroid Build Coastguard Worker if (sizeCheck != seg0SizeT) END_PROCESS(73, "Write error : cannot write decoded block");
1642*27162e4eSAndroid Build Coastguard Worker } }
1643*27162e4eSAndroid Build Coastguard Worker ptrT += seg0SizeT;
1644*27162e4eSAndroid Build Coastguard Worker }
1645*27162e4eSAndroid Build Coastguard Worker
1646*27162e4eSAndroid Build Coastguard Worker if (bufferSize & maskT) { /* size not multiple of sizeT : implies end of block */
1647*27162e4eSAndroid Build Coastguard Worker const char* const restStart = (const char*)bufferTEnd;
1648*27162e4eSAndroid Build Coastguard Worker const char* restPtr = restStart;
1649*27162e4eSAndroid Build Coastguard Worker size_t const restSize = bufferSize & maskT;
1650*27162e4eSAndroid Build Coastguard Worker const char* const restEnd = restStart + restSize;
1651*27162e4eSAndroid Build Coastguard Worker for (; (restPtr < restEnd) && (*restPtr == 0); restPtr++) ;
1652*27162e4eSAndroid Build Coastguard Worker storedSkips += (unsigned) (restPtr - restStart);
1653*27162e4eSAndroid Build Coastguard Worker if (restPtr != restEnd) {
1654*27162e4eSAndroid Build Coastguard Worker int const seekResult = UTIL_fseek(file, storedSkips, SEEK_CUR);
1655*27162e4eSAndroid Build Coastguard Worker if (seekResult) END_PROCESS(74, "Sparse skip error ; try --no-sparse");
1656*27162e4eSAndroid Build Coastguard Worker storedSkips = 0;
1657*27162e4eSAndroid Build Coastguard Worker { size_t const sizeCheck = fwrite(restPtr, 1, (size_t)(restEnd - restPtr), file);
1658*27162e4eSAndroid Build Coastguard Worker if (sizeCheck != (size_t)(restEnd - restPtr)) END_PROCESS(75, "Write error : cannot write decoded end of block");
1659*27162e4eSAndroid Build Coastguard Worker } }
1660*27162e4eSAndroid Build Coastguard Worker }
1661*27162e4eSAndroid Build Coastguard Worker
1662*27162e4eSAndroid Build Coastguard Worker return storedSkips;
1663*27162e4eSAndroid Build Coastguard Worker }
1664*27162e4eSAndroid Build Coastguard Worker
LZ4IO_fwriteSparseEnd(FILE * file,unsigned storedSkips)1665*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_fwriteSparseEnd(FILE* file, unsigned storedSkips)
1666*27162e4eSAndroid Build Coastguard Worker {
1667*27162e4eSAndroid Build Coastguard Worker if (storedSkips>0) { /* implies sparseFileSupport>0 */
1668*27162e4eSAndroid Build Coastguard Worker const char lastZeroByte[1] = { 0 };
1669*27162e4eSAndroid Build Coastguard Worker if (UTIL_fseek(file, storedSkips-1, SEEK_CUR) != 0)
1670*27162e4eSAndroid Build Coastguard Worker END_PROCESS(69, "Final skip error (sparse file)\n");
1671*27162e4eSAndroid Build Coastguard Worker if (fwrite(lastZeroByte, 1, 1, file) != 1)
1672*27162e4eSAndroid Build Coastguard Worker END_PROCESS(69, "Write error : cannot write last zero\n");
1673*27162e4eSAndroid Build Coastguard Worker }
1674*27162e4eSAndroid Build Coastguard Worker }
1675*27162e4eSAndroid Build Coastguard Worker
1676*27162e4eSAndroid Build Coastguard Worker
1677*27162e4eSAndroid Build Coastguard Worker static unsigned g_magicRead = 0; /* out-parameter of LZ4IO_decodeLegacyStream() */
1678*27162e4eSAndroid Build Coastguard Worker
1679*27162e4eSAndroid Build Coastguard Worker #if LZ4IO_MULTITHREAD
1680*27162e4eSAndroid Build Coastguard Worker
1681*27162e4eSAndroid Build Coastguard Worker typedef struct {
1682*27162e4eSAndroid Build Coastguard Worker void* buffer;
1683*27162e4eSAndroid Build Coastguard Worker size_t size;
1684*27162e4eSAndroid Build Coastguard Worker FILE* f;
1685*27162e4eSAndroid Build Coastguard Worker int sparseEnable;
1686*27162e4eSAndroid Build Coastguard Worker unsigned* storedSkips;
1687*27162e4eSAndroid Build Coastguard Worker const unsigned long long* totalSize;
1688*27162e4eSAndroid Build Coastguard Worker } ChunkToWrite;
1689*27162e4eSAndroid Build Coastguard Worker
LZ4IO_writeDecodedChunk(void * arg)1690*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_writeDecodedChunk(void* arg)
1691*27162e4eSAndroid Build Coastguard Worker {
1692*27162e4eSAndroid Build Coastguard Worker ChunkToWrite* const ctw = (ChunkToWrite*)arg;
1693*27162e4eSAndroid Build Coastguard Worker assert(ctw != NULL);
1694*27162e4eSAndroid Build Coastguard Worker
1695*27162e4eSAndroid Build Coastguard Worker /* note: works because only 1 thread */
1696*27162e4eSAndroid Build Coastguard Worker *ctw->storedSkips = LZ4IO_fwriteSparse(ctw->f, ctw->buffer, ctw->size, ctw->sparseEnable, *ctw->storedSkips); /* success or die */
1697*27162e4eSAndroid Build Coastguard Worker DISPLAYUPDATE(2, "\rDecompressed : %u MiB ", (unsigned)(ctw->totalSize[0] >>20));
1698*27162e4eSAndroid Build Coastguard Worker
1699*27162e4eSAndroid Build Coastguard Worker /* clean up */
1700*27162e4eSAndroid Build Coastguard Worker free(ctw);
1701*27162e4eSAndroid Build Coastguard Worker }
1702*27162e4eSAndroid Build Coastguard Worker
1703*27162e4eSAndroid Build Coastguard Worker typedef struct {
1704*27162e4eSAndroid Build Coastguard Worker void* inBuffer;
1705*27162e4eSAndroid Build Coastguard Worker size_t inSize;
1706*27162e4eSAndroid Build Coastguard Worker void* outBuffer;
1707*27162e4eSAndroid Build Coastguard Worker unsigned long long* totalSize;
1708*27162e4eSAndroid Build Coastguard Worker TPool* wPool;
1709*27162e4eSAndroid Build Coastguard Worker FILE* foutput;
1710*27162e4eSAndroid Build Coastguard Worker int sparseEnable;
1711*27162e4eSAndroid Build Coastguard Worker unsigned* storedSkips;
1712*27162e4eSAndroid Build Coastguard Worker } LegacyBlockInput;
1713*27162e4eSAndroid Build Coastguard Worker
LZ4IO_decompressBlockLegacy(void * arg)1714*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_decompressBlockLegacy(void* arg)
1715*27162e4eSAndroid Build Coastguard Worker {
1716*27162e4eSAndroid Build Coastguard Worker int decodedSize;
1717*27162e4eSAndroid Build Coastguard Worker LegacyBlockInput* const lbi = (LegacyBlockInput*)arg;
1718*27162e4eSAndroid Build Coastguard Worker
1719*27162e4eSAndroid Build Coastguard Worker decodedSize = LZ4_decompress_safe((const char*)lbi->inBuffer, (char*)lbi->outBuffer, (int)lbi->inSize, LEGACY_BLOCKSIZE);
1720*27162e4eSAndroid Build Coastguard Worker if (decodedSize < 0) END_PROCESS(64, "Decoding Failed ! Corrupted input detected !");
1721*27162e4eSAndroid Build Coastguard Worker *lbi->totalSize += (unsigned long long)decodedSize; /* note: works because only 1 thread */
1722*27162e4eSAndroid Build Coastguard Worker
1723*27162e4eSAndroid Build Coastguard Worker /* push to write thread */
1724*27162e4eSAndroid Build Coastguard Worker { ChunkToWrite* const ctw = (ChunkToWrite*)malloc(sizeof(*ctw));
1725*27162e4eSAndroid Build Coastguard Worker if (ctw==NULL) {
1726*27162e4eSAndroid Build Coastguard Worker END_PROCESS(33, "Allocation error : can't describe new write job");
1727*27162e4eSAndroid Build Coastguard Worker }
1728*27162e4eSAndroid Build Coastguard Worker ctw->buffer = lbi->outBuffer;
1729*27162e4eSAndroid Build Coastguard Worker ctw->size = (size_t)decodedSize;
1730*27162e4eSAndroid Build Coastguard Worker ctw->f = lbi->foutput;
1731*27162e4eSAndroid Build Coastguard Worker ctw->sparseEnable = lbi->sparseEnable;
1732*27162e4eSAndroid Build Coastguard Worker ctw->storedSkips = lbi->storedSkips;
1733*27162e4eSAndroid Build Coastguard Worker ctw->totalSize = lbi->totalSize;
1734*27162e4eSAndroid Build Coastguard Worker TPool_submitJob(lbi->wPool, LZ4IO_writeDecodedChunk, ctw);
1735*27162e4eSAndroid Build Coastguard Worker }
1736*27162e4eSAndroid Build Coastguard Worker
1737*27162e4eSAndroid Build Coastguard Worker /* clean up */
1738*27162e4eSAndroid Build Coastguard Worker free(lbi);
1739*27162e4eSAndroid Build Coastguard Worker }
1740*27162e4eSAndroid Build Coastguard Worker
1741*27162e4eSAndroid Build Coastguard Worker static unsigned long long
LZ4IO_decodeLegacyStream(FILE * finput,FILE * foutput,const LZ4IO_prefs_t * prefs)1742*27162e4eSAndroid Build Coastguard Worker LZ4IO_decodeLegacyStream(FILE* finput, FILE* foutput, const LZ4IO_prefs_t* prefs)
1743*27162e4eSAndroid Build Coastguard Worker {
1744*27162e4eSAndroid Build Coastguard Worker unsigned long long streamSize = 0;
1745*27162e4eSAndroid Build Coastguard Worker unsigned storedSkips = 0;
1746*27162e4eSAndroid Build Coastguard Worker
1747*27162e4eSAndroid Build Coastguard Worker TPool* const tPool = TPool_create(1, 1);
1748*27162e4eSAndroid Build Coastguard Worker TPool* const wPool = TPool_create(1, 1);
1749*27162e4eSAndroid Build Coastguard Worker #define NB_BUFFSETS 4 /* 1 being read, 1 being processed, 1 being written, 1 being queued */
1750*27162e4eSAndroid Build Coastguard Worker void* inBuffs[NB_BUFFSETS];
1751*27162e4eSAndroid Build Coastguard Worker void* outBuffs[NB_BUFFSETS];
1752*27162e4eSAndroid Build Coastguard Worker int bSetNb;
1753*27162e4eSAndroid Build Coastguard Worker
1754*27162e4eSAndroid Build Coastguard Worker if (tPool == NULL || wPool == NULL)
1755*27162e4eSAndroid Build Coastguard Worker END_PROCESS(21, "threadpool creation error ");
1756*27162e4eSAndroid Build Coastguard Worker
1757*27162e4eSAndroid Build Coastguard Worker /* allocate buffers up front */
1758*27162e4eSAndroid Build Coastguard Worker for (bSetNb=0; bSetNb<NB_BUFFSETS; bSetNb++) {
1759*27162e4eSAndroid Build Coastguard Worker inBuffs[bSetNb] = malloc((size_t)LZ4_compressBound(LEGACY_BLOCKSIZE));
1760*27162e4eSAndroid Build Coastguard Worker outBuffs[bSetNb] = malloc(LEGACY_BLOCKSIZE);
1761*27162e4eSAndroid Build Coastguard Worker if (!inBuffs[bSetNb] || !outBuffs[bSetNb])
1762*27162e4eSAndroid Build Coastguard Worker END_PROCESS(31, "Allocation error : can't allocate buffer for legacy decoding");
1763*27162e4eSAndroid Build Coastguard Worker }
1764*27162e4eSAndroid Build Coastguard Worker
1765*27162e4eSAndroid Build Coastguard Worker /* Main Loop */
1766*27162e4eSAndroid Build Coastguard Worker for (bSetNb = 0;;bSetNb = (bSetNb+1) % NB_BUFFSETS) {
1767*27162e4eSAndroid Build Coastguard Worker char header[LZ4IO_LEGACY_BLOCK_HEADER_SIZE];
1768*27162e4eSAndroid Build Coastguard Worker unsigned int blockSize;
1769*27162e4eSAndroid Build Coastguard Worker
1770*27162e4eSAndroid Build Coastguard Worker /* Block Size */
1771*27162e4eSAndroid Build Coastguard Worker { size_t const sizeCheck = fread(header, 1, LZ4IO_LEGACY_BLOCK_HEADER_SIZE, finput);
1772*27162e4eSAndroid Build Coastguard Worker if (sizeCheck == 0) break; /* Nothing to read : file read is completed */
1773*27162e4eSAndroid Build Coastguard Worker if (sizeCheck != LZ4IO_LEGACY_BLOCK_HEADER_SIZE)
1774*27162e4eSAndroid Build Coastguard Worker END_PROCESS(61, "Error: cannot read block size in Legacy format");
1775*27162e4eSAndroid Build Coastguard Worker }
1776*27162e4eSAndroid Build Coastguard Worker blockSize = LZ4IO_readLE32(header); /* Convert to Little Endian */
1777*27162e4eSAndroid Build Coastguard Worker if (blockSize > LZ4_COMPRESSBOUND(LEGACY_BLOCKSIZE)) {
1778*27162e4eSAndroid Build Coastguard Worker /* Cannot read next block : maybe new stream ? */
1779*27162e4eSAndroid Build Coastguard Worker g_magicRead = blockSize;
1780*27162e4eSAndroid Build Coastguard Worker break;
1781*27162e4eSAndroid Build Coastguard Worker }
1782*27162e4eSAndroid Build Coastguard Worker
1783*27162e4eSAndroid Build Coastguard Worker /* Read Block */
1784*27162e4eSAndroid Build Coastguard Worker { size_t const sizeCheck = fread(inBuffs[bSetNb], 1, blockSize, finput);
1785*27162e4eSAndroid Build Coastguard Worker if (sizeCheck != blockSize)
1786*27162e4eSAndroid Build Coastguard Worker END_PROCESS(63, "Read error : cannot access compressed block !");
1787*27162e4eSAndroid Build Coastguard Worker /* push to decoding thread */
1788*27162e4eSAndroid Build Coastguard Worker { LegacyBlockInput* const lbi = (LegacyBlockInput*)malloc(sizeof(*lbi));
1789*27162e4eSAndroid Build Coastguard Worker if (lbi==NULL)
1790*27162e4eSAndroid Build Coastguard Worker END_PROCESS(64, "Allocation error : not enough memory to allocate job descriptor");
1791*27162e4eSAndroid Build Coastguard Worker lbi->inBuffer = inBuffs[bSetNb];
1792*27162e4eSAndroid Build Coastguard Worker lbi->inSize = blockSize;
1793*27162e4eSAndroid Build Coastguard Worker lbi->outBuffer = outBuffs[bSetNb];
1794*27162e4eSAndroid Build Coastguard Worker lbi->wPool = wPool;
1795*27162e4eSAndroid Build Coastguard Worker lbi->totalSize = &streamSize;
1796*27162e4eSAndroid Build Coastguard Worker lbi->foutput = foutput;
1797*27162e4eSAndroid Build Coastguard Worker lbi->sparseEnable = prefs->sparseFileSupport;
1798*27162e4eSAndroid Build Coastguard Worker lbi->storedSkips = &storedSkips;
1799*27162e4eSAndroid Build Coastguard Worker TPool_submitJob(tPool, LZ4IO_decompressBlockLegacy, lbi);
1800*27162e4eSAndroid Build Coastguard Worker }
1801*27162e4eSAndroid Build Coastguard Worker }
1802*27162e4eSAndroid Build Coastguard Worker }
1803*27162e4eSAndroid Build Coastguard Worker if (ferror(finput)) END_PROCESS(65, "Read error : ferror");
1804*27162e4eSAndroid Build Coastguard Worker
1805*27162e4eSAndroid Build Coastguard Worker /* Wait for all completion */
1806*27162e4eSAndroid Build Coastguard Worker TPool_jobsCompleted(tPool);
1807*27162e4eSAndroid Build Coastguard Worker TPool_jobsCompleted(wPool);
1808*27162e4eSAndroid Build Coastguard Worker
1809*27162e4eSAndroid Build Coastguard Worker /* flush last zeroes */
1810*27162e4eSAndroid Build Coastguard Worker LZ4IO_fwriteSparseEnd(foutput, storedSkips);
1811*27162e4eSAndroid Build Coastguard Worker
1812*27162e4eSAndroid Build Coastguard Worker /* Free */
1813*27162e4eSAndroid Build Coastguard Worker TPool_free(wPool);
1814*27162e4eSAndroid Build Coastguard Worker TPool_free(tPool);
1815*27162e4eSAndroid Build Coastguard Worker for (bSetNb=0; bSetNb<NB_BUFFSETS; bSetNb++) {
1816*27162e4eSAndroid Build Coastguard Worker free(inBuffs[bSetNb]);
1817*27162e4eSAndroid Build Coastguard Worker free(outBuffs[bSetNb]);
1818*27162e4eSAndroid Build Coastguard Worker }
1819*27162e4eSAndroid Build Coastguard Worker
1820*27162e4eSAndroid Build Coastguard Worker return streamSize;
1821*27162e4eSAndroid Build Coastguard Worker }
1822*27162e4eSAndroid Build Coastguard Worker
1823*27162e4eSAndroid Build Coastguard Worker #else
1824*27162e4eSAndroid Build Coastguard Worker
1825*27162e4eSAndroid Build Coastguard Worker static unsigned long long
LZ4IO_decodeLegacyStream(FILE * finput,FILE * foutput,const LZ4IO_prefs_t * prefs)1826*27162e4eSAndroid Build Coastguard Worker LZ4IO_decodeLegacyStream(FILE* finput, FILE* foutput, const LZ4IO_prefs_t* prefs)
1827*27162e4eSAndroid Build Coastguard Worker {
1828*27162e4eSAndroid Build Coastguard Worker unsigned long long streamSize = 0;
1829*27162e4eSAndroid Build Coastguard Worker unsigned storedSkips = 0;
1830*27162e4eSAndroid Build Coastguard Worker
1831*27162e4eSAndroid Build Coastguard Worker /* Allocate Memory */
1832*27162e4eSAndroid Build Coastguard Worker char* const in_buff = (char*)malloc((size_t)LZ4_compressBound(LEGACY_BLOCKSIZE));
1833*27162e4eSAndroid Build Coastguard Worker char* const out_buff = (char*)malloc(LEGACY_BLOCKSIZE);
1834*27162e4eSAndroid Build Coastguard Worker if (!in_buff || !out_buff) END_PROCESS(61, "Allocation error : not enough memory");
1835*27162e4eSAndroid Build Coastguard Worker
1836*27162e4eSAndroid Build Coastguard Worker /* Main Loop */
1837*27162e4eSAndroid Build Coastguard Worker while (1) {
1838*27162e4eSAndroid Build Coastguard Worker unsigned int blockSize;
1839*27162e4eSAndroid Build Coastguard Worker
1840*27162e4eSAndroid Build Coastguard Worker /* Block Size */
1841*27162e4eSAndroid Build Coastguard Worker { size_t const sizeCheck = fread(in_buff, 1, LZ4IO_LEGACY_BLOCK_HEADER_SIZE, finput);
1842*27162e4eSAndroid Build Coastguard Worker if (sizeCheck == 0) break; /* Nothing to read : file read is completed */
1843*27162e4eSAndroid Build Coastguard Worker if (sizeCheck != LZ4IO_LEGACY_BLOCK_HEADER_SIZE)
1844*27162e4eSAndroid Build Coastguard Worker END_PROCESS(62, "Error: cannot read block size in Legacy format");
1845*27162e4eSAndroid Build Coastguard Worker }
1846*27162e4eSAndroid Build Coastguard Worker blockSize = LZ4IO_readLE32(in_buff); /* Convert to Little Endian */
1847*27162e4eSAndroid Build Coastguard Worker if (blockSize > LZ4_COMPRESSBOUND(LEGACY_BLOCKSIZE)) {
1848*27162e4eSAndroid Build Coastguard Worker /* Cannot read next block : maybe new stream ? */
1849*27162e4eSAndroid Build Coastguard Worker g_magicRead = blockSize;
1850*27162e4eSAndroid Build Coastguard Worker break;
1851*27162e4eSAndroid Build Coastguard Worker }
1852*27162e4eSAndroid Build Coastguard Worker
1853*27162e4eSAndroid Build Coastguard Worker /* Read Block */
1854*27162e4eSAndroid Build Coastguard Worker { size_t const sizeCheck = fread(in_buff, 1, blockSize, finput);
1855*27162e4eSAndroid Build Coastguard Worker if (sizeCheck != blockSize) END_PROCESS(63, "Read error : cannot access compressed block !"); }
1856*27162e4eSAndroid Build Coastguard Worker
1857*27162e4eSAndroid Build Coastguard Worker /* Decode Block */
1858*27162e4eSAndroid Build Coastguard Worker { int const decodeSize = LZ4_decompress_safe(in_buff, out_buff, (int)blockSize, LEGACY_BLOCKSIZE);
1859*27162e4eSAndroid Build Coastguard Worker if (decodeSize < 0) END_PROCESS(64, "Decoding Failed ! Corrupted input detected !");
1860*27162e4eSAndroid Build Coastguard Worker streamSize += (unsigned long long)decodeSize;
1861*27162e4eSAndroid Build Coastguard Worker /* Write Block */
1862*27162e4eSAndroid Build Coastguard Worker storedSkips = LZ4IO_fwriteSparse(foutput, out_buff, (size_t)decodeSize, prefs->sparseFileSupport, storedSkips); /* success or die */
1863*27162e4eSAndroid Build Coastguard Worker } }
1864*27162e4eSAndroid Build Coastguard Worker if (ferror(finput)) END_PROCESS(65, "Read error : ferror");
1865*27162e4eSAndroid Build Coastguard Worker
1866*27162e4eSAndroid Build Coastguard Worker LZ4IO_fwriteSparseEnd(foutput, storedSkips);
1867*27162e4eSAndroid Build Coastguard Worker
1868*27162e4eSAndroid Build Coastguard Worker /* Free */
1869*27162e4eSAndroid Build Coastguard Worker free(in_buff);
1870*27162e4eSAndroid Build Coastguard Worker free(out_buff);
1871*27162e4eSAndroid Build Coastguard Worker
1872*27162e4eSAndroid Build Coastguard Worker return streamSize;
1873*27162e4eSAndroid Build Coastguard Worker }
1874*27162e4eSAndroid Build Coastguard Worker #endif
1875*27162e4eSAndroid Build Coastguard Worker
1876*27162e4eSAndroid Build Coastguard Worker
1877*27162e4eSAndroid Build Coastguard Worker typedef struct {
1878*27162e4eSAndroid Build Coastguard Worker void* srcBuffer;
1879*27162e4eSAndroid Build Coastguard Worker size_t srcBufferSize;
1880*27162e4eSAndroid Build Coastguard Worker void* dstBuffer;
1881*27162e4eSAndroid Build Coastguard Worker size_t dstBufferSize;
1882*27162e4eSAndroid Build Coastguard Worker FILE* dstFile;
1883*27162e4eSAndroid Build Coastguard Worker LZ4F_decompressionContext_t dCtx;
1884*27162e4eSAndroid Build Coastguard Worker void* dictBuffer;
1885*27162e4eSAndroid Build Coastguard Worker size_t dictBufferSize;
1886*27162e4eSAndroid Build Coastguard Worker } dRess_t;
1887*27162e4eSAndroid Build Coastguard Worker
LZ4IO_loadDDict(dRess_t * ress,const LZ4IO_prefs_t * const prefs)1888*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_loadDDict(dRess_t* ress, const LZ4IO_prefs_t* const prefs)
1889*27162e4eSAndroid Build Coastguard Worker {
1890*27162e4eSAndroid Build Coastguard Worker if (!prefs->useDictionary) {
1891*27162e4eSAndroid Build Coastguard Worker ress->dictBuffer = NULL;
1892*27162e4eSAndroid Build Coastguard Worker ress->dictBufferSize = 0;
1893*27162e4eSAndroid Build Coastguard Worker return;
1894*27162e4eSAndroid Build Coastguard Worker }
1895*27162e4eSAndroid Build Coastguard Worker
1896*27162e4eSAndroid Build Coastguard Worker ress->dictBuffer = LZ4IO_createDict(&ress->dictBufferSize, prefs->dictionaryFilename);
1897*27162e4eSAndroid Build Coastguard Worker if (!ress->dictBuffer) END_PROCESS(25, "Dictionary error : could not create dictionary");
1898*27162e4eSAndroid Build Coastguard Worker }
1899*27162e4eSAndroid Build Coastguard Worker
1900*27162e4eSAndroid Build Coastguard Worker static const size_t LZ4IO_dBufferSize = 64 KB;
LZ4IO_createDResources(const LZ4IO_prefs_t * const prefs)1901*27162e4eSAndroid Build Coastguard Worker static dRess_t LZ4IO_createDResources(const LZ4IO_prefs_t* const prefs)
1902*27162e4eSAndroid Build Coastguard Worker {
1903*27162e4eSAndroid Build Coastguard Worker dRess_t ress;
1904*27162e4eSAndroid Build Coastguard Worker
1905*27162e4eSAndroid Build Coastguard Worker /* init */
1906*27162e4eSAndroid Build Coastguard Worker LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext(&ress.dCtx, LZ4F_VERSION);
1907*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(errorCode)) END_PROCESS(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode));
1908*27162e4eSAndroid Build Coastguard Worker
1909*27162e4eSAndroid Build Coastguard Worker /* Allocate Memory */
1910*27162e4eSAndroid Build Coastguard Worker ress.srcBufferSize = LZ4IO_dBufferSize;
1911*27162e4eSAndroid Build Coastguard Worker ress.srcBuffer = malloc(ress.srcBufferSize);
1912*27162e4eSAndroid Build Coastguard Worker ress.dstBufferSize = LZ4IO_dBufferSize;
1913*27162e4eSAndroid Build Coastguard Worker ress.dstBuffer = malloc(ress.dstBufferSize);
1914*27162e4eSAndroid Build Coastguard Worker if (!ress.srcBuffer || !ress.dstBuffer) END_PROCESS(61, "Allocation error : not enough memory");
1915*27162e4eSAndroid Build Coastguard Worker
1916*27162e4eSAndroid Build Coastguard Worker LZ4IO_loadDDict(&ress, prefs);
1917*27162e4eSAndroid Build Coastguard Worker
1918*27162e4eSAndroid Build Coastguard Worker ress.dstFile = NULL;
1919*27162e4eSAndroid Build Coastguard Worker return ress;
1920*27162e4eSAndroid Build Coastguard Worker }
1921*27162e4eSAndroid Build Coastguard Worker
LZ4IO_freeDResources(dRess_t ress)1922*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_freeDResources(dRess_t ress)
1923*27162e4eSAndroid Build Coastguard Worker {
1924*27162e4eSAndroid Build Coastguard Worker LZ4F_errorCode_t errorCode = LZ4F_freeDecompressionContext(ress.dCtx);
1925*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(errorCode)) END_PROCESS(69, "Error : can't free LZ4F context resource : %s", LZ4F_getErrorName(errorCode));
1926*27162e4eSAndroid Build Coastguard Worker free(ress.srcBuffer);
1927*27162e4eSAndroid Build Coastguard Worker free(ress.dstBuffer);
1928*27162e4eSAndroid Build Coastguard Worker free(ress.dictBuffer);
1929*27162e4eSAndroid Build Coastguard Worker }
1930*27162e4eSAndroid Build Coastguard Worker
1931*27162e4eSAndroid Build Coastguard Worker
1932*27162e4eSAndroid Build Coastguard Worker #if LZ4IO_MULTITHREAD
1933*27162e4eSAndroid Build Coastguard Worker
1934*27162e4eSAndroid Build Coastguard Worker #define INBUFF_SIZE (4 MB)
1935*27162e4eSAndroid Build Coastguard Worker #define OUTBUFF_SIZE (1 * INBUFF_SIZE)
1936*27162e4eSAndroid Build Coastguard Worker #define OUTBUFF_QUEUE 1
1937*27162e4eSAndroid Build Coastguard Worker #define PBUFFERS_NB (1 /* being decompressed */ + OUTBUFF_QUEUE + 1 /* being written to io */)
1938*27162e4eSAndroid Build Coastguard Worker
1939*27162e4eSAndroid Build Coastguard Worker typedef struct {
1940*27162e4eSAndroid Build Coastguard Worker void* ptr;
1941*27162e4eSAndroid Build Coastguard Worker size_t capacity;
1942*27162e4eSAndroid Build Coastguard Worker size_t size;
1943*27162e4eSAndroid Build Coastguard Worker } Buffer;
1944*27162e4eSAndroid Build Coastguard Worker
1945*27162e4eSAndroid Build Coastguard Worker /* BufferPool:
1946*27162e4eSAndroid Build Coastguard Worker * Based on ayncio property :
1947*27162e4eSAndroid Build Coastguard Worker * all buffers are allocated and released in order,
1948*27162e4eSAndroid Build Coastguard Worker * maximum nb of buffers limited by queues */
1949*27162e4eSAndroid Build Coastguard Worker
1950*27162e4eSAndroid Build Coastguard Worker typedef struct {
1951*27162e4eSAndroid Build Coastguard Worker Buffer buffers[PBUFFERS_NB];
1952*27162e4eSAndroid Build Coastguard Worker int availNext;
1953*27162e4eSAndroid Build Coastguard Worker int usedIdx;
1954*27162e4eSAndroid Build Coastguard Worker } BufferPool;
1955*27162e4eSAndroid Build Coastguard Worker
LZ4IO_freeBufferPool(BufferPool * bp)1956*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_freeBufferPool(BufferPool* bp)
1957*27162e4eSAndroid Build Coastguard Worker {
1958*27162e4eSAndroid Build Coastguard Worker int i;
1959*27162e4eSAndroid Build Coastguard Worker if (bp==NULL) return;
1960*27162e4eSAndroid Build Coastguard Worker for (i=0; i<PBUFFERS_NB; i++)
1961*27162e4eSAndroid Build Coastguard Worker free(bp->buffers[i].ptr);
1962*27162e4eSAndroid Build Coastguard Worker free(bp);
1963*27162e4eSAndroid Build Coastguard Worker }
1964*27162e4eSAndroid Build Coastguard Worker
LZ4IO_createBufferPool(size_t bufSize)1965*27162e4eSAndroid Build Coastguard Worker static BufferPool* LZ4IO_createBufferPool(size_t bufSize)
1966*27162e4eSAndroid Build Coastguard Worker {
1967*27162e4eSAndroid Build Coastguard Worker BufferPool* const bp = (BufferPool*)calloc(1, sizeof(*bp));
1968*27162e4eSAndroid Build Coastguard Worker int i;
1969*27162e4eSAndroid Build Coastguard Worker if (bp==NULL) return NULL;
1970*27162e4eSAndroid Build Coastguard Worker for (i=0; i<PBUFFERS_NB; i++) {
1971*27162e4eSAndroid Build Coastguard Worker bp->buffers[i].ptr = malloc(bufSize);
1972*27162e4eSAndroid Build Coastguard Worker if (bp->buffers[i].ptr == NULL) {
1973*27162e4eSAndroid Build Coastguard Worker LZ4IO_freeBufferPool(bp);
1974*27162e4eSAndroid Build Coastguard Worker return NULL;
1975*27162e4eSAndroid Build Coastguard Worker }
1976*27162e4eSAndroid Build Coastguard Worker bp->buffers[i].capacity = bufSize;
1977*27162e4eSAndroid Build Coastguard Worker bp->buffers[i].size = 0;
1978*27162e4eSAndroid Build Coastguard Worker }
1979*27162e4eSAndroid Build Coastguard Worker bp->availNext = 0;
1980*27162e4eSAndroid Build Coastguard Worker bp->usedIdx = 0;
1981*27162e4eSAndroid Build Coastguard Worker return bp;
1982*27162e4eSAndroid Build Coastguard Worker }
1983*27162e4eSAndroid Build Coastguard Worker
1984*27162e4eSAndroid Build Coastguard Worker /* Note: Thread Sanitizer can be detected with below macro
1985*27162e4eSAndroid Build Coastguard Worker * but it's not guaranteed (doesn't seem to work with clang) */
1986*27162e4eSAndroid Build Coastguard Worker #ifdef __SANITIZE_THREAD__
1987*27162e4eSAndroid Build Coastguard Worker # undef LZ4IO_NO_TSAN_ONLY
1988*27162e4eSAndroid Build Coastguard Worker #endif
1989*27162e4eSAndroid Build Coastguard Worker
BufPool_getBuffer(BufferPool * bp)1990*27162e4eSAndroid Build Coastguard Worker static Buffer BufPool_getBuffer(BufferPool* bp)
1991*27162e4eSAndroid Build Coastguard Worker {
1992*27162e4eSAndroid Build Coastguard Worker assert(bp != NULL);
1993*27162e4eSAndroid Build Coastguard Worker #ifdef LZ4IO_NO_TSAN_ONLY
1994*27162e4eSAndroid Build Coastguard Worker /* The following assert() are susceptible to race conditions */
1995*27162e4eSAndroid Build Coastguard Worker assert(bp->availNext >= bp->usedIdx);
1996*27162e4eSAndroid Build Coastguard Worker assert(bp->availNext < bp->usedIdx + PBUFFERS_NB);
1997*27162e4eSAndroid Build Coastguard Worker #endif
1998*27162e4eSAndroid Build Coastguard Worker { int id = bp->availNext++ % PBUFFERS_NB;
1999*27162e4eSAndroid Build Coastguard Worker assert(bp->buffers[id].size == 0);
2000*27162e4eSAndroid Build Coastguard Worker return bp->buffers[id];
2001*27162e4eSAndroid Build Coastguard Worker } }
2002*27162e4eSAndroid Build Coastguard Worker
BufPool_releaseBuffer(BufferPool * bp,Buffer buf)2003*27162e4eSAndroid Build Coastguard Worker void BufPool_releaseBuffer(BufferPool* bp, Buffer buf)
2004*27162e4eSAndroid Build Coastguard Worker {
2005*27162e4eSAndroid Build Coastguard Worker assert(bp != NULL);
2006*27162e4eSAndroid Build Coastguard Worker #ifdef LZ4IO_NO_TSAN_ONLY
2007*27162e4eSAndroid Build Coastguard Worker /* The following assert() is susceptible to race conditions */
2008*27162e4eSAndroid Build Coastguard Worker assert(bp->usedIdx < bp->availNext);
2009*27162e4eSAndroid Build Coastguard Worker #endif
2010*27162e4eSAndroid Build Coastguard Worker { int id = bp->usedIdx++ % PBUFFERS_NB;
2011*27162e4eSAndroid Build Coastguard Worker assert(bp->buffers[id].ptr == buf.ptr);
2012*27162e4eSAndroid Build Coastguard Worker bp->buffers[id].size = 0;
2013*27162e4eSAndroid Build Coastguard Worker } }
2014*27162e4eSAndroid Build Coastguard Worker
2015*27162e4eSAndroid Build Coastguard Worker typedef struct {
2016*27162e4eSAndroid Build Coastguard Worker Buffer bufOut;
2017*27162e4eSAndroid Build Coastguard Worker FILE* fOut;
2018*27162e4eSAndroid Build Coastguard Worker BufferPool* bp;
2019*27162e4eSAndroid Build Coastguard Worker int sparseEnable;
2020*27162e4eSAndroid Build Coastguard Worker unsigned* storedSkips;
2021*27162e4eSAndroid Build Coastguard Worker unsigned long long* totalSize;
2022*27162e4eSAndroid Build Coastguard Worker } LZ4FChunkToWrite;
2023*27162e4eSAndroid Build Coastguard Worker
LZ4IO_writeDecodedLZ4FChunk(void * arg)2024*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_writeDecodedLZ4FChunk(void* arg)
2025*27162e4eSAndroid Build Coastguard Worker {
2026*27162e4eSAndroid Build Coastguard Worker LZ4FChunkToWrite* const ctw = (LZ4FChunkToWrite*)arg;
2027*27162e4eSAndroid Build Coastguard Worker assert(ctw != NULL);
2028*27162e4eSAndroid Build Coastguard Worker
2029*27162e4eSAndroid Build Coastguard Worker /* note: works because only 1 thread */
2030*27162e4eSAndroid Build Coastguard Worker *ctw->storedSkips = LZ4IO_fwriteSparse(ctw->fOut, ctw->bufOut.ptr, ctw->bufOut.size, ctw->sparseEnable, *ctw->storedSkips); /* success or die */
2031*27162e4eSAndroid Build Coastguard Worker *ctw->totalSize += (unsigned long long)ctw->bufOut.size; /* note: works because only 1 thread */
2032*27162e4eSAndroid Build Coastguard Worker DISPLAYUPDATE(2, "\rDecompressed : %u MiB ", (unsigned)(ctw->totalSize[0] >> 20));
2033*27162e4eSAndroid Build Coastguard Worker
2034*27162e4eSAndroid Build Coastguard Worker /* clean up */
2035*27162e4eSAndroid Build Coastguard Worker BufPool_releaseBuffer(ctw->bp, ctw->bufOut);
2036*27162e4eSAndroid Build Coastguard Worker free(ctw);
2037*27162e4eSAndroid Build Coastguard Worker }
2038*27162e4eSAndroid Build Coastguard Worker
2039*27162e4eSAndroid Build Coastguard Worker typedef struct {
2040*27162e4eSAndroid Build Coastguard Worker LZ4F_dctx* dctx;
2041*27162e4eSAndroid Build Coastguard Worker const void* inBuffer;
2042*27162e4eSAndroid Build Coastguard Worker size_t inSize;
2043*27162e4eSAndroid Build Coastguard Worker const void* dictBuffer;
2044*27162e4eSAndroid Build Coastguard Worker size_t dictBufferSize;
2045*27162e4eSAndroid Build Coastguard Worker BufferPool* bp;
2046*27162e4eSAndroid Build Coastguard Worker unsigned long long* totalSize;
2047*27162e4eSAndroid Build Coastguard Worker LZ4F_errorCode_t* lastStatus;
2048*27162e4eSAndroid Build Coastguard Worker TPool* wPool;
2049*27162e4eSAndroid Build Coastguard Worker FILE* foutput;
2050*27162e4eSAndroid Build Coastguard Worker int sparseEnable;
2051*27162e4eSAndroid Build Coastguard Worker unsigned* storedSkips;
2052*27162e4eSAndroid Build Coastguard Worker } LZ4FChunk;
2053*27162e4eSAndroid Build Coastguard Worker
LZ4IO_decompressLZ4FChunk(void * arg)2054*27162e4eSAndroid Build Coastguard Worker static void LZ4IO_decompressLZ4FChunk(void* arg)
2055*27162e4eSAndroid Build Coastguard Worker {
2056*27162e4eSAndroid Build Coastguard Worker LZ4FChunk* const lz4fc = (LZ4FChunk*)arg;
2057*27162e4eSAndroid Build Coastguard Worker const char* inPtr = (const char*)lz4fc->inBuffer;
2058*27162e4eSAndroid Build Coastguard Worker size_t pos = 0;
2059*27162e4eSAndroid Build Coastguard Worker
2060*27162e4eSAndroid Build Coastguard Worker while ((pos < lz4fc->inSize)) { /* still to read */
2061*27162e4eSAndroid Build Coastguard Worker size_t remainingInSize = lz4fc->inSize - pos;
2062*27162e4eSAndroid Build Coastguard Worker Buffer b = BufPool_getBuffer(lz4fc->bp);
2063*27162e4eSAndroid Build Coastguard Worker if (b.capacity != OUTBUFF_SIZE)
2064*27162e4eSAndroid Build Coastguard Worker END_PROCESS(33, "Could not allocate output buffer!");
2065*27162e4eSAndroid Build Coastguard Worker assert(b.size == 0);
2066*27162e4eSAndroid Build Coastguard Worker b.size = b.capacity;
2067*27162e4eSAndroid Build Coastguard Worker { size_t nextToLoad = LZ4F_decompress_usingDict(lz4fc->dctx,
2068*27162e4eSAndroid Build Coastguard Worker b.ptr, &b.size,
2069*27162e4eSAndroid Build Coastguard Worker inPtr + pos, &remainingInSize,
2070*27162e4eSAndroid Build Coastguard Worker lz4fc->dictBuffer, lz4fc->dictBufferSize,
2071*27162e4eSAndroid Build Coastguard Worker NULL);
2072*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(nextToLoad))
2073*27162e4eSAndroid Build Coastguard Worker END_PROCESS(34, "Decompression error : %s", LZ4F_getErrorName(nextToLoad));
2074*27162e4eSAndroid Build Coastguard Worker *lz4fc->lastStatus = nextToLoad;
2075*27162e4eSAndroid Build Coastguard Worker }
2076*27162e4eSAndroid Build Coastguard Worker assert(remainingInSize <= lz4fc->inSize - pos);
2077*27162e4eSAndroid Build Coastguard Worker pos += remainingInSize;
2078*27162e4eSAndroid Build Coastguard Worker assert(b.size <= b.capacity);
2079*27162e4eSAndroid Build Coastguard Worker
2080*27162e4eSAndroid Build Coastguard Worker /* push to write thread */
2081*27162e4eSAndroid Build Coastguard Worker { LZ4FChunkToWrite* const ctw = (LZ4FChunkToWrite*)malloc(sizeof(*ctw));
2082*27162e4eSAndroid Build Coastguard Worker if (ctw==NULL) {
2083*27162e4eSAndroid Build Coastguard Worker END_PROCESS(35, "Allocation error : can't describe new write job");
2084*27162e4eSAndroid Build Coastguard Worker }
2085*27162e4eSAndroid Build Coastguard Worker ctw->bufOut = b;
2086*27162e4eSAndroid Build Coastguard Worker ctw->fOut = lz4fc->foutput;
2087*27162e4eSAndroid Build Coastguard Worker ctw->bp = lz4fc->bp;
2088*27162e4eSAndroid Build Coastguard Worker ctw->sparseEnable = lz4fc->sparseEnable;
2089*27162e4eSAndroid Build Coastguard Worker ctw->storedSkips = lz4fc->storedSkips;
2090*27162e4eSAndroid Build Coastguard Worker ctw->totalSize = lz4fc->totalSize;
2091*27162e4eSAndroid Build Coastguard Worker TPool_submitJob(lz4fc->wPool, LZ4IO_writeDecodedLZ4FChunk, ctw);
2092*27162e4eSAndroid Build Coastguard Worker }
2093*27162e4eSAndroid Build Coastguard Worker }
2094*27162e4eSAndroid Build Coastguard Worker
2095*27162e4eSAndroid Build Coastguard Worker /* clean up */
2096*27162e4eSAndroid Build Coastguard Worker free(lz4fc);
2097*27162e4eSAndroid Build Coastguard Worker }
2098*27162e4eSAndroid Build Coastguard Worker
2099*27162e4eSAndroid Build Coastguard Worker static unsigned long long
LZ4IO_decompressLZ4F(dRess_t ress,FILE * const srcFile,FILE * const dstFile,const LZ4IO_prefs_t * const prefs)2100*27162e4eSAndroid Build Coastguard Worker LZ4IO_decompressLZ4F(dRess_t ress,
2101*27162e4eSAndroid Build Coastguard Worker FILE* const srcFile, FILE* const dstFile,
2102*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* const prefs)
2103*27162e4eSAndroid Build Coastguard Worker {
2104*27162e4eSAndroid Build Coastguard Worker unsigned long long filesize = 0;
2105*27162e4eSAndroid Build Coastguard Worker LZ4F_errorCode_t nextToLoad;
2106*27162e4eSAndroid Build Coastguard Worker LZ4F_errorCode_t lastStatus = 1;
2107*27162e4eSAndroid Build Coastguard Worker unsigned storedSkips = 0;
2108*27162e4eSAndroid Build Coastguard Worker LZ4F_decompressOptions_t const dOpt_skipCrc = { 0, 1, 0, 0 };
2109*27162e4eSAndroid Build Coastguard Worker const LZ4F_decompressOptions_t* const dOptPtr =
2110*27162e4eSAndroid Build Coastguard Worker ((prefs->blockChecksum==0) && (prefs->streamChecksum==0)) ?
2111*27162e4eSAndroid Build Coastguard Worker &dOpt_skipCrc : NULL;
2112*27162e4eSAndroid Build Coastguard Worker TPool* const tPool = TPool_create(1, 1);
2113*27162e4eSAndroid Build Coastguard Worker TPool* const wPool = TPool_create(1, 1);
2114*27162e4eSAndroid Build Coastguard Worker BufferPool* const bp = LZ4IO_createBufferPool(OUTBUFF_SIZE);
2115*27162e4eSAndroid Build Coastguard Worker #define NB_BUFFSETS 4 /* 1 being read, 1 being processed, 1 being written, 1 being queued */
2116*27162e4eSAndroid Build Coastguard Worker void* inBuffs[NB_BUFFSETS];
2117*27162e4eSAndroid Build Coastguard Worker int bSetNb;
2118*27162e4eSAndroid Build Coastguard Worker
2119*27162e4eSAndroid Build Coastguard Worker /* checks */
2120*27162e4eSAndroid Build Coastguard Worker if (tPool == NULL || wPool == NULL || bp==NULL)
2121*27162e4eSAndroid Build Coastguard Worker END_PROCESS(22, "threadpool creation error ");
2122*27162e4eSAndroid Build Coastguard Worker
2123*27162e4eSAndroid Build Coastguard Worker /* allocate buffers up front */
2124*27162e4eSAndroid Build Coastguard Worker for (bSetNb=0; bSetNb<NB_BUFFSETS; bSetNb++) {
2125*27162e4eSAndroid Build Coastguard Worker inBuffs[bSetNb] = malloc((size_t)INBUFF_SIZE);
2126*27162e4eSAndroid Build Coastguard Worker if (!inBuffs[bSetNb])
2127*27162e4eSAndroid Build Coastguard Worker END_PROCESS(23, "Allocation error : can't allocate buffer for legacy decoding");
2128*27162e4eSAndroid Build Coastguard Worker }
2129*27162e4eSAndroid Build Coastguard Worker
2130*27162e4eSAndroid Build Coastguard Worker /* Init feed with magic number (already consumed from FILE* sFile) */
2131*27162e4eSAndroid Build Coastguard Worker { size_t inSize = MAGICNUMBER_SIZE;
2132*27162e4eSAndroid Build Coastguard Worker size_t outSize= 0;
2133*27162e4eSAndroid Build Coastguard Worker LZ4IO_writeLE32(ress.srcBuffer, LZ4IO_MAGICNUMBER);
2134*27162e4eSAndroid Build Coastguard Worker nextToLoad = LZ4F_decompress_usingDict(ress.dCtx,
2135*27162e4eSAndroid Build Coastguard Worker ress.dstBuffer, &outSize,
2136*27162e4eSAndroid Build Coastguard Worker ress.srcBuffer, &inSize,
2137*27162e4eSAndroid Build Coastguard Worker ress.dictBuffer, ress.dictBufferSize,
2138*27162e4eSAndroid Build Coastguard Worker dOptPtr); /* set it once, it's enough */
2139*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(nextToLoad))
2140*27162e4eSAndroid Build Coastguard Worker END_PROCESS(23, "Header error : %s", LZ4F_getErrorName(nextToLoad));
2141*27162e4eSAndroid Build Coastguard Worker }
2142*27162e4eSAndroid Build Coastguard Worker
2143*27162e4eSAndroid Build Coastguard Worker /* Main Loop */
2144*27162e4eSAndroid Build Coastguard Worker assert(nextToLoad);
2145*27162e4eSAndroid Build Coastguard Worker for (bSetNb = 0; ; bSetNb = (bSetNb+1) % NB_BUFFSETS) {
2146*27162e4eSAndroid Build Coastguard Worker size_t readSize;
2147*27162e4eSAndroid Build Coastguard Worker
2148*27162e4eSAndroid Build Coastguard Worker /* Read input */
2149*27162e4eSAndroid Build Coastguard Worker readSize = fread(inBuffs[bSetNb], 1, INBUFF_SIZE, srcFile);
2150*27162e4eSAndroid Build Coastguard Worker if (ferror(srcFile)) END_PROCESS(26, "Read error");
2151*27162e4eSAndroid Build Coastguard Worker
2152*27162e4eSAndroid Build Coastguard Worker /* push to decoding thread */
2153*27162e4eSAndroid Build Coastguard Worker { LZ4FChunk* const lbi = (LZ4FChunk*)malloc(sizeof(*lbi));
2154*27162e4eSAndroid Build Coastguard Worker if (lbi==NULL)
2155*27162e4eSAndroid Build Coastguard Worker END_PROCESS(25, "Allocation error : not enough memory to allocate job descriptor");
2156*27162e4eSAndroid Build Coastguard Worker lbi->dctx = ress.dCtx;
2157*27162e4eSAndroid Build Coastguard Worker lbi->inBuffer = inBuffs[bSetNb];
2158*27162e4eSAndroid Build Coastguard Worker lbi->inSize = readSize;
2159*27162e4eSAndroid Build Coastguard Worker lbi->dictBuffer = ress.dictBuffer;
2160*27162e4eSAndroid Build Coastguard Worker lbi->dictBufferSize = ress.dictBufferSize;
2161*27162e4eSAndroid Build Coastguard Worker lbi->bp = bp;
2162*27162e4eSAndroid Build Coastguard Worker lbi->wPool = wPool;
2163*27162e4eSAndroid Build Coastguard Worker lbi->totalSize = &filesize;
2164*27162e4eSAndroid Build Coastguard Worker lbi->lastStatus = &lastStatus;
2165*27162e4eSAndroid Build Coastguard Worker lbi->foutput = dstFile;
2166*27162e4eSAndroid Build Coastguard Worker lbi->sparseEnable = prefs->sparseFileSupport;
2167*27162e4eSAndroid Build Coastguard Worker lbi->storedSkips = &storedSkips;
2168*27162e4eSAndroid Build Coastguard Worker TPool_submitJob(tPool, LZ4IO_decompressLZ4FChunk, lbi);
2169*27162e4eSAndroid Build Coastguard Worker }
2170*27162e4eSAndroid Build Coastguard Worker if (readSize < INBUFF_SIZE) break; /* likely reached end of stream */
2171*27162e4eSAndroid Build Coastguard Worker }
2172*27162e4eSAndroid Build Coastguard Worker assert(feof(srcFile));
2173*27162e4eSAndroid Build Coastguard Worker
2174*27162e4eSAndroid Build Coastguard Worker /* Wait for all decompression completion */
2175*27162e4eSAndroid Build Coastguard Worker TPool_jobsCompleted(tPool);
2176*27162e4eSAndroid Build Coastguard Worker
2177*27162e4eSAndroid Build Coastguard Worker /* flush */
2178*27162e4eSAndroid Build Coastguard Worker if (lastStatus != 0) {
2179*27162e4eSAndroid Build Coastguard Worker END_PROCESS(26, "LZ4F frame decoding could not complete: invalid frame");
2180*27162e4eSAndroid Build Coastguard Worker }
2181*27162e4eSAndroid Build Coastguard Worker TPool_jobsCompleted(wPool);
2182*27162e4eSAndroid Build Coastguard Worker if (!prefs->testMode) LZ4IO_fwriteSparseEnd(dstFile, storedSkips);
2183*27162e4eSAndroid Build Coastguard Worker
2184*27162e4eSAndroid Build Coastguard Worker /* Clean */
2185*27162e4eSAndroid Build Coastguard Worker for (bSetNb=0; bSetNb<NB_BUFFSETS; bSetNb++) {
2186*27162e4eSAndroid Build Coastguard Worker free(inBuffs[bSetNb]);
2187*27162e4eSAndroid Build Coastguard Worker }
2188*27162e4eSAndroid Build Coastguard Worker LZ4IO_freeBufferPool(bp);
2189*27162e4eSAndroid Build Coastguard Worker TPool_free(wPool);
2190*27162e4eSAndroid Build Coastguard Worker TPool_free(tPool);
2191*27162e4eSAndroid Build Coastguard Worker
2192*27162e4eSAndroid Build Coastguard Worker return filesize;
2193*27162e4eSAndroid Build Coastguard Worker }
2194*27162e4eSAndroid Build Coastguard Worker
2195*27162e4eSAndroid Build Coastguard Worker #else
2196*27162e4eSAndroid Build Coastguard Worker
2197*27162e4eSAndroid Build Coastguard Worker static unsigned long long
LZ4IO_decompressLZ4F(dRess_t ress,FILE * const srcFile,FILE * const dstFile,const LZ4IO_prefs_t * const prefs)2198*27162e4eSAndroid Build Coastguard Worker LZ4IO_decompressLZ4F(dRess_t ress,
2199*27162e4eSAndroid Build Coastguard Worker FILE* const srcFile, FILE* const dstFile,
2200*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* const prefs)
2201*27162e4eSAndroid Build Coastguard Worker {
2202*27162e4eSAndroid Build Coastguard Worker unsigned long long filesize = 0;
2203*27162e4eSAndroid Build Coastguard Worker LZ4F_errorCode_t nextToLoad;
2204*27162e4eSAndroid Build Coastguard Worker unsigned storedSkips = 0;
2205*27162e4eSAndroid Build Coastguard Worker LZ4F_decompressOptions_t const dOpt_skipCrc = { 0, 1, 0, 0 };
2206*27162e4eSAndroid Build Coastguard Worker const LZ4F_decompressOptions_t* const dOptPtr =
2207*27162e4eSAndroid Build Coastguard Worker ((prefs->blockChecksum==0) && (prefs->streamChecksum==0)) ?
2208*27162e4eSAndroid Build Coastguard Worker &dOpt_skipCrc : NULL;
2209*27162e4eSAndroid Build Coastguard Worker
2210*27162e4eSAndroid Build Coastguard Worker /* Init feed with magic number (already consumed from FILE* sFile) */
2211*27162e4eSAndroid Build Coastguard Worker { size_t inSize = MAGICNUMBER_SIZE;
2212*27162e4eSAndroid Build Coastguard Worker size_t outSize= 0;
2213*27162e4eSAndroid Build Coastguard Worker LZ4IO_writeLE32(ress.srcBuffer, LZ4IO_MAGICNUMBER);
2214*27162e4eSAndroid Build Coastguard Worker nextToLoad = LZ4F_decompress_usingDict(ress.dCtx,
2215*27162e4eSAndroid Build Coastguard Worker ress.dstBuffer, &outSize,
2216*27162e4eSAndroid Build Coastguard Worker ress.srcBuffer, &inSize,
2217*27162e4eSAndroid Build Coastguard Worker ress.dictBuffer, ress.dictBufferSize,
2218*27162e4eSAndroid Build Coastguard Worker dOptPtr); /* set it once, it's enough */
2219*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(nextToLoad))
2220*27162e4eSAndroid Build Coastguard Worker END_PROCESS(62, "Header error : %s", LZ4F_getErrorName(nextToLoad));
2221*27162e4eSAndroid Build Coastguard Worker }
2222*27162e4eSAndroid Build Coastguard Worker
2223*27162e4eSAndroid Build Coastguard Worker /* Main Loop */
2224*27162e4eSAndroid Build Coastguard Worker for (;nextToLoad;) {
2225*27162e4eSAndroid Build Coastguard Worker size_t readSize;
2226*27162e4eSAndroid Build Coastguard Worker size_t pos = 0;
2227*27162e4eSAndroid Build Coastguard Worker size_t decodedBytes = ress.dstBufferSize;
2228*27162e4eSAndroid Build Coastguard Worker
2229*27162e4eSAndroid Build Coastguard Worker /* Read input */
2230*27162e4eSAndroid Build Coastguard Worker if (nextToLoad > ress.srcBufferSize) nextToLoad = ress.srcBufferSize;
2231*27162e4eSAndroid Build Coastguard Worker readSize = fread(ress.srcBuffer, 1, nextToLoad, srcFile);
2232*27162e4eSAndroid Build Coastguard Worker if (!readSize) break; /* reached end of file or stream */
2233*27162e4eSAndroid Build Coastguard Worker
2234*27162e4eSAndroid Build Coastguard Worker while ((pos < readSize) || (decodedBytes == ress.dstBufferSize)) { /* still to read, or still to flush */
2235*27162e4eSAndroid Build Coastguard Worker /* Decode Input (at least partially) */
2236*27162e4eSAndroid Build Coastguard Worker size_t remaining = readSize - pos;
2237*27162e4eSAndroid Build Coastguard Worker decodedBytes = ress.dstBufferSize;
2238*27162e4eSAndroid Build Coastguard Worker nextToLoad = LZ4F_decompress_usingDict(ress.dCtx,
2239*27162e4eSAndroid Build Coastguard Worker ress.dstBuffer, &decodedBytes,
2240*27162e4eSAndroid Build Coastguard Worker (char*)(ress.srcBuffer)+pos, &remaining,
2241*27162e4eSAndroid Build Coastguard Worker ress.dictBuffer, ress.dictBufferSize,
2242*27162e4eSAndroid Build Coastguard Worker NULL);
2243*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(nextToLoad))
2244*27162e4eSAndroid Build Coastguard Worker END_PROCESS(66, "Decompression error : %s", LZ4F_getErrorName(nextToLoad));
2245*27162e4eSAndroid Build Coastguard Worker pos += remaining;
2246*27162e4eSAndroid Build Coastguard Worker
2247*27162e4eSAndroid Build Coastguard Worker /* Write Block */
2248*27162e4eSAndroid Build Coastguard Worker if (decodedBytes) {
2249*27162e4eSAndroid Build Coastguard Worker if (!prefs->testMode)
2250*27162e4eSAndroid Build Coastguard Worker storedSkips = LZ4IO_fwriteSparse(dstFile, ress.dstBuffer, decodedBytes, prefs->sparseFileSupport, storedSkips);
2251*27162e4eSAndroid Build Coastguard Worker filesize += decodedBytes;
2252*27162e4eSAndroid Build Coastguard Worker DISPLAYUPDATE(2, "\rDecompressed : %u MiB ", (unsigned)(filesize>>20));
2253*27162e4eSAndroid Build Coastguard Worker }
2254*27162e4eSAndroid Build Coastguard Worker
2255*27162e4eSAndroid Build Coastguard Worker if (!nextToLoad) break;
2256*27162e4eSAndroid Build Coastguard Worker }
2257*27162e4eSAndroid Build Coastguard Worker }
2258*27162e4eSAndroid Build Coastguard Worker /* can be out because readSize == 0, which could be an fread() error */
2259*27162e4eSAndroid Build Coastguard Worker if (ferror(srcFile)) END_PROCESS(67, "Read error");
2260*27162e4eSAndroid Build Coastguard Worker
2261*27162e4eSAndroid Build Coastguard Worker if (!prefs->testMode) LZ4IO_fwriteSparseEnd(dstFile, storedSkips);
2262*27162e4eSAndroid Build Coastguard Worker if (nextToLoad!=0)
2263*27162e4eSAndroid Build Coastguard Worker END_PROCESS(68, "Unfinished stream (nextToLoad=%u)", (unsigned)nextToLoad);
2264*27162e4eSAndroid Build Coastguard Worker
2265*27162e4eSAndroid Build Coastguard Worker return filesize;
2266*27162e4eSAndroid Build Coastguard Worker }
2267*27162e4eSAndroid Build Coastguard Worker
2268*27162e4eSAndroid Build Coastguard Worker #endif /* LZ4IO_MULTITHREAD */
2269*27162e4eSAndroid Build Coastguard Worker
2270*27162e4eSAndroid Build Coastguard Worker /* LZ4IO_passThrough:
2271*27162e4eSAndroid Build Coastguard Worker * just output the same content as input, no decoding.
2272*27162e4eSAndroid Build Coastguard Worker * This is a capability of zcat, and by extension lz4cat
2273*27162e4eSAndroid Build Coastguard Worker * MNstore : contain the first MAGICNUMBER_SIZE bytes already read from finput
2274*27162e4eSAndroid Build Coastguard Worker */
2275*27162e4eSAndroid Build Coastguard Worker #define PTSIZE (64 KB)
2276*27162e4eSAndroid Build Coastguard Worker #define PTSIZET (PTSIZE / sizeof(size_t))
2277*27162e4eSAndroid Build Coastguard Worker static unsigned long long
LZ4IO_passThrough(FILE * finput,FILE * foutput,unsigned char MNstore[MAGICNUMBER_SIZE],int sparseFileSupport)2278*27162e4eSAndroid Build Coastguard Worker LZ4IO_passThrough(FILE* finput, FILE* foutput,
2279*27162e4eSAndroid Build Coastguard Worker unsigned char MNstore[MAGICNUMBER_SIZE],
2280*27162e4eSAndroid Build Coastguard Worker int sparseFileSupport)
2281*27162e4eSAndroid Build Coastguard Worker {
2282*27162e4eSAndroid Build Coastguard Worker size_t buffer[PTSIZET];
2283*27162e4eSAndroid Build Coastguard Worker size_t readBytes = 1;
2284*27162e4eSAndroid Build Coastguard Worker unsigned long long total = MAGICNUMBER_SIZE;
2285*27162e4eSAndroid Build Coastguard Worker unsigned storedSkips = 0;
2286*27162e4eSAndroid Build Coastguard Worker
2287*27162e4eSAndroid Build Coastguard Worker if (fwrite(MNstore, 1, MAGICNUMBER_SIZE, foutput) != MAGICNUMBER_SIZE) {
2288*27162e4eSAndroid Build Coastguard Worker END_PROCESS(50, "Pass-through write error");
2289*27162e4eSAndroid Build Coastguard Worker }
2290*27162e4eSAndroid Build Coastguard Worker while (readBytes) {
2291*27162e4eSAndroid Build Coastguard Worker readBytes = fread(buffer, 1, sizeof(buffer), finput);
2292*27162e4eSAndroid Build Coastguard Worker total += readBytes;
2293*27162e4eSAndroid Build Coastguard Worker storedSkips = LZ4IO_fwriteSparse(foutput, buffer, readBytes, sparseFileSupport, storedSkips);
2294*27162e4eSAndroid Build Coastguard Worker }
2295*27162e4eSAndroid Build Coastguard Worker if (ferror(finput)) END_PROCESS(51, "Read Error");
2296*27162e4eSAndroid Build Coastguard Worker
2297*27162e4eSAndroid Build Coastguard Worker LZ4IO_fwriteSparseEnd(foutput, storedSkips);
2298*27162e4eSAndroid Build Coastguard Worker return total;
2299*27162e4eSAndroid Build Coastguard Worker }
2300*27162e4eSAndroid Build Coastguard Worker
2301*27162e4eSAndroid Build Coastguard Worker /* when fseek() doesn't work (pipe scenario),
2302*27162e4eSAndroid Build Coastguard Worker * read and forget from input.
2303*27162e4eSAndroid Build Coastguard Worker **/
2304*27162e4eSAndroid Build Coastguard Worker #define SKIP_BUFF_SIZE (16 KB)
skipStream(FILE * f,unsigned offset)2305*27162e4eSAndroid Build Coastguard Worker static int skipStream(FILE* f, unsigned offset)
2306*27162e4eSAndroid Build Coastguard Worker {
2307*27162e4eSAndroid Build Coastguard Worker char buf[SKIP_BUFF_SIZE];
2308*27162e4eSAndroid Build Coastguard Worker while (offset > 0) {
2309*27162e4eSAndroid Build Coastguard Worker size_t const tr = MIN(offset, sizeof(buf));
2310*27162e4eSAndroid Build Coastguard Worker size_t const r = fread(buf, 1, tr, f);
2311*27162e4eSAndroid Build Coastguard Worker if (r != tr) return 1; /* error reading f */
2312*27162e4eSAndroid Build Coastguard Worker offset -= (unsigned)tr;
2313*27162e4eSAndroid Build Coastguard Worker }
2314*27162e4eSAndroid Build Coastguard Worker assert(offset == 0);
2315*27162e4eSAndroid Build Coastguard Worker return 0;
2316*27162e4eSAndroid Build Coastguard Worker }
2317*27162e4eSAndroid Build Coastguard Worker
2318*27162e4eSAndroid Build Coastguard Worker /** Safely handle cases when (unsigned)offset > LONG_MAX */
fseek_u32(FILE * fp,unsigned offset,int where)2319*27162e4eSAndroid Build Coastguard Worker static int fseek_u32(FILE *fp, unsigned offset, int where)
2320*27162e4eSAndroid Build Coastguard Worker {
2321*27162e4eSAndroid Build Coastguard Worker const unsigned stepMax = 1U << 30;
2322*27162e4eSAndroid Build Coastguard Worker int errorNb = 0;
2323*27162e4eSAndroid Build Coastguard Worker
2324*27162e4eSAndroid Build Coastguard Worker if (where != SEEK_CUR) return -1; /* Only allows SEEK_CUR */
2325*27162e4eSAndroid Build Coastguard Worker while (offset > 0) {
2326*27162e4eSAndroid Build Coastguard Worker unsigned s = offset;
2327*27162e4eSAndroid Build Coastguard Worker if (s > stepMax) s = stepMax;
2328*27162e4eSAndroid Build Coastguard Worker errorNb = UTIL_fseek(fp, (long)s, SEEK_CUR);
2329*27162e4eSAndroid Build Coastguard Worker if (errorNb==0) { offset -= s; continue; }
2330*27162e4eSAndroid Build Coastguard Worker errorNb = skipStream(fp, offset);
2331*27162e4eSAndroid Build Coastguard Worker offset = 0;
2332*27162e4eSAndroid Build Coastguard Worker }
2333*27162e4eSAndroid Build Coastguard Worker return errorNb;
2334*27162e4eSAndroid Build Coastguard Worker }
2335*27162e4eSAndroid Build Coastguard Worker
2336*27162e4eSAndroid Build Coastguard Worker
2337*27162e4eSAndroid Build Coastguard Worker #define ENDOFSTREAM ((unsigned long long)-1)
2338*27162e4eSAndroid Build Coastguard Worker #define DECODING_ERROR ((unsigned long long)-2)
2339*27162e4eSAndroid Build Coastguard Worker static unsigned long long
selectDecoder(dRess_t ress,FILE * finput,FILE * foutput,const LZ4IO_prefs_t * const prefs)2340*27162e4eSAndroid Build Coastguard Worker selectDecoder(dRess_t ress,
2341*27162e4eSAndroid Build Coastguard Worker FILE* finput, FILE* foutput,
2342*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* const prefs)
2343*27162e4eSAndroid Build Coastguard Worker {
2344*27162e4eSAndroid Build Coastguard Worker unsigned char MNstore[MAGICNUMBER_SIZE];
2345*27162e4eSAndroid Build Coastguard Worker unsigned magicNumber;
2346*27162e4eSAndroid Build Coastguard Worker static unsigned nbFrames = 0;
2347*27162e4eSAndroid Build Coastguard Worker
2348*27162e4eSAndroid Build Coastguard Worker /* init */
2349*27162e4eSAndroid Build Coastguard Worker nbFrames++;
2350*27162e4eSAndroid Build Coastguard Worker
2351*27162e4eSAndroid Build Coastguard Worker /* Check Archive Header */
2352*27162e4eSAndroid Build Coastguard Worker if (g_magicRead) { /* magic number already read from finput (see legacy frame)*/
2353*27162e4eSAndroid Build Coastguard Worker magicNumber = g_magicRead;
2354*27162e4eSAndroid Build Coastguard Worker g_magicRead = 0;
2355*27162e4eSAndroid Build Coastguard Worker } else {
2356*27162e4eSAndroid Build Coastguard Worker size_t const nbReadBytes = fread(MNstore, 1, MAGICNUMBER_SIZE, finput);
2357*27162e4eSAndroid Build Coastguard Worker if (nbReadBytes==0) { nbFrames = 0; return ENDOFSTREAM; } /* EOF */
2358*27162e4eSAndroid Build Coastguard Worker if (nbReadBytes != MAGICNUMBER_SIZE)
2359*27162e4eSAndroid Build Coastguard Worker END_PROCESS(40, "Unrecognized header : Magic Number unreadable");
2360*27162e4eSAndroid Build Coastguard Worker magicNumber = LZ4IO_readLE32(MNstore); /* Little Endian format */
2361*27162e4eSAndroid Build Coastguard Worker }
2362*27162e4eSAndroid Build Coastguard Worker if (LZ4IO_isSkippableMagicNumber(magicNumber))
2363*27162e4eSAndroid Build Coastguard Worker magicNumber = LZ4IO_SKIPPABLE0; /* fold skippable magic numbers */
2364*27162e4eSAndroid Build Coastguard Worker
2365*27162e4eSAndroid Build Coastguard Worker switch(magicNumber)
2366*27162e4eSAndroid Build Coastguard Worker {
2367*27162e4eSAndroid Build Coastguard Worker case LZ4IO_MAGICNUMBER:
2368*27162e4eSAndroid Build Coastguard Worker return LZ4IO_decompressLZ4F(ress, finput, foutput, prefs);
2369*27162e4eSAndroid Build Coastguard Worker case LEGACY_MAGICNUMBER:
2370*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(4, "Detected : Legacy format \n");
2371*27162e4eSAndroid Build Coastguard Worker return LZ4IO_decodeLegacyStream(finput, foutput, prefs);
2372*27162e4eSAndroid Build Coastguard Worker case LZ4IO_SKIPPABLE0:
2373*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(4, "Skipping detected skippable area \n");
2374*27162e4eSAndroid Build Coastguard Worker { size_t const nbReadBytes = fread(MNstore, 1, 4, finput);
2375*27162e4eSAndroid Build Coastguard Worker if (nbReadBytes != 4)
2376*27162e4eSAndroid Build Coastguard Worker END_PROCESS(42, "Stream error : skippable size unreadable");
2377*27162e4eSAndroid Build Coastguard Worker }
2378*27162e4eSAndroid Build Coastguard Worker { unsigned const size = LZ4IO_readLE32(MNstore);
2379*27162e4eSAndroid Build Coastguard Worker int const errorNb = fseek_u32(finput, size, SEEK_CUR);
2380*27162e4eSAndroid Build Coastguard Worker if (errorNb != 0)
2381*27162e4eSAndroid Build Coastguard Worker END_PROCESS(43, "Stream error : cannot skip skippable area");
2382*27162e4eSAndroid Build Coastguard Worker }
2383*27162e4eSAndroid Build Coastguard Worker return 0;
2384*27162e4eSAndroid Build Coastguard Worker default:
2385*27162e4eSAndroid Build Coastguard Worker if (nbFrames == 1) { /* just started */
2386*27162e4eSAndroid Build Coastguard Worker /* Wrong magic number at the beginning of 1st stream */
2387*27162e4eSAndroid Build Coastguard Worker if (!prefs->testMode && prefs->overwrite && prefs->passThrough) {
2388*27162e4eSAndroid Build Coastguard Worker nbFrames = 0;
2389*27162e4eSAndroid Build Coastguard Worker return LZ4IO_passThrough(finput, foutput, MNstore, prefs->sparseFileSupport);
2390*27162e4eSAndroid Build Coastguard Worker }
2391*27162e4eSAndroid Build Coastguard Worker END_PROCESS(44,"Unrecognized header : file cannot be decoded");
2392*27162e4eSAndroid Build Coastguard Worker }
2393*27162e4eSAndroid Build Coastguard Worker { long int const position = ftell(finput); /* only works for files < 2 GB */
2394*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2, "Stream followed by undecodable data ");
2395*27162e4eSAndroid Build Coastguard Worker if (position != -1L)
2396*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2, "at position %i ", (int)position);
2397*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2, "\n");
2398*27162e4eSAndroid Build Coastguard Worker }
2399*27162e4eSAndroid Build Coastguard Worker return DECODING_ERROR;
2400*27162e4eSAndroid Build Coastguard Worker }
2401*27162e4eSAndroid Build Coastguard Worker }
2402*27162e4eSAndroid Build Coastguard Worker
2403*27162e4eSAndroid Build Coastguard Worker
2404*27162e4eSAndroid Build Coastguard Worker static int
LZ4IO_decompressSrcFile(unsigned long long * outGenSize,dRess_t ress,const char * input_filename,const char * output_filename,const LZ4IO_prefs_t * const prefs)2405*27162e4eSAndroid Build Coastguard Worker LZ4IO_decompressSrcFile(unsigned long long* outGenSize,
2406*27162e4eSAndroid Build Coastguard Worker dRess_t ress,
2407*27162e4eSAndroid Build Coastguard Worker const char* input_filename, const char* output_filename,
2408*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* const prefs)
2409*27162e4eSAndroid Build Coastguard Worker {
2410*27162e4eSAndroid Build Coastguard Worker FILE* const foutput = ress.dstFile;
2411*27162e4eSAndroid Build Coastguard Worker unsigned long long filesize = 0;
2412*27162e4eSAndroid Build Coastguard Worker int result = 0;
2413*27162e4eSAndroid Build Coastguard Worker
2414*27162e4eSAndroid Build Coastguard Worker /* Init */
2415*27162e4eSAndroid Build Coastguard Worker FILE* const finput = LZ4IO_openSrcFile(input_filename);
2416*27162e4eSAndroid Build Coastguard Worker if (finput==NULL) return 1;
2417*27162e4eSAndroid Build Coastguard Worker assert(foutput != NULL);
2418*27162e4eSAndroid Build Coastguard Worker
2419*27162e4eSAndroid Build Coastguard Worker /* Loop over multiple streams */
2420*27162e4eSAndroid Build Coastguard Worker for ( ; ; ) { /* endless loop, see break condition */
2421*27162e4eSAndroid Build Coastguard Worker unsigned long long const decodedSize =
2422*27162e4eSAndroid Build Coastguard Worker selectDecoder(ress, finput, foutput, prefs);
2423*27162e4eSAndroid Build Coastguard Worker if (decodedSize == ENDOFSTREAM) break;
2424*27162e4eSAndroid Build Coastguard Worker if (decodedSize == DECODING_ERROR) { result=1; break; }
2425*27162e4eSAndroid Build Coastguard Worker filesize += decodedSize;
2426*27162e4eSAndroid Build Coastguard Worker }
2427*27162e4eSAndroid Build Coastguard Worker
2428*27162e4eSAndroid Build Coastguard Worker /* Close input */
2429*27162e4eSAndroid Build Coastguard Worker fclose(finput);
2430*27162e4eSAndroid Build Coastguard Worker if (prefs->removeSrcFile) { /* --rm */
2431*27162e4eSAndroid Build Coastguard Worker if (remove(input_filename))
2432*27162e4eSAndroid Build Coastguard Worker END_PROCESS(45, "Remove error : %s: %s", input_filename, strerror(errno));
2433*27162e4eSAndroid Build Coastguard Worker }
2434*27162e4eSAndroid Build Coastguard Worker
2435*27162e4eSAndroid Build Coastguard Worker /* Final Status */
2436*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2, "\r%79s\r", "");
2437*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(2, "%-30.30s : decoded %llu bytes \n", input_filename, filesize);
2438*27162e4eSAndroid Build Coastguard Worker *outGenSize = filesize;
2439*27162e4eSAndroid Build Coastguard Worker (void)output_filename;
2440*27162e4eSAndroid Build Coastguard Worker
2441*27162e4eSAndroid Build Coastguard Worker return result;
2442*27162e4eSAndroid Build Coastguard Worker }
2443*27162e4eSAndroid Build Coastguard Worker
2444*27162e4eSAndroid Build Coastguard Worker
2445*27162e4eSAndroid Build Coastguard Worker static int
LZ4IO_decompressDstFile(unsigned long long * outGenSize,dRess_t ress,const char * input_filename,const char * output_filename,const LZ4IO_prefs_t * const prefs)2446*27162e4eSAndroid Build Coastguard Worker LZ4IO_decompressDstFile(unsigned long long* outGenSize,
2447*27162e4eSAndroid Build Coastguard Worker dRess_t ress,
2448*27162e4eSAndroid Build Coastguard Worker const char* input_filename,
2449*27162e4eSAndroid Build Coastguard Worker const char* output_filename,
2450*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* const prefs)
2451*27162e4eSAndroid Build Coastguard Worker {
2452*27162e4eSAndroid Build Coastguard Worker int result;
2453*27162e4eSAndroid Build Coastguard Worker stat_t statbuf;
2454*27162e4eSAndroid Build Coastguard Worker int stat_result = 0;
2455*27162e4eSAndroid Build Coastguard Worker FILE* const foutput = LZ4IO_openDstFile(output_filename, prefs);
2456*27162e4eSAndroid Build Coastguard Worker if (foutput==NULL) return 1; /* failure */
2457*27162e4eSAndroid Build Coastguard Worker
2458*27162e4eSAndroid Build Coastguard Worker if ( !LZ4IO_isStdin(input_filename)
2459*27162e4eSAndroid Build Coastguard Worker && UTIL_getFileStat(input_filename, &statbuf))
2460*27162e4eSAndroid Build Coastguard Worker stat_result = 1;
2461*27162e4eSAndroid Build Coastguard Worker
2462*27162e4eSAndroid Build Coastguard Worker ress.dstFile = foutput;
2463*27162e4eSAndroid Build Coastguard Worker result = LZ4IO_decompressSrcFile(outGenSize, ress, input_filename, output_filename, prefs);
2464*27162e4eSAndroid Build Coastguard Worker
2465*27162e4eSAndroid Build Coastguard Worker fclose(foutput);
2466*27162e4eSAndroid Build Coastguard Worker
2467*27162e4eSAndroid Build Coastguard Worker /* Copy owner, file permissions and modification time */
2468*27162e4eSAndroid Build Coastguard Worker if ( stat_result != 0
2469*27162e4eSAndroid Build Coastguard Worker && !LZ4IO_isStdout(output_filename)
2470*27162e4eSAndroid Build Coastguard Worker && !LZ4IO_isDevNull(output_filename)) {
2471*27162e4eSAndroid Build Coastguard Worker UTIL_setFileStat(output_filename, &statbuf);
2472*27162e4eSAndroid Build Coastguard Worker /* should return value be read ? or is silent fail good enough ? */
2473*27162e4eSAndroid Build Coastguard Worker }
2474*27162e4eSAndroid Build Coastguard Worker
2475*27162e4eSAndroid Build Coastguard Worker return result;
2476*27162e4eSAndroid Build Coastguard Worker }
2477*27162e4eSAndroid Build Coastguard Worker
2478*27162e4eSAndroid Build Coastguard Worker
2479*27162e4eSAndroid Build Coastguard Worker /* Note : LZ4IO_decompressFilename()
2480*27162e4eSAndroid Build Coastguard Worker * can provide total decompression time for the specified fileName.
2481*27162e4eSAndroid Build Coastguard Worker * This information is not available with LZ4IO_decompressMultipleFilenames().
2482*27162e4eSAndroid Build Coastguard Worker */
LZ4IO_decompressFilename(const char * input_filename,const char * output_filename,const LZ4IO_prefs_t * prefs)2483*27162e4eSAndroid Build Coastguard Worker int LZ4IO_decompressFilename(const char* input_filename, const char* output_filename, const LZ4IO_prefs_t* prefs)
2484*27162e4eSAndroid Build Coastguard Worker {
2485*27162e4eSAndroid Build Coastguard Worker dRess_t const ress = LZ4IO_createDResources(prefs);
2486*27162e4eSAndroid Build Coastguard Worker TIME_t const timeStart = TIME_getTime();
2487*27162e4eSAndroid Build Coastguard Worker clock_t const cpuStart = clock();
2488*27162e4eSAndroid Build Coastguard Worker unsigned long long processed = 0;
2489*27162e4eSAndroid Build Coastguard Worker
2490*27162e4eSAndroid Build Coastguard Worker int const errStat = LZ4IO_decompressDstFile(&processed, ress, input_filename, output_filename, prefs);
2491*27162e4eSAndroid Build Coastguard Worker if (errStat)
2492*27162e4eSAndroid Build Coastguard Worker LZ4IO_finalTimeDisplay(timeStart, cpuStart, processed);
2493*27162e4eSAndroid Build Coastguard Worker LZ4IO_freeDResources(ress);
2494*27162e4eSAndroid Build Coastguard Worker return errStat;
2495*27162e4eSAndroid Build Coastguard Worker }
2496*27162e4eSAndroid Build Coastguard Worker
2497*27162e4eSAndroid Build Coastguard Worker
LZ4IO_decompressMultipleFilenames(const char ** inFileNamesTable,int ifntSize,const char * suffix,const LZ4IO_prefs_t * prefs)2498*27162e4eSAndroid Build Coastguard Worker int LZ4IO_decompressMultipleFilenames(
2499*27162e4eSAndroid Build Coastguard Worker const char** inFileNamesTable, int ifntSize,
2500*27162e4eSAndroid Build Coastguard Worker const char* suffix,
2501*27162e4eSAndroid Build Coastguard Worker const LZ4IO_prefs_t* prefs)
2502*27162e4eSAndroid Build Coastguard Worker {
2503*27162e4eSAndroid Build Coastguard Worker int i;
2504*27162e4eSAndroid Build Coastguard Worker unsigned long long totalProcessed = 0;
2505*27162e4eSAndroid Build Coastguard Worker int skippedFiles = 0;
2506*27162e4eSAndroid Build Coastguard Worker int missingFiles = 0;
2507*27162e4eSAndroid Build Coastguard Worker char* outFileName = (char*)malloc(FNSPACE);
2508*27162e4eSAndroid Build Coastguard Worker size_t ofnSize = FNSPACE;
2509*27162e4eSAndroid Build Coastguard Worker size_t const suffixSize = strlen(suffix);
2510*27162e4eSAndroid Build Coastguard Worker dRess_t ress = LZ4IO_createDResources(prefs);
2511*27162e4eSAndroid Build Coastguard Worker TIME_t timeStart = TIME_getTime();
2512*27162e4eSAndroid Build Coastguard Worker clock_t cpuStart = clock();
2513*27162e4eSAndroid Build Coastguard Worker
2514*27162e4eSAndroid Build Coastguard Worker if (outFileName==NULL) END_PROCESS(70, "Memory allocation error");
2515*27162e4eSAndroid Build Coastguard Worker if (prefs->blockChecksum==0 && prefs->streamChecksum==0) {
2516*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(4, "disabling checksum validation during decoding \n");
2517*27162e4eSAndroid Build Coastguard Worker }
2518*27162e4eSAndroid Build Coastguard Worker ress.dstFile = LZ4IO_openDstFile(stdoutmark, prefs);
2519*27162e4eSAndroid Build Coastguard Worker
2520*27162e4eSAndroid Build Coastguard Worker for (i=0; i<ifntSize; i++) {
2521*27162e4eSAndroid Build Coastguard Worker unsigned long long processed = 0;
2522*27162e4eSAndroid Build Coastguard Worker size_t const ifnSize = strlen(inFileNamesTable[i]);
2523*27162e4eSAndroid Build Coastguard Worker const char* const suffixPtr = inFileNamesTable[i] + ifnSize - suffixSize;
2524*27162e4eSAndroid Build Coastguard Worker if (LZ4IO_isStdout(suffix) || LZ4IO_isDevNull(suffix)) {
2525*27162e4eSAndroid Build Coastguard Worker missingFiles += LZ4IO_decompressSrcFile(&processed, ress, inFileNamesTable[i], suffix, prefs);
2526*27162e4eSAndroid Build Coastguard Worker totalProcessed += processed;
2527*27162e4eSAndroid Build Coastguard Worker continue;
2528*27162e4eSAndroid Build Coastguard Worker }
2529*27162e4eSAndroid Build Coastguard Worker if (ofnSize <= ifnSize-suffixSize+1) {
2530*27162e4eSAndroid Build Coastguard Worker free(outFileName);
2531*27162e4eSAndroid Build Coastguard Worker ofnSize = ifnSize + 20;
2532*27162e4eSAndroid Build Coastguard Worker outFileName = (char*)malloc(ofnSize);
2533*27162e4eSAndroid Build Coastguard Worker if (outFileName==NULL) END_PROCESS(71, "Memory allocation error");
2534*27162e4eSAndroid Build Coastguard Worker }
2535*27162e4eSAndroid Build Coastguard Worker if (ifnSize <= suffixSize || !UTIL_sameString(suffixPtr, suffix) ) {
2536*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(1, "File extension doesn't match expected LZ4_EXTENSION (%4s); will not process file: %s\n", suffix, inFileNamesTable[i]);
2537*27162e4eSAndroid Build Coastguard Worker skippedFiles++;
2538*27162e4eSAndroid Build Coastguard Worker continue;
2539*27162e4eSAndroid Build Coastguard Worker }
2540*27162e4eSAndroid Build Coastguard Worker memcpy(outFileName, inFileNamesTable[i], ifnSize - suffixSize);
2541*27162e4eSAndroid Build Coastguard Worker outFileName[ifnSize-suffixSize] = '\0';
2542*27162e4eSAndroid Build Coastguard Worker missingFiles += LZ4IO_decompressDstFile(&processed, ress, inFileNamesTable[i], outFileName, prefs);
2543*27162e4eSAndroid Build Coastguard Worker totalProcessed += processed;
2544*27162e4eSAndroid Build Coastguard Worker }
2545*27162e4eSAndroid Build Coastguard Worker
2546*27162e4eSAndroid Build Coastguard Worker LZ4IO_freeDResources(ress);
2547*27162e4eSAndroid Build Coastguard Worker free(outFileName);
2548*27162e4eSAndroid Build Coastguard Worker LZ4IO_finalTimeDisplay(timeStart, cpuStart, totalProcessed);
2549*27162e4eSAndroid Build Coastguard Worker return missingFiles + skippedFiles;
2550*27162e4eSAndroid Build Coastguard Worker }
2551*27162e4eSAndroid Build Coastguard Worker
2552*27162e4eSAndroid Build Coastguard Worker
2553*27162e4eSAndroid Build Coastguard Worker /* ********************************************************************* */
2554*27162e4eSAndroid Build Coastguard Worker /* ********************** LZ4 --list command *********************** */
2555*27162e4eSAndroid Build Coastguard Worker /* ********************************************************************* */
2556*27162e4eSAndroid Build Coastguard Worker
2557*27162e4eSAndroid Build Coastguard Worker typedef enum
2558*27162e4eSAndroid Build Coastguard Worker {
2559*27162e4eSAndroid Build Coastguard Worker lz4Frame = 0,
2560*27162e4eSAndroid Build Coastguard Worker legacyFrame,
2561*27162e4eSAndroid Build Coastguard Worker skippableFrame
2562*27162e4eSAndroid Build Coastguard Worker } LZ4IO_frameType_t;
2563*27162e4eSAndroid Build Coastguard Worker
2564*27162e4eSAndroid Build Coastguard Worker typedef struct {
2565*27162e4eSAndroid Build Coastguard Worker LZ4F_frameInfo_t lz4FrameInfo;
2566*27162e4eSAndroid Build Coastguard Worker LZ4IO_frameType_t frameType;
2567*27162e4eSAndroid Build Coastguard Worker } LZ4IO_frameInfo_t;
2568*27162e4eSAndroid Build Coastguard Worker
2569*27162e4eSAndroid Build Coastguard Worker #define LZ4IO_INIT_FRAMEINFO { LZ4F_INIT_FRAMEINFO, lz4Frame }
2570*27162e4eSAndroid Build Coastguard Worker
2571*27162e4eSAndroid Build Coastguard Worker typedef struct {
2572*27162e4eSAndroid Build Coastguard Worker const char* fileName;
2573*27162e4eSAndroid Build Coastguard Worker unsigned long long fileSize;
2574*27162e4eSAndroid Build Coastguard Worker unsigned long long frameCount;
2575*27162e4eSAndroid Build Coastguard Worker LZ4IO_frameInfo_t frameSummary;
2576*27162e4eSAndroid Build Coastguard Worker unsigned short eqFrameTypes;
2577*27162e4eSAndroid Build Coastguard Worker unsigned short eqBlockTypes;
2578*27162e4eSAndroid Build Coastguard Worker unsigned short allContentSize;
2579*27162e4eSAndroid Build Coastguard Worker } LZ4IO_cFileInfo_t;
2580*27162e4eSAndroid Build Coastguard Worker
2581*27162e4eSAndroid Build Coastguard Worker #define LZ4IO_INIT_CFILEINFO { NULL, 0ULL, 0, LZ4IO_INIT_FRAMEINFO, 1, 1, 1 }
2582*27162e4eSAndroid Build Coastguard Worker
2583*27162e4eSAndroid Build Coastguard Worker typedef enum { LZ4IO_LZ4F_OK, LZ4IO_format_not_known, LZ4IO_not_a_file } LZ4IO_infoResult;
2584*27162e4eSAndroid Build Coastguard Worker
2585*27162e4eSAndroid Build Coastguard Worker static const char * LZ4IO_frameTypeNames[] = {"LZ4Frame", "LegacyFrame", "SkippableFrame" };
2586*27162e4eSAndroid Build Coastguard Worker
2587*27162e4eSAndroid Build Coastguard Worker /* Read block headers and skip block data
2588*27162e4eSAndroid Build Coastguard Worker Return total blocks size for this frame including block headers,
2589*27162e4eSAndroid Build Coastguard Worker block checksums and content checksums.
2590*27162e4eSAndroid Build Coastguard Worker returns 0 in case it can't successfully skip block data.
2591*27162e4eSAndroid Build Coastguard Worker Assumes SEEK_CUR after frame header.
2592*27162e4eSAndroid Build Coastguard Worker */
2593*27162e4eSAndroid Build Coastguard Worker static unsigned long long
LZ4IO_skipBlocksData(FILE * finput,const LZ4F_blockChecksum_t blockChecksumFlag,const LZ4F_contentChecksum_t contentChecksumFlag)2594*27162e4eSAndroid Build Coastguard Worker LZ4IO_skipBlocksData(FILE* finput,
2595*27162e4eSAndroid Build Coastguard Worker const LZ4F_blockChecksum_t blockChecksumFlag,
2596*27162e4eSAndroid Build Coastguard Worker const LZ4F_contentChecksum_t contentChecksumFlag)
2597*27162e4eSAndroid Build Coastguard Worker {
2598*27162e4eSAndroid Build Coastguard Worker unsigned char blockInfo[LZ4F_BLOCK_HEADER_SIZE];
2599*27162e4eSAndroid Build Coastguard Worker unsigned long long totalBlocksSize = 0;
2600*27162e4eSAndroid Build Coastguard Worker for (;;) {
2601*27162e4eSAndroid Build Coastguard Worker if (!fread(blockInfo, 1, LZ4F_BLOCK_HEADER_SIZE, finput)) {
2602*27162e4eSAndroid Build Coastguard Worker if (feof(finput)) return totalBlocksSize;
2603*27162e4eSAndroid Build Coastguard Worker return 0;
2604*27162e4eSAndroid Build Coastguard Worker }
2605*27162e4eSAndroid Build Coastguard Worker totalBlocksSize += LZ4F_BLOCK_HEADER_SIZE;
2606*27162e4eSAndroid Build Coastguard Worker { const unsigned long nextCBlockSize = LZ4IO_readLE32(&blockInfo) & 0x7FFFFFFFU;
2607*27162e4eSAndroid Build Coastguard Worker const unsigned long nextBlock = nextCBlockSize + (blockChecksumFlag * LZ4F_BLOCK_CHECKSUM_SIZE);
2608*27162e4eSAndroid Build Coastguard Worker if (nextCBlockSize == 0) {
2609*27162e4eSAndroid Build Coastguard Worker /* Reached EndMark */
2610*27162e4eSAndroid Build Coastguard Worker if (contentChecksumFlag) {
2611*27162e4eSAndroid Build Coastguard Worker /* Skip content checksum */
2612*27162e4eSAndroid Build Coastguard Worker if (UTIL_fseek(finput, LZ4F_CONTENT_CHECKSUM_SIZE, SEEK_CUR) != 0) {
2613*27162e4eSAndroid Build Coastguard Worker return 0;
2614*27162e4eSAndroid Build Coastguard Worker }
2615*27162e4eSAndroid Build Coastguard Worker totalBlocksSize += LZ4F_CONTENT_CHECKSUM_SIZE;
2616*27162e4eSAndroid Build Coastguard Worker }
2617*27162e4eSAndroid Build Coastguard Worker break;
2618*27162e4eSAndroid Build Coastguard Worker }
2619*27162e4eSAndroid Build Coastguard Worker totalBlocksSize += nextBlock;
2620*27162e4eSAndroid Build Coastguard Worker /* skip to the next block */
2621*27162e4eSAndroid Build Coastguard Worker assert(nextBlock < LONG_MAX);
2622*27162e4eSAndroid Build Coastguard Worker if (UTIL_fseek(finput, (long)nextBlock, SEEK_CUR) != 0) return 0;
2623*27162e4eSAndroid Build Coastguard Worker } }
2624*27162e4eSAndroid Build Coastguard Worker return totalBlocksSize;
2625*27162e4eSAndroid Build Coastguard Worker }
2626*27162e4eSAndroid Build Coastguard Worker
2627*27162e4eSAndroid Build Coastguard Worker static const unsigned long long legacyFrameUndecodable = (0ULL-1);
2628*27162e4eSAndroid Build Coastguard Worker /* For legacy frames only.
2629*27162e4eSAndroid Build Coastguard Worker Read block headers and skip block data.
2630*27162e4eSAndroid Build Coastguard Worker Return total blocks size for this frame including block headers.
2631*27162e4eSAndroid Build Coastguard Worker or legacyFrameUndecodable in case it can't successfully skip block data.
2632*27162e4eSAndroid Build Coastguard Worker This works as long as legacy block header size = magic number size.
2633*27162e4eSAndroid Build Coastguard Worker Assumes SEEK_CUR after frame header.
2634*27162e4eSAndroid Build Coastguard Worker */
LZ4IO_skipLegacyBlocksData(FILE * finput)2635*27162e4eSAndroid Build Coastguard Worker static unsigned long long LZ4IO_skipLegacyBlocksData(FILE* finput)
2636*27162e4eSAndroid Build Coastguard Worker {
2637*27162e4eSAndroid Build Coastguard Worker unsigned char blockInfo[LZ4IO_LEGACY_BLOCK_HEADER_SIZE];
2638*27162e4eSAndroid Build Coastguard Worker unsigned long long totalBlocksSize = 0;
2639*27162e4eSAndroid Build Coastguard Worker LZ4IO_STATIC_ASSERT(LZ4IO_LEGACY_BLOCK_HEADER_SIZE == MAGICNUMBER_SIZE);
2640*27162e4eSAndroid Build Coastguard Worker for (;;) {
2641*27162e4eSAndroid Build Coastguard Worker size_t const bhs = fread(blockInfo, 1, LZ4IO_LEGACY_BLOCK_HEADER_SIZE, finput);
2642*27162e4eSAndroid Build Coastguard Worker if (bhs == 0) {
2643*27162e4eSAndroid Build Coastguard Worker if (feof(finput)) return totalBlocksSize;
2644*27162e4eSAndroid Build Coastguard Worker return legacyFrameUndecodable;
2645*27162e4eSAndroid Build Coastguard Worker }
2646*27162e4eSAndroid Build Coastguard Worker if (bhs != 4) {
2647*27162e4eSAndroid Build Coastguard Worker return legacyFrameUndecodable;
2648*27162e4eSAndroid Build Coastguard Worker }
2649*27162e4eSAndroid Build Coastguard Worker { const unsigned int nextCBlockSize = LZ4IO_readLE32(&blockInfo);
2650*27162e4eSAndroid Build Coastguard Worker if ( nextCBlockSize == LEGACY_MAGICNUMBER
2651*27162e4eSAndroid Build Coastguard Worker || nextCBlockSize == LZ4IO_MAGICNUMBER
2652*27162e4eSAndroid Build Coastguard Worker || LZ4IO_isSkippableMagicNumber(nextCBlockSize) ) {
2653*27162e4eSAndroid Build Coastguard Worker /* Rewind back. we want cursor at the beginning of next frame */
2654*27162e4eSAndroid Build Coastguard Worker if (UTIL_fseek(finput, -LZ4IO_LEGACY_BLOCK_HEADER_SIZE, SEEK_CUR) != 0) {
2655*27162e4eSAndroid Build Coastguard Worker END_PROCESS(37, "impossible to skip backward");
2656*27162e4eSAndroid Build Coastguard Worker }
2657*27162e4eSAndroid Build Coastguard Worker break;
2658*27162e4eSAndroid Build Coastguard Worker }
2659*27162e4eSAndroid Build Coastguard Worker if (nextCBlockSize > LZ4IO_LEGACY_BLOCK_SIZE_MAX) {
2660*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(4, "Error : block in legacy frame is too large \n");
2661*27162e4eSAndroid Build Coastguard Worker return legacyFrameUndecodable;
2662*27162e4eSAndroid Build Coastguard Worker }
2663*27162e4eSAndroid Build Coastguard Worker totalBlocksSize += LZ4IO_LEGACY_BLOCK_HEADER_SIZE + nextCBlockSize;
2664*27162e4eSAndroid Build Coastguard Worker /* skip to the next block
2665*27162e4eSAndroid Build Coastguard Worker * note : this won't fail if nextCBlockSize is too large, skipping past the end of finput */
2666*27162e4eSAndroid Build Coastguard Worker if (UTIL_fseek(finput, nextCBlockSize, SEEK_CUR) != 0) {
2667*27162e4eSAndroid Build Coastguard Worker return legacyFrameUndecodable;
2668*27162e4eSAndroid Build Coastguard Worker } } }
2669*27162e4eSAndroid Build Coastguard Worker return totalBlocksSize;
2670*27162e4eSAndroid Build Coastguard Worker }
2671*27162e4eSAndroid Build Coastguard Worker
2672*27162e4eSAndroid Build Coastguard Worker /* LZ4IO_blockTypeID:
2673*27162e4eSAndroid Build Coastguard Worker * return human-readable block type, following command line convention
2674*27162e4eSAndroid Build Coastguard Worker * buffer : must be a valid memory area of at least 4 bytes */
LZ4IO_blockTypeID(LZ4F_blockSizeID_t sizeID,LZ4F_blockMode_t blockMode,char buffer[4])2675*27162e4eSAndroid Build Coastguard Worker const char* LZ4IO_blockTypeID(LZ4F_blockSizeID_t sizeID, LZ4F_blockMode_t blockMode, char buffer[4])
2676*27162e4eSAndroid Build Coastguard Worker {
2677*27162e4eSAndroid Build Coastguard Worker buffer[0] = 'B';
2678*27162e4eSAndroid Build Coastguard Worker assert(sizeID >= 4); assert(sizeID <= 7);
2679*27162e4eSAndroid Build Coastguard Worker buffer[1] = (char)(sizeID + '0');
2680*27162e4eSAndroid Build Coastguard Worker buffer[2] = (blockMode == LZ4F_blockIndependent) ? 'I' : 'D';
2681*27162e4eSAndroid Build Coastguard Worker buffer[3] = 0;
2682*27162e4eSAndroid Build Coastguard Worker return buffer;
2683*27162e4eSAndroid Build Coastguard Worker }
2684*27162e4eSAndroid Build Coastguard Worker
2685*27162e4eSAndroid Build Coastguard Worker /* buffer : must be valid memory area of at least 10 bytes */
LZ4IO_toHuman(long double size,char * buf)2686*27162e4eSAndroid Build Coastguard Worker static const char* LZ4IO_toHuman(long double size, char* buf)
2687*27162e4eSAndroid Build Coastguard Worker {
2688*27162e4eSAndroid Build Coastguard Worker const char units[] = {"\0KMGTPEZY"};
2689*27162e4eSAndroid Build Coastguard Worker size_t i = 0;
2690*27162e4eSAndroid Build Coastguard Worker for (; size >= 1024; i++) size /= 1024;
2691*27162e4eSAndroid Build Coastguard Worker sprintf(buf, "%.2Lf%c", size, units[i]);
2692*27162e4eSAndroid Build Coastguard Worker return buf;
2693*27162e4eSAndroid Build Coastguard Worker }
2694*27162e4eSAndroid Build Coastguard Worker
2695*27162e4eSAndroid Build Coastguard Worker /* Get filename without path prefix */
LZ4IO_baseName(const char * input_filename)2696*27162e4eSAndroid Build Coastguard Worker static const char* LZ4IO_baseName(const char* input_filename)
2697*27162e4eSAndroid Build Coastguard Worker {
2698*27162e4eSAndroid Build Coastguard Worker const char* b = strrchr(input_filename, '/');
2699*27162e4eSAndroid Build Coastguard Worker if (!b) b = strrchr(input_filename, '\\');
2700*27162e4eSAndroid Build Coastguard Worker if (!b) return input_filename;
2701*27162e4eSAndroid Build Coastguard Worker return b + 1;
2702*27162e4eSAndroid Build Coastguard Worker }
2703*27162e4eSAndroid Build Coastguard Worker
2704*27162e4eSAndroid Build Coastguard Worker /* Report frame/s information (--list) in verbose mode (-v).
2705*27162e4eSAndroid Build Coastguard Worker * Will populate file info with fileName and frameSummary where applicable.
2706*27162e4eSAndroid Build Coastguard Worker * - TODO :
2707*27162e4eSAndroid Build Coastguard Worker * + report nb of blocks, hence max. possible decompressed size (when not reported in header)
2708*27162e4eSAndroid Build Coastguard Worker */
2709*27162e4eSAndroid Build Coastguard Worker static LZ4IO_infoResult
LZ4IO_getCompressedFileInfo(LZ4IO_cFileInfo_t * cfinfo,const char * input_filename,int displayNow)2710*27162e4eSAndroid Build Coastguard Worker LZ4IO_getCompressedFileInfo(LZ4IO_cFileInfo_t* cfinfo, const char* input_filename, int displayNow)
2711*27162e4eSAndroid Build Coastguard Worker {
2712*27162e4eSAndroid Build Coastguard Worker LZ4IO_infoResult result = LZ4IO_format_not_known; /* default result (error) */
2713*27162e4eSAndroid Build Coastguard Worker unsigned char buffer[LZ4F_HEADER_SIZE_MAX];
2714*27162e4eSAndroid Build Coastguard Worker FILE* const finput = LZ4IO_openSrcFile(input_filename);
2715*27162e4eSAndroid Build Coastguard Worker
2716*27162e4eSAndroid Build Coastguard Worker if (finput == NULL) return LZ4IO_not_a_file;
2717*27162e4eSAndroid Build Coastguard Worker cfinfo->fileSize = UTIL_getOpenFileSize(finput);
2718*27162e4eSAndroid Build Coastguard Worker
2719*27162e4eSAndroid Build Coastguard Worker while (!feof(finput)) {
2720*27162e4eSAndroid Build Coastguard Worker LZ4IO_frameInfo_t frameInfo = LZ4IO_INIT_FRAMEINFO;
2721*27162e4eSAndroid Build Coastguard Worker unsigned magicNumber;
2722*27162e4eSAndroid Build Coastguard Worker /* Get MagicNumber */
2723*27162e4eSAndroid Build Coastguard Worker { size_t const nbReadBytes = fread(buffer, 1, MAGICNUMBER_SIZE, finput);
2724*27162e4eSAndroid Build Coastguard Worker if (nbReadBytes == 0) { break; } /* EOF */
2725*27162e4eSAndroid Build Coastguard Worker result = LZ4IO_format_not_known; /* default result (error) */
2726*27162e4eSAndroid Build Coastguard Worker if (nbReadBytes != MAGICNUMBER_SIZE) {
2727*27162e4eSAndroid Build Coastguard Worker END_PROCESS(40, "Unrecognized header : Magic Number unreadable");
2728*27162e4eSAndroid Build Coastguard Worker } }
2729*27162e4eSAndroid Build Coastguard Worker magicNumber = LZ4IO_readLE32(buffer); /* Little Endian format */
2730*27162e4eSAndroid Build Coastguard Worker if (LZ4IO_isSkippableMagicNumber(magicNumber))
2731*27162e4eSAndroid Build Coastguard Worker magicNumber = LZ4IO_SKIPPABLE0; /* fold skippable magic numbers */
2732*27162e4eSAndroid Build Coastguard Worker
2733*27162e4eSAndroid Build Coastguard Worker switch (magicNumber) {
2734*27162e4eSAndroid Build Coastguard Worker case LZ4IO_MAGICNUMBER:
2735*27162e4eSAndroid Build Coastguard Worker if (cfinfo->frameSummary.frameType != lz4Frame) cfinfo->eqFrameTypes = 0;
2736*27162e4eSAndroid Build Coastguard Worker /* Get frame info */
2737*27162e4eSAndroid Build Coastguard Worker { const size_t readBytes = fread(buffer + MAGICNUMBER_SIZE, 1, LZ4F_HEADER_SIZE_MIN - MAGICNUMBER_SIZE, finput);
2738*27162e4eSAndroid Build Coastguard Worker if (!readBytes || ferror(finput)) END_PROCESS(71, "Error reading %s", input_filename);
2739*27162e4eSAndroid Build Coastguard Worker }
2740*27162e4eSAndroid Build Coastguard Worker { size_t hSize = LZ4F_headerSize(&buffer, LZ4F_HEADER_SIZE_MIN);
2741*27162e4eSAndroid Build Coastguard Worker if (LZ4F_isError(hSize)) break;
2742*27162e4eSAndroid Build Coastguard Worker if (hSize > (LZ4F_HEADER_SIZE_MIN + MAGICNUMBER_SIZE)) {
2743*27162e4eSAndroid Build Coastguard Worker /* We've already read LZ4F_HEADER_SIZE_MIN so read any extra until hSize*/
2744*27162e4eSAndroid Build Coastguard Worker const size_t readBytes = fread(buffer + LZ4F_HEADER_SIZE_MIN, 1, hSize - LZ4F_HEADER_SIZE_MIN, finput);
2745*27162e4eSAndroid Build Coastguard Worker if (!readBytes || ferror(finput)) END_PROCESS(72, "Error reading %s", input_filename);
2746*27162e4eSAndroid Build Coastguard Worker }
2747*27162e4eSAndroid Build Coastguard Worker /* Create decompression context */
2748*27162e4eSAndroid Build Coastguard Worker { LZ4F_dctx* dctx;
2749*27162e4eSAndroid Build Coastguard Worker if ( LZ4F_isError(LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION)) ) break;
2750*27162e4eSAndroid Build Coastguard Worker { unsigned const frameInfoError = LZ4F_isError(LZ4F_getFrameInfo(dctx, &frameInfo.lz4FrameInfo, buffer, &hSize));
2751*27162e4eSAndroid Build Coastguard Worker LZ4F_freeDecompressionContext(dctx);
2752*27162e4eSAndroid Build Coastguard Worker if (frameInfoError) break;
2753*27162e4eSAndroid Build Coastguard Worker if ((cfinfo->frameSummary.lz4FrameInfo.blockSizeID != frameInfo.lz4FrameInfo.blockSizeID ||
2754*27162e4eSAndroid Build Coastguard Worker cfinfo->frameSummary.lz4FrameInfo.blockMode != frameInfo.lz4FrameInfo.blockMode)
2755*27162e4eSAndroid Build Coastguard Worker && cfinfo->frameCount != 0)
2756*27162e4eSAndroid Build Coastguard Worker cfinfo->eqBlockTypes = 0;
2757*27162e4eSAndroid Build Coastguard Worker { const unsigned long long totalBlocksSize = LZ4IO_skipBlocksData(finput,
2758*27162e4eSAndroid Build Coastguard Worker frameInfo.lz4FrameInfo.blockChecksumFlag,
2759*27162e4eSAndroid Build Coastguard Worker frameInfo.lz4FrameInfo.contentChecksumFlag);
2760*27162e4eSAndroid Build Coastguard Worker if (totalBlocksSize) {
2761*27162e4eSAndroid Build Coastguard Worker char bTypeBuffer[5];
2762*27162e4eSAndroid Build Coastguard Worker LZ4IO_blockTypeID(frameInfo.lz4FrameInfo.blockSizeID, frameInfo.lz4FrameInfo.blockMode, bTypeBuffer);
2763*27162e4eSAndroid Build Coastguard Worker if (displayNow) DISPLAYOUT(" %6llu %14s %5s %8s",
2764*27162e4eSAndroid Build Coastguard Worker cfinfo->frameCount + 1,
2765*27162e4eSAndroid Build Coastguard Worker LZ4IO_frameTypeNames[frameInfo.frameType],
2766*27162e4eSAndroid Build Coastguard Worker bTypeBuffer,
2767*27162e4eSAndroid Build Coastguard Worker frameInfo.lz4FrameInfo.contentChecksumFlag ? "XXH32" : "-");
2768*27162e4eSAndroid Build Coastguard Worker if (frameInfo.lz4FrameInfo.contentSize) {
2769*27162e4eSAndroid Build Coastguard Worker double const ratio = (double)(totalBlocksSize + hSize) / (double)frameInfo.lz4FrameInfo.contentSize * 100;
2770*27162e4eSAndroid Build Coastguard Worker if (displayNow) DISPLAYOUT(" %20llu %20llu %9.2f%%\n",
2771*27162e4eSAndroid Build Coastguard Worker totalBlocksSize + hSize,
2772*27162e4eSAndroid Build Coastguard Worker frameInfo.lz4FrameInfo.contentSize,
2773*27162e4eSAndroid Build Coastguard Worker ratio);
2774*27162e4eSAndroid Build Coastguard Worker /* Now we've consumed frameInfo we can use it to store the total contentSize */
2775*27162e4eSAndroid Build Coastguard Worker frameInfo.lz4FrameInfo.contentSize += cfinfo->frameSummary.lz4FrameInfo.contentSize;
2776*27162e4eSAndroid Build Coastguard Worker }
2777*27162e4eSAndroid Build Coastguard Worker else {
2778*27162e4eSAndroid Build Coastguard Worker if (displayNow) DISPLAYOUT(" %20llu %20s %9s \n", totalBlocksSize + hSize, "-", "-");
2779*27162e4eSAndroid Build Coastguard Worker cfinfo->allContentSize = 0;
2780*27162e4eSAndroid Build Coastguard Worker }
2781*27162e4eSAndroid Build Coastguard Worker result = LZ4IO_LZ4F_OK;
2782*27162e4eSAndroid Build Coastguard Worker } } } } }
2783*27162e4eSAndroid Build Coastguard Worker break;
2784*27162e4eSAndroid Build Coastguard Worker case LEGACY_MAGICNUMBER:
2785*27162e4eSAndroid Build Coastguard Worker frameInfo.frameType = legacyFrame;
2786*27162e4eSAndroid Build Coastguard Worker if (cfinfo->frameSummary.frameType != legacyFrame && cfinfo->frameCount != 0) cfinfo->eqFrameTypes = 0;
2787*27162e4eSAndroid Build Coastguard Worker cfinfo->eqBlockTypes = 0;
2788*27162e4eSAndroid Build Coastguard Worker cfinfo->allContentSize = 0;
2789*27162e4eSAndroid Build Coastguard Worker { const unsigned long long totalBlocksSize = LZ4IO_skipLegacyBlocksData(finput);
2790*27162e4eSAndroid Build Coastguard Worker if (totalBlocksSize == legacyFrameUndecodable) {
2791*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(1, "Corrupted legacy frame \n");
2792*27162e4eSAndroid Build Coastguard Worker result = LZ4IO_format_not_known;
2793*27162e4eSAndroid Build Coastguard Worker break;
2794*27162e4eSAndroid Build Coastguard Worker }
2795*27162e4eSAndroid Build Coastguard Worker if (totalBlocksSize) {
2796*27162e4eSAndroid Build Coastguard Worker if (displayNow) DISPLAYOUT(" %6llu %14s %5s %8s %20llu %20s %9s\n",
2797*27162e4eSAndroid Build Coastguard Worker cfinfo->frameCount + 1,
2798*27162e4eSAndroid Build Coastguard Worker LZ4IO_frameTypeNames[frameInfo.frameType],
2799*27162e4eSAndroid Build Coastguard Worker "-", "-",
2800*27162e4eSAndroid Build Coastguard Worker totalBlocksSize + 4,
2801*27162e4eSAndroid Build Coastguard Worker "-", "-");
2802*27162e4eSAndroid Build Coastguard Worker result = LZ4IO_LZ4F_OK;
2803*27162e4eSAndroid Build Coastguard Worker } }
2804*27162e4eSAndroid Build Coastguard Worker break;
2805*27162e4eSAndroid Build Coastguard Worker case LZ4IO_SKIPPABLE0:
2806*27162e4eSAndroid Build Coastguard Worker frameInfo.frameType = skippableFrame;
2807*27162e4eSAndroid Build Coastguard Worker if (cfinfo->frameSummary.frameType != skippableFrame && cfinfo->frameCount != 0) cfinfo->eqFrameTypes = 0;
2808*27162e4eSAndroid Build Coastguard Worker cfinfo->eqBlockTypes = 0;
2809*27162e4eSAndroid Build Coastguard Worker cfinfo->allContentSize = 0;
2810*27162e4eSAndroid Build Coastguard Worker { size_t const nbReadBytes = fread(buffer, 1, 4, finput);
2811*27162e4eSAndroid Build Coastguard Worker if (nbReadBytes != 4)
2812*27162e4eSAndroid Build Coastguard Worker END_PROCESS(42, "Stream error : skippable size unreadable");
2813*27162e4eSAndroid Build Coastguard Worker }
2814*27162e4eSAndroid Build Coastguard Worker { unsigned const size = LZ4IO_readLE32(buffer);
2815*27162e4eSAndroid Build Coastguard Worker int const errorNb = fseek_u32(finput, size, SEEK_CUR);
2816*27162e4eSAndroid Build Coastguard Worker if (errorNb != 0)
2817*27162e4eSAndroid Build Coastguard Worker END_PROCESS(43, "Stream error : cannot skip skippable area");
2818*27162e4eSAndroid Build Coastguard Worker if (displayNow) DISPLAYOUT(" %6llu %14s %5s %8s %20u %20s %9s\n",
2819*27162e4eSAndroid Build Coastguard Worker cfinfo->frameCount + 1,
2820*27162e4eSAndroid Build Coastguard Worker "SkippableFrame",
2821*27162e4eSAndroid Build Coastguard Worker "-", "-", size + 8, "-", "-");
2822*27162e4eSAndroid Build Coastguard Worker
2823*27162e4eSAndroid Build Coastguard Worker result = LZ4IO_LZ4F_OK;
2824*27162e4eSAndroid Build Coastguard Worker }
2825*27162e4eSAndroid Build Coastguard Worker break;
2826*27162e4eSAndroid Build Coastguard Worker default:
2827*27162e4eSAndroid Build Coastguard Worker { long int const position = ftell(finput); /* only works for files < 2 GB */
2828*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(3, "Stream followed by undecodable data ");
2829*27162e4eSAndroid Build Coastguard Worker if (position != -1L)
2830*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(3, "at position %i ", (int)position);
2831*27162e4eSAndroid Build Coastguard Worker result = LZ4IO_format_not_known;
2832*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(3, "\n");
2833*27162e4eSAndroid Build Coastguard Worker }
2834*27162e4eSAndroid Build Coastguard Worker break;
2835*27162e4eSAndroid Build Coastguard Worker }
2836*27162e4eSAndroid Build Coastguard Worker if (result != LZ4IO_LZ4F_OK) break;
2837*27162e4eSAndroid Build Coastguard Worker cfinfo->frameSummary = frameInfo;
2838*27162e4eSAndroid Build Coastguard Worker cfinfo->frameCount++;
2839*27162e4eSAndroid Build Coastguard Worker } /* while (!feof(finput)) */
2840*27162e4eSAndroid Build Coastguard Worker fclose(finput);
2841*27162e4eSAndroid Build Coastguard Worker return result;
2842*27162e4eSAndroid Build Coastguard Worker }
2843*27162e4eSAndroid Build Coastguard Worker
2844*27162e4eSAndroid Build Coastguard Worker
LZ4IO_displayCompressedFilesInfo(const char ** inFileNames,size_t ifnIdx)2845*27162e4eSAndroid Build Coastguard Worker int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, size_t ifnIdx)
2846*27162e4eSAndroid Build Coastguard Worker {
2847*27162e4eSAndroid Build Coastguard Worker int result = 0;
2848*27162e4eSAndroid Build Coastguard Worker size_t idx = 0;
2849*27162e4eSAndroid Build Coastguard Worker if (g_displayLevel < 3) {
2850*27162e4eSAndroid Build Coastguard Worker DISPLAYOUT("%10s %14s %5s %11s %13s %8s %s\n",
2851*27162e4eSAndroid Build Coastguard Worker "Frames", "Type", "Block", "Compressed", "Uncompressed", "Ratio", "Filename");
2852*27162e4eSAndroid Build Coastguard Worker }
2853*27162e4eSAndroid Build Coastguard Worker for (; idx < ifnIdx; idx++) {
2854*27162e4eSAndroid Build Coastguard Worker /* Get file info */
2855*27162e4eSAndroid Build Coastguard Worker LZ4IO_cFileInfo_t cfinfo = LZ4IO_INIT_CFILEINFO;
2856*27162e4eSAndroid Build Coastguard Worker cfinfo.fileName = LZ4IO_baseName(inFileNames[idx]);
2857*27162e4eSAndroid Build Coastguard Worker if (LZ4IO_isStdin(inFileNames[idx]) ? !UTIL_isRegFD(0) : !UTIL_isRegFile(inFileNames[idx])) {
2858*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(1, "lz4: %s is not a regular file \n", inFileNames[idx]);
2859*27162e4eSAndroid Build Coastguard Worker return 1;
2860*27162e4eSAndroid Build Coastguard Worker }
2861*27162e4eSAndroid Build Coastguard Worker if (g_displayLevel >= 3) {
2862*27162e4eSAndroid Build Coastguard Worker /* verbose mode */
2863*27162e4eSAndroid Build Coastguard Worker DISPLAYOUT("%s(%llu/%llu)\n", cfinfo.fileName, (unsigned long long)idx + 1, (unsigned long long)ifnIdx);
2864*27162e4eSAndroid Build Coastguard Worker DISPLAYOUT(" %6s %14s %5s %8s %20s %20s %9s\n",
2865*27162e4eSAndroid Build Coastguard Worker "Frame", "Type", "Block", "Checksum", "Compressed", "Uncompressed", "Ratio");
2866*27162e4eSAndroid Build Coastguard Worker }
2867*27162e4eSAndroid Build Coastguard Worker { LZ4IO_infoResult const op_result = LZ4IO_getCompressedFileInfo(&cfinfo, inFileNames[idx], g_displayLevel >= 3);
2868*27162e4eSAndroid Build Coastguard Worker if (op_result != LZ4IO_LZ4F_OK) {
2869*27162e4eSAndroid Build Coastguard Worker assert(op_result == LZ4IO_format_not_known);
2870*27162e4eSAndroid Build Coastguard Worker DISPLAYLEVEL(1, "lz4: %s: File format not recognized \n", inFileNames[idx]);
2871*27162e4eSAndroid Build Coastguard Worker return 1;
2872*27162e4eSAndroid Build Coastguard Worker } }
2873*27162e4eSAndroid Build Coastguard Worker if (g_displayLevel >= 3) {
2874*27162e4eSAndroid Build Coastguard Worker DISPLAYOUT("\n");
2875*27162e4eSAndroid Build Coastguard Worker }
2876*27162e4eSAndroid Build Coastguard Worker if (g_displayLevel < 3) {
2877*27162e4eSAndroid Build Coastguard Worker /* Display summary */
2878*27162e4eSAndroid Build Coastguard Worker char buffers[3][10];
2879*27162e4eSAndroid Build Coastguard Worker DISPLAYOUT("%10llu %14s %5s %11s %13s ",
2880*27162e4eSAndroid Build Coastguard Worker cfinfo.frameCount,
2881*27162e4eSAndroid Build Coastguard Worker cfinfo.eqFrameTypes ? LZ4IO_frameTypeNames[cfinfo.frameSummary.frameType] : "-" ,
2882*27162e4eSAndroid Build Coastguard Worker cfinfo.eqBlockTypes ? LZ4IO_blockTypeID(cfinfo.frameSummary.lz4FrameInfo.blockSizeID,
2883*27162e4eSAndroid Build Coastguard Worker cfinfo.frameSummary.lz4FrameInfo.blockMode, buffers[0]) : "-",
2884*27162e4eSAndroid Build Coastguard Worker LZ4IO_toHuman((long double)cfinfo.fileSize, buffers[1]),
2885*27162e4eSAndroid Build Coastguard Worker cfinfo.allContentSize ? LZ4IO_toHuman((long double)cfinfo.frameSummary.lz4FrameInfo.contentSize, buffers[2]) : "-");
2886*27162e4eSAndroid Build Coastguard Worker if (cfinfo.allContentSize) {
2887*27162e4eSAndroid Build Coastguard Worker double const ratio = (double)cfinfo.fileSize / (double)cfinfo.frameSummary.lz4FrameInfo.contentSize * 100;
2888*27162e4eSAndroid Build Coastguard Worker DISPLAYOUT("%8.2f%% %s \n", ratio, cfinfo.fileName);
2889*27162e4eSAndroid Build Coastguard Worker } else {
2890*27162e4eSAndroid Build Coastguard Worker DISPLAYOUT("%8s %s\n",
2891*27162e4eSAndroid Build Coastguard Worker "-",
2892*27162e4eSAndroid Build Coastguard Worker cfinfo.fileName);
2893*27162e4eSAndroid Build Coastguard Worker } } /* if (g_displayLevel < 3) */
2894*27162e4eSAndroid Build Coastguard Worker } /* for (; idx < ifnIdx; idx++) */
2895*27162e4eSAndroid Build Coastguard Worker
2896*27162e4eSAndroid Build Coastguard Worker return result;
2897*27162e4eSAndroid Build Coastguard Worker }
2898