35 #define _CRT_SECURE_NO_WARNINGS
36 #define _CRT_SECURE_NO_DEPRECATE // VS2005
58 #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
60 #if defined(_MSC_VER) // Visual Studio
61 #define swap32 _byteswap_ulong
62 #elif GCC_VERSION >= 403
63 #define swap32 __builtin_bswap32
65 static inline unsigned int swap32(
unsigned int x) {
66 return ((x << 24) & 0xff000000 ) |
67 ((x << 8) & 0x00ff0000 ) |
68 ((x >> 8) & 0x0000ff00 ) |
69 ((x >> 24) & 0x000000ff );
77 #define COMPRESSOR_NAME "Compression CLI using LZ4 algorithm"
78 #define COMPRESSOR_VERSION ""
79 #define COMPILED __DATE__
80 #define AUTHOR "Yann Collet"
81 #define EXTENSION ".lz4"
82 #define WELCOME_MESSAGE "*** %s %s, by %s (%s) ***\n", COMPRESSOR_NAME, COMPRESSOR_VERSION, AUTHOR, COMPILED
84 #define CHUNKSIZE (8<<20) // 8 MB
86 #define ARCHIVE_MAGICNUMBER 0x184C2102
87 #define ARCHIVE_MAGICNUMBER_SIZE 4
93 static const int one = 1;
94 #define CPU_LITTLE_ENDIAN (*(char*)(&one))
95 #define CPU_BIG_ENDIAN (!CPU_LITTLE_ENDIAN)
96 #define LITTLE_ENDIAN32(i) if (CPU_BIG_ENDIAN) { i = swap32(i); }
102 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
111 DISPLAY(
" %s [arg] input output\n", exename);
113 DISPLAY(
" -c0: Fast compression (default) \n");
114 DISPLAY(
" -c1: High compression \n");
115 DISPLAY(
" -d : decompression \n");
116 DISPLAY(
" -b#: Benchmark files, using # compression level\n");
117 DISPLAY(
" -t : check compressed file \n");
118 DISPLAY(
" -h : help (this text)\n");
119 DISPLAY(
"input : can be 'stdin' (pipe) or a filename\n");
120 DISPLAY(
"output : can be 'stdout'(pipe) or a filename or 'null'\n");
134 int get_fileHandle(
char* input_filename,
char* output_filename, FILE** pfinput, FILE** pfoutput)
136 char stdinmark[] =
"stdin";
137 char stdoutmark[] =
"stdout";
139 if (!strcmp (input_filename, stdinmark)) {
140 DISPLAY(
"Using stdin for input\n");
142 #ifdef _WIN32 // Need to set stdin/stdout to binary mode specifically for windows
143 _setmode( _fileno( stdin ), _O_BINARY );
146 *pfinput = fopen( input_filename,
"rb" );
149 if (!strcmp (output_filename, stdoutmark)) {
150 DISPLAY(
"Using stdout for output\n");
152 #ifdef _WIN32 // Need to set stdin/stdout to binary mode specifically for windows
153 _setmode( _fileno( stdout ), _O_BINARY );
156 *pfoutput = fopen( output_filename,
"wb" );
159 if ( *pfinput==0 ) {
DISPLAY(
"Pb opening %s\n", input_filename);
return 2; }
160 if ( *pfoutput==0) {
DISPLAY(
"Pb opening %s\n", output_filename);
return 3; }
167 int compress_file(
char* input_filename,
char* output_filename,
int compressionlevel)
169 int (*compressionFunction)(
const char*,
char*, int);
170 unsigned long long filesize = 0;
178 int displayLevel = (compressionlevel>0);
184 switch (compressionlevel)
191 r =
get_fileHandle(input_filename, output_filename, &finput, &foutput);
197 if (!in_buff || !out_buff) {
DISPLAY(
"Allocation error : not enough memory\n");
return 8; }
202 *(
unsigned int*)out_buff = u32var;
211 int inSize = (int) fread(in_buff, (
size_t)1, (size_t)
CHUNKSIZE, finput);
212 if( inSize<=0 )
break;
214 if (displayLevel)
DISPLAY(
"Read : %i MB \r", (
int)(filesize>>20));
217 outSize = compressionFunction(in_buff, out_buff+4, inSize);
218 compressedfilesize += outSize+4;
219 if (displayLevel)
DISPLAY(
"Read : %i MB ==> %.2f%%\r", (
int)(filesize>>20), (
double)compressedfilesize/filesize*100);
223 * (
unsigned int*) out_buff = outSize;
225 sizeCheck = fwrite(out_buff, 1, outSize+4, foutput);
226 if (sizeCheck!=(
size_t)(outSize+4)) {
DISPLAY(
"write error\n");
return 11; }
231 DISPLAY(
"Compressed %llu bytes into %llu bytes ==> %.2f%%\n",
232 (
unsigned long long) filesize, (
unsigned long long) compressedfilesize, (
double)compressedfilesize/filesize*100);
234 double seconds = (double)(end - start)/CLOCKS_PER_SEC;
235 DISPLAY(
"Done in %.2f s ==> %.2f MB/s\n", seconds, (
double)filesize / seconds / 1024 / 1024);
250 unsigned long long filesize = 0;
265 r =
get_fileHandle(input_filename, output_filename, &finput, &foutput);
271 if (!in_buff || !out_buff) {
DISPLAY(
"Allocation error : not enough memory\n");
return 7; }
283 uselessRet = fread(&chunkSize, 1, 4, finput);
284 if( uselessRet==0 )
break;
290 uselessRet = fread(in_buff, 1, chunkSize, finput);
294 if (sinkint < 0) {
DISPLAY(
"Decoding Failed ! Corrupted input !\n");
return 9; }
298 sizeCheck = fwrite(out_buff, 1, sinkint, foutput);
299 if (sizeCheck != (
size_t)sinkint) {
DISPLAY(
"write error\n");
return 12; }
304 DISPLAY(
"Successfully decoded %llu bytes \n", (
unsigned long long)filesize);
306 double seconds = (double)(end - start)/CLOCKS_PER_SEC;
307 DISPLAY(
"Done in %.2f s ==> %.2f MB/s\n", seconds, (
double)filesize / seconds / 1024 / 1024);
320 int main(
int argc,
char** argv)
327 char* exename=argv[0];
328 char* input_filename=0;
329 char* output_filename=0;
331 char nulmark[] =
"nul";
333 char nulmark[] =
"/dev/null";
335 char nullinput[] =
"null";
340 if (argc<2) {
badusage(exename);
return 1; }
342 for(i=1; i<argc; i++)
344 char* argument = argv[i];
346 if(!argument)
continue;
349 if (argument[0]==
'-')
354 if ( argument[0] ==
'h' ) {
usage(exename);
return 0; }
357 if ( argument[0] ==
'c' ) {
if (argument[1] >=
'0') cLevel=argument[1] -
'0';
continue; }
360 if ( argument[0] ==
'd' ) { decode=1;
continue; }
363 if ( argument[0] ==
'b' ) { bench=1;
if (argument[1] >=
'0') cLevel=argument[1] -
'0';
continue; }
366 if ( argument[0] ==
'B' ) {
int B = argument[1] -
'0';
int S = 1 << (10 + 2*B);
BMK_SetBlocksize(S);
continue; }
369 if ( argument[0] ==
'i' ) {
int iters = argument[1] -
'0';
BMK_SetNbIterations(iters);
continue; }
375 if ( argument[0] ==
't' ) { decode=1; output_filename=nulmark;
continue; }
379 if (!input_filename) { input_filename=argument; filenamesStart=i;
continue; }
382 if (!output_filename)
384 output_filename=argument;
385 if (!strcmp (output_filename, nullinput)) output_filename = nulmark;
391 if(!input_filename) {
badusage(exename);
return 1; }
393 if (bench)
return BMK_benchFile(argv+filenamesStart, argc-filenamesStart, cLevel);
396 if (!output_filename) {
badusage(exename);
return 1; }
398 if (decode)
return decode_file(input_filename, output_filename);
400 return compress_file(input_filename, output_filename, cLevel);