benchmark silo added
[c11concurrency-benchmarks.git] / silo / third-party / lz4 / lz4c.c
1 /*\r
2   LZ4c - LZ4 Compression CLI program \r
3   Copyright (C) Yann Collet 2011-2013\r
4   GPL v2 License\r
5 \r
6   This program is free software; you can redistribute it and/or modify\r
7   it under the terms of the GNU General Public License as published by\r
8   the Free Software Foundation; either version 2 of the License, or\r
9   (at your option) any later version.\r
10 \r
11   This program is distributed in the hope that it will be useful,\r
12   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14   GNU General Public License for more details.\r
15 \r
16   You should have received a copy of the GNU General Public License along\r
17   with this program; if not, write to the Free Software Foundation, Inc.,\r
18   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
19 \r
20   You can contact the author at :\r
21   - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html\r
22   - LZ4 source repository : http://code.google.com/p/lz4/\r
23 */\r
24 /*\r
25   Note : this is stand-alone program.\r
26   It is not part of LZ4 compression library, it is a user program of LZ4 library.\r
27   The license of LZ4 library is BSD.\r
28   The license of xxHash library is BSD.\r
29   The license of this compression CLI program is GPLv2.\r
30 */\r
31 \r
32 //**************************************\r
33 // Compiler Options\r
34 //**************************************\r
35 // Disable some Visual warning messages\r
36 #ifdef _MSC_VER  // Visual Studio\r
37 #  define _CRT_SECURE_NO_WARNINGS\r
38 #  define _CRT_SECURE_NO_DEPRECATE     // VS2005\r
39 #  pragma warning(disable : 4127)      // disable: C4127: conditional expression is constant\r
40 #endif\r
41 \r
42 \r
43 //****************************\r
44 // Includes\r
45 //****************************\r
46 #include <stdio.h>    // fprintf, fopen, fread, _fileno(?)\r
47 #include <stdlib.h>   // malloc\r
48 #include <string.h>   // strcmp\r
49 #include <time.h>     // clock\r
50 #ifdef _WIN32\r
51 #include <io.h>       // _setmode\r
52 #include <fcntl.h>    // _O_BINARY\r
53 #endif\r
54 #include "lz4.h"\r
55 #include "lz4hc.h"\r
56 #include "bench.h"\r
57 #include "xxhash.h"\r
58 \r
59 \r
60 //**************************************\r
61 // Compiler-specific functions\r
62 //**************************************\r
63 #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)\r
64 \r
65 #if defined(_MSC_VER)    // Visual Studio\r
66 #  define swap32 _byteswap_ulong\r
67 #elif GCC_VERSION >= 403\r
68 #  define swap32 __builtin_bswap32\r
69 #else\r
70   static inline unsigned int swap32(unsigned int x) {\r
71     return      ((x << 24) & 0xff000000 ) |\r
72         ((x <<  8) & 0x00ff0000 ) |\r
73         ((x >>  8) & 0x0000ff00 ) |\r
74         ((x >> 24) & 0x000000ff );\r
75   }\r
76 #endif\r
77 \r
78 \r
79 //****************************\r
80 // Constants\r
81 //****************************\r
82 #define COMPRESSOR_NAME "LZ4 Compression CLI"\r
83 #define COMPRESSOR_VERSION ""\r
84 #define COMPILED __DATE__\r
85 #define AUTHOR "Yann Collet"\r
86 #define EXTENSION ".lz4"\r
87 #define WELCOME_MESSAGE "*** %s %s, by %s (%s) ***\n", COMPRESSOR_NAME, COMPRESSOR_VERSION, AUTHOR, COMPILED\r
88 \r
89 #define KB *(1U<<10)\r
90 #define MB *(1U<<20)\r
91 #define GB *(1U<<30)\r
92 \r
93 #define _1BIT  0x01\r
94 #define _2BITS 0x03\r
95 #define _3BITS 0x07\r
96 #define _4BITS 0x0F\r
97 #define _8BITS 0xFF\r
98 \r
99 #define MAGICNUMBER_SIZE 4\r
100 #define LZ4S_MAGICNUMBER   0x184D2204\r
101 #define LZ4S_SKIPPABLE0    0x184D2A50\r
102 #define LZ4S_SKIPPABLEMASK 0xFFFFFFF0\r
103 #define LEGACY_MAGICNUMBER 0x184C2102\r
104 \r
105 #define CACHELINE 64\r
106 #define LEGACY_BLOCKSIZE   (8 MB)\r
107 #define MIN_STREAM_BUFSIZE (1 MB + 64 KB)\r
108 #define LZ4S_BLOCKSIZEID_DEFAULT 7\r
109 #define LZ4S_CHECKSUM_SEED 0\r
110 #define LZ4S_EOS 0\r
111 #define LZ4S_MAXHEADERSIZE (4+2+8+4+1)\r
112 \r
113 \r
114 //**************************************\r
115 // Architecture Macros\r
116 //**************************************\r
117 static const int one = 1;\r
118 #define CPU_LITTLE_ENDIAN   (*(char*)(&one))\r
119 #define CPU_BIG_ENDIAN      (!CPU_LITTLE_ENDIAN)\r
120 #define LITTLE_ENDIAN_32(i) (CPU_LITTLE_ENDIAN?(i):swap32(i))\r
121 \r
122 \r
123 //**************************************\r
124 // Macros\r
125 //**************************************\r
126 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)\r
127 \r
128 \r
129 //**************************************\r
130 // Special input/output\r
131 //**************************************\r
132 #define NULL_INPUT "null"\r
133 char stdinmark[] = "stdin";\r
134 char stdoutmark[] = "stdout";\r
135 #ifdef _WIN32\r
136 char nulmark[] = "nul";\r
137 #else\r
138 char nulmark[] = "/dev/null";\r
139 #endif\r
140 \r
141 \r
142 //**************************************\r
143 // Local Parameters\r
144 //**************************************\r
145 static int overwrite = 0;\r
146 static int blockSizeId = LZ4S_BLOCKSIZEID_DEFAULT;\r
147 static int blockChecksum = 0;\r
148 static int streamChecksum = 1;\r
149 static int blockIndependence = 1;\r
150 \r
151 //**************************************\r
152 // Exceptions\r
153 //**************************************\r
154 #define DEBUG 0\r
155 #define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);\r
156 #define EXM_THROW(error, ...)                                             \\r
157 {                                                                         \\r
158     DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \\r
159     DISPLAY("Error %i : ", error);                                        \\r
160     DISPLAY(__VA_ARGS__);                                                 \\r
161     DISPLAY("\n");                                                        \\r
162     exit(error);                                                          \\r
163 }\r
164 \r
165 \r
166 \r
167 //****************************\r
168 // Functions\r
169 //****************************\r
170 int usage(char* exename)\r
171 {\r
172     DISPLAY( "Usage :\n");\r
173     DISPLAY( "      %s [arg] input [output]\n", exename);\r
174     DISPLAY( "Arguments :\n");\r
175     DISPLAY( " -c0/-c : Fast compression (default) \n");\r
176     DISPLAY( " -c1/-hc: High compression \n");\r
177     DISPLAY( " -d     : decompression \n");\r
178     DISPLAY( " -y     : overwrite without prompting \n");\r
179     DISPLAY( " -H     : Help (this text + advanced options)\n");\r
180     return 0;\r
181 }\r
182 \r
183 int usage_advanced()\r
184 {\r
185     DISPLAY( "\nAdvanced options :\n");\r
186     DISPLAY( " -t     : test compressed file \n");\r
187     DISPLAY( " -B#    : Block size [4-7](default : 7)\n");\r
188     DISPLAY( " -BD    : Block dependency (improve compression ratio)\n");\r
189     DISPLAY( " -BX    : enable block checksum (default:disabled)\n");\r
190     DISPLAY( " -Sx    : disable stream checksum (default:enabled)\n");\r
191     DISPLAY( " -b#    : benchmark files, using # [0-1] compression level\n");\r
192     DISPLAY( " -i#    : iteration loops [1-9](default : 3), benchmark mode only\n");\r
193     DISPLAY( "input   : can be 'stdin' (pipe) or a filename\n");\r
194     DISPLAY( "output  : can be 'stdout'(pipe) or a filename or 'null'\n");\r
195     DISPLAY( "          example 1 : lz4c -hc stdin compressedfile.lz4\n");\r
196     DISPLAY( "          example 2 : lz4c -hcyB4D filename \n");\r
197     return 0;\r
198 }\r
199 \r
200 int badusage(char* exename)\r
201 {\r
202     DISPLAY("Wrong parameters\n");\r
203     usage(exename);\r
204     return 0;\r
205 }\r
206 \r
207 \r
208 static int          LZ4S_GetBlockSize_FromBlockId (int id) { return (1 << (8 + (2 * id))); }\r
209 static unsigned int LZ4S_GetCheckBits_FromXXH (unsigned int xxh) { return (xxh >> 8) & _8BITS; }\r
210 static int          LZ4S_isSkippableMagicNumber(unsigned int magic) { return (magic & LZ4S_SKIPPABLEMASK) == LZ4S_SKIPPABLE0; }\r
211 \r
212 \r
213 int get_fileHandle(char* input_filename, char* output_filename, FILE** pfinput, FILE** pfoutput)\r
214 {\r
215 \r
216     if (!strcmp (input_filename, stdinmark)) \r
217     {\r
218         DISPLAY( "Using stdin for input\n");\r
219         *pfinput = stdin;\r
220 #ifdef _WIN32 // Need to set stdin/stdout to binary mode specifically for windows\r
221         _setmode( _fileno( stdin ), _O_BINARY );\r
222 #endif\r
223     } \r
224     else \r
225     {\r
226         *pfinput = fopen(input_filename, "rb");\r
227     }\r
228 \r
229     if (!strcmp (output_filename, stdoutmark)) \r
230     {\r
231         DISPLAY( "Using stdout for output\n");\r
232         *pfoutput = stdout;\r
233 #ifdef _WIN32 // Need to set stdin/stdout to binary mode specifically for windows\r
234         _setmode( _fileno( stdout ), _O_BINARY );\r
235 #endif\r
236     } \r
237     else \r
238     {\r
239         // Check if destination file already exists\r
240         *pfoutput=0;\r
241         if (output_filename != nulmark) *pfoutput = fopen( output_filename, "rb" );\r
242         if (*pfoutput!=0) \r
243         { \r
244             char ch;\r
245             fclose(*pfoutput); \r
246             DISPLAY( "Warning : %s already exists\n", output_filename); \r
247             if (!overwrite)\r
248             {\r
249                 DISPLAY( "Overwrite ? (Y/N) : ");\r
250                 ch = (char)getchar();\r
251                 if (ch!='Y') EXM_THROW(11, "Operation aborted : %s already exists", output_filename);\r
252             }\r
253         }\r
254         *pfoutput = fopen( output_filename, "wb" );\r
255     }\r
256 \r
257     if ( *pfinput==0 ) EXM_THROW(12, "Pb opening %s", input_filename);\r
258     if ( *pfoutput==0) EXM_THROW(13, "Pb opening %s", output_filename); \r
259 \r
260     return 0;\r
261 }\r
262 \r
263 \r
264 \r
265 int legacy_compress_file(char* input_filename, char* output_filename, int compressionlevel)\r
266 {\r
267     int (*compressionFunction)(const char*, char*, int);\r
268     unsigned long long filesize = 0;\r
269     unsigned long long compressedfilesize = MAGICNUMBER_SIZE;\r
270     char* in_buff;\r
271     char* out_buff;\r
272     FILE* finput;\r
273     FILE* foutput;\r
274     int displayLevel = (compressionlevel>0);\r
275     clock_t start, end;\r
276     size_t sizeCheck;\r
277 \r
278 \r
279     // Init\r
280     switch (compressionlevel)\r
281     {\r
282     case 0 : compressionFunction = LZ4_compress; break;\r
283     case 1 : compressionFunction = LZ4_compressHC; break;\r
284     default: compressionFunction = LZ4_compress;\r
285     }\r
286     start = clock();\r
287     get_fileHandle(input_filename, output_filename, &finput, &foutput);\r
288 \r
289     // Allocate Memory\r
290     in_buff = (char*)malloc(LEGACY_BLOCKSIZE);\r
291     out_buff = (char*)malloc(LZ4_compressBound(LEGACY_BLOCKSIZE));\r
292     if (!in_buff || !out_buff) EXM_THROW(21, "Allocation error : not enough memory");\r
293 \r
294     // Write Archive Header\r
295     *(unsigned int*)out_buff = LITTLE_ENDIAN_32(LEGACY_MAGICNUMBER);\r
296     sizeCheck = fwrite(out_buff, 1, MAGICNUMBER_SIZE, foutput);\r
297     if (sizeCheck!=MAGICNUMBER_SIZE) EXM_THROW(22, "Write error : cannot write header");\r
298 \r
299     // Main Loop\r
300     while (1)\r
301     {\r
302         unsigned int outSize;\r
303         // Read Block\r
304         int inSize = (int) fread(in_buff, (size_t)1, (size_t)LEGACY_BLOCKSIZE, finput);\r
305         if( inSize<=0 ) break;\r
306         filesize += inSize;\r
307         if (displayLevel) DISPLAY("Read : %i MB  \r", (int)(filesize>>20));\r
308 \r
309         // Compress Block\r
310         outSize = compressionFunction(in_buff, out_buff+4, inSize);\r
311         compressedfilesize += outSize+4;\r
312         if (displayLevel) DISPLAY("Read : %i MB  ==> %.2f%%\r", (int)(filesize>>20), (double)compressedfilesize/filesize*100);\r
313 \r
314         // Write Block\r
315         * (unsigned int*) out_buff = LITTLE_ENDIAN_32(outSize);\r
316         sizeCheck = fwrite(out_buff, 1, outSize+4, foutput);\r
317         if (sizeCheck!=(size_t)(outSize+4)) EXM_THROW(23, "Write error : cannot write compressed block");\r
318     }\r
319 \r
320     // Status\r
321     end = clock();\r
322     DISPLAY( "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",\r
323         (unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);\r
324     {\r
325         double seconds = (double)(end - start)/CLOCKS_PER_SEC;\r
326         DISPLAY( "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
327     }\r
328 \r
329     // Close & Free\r
330     free(in_buff);\r
331     free(out_buff);\r
332     fclose(finput);\r
333     fclose(foutput);\r
334 \r
335     return 0;\r
336 }\r
337 \r
338 \r
339 int compress_file_blockDependency(char* input_filename, char* output_filename, int compressionlevel)\r
340 {\r
341     void* (*initFunction)       (const char*);\r
342     int   (*compressionFunction)(void*, const char*, char*, int, int);\r
343     char* (*translateFunction)  (void*);\r
344     int   (*freeFunction)       (void*);\r
345     void* ctx;\r
346     unsigned long long filesize = 0;\r
347     unsigned long long compressedfilesize = 0;\r
348     unsigned int checkbits;\r
349     char* in_buff, *in_start, *in_end;\r
350     char* out_buff;\r
351     FILE* finput;\r
352     FILE* foutput;\r
353     int errorcode;\r
354     int displayLevel = (compressionlevel>0);\r
355     clock_t start, end;\r
356     unsigned int blockSize, inputBufferSize;\r
357     size_t sizeCheck, header_size;\r
358     void* streamChecksumState=NULL;\r
359 \r
360 \r
361     // Init\r
362     start = clock();\r
363     switch (compressionlevel)\r
364     {\r
365     case 0 :\r
366     case 1 :\r
367     default:\r
368         initFunction = LZ4_createHC;\r
369         compressionFunction = LZ4_compressHC_limitedOutput_continue;\r
370         translateFunction = LZ4_slideInputBufferHC;\r
371         freeFunction = LZ4_freeHC;\r
372     }\r
373     errorcode = get_fileHandle(input_filename, output_filename, &finput, &foutput);\r
374     if (errorcode) return errorcode;\r
375     blockSize = LZ4S_GetBlockSize_FromBlockId (blockSizeId);\r
376 \r
377     // Allocate Memory\r
378     inputBufferSize = blockSize + 64 KB;\r
379     if (inputBufferSize < MIN_STREAM_BUFSIZE) inputBufferSize = MIN_STREAM_BUFSIZE;\r
380     in_buff  = (char*)malloc(inputBufferSize);\r
381     out_buff = (char*)malloc(blockSize+CACHELINE);\r
382     if (!in_buff || !out_buff) EXM_THROW(31, "Allocation error : not enough memory");\r
383     in_start = in_buff; in_end = in_buff + inputBufferSize;\r
384     if (streamChecksum) streamChecksumState = XXH32_init(LZ4S_CHECKSUM_SEED);\r
385     ctx = initFunction(in_buff);\r
386 \r
387     // Write Archive Header\r
388     *(unsigned int*)out_buff = LITTLE_ENDIAN_32(LZ4S_MAGICNUMBER);   // Magic Number, in Little Endian convention\r
389     *(out_buff+4)  = (1 & _2BITS) << 6 ;                             // Version('01')\r
390     *(out_buff+4) |= (blockIndependence & _1BIT) << 5;\r
391     *(out_buff+4) |= (blockChecksum & _1BIT) << 4;\r
392     *(out_buff+4) |= (streamChecksum & _1BIT) << 2;\r
393     *(out_buff+5)  = (char)((blockSizeId & _3BITS) << 4);\r
394     checkbits = XXH32((out_buff+4), 2, LZ4S_CHECKSUM_SEED);\r
395     checkbits = LZ4S_GetCheckBits_FromXXH(checkbits);\r
396     *(out_buff+6)  = (unsigned char) checkbits;\r
397     header_size = 7;\r
398     sizeCheck = fwrite(out_buff, 1, header_size, foutput);\r
399     if (sizeCheck!=header_size) EXM_THROW(32, "Write error : cannot write header");\r
400     compressedfilesize += header_size;\r
401 \r
402     // Main Loop\r
403     while (1)\r
404     {\r
405         unsigned int outSize;\r
406         unsigned int inSize;\r
407         // Read Block\r
408         if ((in_start+blockSize) > in_end) in_start = translateFunction(ctx);\r
409         inSize = (unsigned int) fread(in_start, (size_t)1, (size_t)blockSize, finput);\r
410         if( inSize<=0 ) break;   // No more input : end of compression\r
411         filesize += inSize;\r
412         if (displayLevel) DISPLAY("Read : %i MB  \r", (int)(filesize>>20));\r
413         if (streamChecksum) XXH32_update(streamChecksumState, in_start, inSize);\r
414 \r
415         // Compress Block\r
416         outSize = compressionFunction(ctx, in_start, out_buff+4, inSize, inSize-1);\r
417         if (outSize > 0) compressedfilesize += outSize+4; else compressedfilesize += inSize+4;\r
418         if (blockChecksum) compressedfilesize+=4;\r
419         if (displayLevel) DISPLAY("Read : %i MB  ==> %.2f%%\r", (int)(filesize>>20), (double)compressedfilesize/filesize*100);\r
420 \r
421         // Write Block\r
422         if (outSize > 0)\r
423         {\r
424             unsigned int checksum;\r
425             int sizeToWrite;\r
426             * (unsigned int*) out_buff = LITTLE_ENDIAN_32(outSize);\r
427             if (blockChecksum)\r
428             {\r
429                 checksum = XXH32(out_buff+4, outSize, LZ4S_CHECKSUM_SEED);\r
430                 * (unsigned int*) (out_buff+4+outSize) = LITTLE_ENDIAN_32(checksum);\r
431             }\r
432             sizeToWrite = 4 + outSize + (4*blockChecksum);\r
433             sizeCheck = fwrite(out_buff, 1, sizeToWrite, foutput);\r
434             if (sizeCheck!=(size_t)(sizeToWrite)) EXM_THROW(33, "Write error : cannot write compressed block");\r
435 \r
436         }\r
437         else   // Copy Original\r
438         {\r
439             unsigned int checksum;\r
440             * (unsigned int*) out_buff = LITTLE_ENDIAN_32(inSize|0x80000000);   // Add Uncompressed flag\r
441             sizeCheck = fwrite(out_buff, 1, 4, foutput);\r
442             if (sizeCheck!=(size_t)(4)) EXM_THROW(34, "Write error : cannot write block header");\r
443             sizeCheck = fwrite(in_start, 1, inSize, foutput);\r
444             if (sizeCheck!=(size_t)(inSize)) EXM_THROW(35, "Write error : cannot write block");\r
445             if (blockChecksum)\r
446             {\r
447                 checksum = XXH32(in_start, inSize, LZ4S_CHECKSUM_SEED);\r
448                 * (unsigned int*) out_buff = LITTLE_ENDIAN_32(checksum);\r
449                 sizeCheck = fwrite(out_buff, 1, 4, foutput);\r
450                 if (sizeCheck!=(size_t)(4)) EXM_THROW(36, "Write error : cannot write block checksum");\r
451             }\r
452         }\r
453         in_start += inSize;\r
454     }\r
455 \r
456     // End of Stream mark\r
457     * (unsigned int*) out_buff = LZ4S_EOS;\r
458     sizeCheck = fwrite(out_buff, 1, 4, foutput);\r
459     if (sizeCheck!=(size_t)(4)) EXM_THROW(37, "Write error : cannot write end of stream");\r
460     compressedfilesize += 4;\r
461     if (streamChecksum)\r
462     {\r
463         unsigned int checksum = XXH32_digest(streamChecksumState);\r
464         * (unsigned int*) out_buff = LITTLE_ENDIAN_32(checksum);\r
465         sizeCheck = fwrite(out_buff, 1, 4, foutput);\r
466         if (sizeCheck!=(size_t)(4)) EXM_THROW(37, "Write error : cannot write stream checksum");\r
467         compressedfilesize += 4;\r
468     }\r
469 \r
470     // Status\r
471     end = clock();\r
472     DISPLAY( "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",\r
473         (unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);\r
474     {\r
475         double seconds = (double)(end - start)/CLOCKS_PER_SEC;\r
476         DISPLAY( "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
477     }\r
478 \r
479     // Close & Free\r
480     freeFunction(ctx);\r
481     free(in_buff);\r
482     free(out_buff);\r
483     fclose(finput);\r
484     fclose(foutput);\r
485 \r
486     return 0;\r
487 }\r
488 \r
489 \r
490 int compress_file(char* input_filename, char* output_filename, int compressionlevel)\r
491 {\r
492     int (*compressionFunction)(const char*, char*, int, int);\r
493     unsigned long long filesize = 0;\r
494     unsigned long long compressedfilesize = 0;\r
495     unsigned int checkbits;\r
496     char* in_buff;\r
497     char* out_buff;\r
498     FILE* finput;\r
499     FILE* foutput;\r
500     int errorcode;\r
501     int displayLevel = (compressionlevel>0);\r
502     clock_t start, end;\r
503     int blockSize;\r
504     size_t sizeCheck, header_size;\r
505     void* streamChecksumState=NULL;\r
506 \r
507     // Branch out\r
508     if (blockIndependence==0) return compress_file_blockDependency(input_filename, output_filename, compressionlevel);\r
509 \r
510     // Init\r
511     start = clock();\r
512     switch (compressionlevel)\r
513     {\r
514     case 0 : compressionFunction = LZ4_compress_limitedOutput; break;\r
515     case 1 : compressionFunction = LZ4_compressHC_limitedOutput; break;\r
516     default: compressionFunction = LZ4_compress_limitedOutput;\r
517     }\r
518     errorcode = get_fileHandle(input_filename, output_filename, &finput, &foutput);\r
519     if (errorcode) return errorcode;\r
520     blockSize = LZ4S_GetBlockSize_FromBlockId (blockSizeId);\r
521 \r
522     // Allocate Memory\r
523     in_buff  = (char*)malloc(blockSize);\r
524     out_buff = (char*)malloc(blockSize+CACHELINE);\r
525     if (!in_buff || !out_buff) EXM_THROW(31, "Allocation error : not enough memory");\r
526     if (streamChecksum) streamChecksumState = XXH32_init(LZ4S_CHECKSUM_SEED);\r
527 \r
528     // Write Archive Header\r
529     *(unsigned int*)out_buff = LITTLE_ENDIAN_32(LZ4S_MAGICNUMBER);   // Magic Number, in Little Endian convention\r
530     *(out_buff+4)  = (1 & _2BITS) << 6 ;                             // Version('01')\r
531     *(out_buff+4) |= (blockIndependence & _1BIT) << 5;\r
532     *(out_buff+4) |= (blockChecksum & _1BIT) << 4;\r
533     *(out_buff+4) |= (streamChecksum & _1BIT) << 2;\r
534     *(out_buff+5)  = (char)((blockSizeId & _3BITS) << 4);\r
535     checkbits = XXH32((out_buff+4), 2, LZ4S_CHECKSUM_SEED);\r
536     checkbits = LZ4S_GetCheckBits_FromXXH(checkbits);\r
537     *(out_buff+6)  = (unsigned char) checkbits;\r
538     header_size = 7;\r
539     sizeCheck = fwrite(out_buff, 1, header_size, foutput);\r
540     if (sizeCheck!=header_size) EXM_THROW(32, "Write error : cannot write header");\r
541     compressedfilesize += header_size;\r
542 \r
543     // Main Loop\r
544     while (1)\r
545     {\r
546         unsigned int outSize;\r
547         // Read Block\r
548         unsigned int inSize = (unsigned int) fread(in_buff, (size_t)1, (size_t)blockSize, finput);\r
549         if( inSize<=0 ) break;   // No more input : end of compression\r
550         filesize += inSize;\r
551         if (displayLevel) DISPLAY("Read : %i MB  \r", (int)(filesize>>20));\r
552         if (streamChecksum) XXH32_update(streamChecksumState, in_buff, inSize);\r
553 \r
554         // Compress Block\r
555         outSize = compressionFunction(in_buff, out_buff+4, inSize, inSize-1);\r
556         if (outSize > 0) compressedfilesize += outSize+4; else compressedfilesize += inSize+4;\r
557         if (blockChecksum) compressedfilesize+=4;\r
558         if (displayLevel) DISPLAY("Read : %i MB  ==> %.2f%%\r", (int)(filesize>>20), (double)compressedfilesize/filesize*100);\r
559 \r
560         // Write Block\r
561         if (outSize > 0)\r
562         {\r
563             unsigned int checksum;\r
564             int sizeToWrite;\r
565             * (unsigned int*) out_buff = LITTLE_ENDIAN_32(outSize);\r
566             if (blockChecksum)\r
567             {\r
568                 checksum = XXH32(out_buff+4, outSize, LZ4S_CHECKSUM_SEED);\r
569                 * (unsigned int*) (out_buff+4+outSize) = LITTLE_ENDIAN_32(checksum);\r
570             }\r
571             sizeToWrite = 4 + outSize + (4*blockChecksum);\r
572             sizeCheck = fwrite(out_buff, 1, sizeToWrite, foutput);\r
573             if (sizeCheck!=(size_t)(sizeToWrite)) EXM_THROW(33, "Write error : cannot write compressed block");\r
574 \r
575         }\r
576         else  // Copy Original\r
577         {\r
578             unsigned int checksum;\r
579             * (unsigned int*) out_buff = LITTLE_ENDIAN_32(inSize|0x80000000);   // Add Uncompressed flag\r
580             sizeCheck = fwrite(out_buff, 1, 4, foutput);\r
581             if (sizeCheck!=(size_t)(4)) EXM_THROW(34, "Write error : cannot write block header");\r
582             sizeCheck = fwrite(in_buff, 1, inSize, foutput);\r
583             if (sizeCheck!=(size_t)(inSize)) EXM_THROW(35, "Write error : cannot write block");\r
584             if (blockChecksum)\r
585             {\r
586                 checksum = XXH32(in_buff, inSize, LZ4S_CHECKSUM_SEED);\r
587                 * (unsigned int*) out_buff = LITTLE_ENDIAN_32(checksum);\r
588                 sizeCheck = fwrite(out_buff, 1, 4, foutput);\r
589                 if (sizeCheck!=(size_t)(4)) EXM_THROW(36, "Write error : cannot write block checksum");\r
590             }\r
591         }\r
592     }\r
593 \r
594     // End of Stream mark\r
595     * (unsigned int*) out_buff = LZ4S_EOS;\r
596     sizeCheck = fwrite(out_buff, 1, 4, foutput);\r
597     if (sizeCheck!=(size_t)(4)) EXM_THROW(37, "Write error : cannot write end of stream");\r
598     compressedfilesize += 4;\r
599     if (streamChecksum)\r
600     {\r
601         unsigned int checksum = XXH32_digest(streamChecksumState);\r
602         * (unsigned int*) out_buff = LITTLE_ENDIAN_32(checksum);\r
603         sizeCheck = fwrite(out_buff, 1, 4, foutput);\r
604         if (sizeCheck!=(size_t)(4)) EXM_THROW(37, "Write error : cannot write stream checksum");\r
605         compressedfilesize += 4;\r
606     }\r
607 \r
608     // Status\r
609     end = clock();\r
610     DISPLAY( "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",\r
611         (unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);\r
612     {\r
613         double seconds = (double)(end - start)/CLOCKS_PER_SEC;\r
614         DISPLAY( "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
615     }\r
616 \r
617     // Close & Free\r
618     free(in_buff);\r
619     free(out_buff);\r
620     fclose(finput);\r
621     fclose(foutput);\r
622 \r
623     return 0;\r
624 }\r
625 \r
626 \r
627 unsigned long long decodeLegacyStream(FILE* finput, FILE* foutput)\r
628 {\r
629     unsigned long long filesize = 0;\r
630     char* in_buff;\r
631     char* out_buff;\r
632     size_t uselessRet;\r
633     int sinkint;\r
634     unsigned int blockSize;\r
635     size_t sizeCheck;\r
636 \r
637 \r
638     // Allocate Memory\r
639     in_buff = (char*)malloc(LZ4_compressBound(LEGACY_BLOCKSIZE));\r
640     out_buff = (char*)malloc(LEGACY_BLOCKSIZE);\r
641     if (!in_buff || !out_buff) EXM_THROW(51, "Allocation error : not enough memory");\r
642 \r
643     // Main Loop\r
644     while (1)\r
645     {\r
646         // Block Size\r
647         uselessRet = fread(&blockSize, 1, 4, finput);\r
648         if( uselessRet==0 ) break;                 // Nothing to read : file read is completed\r
649         blockSize = LITTLE_ENDIAN_32(blockSize);   // Convert to Little Endian\r
650         if (blockSize > LZ4_COMPRESSBOUND(LEGACY_BLOCKSIZE)) \r
651         {   // Cannot read next block : maybe new stream ?\r
652             fseek(finput, -4, SEEK_CUR);\r
653             break;\r
654         }\r
655 \r
656         // Read Block\r
657         uselessRet = fread(in_buff, 1, blockSize, finput);\r
658 \r
659         // Decode Block\r
660         sinkint = LZ4_decompress_safe(in_buff, out_buff, blockSize, LEGACY_BLOCKSIZE);\r
661         if (sinkint < 0) EXM_THROW(52, "Decoding Failed ! Corrupted input detected !");\r
662         filesize += sinkint;\r
663 \r
664         // Write Block\r
665         sizeCheck = fwrite(out_buff, 1, sinkint, foutput);\r
666         if (sizeCheck != (size_t)sinkint) EXM_THROW(53, "Write error : cannot write decoded block into output\n");\r
667     }\r
668 \r
669     // Free\r
670     free(in_buff);\r
671     free(out_buff);\r
672 \r
673     return filesize;\r
674 }\r
675 \r
676 \r
677 unsigned long long decodeLZ4S(FILE* finput, FILE* foutput)\r
678 {\r
679     unsigned long long filesize = 0;\r
680     char* in_buff;\r
681     char* out_buff, *out_start, *out_end;\r
682     unsigned char descriptor[LZ4S_MAXHEADERSIZE];\r
683     size_t nbReadBytes;\r
684     int decodedBytes=0;\r
685     unsigned int maxBlockSize;\r
686     size_t sizeCheck;\r
687     int blockChecksumFlag, streamChecksumFlag, blockIndependenceFlag;\r
688     void* streamChecksumState=NULL;\r
689     int (*decompressionFunction)(const char*, char*, int, int) = LZ4_decompress_safe;\r
690     unsigned int prefix64k = 0;\r
691 \r
692     // Decode stream descriptor\r
693     nbReadBytes = fread(descriptor, 1, 3, finput);\r
694     if (nbReadBytes != 3) EXM_THROW(61, "Unreadable header");\r
695     {\r
696         int version       = (descriptor[0] >> 6) & _2BITS;\r
697         int streamSize    = (descriptor[0] >> 3) & _1BIT;\r
698         int reserved1     = (descriptor[0] >> 1) & _1BIT;\r
699         int dictionary    = (descriptor[0] >> 0) & _1BIT;\r
700 \r
701         int reserved2     = (descriptor[1] >> 7) & _1BIT;\r
702         int blockSizeId   = (descriptor[1] >> 4) & _3BITS;\r
703         int reserved3     = (descriptor[1] >> 0) & _4BITS;\r
704         int checkBits     = (descriptor[2] >> 0) & _8BITS;\r
705         int checkBits_xxh32;\r
706 \r
707         blockIndependenceFlag=(descriptor[0] >> 5) & _1BIT;\r
708         blockChecksumFlag = (descriptor[0] >> 4) & _1BIT;\r
709         streamChecksumFlag= (descriptor[0] >> 2) & _1BIT;\r
710 \r
711         if (version != 1)       EXM_THROW(62, "Wrong version number");\r
712         if (streamSize == 1)    EXM_THROW(64, "Does not support stream size");  \r
713         if (reserved1 != 0)     EXM_THROW(65, "Wrong value for reserved bits");\r
714         if (dictionary == 1)    EXM_THROW(66, "Does not support dictionary"); \r
715         if (reserved2 != 0)     EXM_THROW(67, "Wrong value for reserved bits");\r
716         if (blockSizeId < 4)    EXM_THROW(68, "Unsupported block size"); \r
717         if (reserved3 != 0)     EXM_THROW(67, "Wrong value for reserved bits");\r
718         maxBlockSize = LZ4S_GetBlockSize_FromBlockId(blockSizeId);\r
719         // Checkbits verification\r
720         descriptor[1] &= 0xF0;\r
721         checkBits_xxh32 = XXH32(descriptor, 2, LZ4S_CHECKSUM_SEED);\r
722         checkBits_xxh32 = LZ4S_GetCheckBits_FromXXH(checkBits_xxh32);\r
723         if (checkBits != checkBits_xxh32) EXM_THROW(69, "Stream descriptor error detected");\r
724     }\r
725 \r
726     if (!blockIndependenceFlag)\r
727     {\r
728         decompressionFunction = LZ4_decompress_safe_withPrefix64k;\r
729         prefix64k = 64 KB;\r
730     }\r
731 \r
732     // Allocate Memory\r
733     {\r
734         unsigned int outbuffSize = prefix64k+maxBlockSize;\r
735         in_buff  = (char*)malloc(maxBlockSize);\r
736         if (outbuffSize < MIN_STREAM_BUFSIZE) outbuffSize = MIN_STREAM_BUFSIZE;\r
737         out_buff = (char*)malloc(outbuffSize); \r
738         out_end = out_buff + outbuffSize;\r
739         out_start = out_buff + prefix64k;\r
740         if (!in_buff || !out_buff) EXM_THROW(70, "Allocation error : not enough memory");\r
741     }\r
742     if (streamChecksumFlag) streamChecksumState = XXH32_init(LZ4S_CHECKSUM_SEED);\r
743 \r
744     // Main Loop\r
745     while (1)\r
746     {\r
747         unsigned int blockSize, uncompressedFlag;\r
748 \r
749         // Block Size\r
750         nbReadBytes = fread(&blockSize, 1, 4, finput);\r
751         if( nbReadBytes != 4 ) EXM_THROW(71, "Read error : cannot read next block size");\r
752         if (blockSize == LZ4S_EOS) break;          // End of Stream Mark : stream is completed\r
753         blockSize = LITTLE_ENDIAN_32(blockSize);   // Convert to little endian\r
754         uncompressedFlag = blockSize >> 31;\r
755         blockSize &= 0x7FFFFFFF;\r
756         if (blockSize > maxBlockSize) EXM_THROW(72, "Error : invalid block size");\r
757 \r
758         // Read Block\r
759         nbReadBytes = fread(in_buff, 1, blockSize, finput);\r
760         if( nbReadBytes != blockSize ) EXM_THROW(73, "Read error : cannot read data block" );\r
761 \r
762         // Check Block\r
763         if (blockChecksumFlag)\r
764         {\r
765             unsigned int checksum = XXH32(in_buff, blockSize, LZ4S_CHECKSUM_SEED);\r
766             unsigned int readChecksum;\r
767             sizeCheck = fread(&readChecksum, 1, 4, finput);\r
768             if( sizeCheck != 4 ) EXM_THROW(74, "Read error : cannot read next block size");\r
769             readChecksum = LITTLE_ENDIAN_32(readChecksum);   // Convert to little endian\r
770             if (checksum != readChecksum) EXM_THROW(75, "Error : invalid block checksum detected");\r
771         }\r
772 \r
773         if (uncompressedFlag)\r
774         {\r
775             // Write uncompressed Block\r
776             sizeCheck = fwrite(in_buff, 1, blockSize, foutput);\r
777             if (sizeCheck != (size_t)blockSize) EXM_THROW(76, "Write error : cannot write data block");\r
778             filesize += blockSize;\r
779             if (streamChecksumFlag) XXH32_update(streamChecksumState, in_buff, blockSize);\r
780             if (!blockIndependenceFlag)\r
781             {\r
782                 if (blockSize >= prefix64k)\r
783                 {\r
784                     memcpy(out_buff, in_buff + (blockSize - prefix64k), prefix64k);   // Required for reference for next blocks\r
785                     out_start = out_buff + prefix64k;\r
786                     continue;\r
787                 }\r
788                 else\r
789                 {\r
790                     memcpy(out_start, in_buff, blockSize);\r
791                 }\r
792             }\r
793         }\r
794         else\r
795         {\r
796             // Decode Block\r
797             decodedBytes = decompressionFunction(in_buff, out_start, blockSize, maxBlockSize);\r
798             if (decodedBytes < 0) EXM_THROW(77, "Decoding Failed ! Corrupted input detected !");\r
799             filesize += decodedBytes;\r
800             if (streamChecksumFlag) XXH32_update(streamChecksumState, out_start, decodedBytes);\r
801 \r
802             // Write Block\r
803             sizeCheck = fwrite(out_start, 1, decodedBytes, foutput);\r
804             if (sizeCheck != (size_t)decodedBytes) EXM_THROW(78, "Write error : cannot write decoded block\n");\r
805         }\r
806 \r
807         if (!blockIndependenceFlag)\r
808         {\r
809             out_start += decodedBytes;\r
810             if (out_start + maxBlockSize > out_end) \r
811             {\r
812                 memcpy(out_buff, out_start - prefix64k, prefix64k); \r
813                 out_start = out_buff + prefix64k; \r
814             }\r
815         }\r
816     }\r
817 \r
818     // Stream Checksum\r
819     if (streamChecksumFlag)\r
820     {\r
821         unsigned int checksum = XXH32_digest(streamChecksumState);\r
822         unsigned int readChecksum;\r
823         sizeCheck = fread(&readChecksum, 1, 4, finput);\r
824         if (sizeCheck != 4) EXM_THROW(74, "Read error : cannot read stream checksum");\r
825         readChecksum = LITTLE_ENDIAN_32(readChecksum);   // Convert to little endian\r
826         if (checksum != readChecksum) EXM_THROW(75, "Error : invalid stream checksum detected");\r
827     }\r
828 \r
829     // Free\r
830     free(in_buff);\r
831     free(out_buff);\r
832 \r
833     return filesize;\r
834 }\r
835 \r
836 \r
837 unsigned long long selectDecoder( FILE* finput,  FILE* foutput)\r
838 {\r
839     unsigned int magicNumber, size;\r
840     int errorNb;\r
841     size_t nbReadBytes;\r
842 \r
843     // Check Archive Header\r
844     nbReadBytes = fread(&magicNumber, 1, MAGICNUMBER_SIZE, finput);\r
845     if (nbReadBytes==0) return 0;                  // EOF\r
846     if (nbReadBytes != MAGICNUMBER_SIZE) EXM_THROW(41, "Unrecognized header : Magic Number unreadable");\r
847     magicNumber = LITTLE_ENDIAN_32(magicNumber);   // Convert to Little Endian format\r
848     if (LZ4S_isSkippableMagicNumber(magicNumber)) magicNumber = LZ4S_SKIPPABLE0;  // fold skippable magic numbers\r
849 \r
850     switch(magicNumber)\r
851     {\r
852     case LZ4S_MAGICNUMBER:\r
853         return decodeLZ4S(finput, foutput);\r
854     case LEGACY_MAGICNUMBER:\r
855         DISPLAY("Detected : Legacy format \n");\r
856         return decodeLegacyStream(finput, foutput);\r
857     case LZ4S_SKIPPABLE0:\r
858         nbReadBytes = fread(&size, 1, 4, finput);\r
859         if (nbReadBytes != 4) EXM_THROW(42, "Stream error : skippable size unreadable");\r
860         size = LITTLE_ENDIAN_32(size);     // Convert to Little Endian format\r
861         errorNb = fseek(finput, size, SEEK_CUR);\r
862         if (errorNb != 0) EXM_THROW(43, "Stream error : cannot skip skippable area");\r
863         return selectDecoder(finput, foutput);\r
864     default:\r
865         if (ftell(finput) == MAGICNUMBER_SIZE) EXM_THROW(44,"Unrecognized header : file cannot be decoded");   // Wrong magic number at the beginning of 1st stream\r
866         DISPLAY("Stream followed by unrecognized data\n");\r
867         return 0;\r
868     }\r
869 }\r
870 \r
871 \r
872 int decodeFile(char* input_filename, char* output_filename)\r
873 {\r
874     unsigned long long filesize = 0, decodedSize=0;\r
875     FILE* finput;\r
876     FILE* foutput;\r
877     clock_t start, end;\r
878 \r
879 \r
880     // Init\r
881     start = clock();\r
882     get_fileHandle(input_filename, output_filename, &finput, &foutput);\r
883 \r
884     // Loop over multiple streams\r
885     do \r
886     {\r
887         decodedSize = selectDecoder(finput, foutput);\r
888         filesize += decodedSize;\r
889     } while (decodedSize);\r
890 \r
891     // Final Status\r
892     end = clock();\r
893     DISPLAY( "Successfully decoded %llu bytes \n", filesize);\r
894     {\r
895         double seconds = (double)(end - start)/CLOCKS_PER_SEC;\r
896         DISPLAY( "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
897     }\r
898 \r
899     // Close\r
900     fclose(finput);\r
901     fclose(foutput);\r
902 \r
903     // Error status = OK\r
904     return 0;\r
905 }\r
906 \r
907 \r
908 int main(int argc, char** argv)\r
909 {\r
910     int i,\r
911         cLevel=0,\r
912         decode=0,\r
913         bench=0,\r
914         filenamesStart=2,\r
915         legacy_format=0;\r
916     char* exename=argv[0];\r
917     char* input_filename=0;\r
918     char* output_filename=0;\r
919     char nullinput[] = NULL_INPUT;\r
920     char extension[] = EXTENSION;\r
921 \r
922     // Welcome message\r
923     DISPLAY( WELCOME_MESSAGE);\r
924 \r
925     if (argc<2) { badusage(exename); return 1; }\r
926 \r
927     for(i=1; i<argc; i++)\r
928     {\r
929         char* argument = argv[i];\r
930 \r
931         if(!argument) continue;   // Protection if argument empty\r
932 \r
933         // Decode command (note : aggregated commands are allowed)\r
934         if (argument[0]=='-')\r
935         {\r
936             while (argument[1]!=0)\r
937             {\r
938                 argument ++;\r
939 \r
940                 switch(argument[0])\r
941                 {\r
942                     // Display help on usage\r
943                 case 'H': usage(exename); usage_advanced(); return 0;\r
944 \r
945                     // Compression (default)\r
946                 case 'c': if ((argument[1] >='0') && (argument[1] <='1')) { cLevel=argument[1] - '0'; argument++; } break;\r
947                 case 'h': if (argument[1]=='c') { cLevel=1; argument++; } break;\r
948 \r
949                     // Use Legacy format (hidden option)\r
950                 case 'l': legacy_format=1; break;\r
951 \r
952                     // Decoding\r
953                 case 'd': decode=1; break;\r
954 \r
955                     // Test\r
956                 case 't': decode=1; output_filename=nulmark; break;\r
957 \r
958                     // Modify Block Properties\r
959                 case 'B':\r
960                     while (argument[1]!=0)\r
961                     switch(argument[1])\r
962                     {\r
963                     case '4':\r
964                     case '5':\r
965                     case '6':\r
966                     case '7':\r
967                     { \r
968                         int B = argument[1] - '0'; \r
969                         int S = 1 << (8 + 2*B); \r
970                         BMK_SetBlocksize(S); \r
971                         blockSizeId = B;\r
972                         argument++;\r
973                         break;\r
974                     }\r
975                     case 'D': blockIndependence = 0, argument++; break;\r
976                     case 'X': blockChecksum = 1, argument ++; break;\r
977                     default : goto _exit_blockProperties;\r
978                     }\r
979 _exit_blockProperties:\r
980                     break;\r
981 \r
982                     // Modify Stream properties\r
983                 case 'S': if (argument[1]=='x') { streamChecksum=0; argument++; break; } else { badusage(exename); return 1; }\r
984 \r
985                     // Bench\r
986                 case 'b': bench=1; \r
987                     if ((argument[1] >='0') && (argument[1] <='1')) { cLevel=argument[1] - '0'; argument++; } \r
988                     break;\r
989 \r
990                     // Modify Nb Iterations (benchmark only)\r
991                 case 'i': \r
992                     if ((argument[1] >='1') && (argument[1] <='9'))\r
993                     {\r
994                         int iters = argument[1] - '0'; \r
995                         BMK_SetNbIterations(iters); \r
996                         argument++;\r
997                     }\r
998                     break;\r
999 \r
1000                     // Pause at the end (benchmark only) (hidden option)\r
1001                 case 'p': BMK_SetPause(); break;\r
1002 \r
1003                     // Overwrite\r
1004                 case 'y': overwrite=1; break;\r
1005 \r
1006                     // Unrecognised command\r
1007                 default : badusage(exename); return 1;\r
1008                 }\r
1009             }\r
1010             continue;\r
1011         }\r
1012 \r
1013         // first provided filename is input\r
1014         if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }\r
1015 \r
1016         // second provided filename is output\r
1017         if (!output_filename)\r
1018         {\r
1019             output_filename=argument;\r
1020             if (!strcmp (output_filename, nullinput)) output_filename = nulmark;\r
1021             continue;\r
1022         }\r
1023     }\r
1024 \r
1025     // No input filename ==> Error\r
1026     if(!input_filename) { badusage(exename); return 1; }\r
1027 \r
1028     if (bench) return BMK_benchFile(argv+filenamesStart, argc-filenamesStart, cLevel);\r
1029 \r
1030     // No output filename ==> build one automatically (when possible)\r
1031     if (!output_filename) \r
1032     { \r
1033         if (!decode)   // compression\r
1034         {\r
1035             int i=0, l=0;\r
1036             while (input_filename[l]!=0) l++;\r
1037             output_filename = (char*)calloc(1,l+5);\r
1038             for (i=0;i<l;i++) output_filename[i] = input_filename[i];\r
1039             for (i=l;i<l+4;i++) output_filename[i] = extension[i-l];\r
1040         }\r
1041         else           // decompression (input file must respect format extension ".lz4")\r
1042         {\r
1043             int inl=0,outl;\r
1044             while (input_filename[inl]!=0) inl++;\r
1045             output_filename = (char*)calloc(1,inl+1);\r
1046             for (outl=0;outl<inl;outl++) output_filename[outl] = input_filename[outl];\r
1047             if (inl>4)\r
1048                 while ((outl >= inl-4) && (input_filename[outl] ==  extension[outl-inl+4])) output_filename[outl--]=0;\r
1049             if (outl != inl-5) output_filename = NULL;\r
1050         }\r
1051         if (!output_filename) { badusage(exename); return 1; }\r
1052     }\r
1053 \r
1054     if (decode) return decodeFile(input_filename, output_filename);\r
1055 \r
1056     // compression is default action\r
1057     if (legacy_format)\r
1058     {\r
1059         DISPLAY("! Generating compressed LZ4 using Legacy format (deprecated !) ! \n");\r
1060         return legacy_compress_file(input_filename, output_filename, cLevel);   \r
1061     }\r
1062     else\r
1063     {\r
1064         return compress_file(input_filename, output_filename, cLevel);   \r
1065     }\r
1066 }\r