xref: /aosp_15_r20/external/lz4/programs/lz4io.c (revision 27162e4e17433d5aa7cb38e7b6a433a09405fc7f)
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 = &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 = &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 = &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