1 /* 2 LZ4cli - LZ4 Command Line Interface 3 Copyright (C) Yann Collet 2011-2016 4 5 GPL v2 License 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License along 18 with this program; if not, write to the Free Software Foundation, Inc., 19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 21 You can contact the author at : 22 - LZ4 source repository : https://github.com/lz4/lz4 23 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c 24 */ 25 /* 26 Note : this is stand-alone program. 27 It is not part of LZ4 compression library, it is a user program of the LZ4 library. 28 The license of LZ4 library is BSD. 29 The license of xxHash library is BSD. 30 The license of this compression CLI program is GPLv2. 31 */ 32 33 /************************************** 34 * Tuning parameters 35 ***************************************/ 36 /* ENABLE_LZ4C_LEGACY_OPTIONS : 37 Control the availability of -c0, -c1 and -hc legacy arguments 38 Default : Legacy options are disabled */ 39 /* #define ENABLE_LZ4C_LEGACY_OPTIONS */ 40 41 42 /**************************** 43 * Includes 44 *****************************/ 45 #include "platform.h" /* Compiler options, IS_CONSOLE */ 46 #include "util.h" /* UTIL_HAS_CREATEFILELIST, UTIL_createFileList */ 47 #include <stdio.h> /* fprintf, getchar */ 48 #include <stdlib.h> /* exit, calloc, free */ 49 #include <string.h> /* strcmp, strlen */ 50 #include "bench.h" /* BMK_benchFile, BMK_SetNbIterations, BMK_SetBlocksize, BMK_SetPause */ 51 #include "lz4io.h" /* LZ4IO_compressFilename, LZ4IO_decompressFilename, LZ4IO_compressMultipleFilenames */ 52 #include "lz4hc.h" /* LZ4HC_DEFAULT_CLEVEL */ 53 #include "lz4.h" /* LZ4_VERSION_STRING */ 54 55 56 /***************************** 57 * Constants 58 ******************************/ 59 #define COMPRESSOR_NAME "LZ4 command line interface" 60 #define AUTHOR "Yann Collet" 61 #define WELCOME_MESSAGE "*** %s %i-bits v%s, by %s ***\n", COMPRESSOR_NAME, (int)(sizeof(void*)*8), LZ4_versionString(), AUTHOR 62 #define LZ4_EXTENSION ".lz4" 63 #define LZ4CAT "lz4cat" 64 #define UNLZ4 "unlz4" 65 66 #define KB *(1U<<10) 67 #define MB *(1U<<20) 68 #define GB *(1U<<30) 69 70 #define LZ4_BLOCKSIZEID_DEFAULT 7 71 72 73 /*-************************************ 74 * Macros 75 ***************************************/ 76 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) 77 #define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); } 78 static unsigned displayLevel = 2; /* 0 : no display ; 1: errors only ; 2 : downgradable normal ; 3 : non-downgradable normal; 4 : + information */ 79 80 81 /*-************************************ 82 * Exceptions 83 ***************************************/ 84 #define DEBUG 0 85 #define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__); 86 #define EXM_THROW(error, ...) \ 87 { \ 88 DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \ 89 DISPLAYLEVEL(1, "Error %i : ", error); \ 90 DISPLAYLEVEL(1, __VA_ARGS__); \ 91 DISPLAYLEVEL(1, "\n"); \ 92 exit(error); \ 93 } 94 95 96 /*-************************************ 97 * Version modifiers 98 ***************************************/ 99 #define EXTENDED_ARGUMENTS 100 #define EXTENDED_HELP 101 #define EXTENDED_FORMAT 102 #define DEFAULT_COMPRESSOR LZ4IO_compressFilename 103 #define DEFAULT_DECOMPRESSOR LZ4IO_decompressFilename 104 int LZ4IO_compressFilename_Legacy(const char* input_filename, const char* output_filename, int compressionlevel); /* hidden function */ 105 106 107 /*-*************************** 108 * Functions 109 *****************************/ 110 static int usage(const char* exeName) 111 { 112 DISPLAY( "Usage : \n"); 113 DISPLAY( " %s [arg] [input] [output] \n", exeName); 114 DISPLAY( "\n"); 115 DISPLAY( "input : a filename \n"); 116 DISPLAY( " with no FILE, or when FILE is - or %s, read standard input\n", stdinmark); 117 DISPLAY( "Arguments : \n"); 118 DISPLAY( " -1 : Fast compression (default) \n"); 119 DISPLAY( " -9 : High compression \n"); 120 DISPLAY( " -d : decompression (default for %s extension)\n", LZ4_EXTENSION); 121 DISPLAY( " -z : force compression \n"); 122 DISPLAY( " -f : overwrite output without prompting \n"); 123 DISPLAY( " -k : preserve source files(s) (default) \n"); 124 DISPLAY( "--rm : remove source file(s) after successful de/compression \n"); 125 DISPLAY( " -h/-H : display help/long help and exit \n"); 126 return 0; 127 } 128 129 static int usage_advanced(const char* exeName) 130 { 131 DISPLAY(WELCOME_MESSAGE); 132 usage(exeName); 133 DISPLAY( "\n"); 134 DISPLAY( "Advanced arguments :\n"); 135 DISPLAY( " -V : display Version number and exit \n"); 136 DISPLAY( " -v : verbose mode \n"); 137 DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n"); 138 DISPLAY( " -c : force write to standard output, even if it is the console\n"); 139 DISPLAY( " -t : test compressed file integrity\n"); 140 DISPLAY( " -m : multiple input files (implies automatic output filenames)\n"); 141 #ifdef UTIL_HAS_CREATEFILELIST 142 DISPLAY( " -r : operate recursively on directories (sets also -m) \n"); 143 #endif 144 DISPLAY( " -l : compress using Legacy format (Linux kernel compression)\n"); 145 DISPLAY( " -B# : Block size [4-7] (default : 7) \n"); 146 DISPLAY( " -BD : Block dependency (improve compression ratio) \n"); 147 /* DISPLAY( " -BX : enable block checksum (default:disabled)\n"); *//* Option currently inactive */ 148 DISPLAY( "--no-frame-crc : disable stream checksum (default:enabled) \n"); 149 DISPLAY( "--content-size : compressed frame includes original size (default:not present)\n"); 150 DISPLAY( "--[no-]sparse : sparse mode (default:enabled on file, disabled on stdout)\n"); 151 DISPLAY( "Benchmark arguments : \n"); 152 DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n"); 153 DISPLAY( " -e# : test all compression levels from -bX to # (default : 1)\n"); 154 DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s) \n"); 155 DISPLAY( " -B# : cut file into independent blocks of size # bytes [32+] \n"); 156 DISPLAY( " or predefined block size [4-7] (default: 7) \n"); 157 #if defined(ENABLE_LZ4C_LEGACY_OPTIONS) 158 DISPLAY( "Legacy arguments : \n"); 159 DISPLAY( " -c0 : fast compression \n"); 160 DISPLAY( " -c1 : high compression \n"); 161 DISPLAY( " -hc : high compression \n"); 162 DISPLAY( " -y : overwrite output without prompting \n"); 163 #endif /* ENABLE_LZ4C_LEGACY_OPTIONS */ 164 EXTENDED_HELP; 165 return 0; 166 } 167 168 static int usage_longhelp(const char* exeName) 169 { 170 usage_advanced(exeName); 171 DISPLAY( "\n"); 172 DISPLAY( "****************************\n"); 173 DISPLAY( "***** Advanced comment *****\n"); 174 DISPLAY( "****************************\n"); 175 DISPLAY( "\n"); 176 DISPLAY( "Which values can [output] have ? \n"); 177 DISPLAY( "---------------------------------\n"); 178 DISPLAY( "[output] : a filename \n"); 179 DISPLAY( " '%s', or '-' for standard output (pipe mode)\n", stdoutmark); 180 DISPLAY( " '%s' to discard output (test mode) \n", NULL_OUTPUT); 181 DISPLAY( "[output] can be left empty. In this case, it receives the following value :\n"); 182 DISPLAY( " - if stdout is not the console, then [output] = stdout \n"); 183 DISPLAY( " - if stdout is console : \n"); 184 DISPLAY( " + for compression, output to filename%s \n", LZ4_EXTENSION); 185 DISPLAY( " + for decompression, output to filename without '%s'\n", LZ4_EXTENSION); 186 DISPLAY( " > if input filename has no '%s' extension : error \n", LZ4_EXTENSION); 187 DISPLAY( "\n"); 188 DISPLAY( "Compression levels : \n"); 189 DISPLAY( "---------------------\n"); 190 DISPLAY( "-0 ... -2 => Fast compression, all identicals\n"); 191 DISPLAY( "-3 ... -%d => High compression; higher number == more compression but slower\n", LZ4HC_CLEVEL_MAX); 192 DISPLAY( "\n"); 193 DISPLAY( "stdin, stdout and the console : \n"); 194 DISPLAY( "--------------------------------\n"); 195 DISPLAY( "To protect the console from binary flooding (bad argument mistake)\n"); 196 DISPLAY( "%s will refuse to read from console, or write to console \n", exeName); 197 DISPLAY( "except if '-c' command is specified, to force output to console \n"); 198 DISPLAY( "\n"); 199 DISPLAY( "Simple example :\n"); 200 DISPLAY( "----------------\n"); 201 DISPLAY( "1 : compress 'filename' fast, using default output name 'filename.lz4'\n"); 202 DISPLAY( " %s filename\n", exeName); 203 DISPLAY( "\n"); 204 DISPLAY( "Short arguments can be aggregated. For example :\n"); 205 DISPLAY( "----------------------------------\n"); 206 DISPLAY( "2 : compress 'filename' in high compression mode, overwrite output if exists\n"); 207 DISPLAY( " %s -9 -f filename \n", exeName); 208 DISPLAY( " is equivalent to :\n"); 209 DISPLAY( " %s -9f filename \n", exeName); 210 DISPLAY( "\n"); 211 DISPLAY( "%s can be used in 'pure pipe mode'. For example :\n", exeName); 212 DISPLAY( "-------------------------------------\n"); 213 DISPLAY( "3 : compress data stream from 'generator', send result to 'consumer'\n"); 214 DISPLAY( " generator | %s | consumer \n", exeName); 215 #if defined(ENABLE_LZ4C_LEGACY_OPTIONS) 216 DISPLAY( "\n"); 217 DISPLAY( "***** Warning *****\n"); 218 DISPLAY( "Legacy arguments take precedence. Therefore : \n"); 219 DISPLAY( "---------------------------------\n"); 220 DISPLAY( " %s -hc filename\n", exeName); 221 DISPLAY( "means 'compress filename in high compression mode'\n"); 222 DISPLAY( "It is not equivalent to :\n"); 223 DISPLAY( " %s -h -c filename\n", exeName); 224 DISPLAY( "which would display help text and exit\n"); 225 #endif /* ENABLE_LZ4C_LEGACY_OPTIONS */ 226 return 0; 227 } 228 229 static int badusage(const char* exeName) 230 { 231 DISPLAYLEVEL(1, "Incorrect parameters\n"); 232 if (displayLevel >= 1) usage(exeName); 233 exit(1); 234 } 235 236 237 static void waitEnter(void) 238 { 239 DISPLAY("Press enter to continue...\n"); 240 (void)getchar(); 241 } 242 243 static const char* lastNameFromPath(const char* path) 244 { 245 const char* name = strrchr(path, '/'); 246 if (name==NULL) name = strrchr(path, '\\'); /* windows */ 247 if (name==NULL) return path; 248 return name+1; 249 } 250 251 /*! readU32FromChar() : 252 @return : unsigned integer value reach from input in `char` format 253 Will also modify `*stringPtr`, advancing it to position where it stopped reading. 254 Note : this function can overflow if result > MAX_UINT */ 255 static unsigned readU32FromChar(const char** stringPtr) 256 { 257 unsigned result = 0; 258 while ((**stringPtr >='0') && (**stringPtr <='9')) 259 result *= 10, result += **stringPtr - '0', (*stringPtr)++ ; 260 return result; 261 } 262 263 typedef enum { om_auto, om_compress, om_decompress, om_test, om_bench } operationMode_e; 264 265 int main(int argc, const char** argv) 266 { 267 int i, 268 cLevel=1, 269 cLevelLast=1, 270 legacy_format=0, 271 forceStdout=0, 272 main_pause=0, 273 multiple_inputs=0, 274 operationResult=0; 275 operationMode_e mode = om_auto; 276 const char* input_filename = NULL; 277 const char* output_filename= NULL; 278 char* dynNameSpace = NULL; 279 const char** inFileNames = (const char**) calloc(argc, sizeof(char*)); 280 unsigned ifnIdx=0; 281 const char nullOutput[] = NULL_OUTPUT; 282 const char extension[] = LZ4_EXTENSION; 283 size_t blockSize = LZ4IO_setBlockSizeID(LZ4_BLOCKSIZEID_DEFAULT); 284 const char* const exeName = lastNameFromPath(argv[0]); 285 #ifdef UTIL_HAS_CREATEFILELIST 286 const char** extendedFileList = NULL; 287 char* fileNamesBuf = NULL; 288 unsigned fileNamesNb, recursive=0; 289 #endif 290 291 /* Init */ 292 if (inFileNames==NULL) { 293 DISPLAY("Allocation error : not enough memory \n"); 294 return 1; 295 } 296 inFileNames[0] = stdinmark; 297 LZ4IO_setOverwrite(0); 298 299 /* lz4cat predefined behavior */ 300 if (!strcmp(exeName, LZ4CAT)) { 301 mode = om_decompress; 302 LZ4IO_setOverwrite(1); 303 LZ4IO_setRemoveSrcFile(0); 304 forceStdout=1; 305 output_filename=stdoutmark; 306 displayLevel=1; 307 multiple_inputs=1; 308 } 309 if (!strcmp(exeName, UNLZ4)) { mode = om_decompress; } 310 311 /* command switches */ 312 for(i=1; i<argc; i++) { 313 const char* argument = argv[i]; 314 315 if(!argument) continue; /* Protection if argument empty */ 316 317 /* Short commands (note : aggregated short commands are allowed) */ 318 if (argument[0]=='-') { 319 /* '-' means stdin/stdout */ 320 if (argument[1]==0) { 321 if (!input_filename) input_filename=stdinmark; 322 else output_filename=stdoutmark; 323 continue; 324 } 325 326 /* long commands (--long-word) */ 327 if (argument[1]=='-') { 328 if (!strcmp(argument, "--compress")) { mode = om_compress; continue; } 329 if ((!strcmp(argument, "--decompress")) 330 || (!strcmp(argument, "--uncompress"))) { mode = om_decompress; continue; } 331 if (!strcmp(argument, "--multiple")) { multiple_inputs = 1; continue; } 332 if (!strcmp(argument, "--test")) { mode = om_test; continue; } 333 if (!strcmp(argument, "--force")) { LZ4IO_setOverwrite(1); continue; } 334 if (!strcmp(argument, "--no-force")) { LZ4IO_setOverwrite(0); continue; } 335 if ((!strcmp(argument, "--stdout")) 336 || (!strcmp(argument, "--to-stdout"))) { forceStdout=1; output_filename=stdoutmark; continue; } 337 if (!strcmp(argument, "--frame-crc")) { LZ4IO_setStreamChecksumMode(1); continue; } 338 if (!strcmp(argument, "--no-frame-crc")) { LZ4IO_setStreamChecksumMode(0); continue; } 339 if (!strcmp(argument, "--content-size")) { LZ4IO_setContentSize(1); continue; } 340 if (!strcmp(argument, "--no-content-size")) { LZ4IO_setContentSize(0); continue; } 341 if (!strcmp(argument, "--sparse")) { LZ4IO_setSparseFile(2); continue; } 342 if (!strcmp(argument, "--no-sparse")) { LZ4IO_setSparseFile(0); continue; } 343 if (!strcmp(argument, "--verbose")) { displayLevel++; continue; } 344 if (!strcmp(argument, "--quiet")) { if (displayLevel) displayLevel--; continue; } 345 if (!strcmp(argument, "--version")) { DISPLAY(WELCOME_MESSAGE); return 0; } 346 if (!strcmp(argument, "--help")) { usage_advanced(exeName); goto _cleanup; } 347 if (!strcmp(argument, "--keep")) { LZ4IO_setRemoveSrcFile(0); continue; } /* keep source file (default) */ 348 if (!strcmp(argument, "--rm")) { LZ4IO_setRemoveSrcFile(1); continue; } 349 } 350 351 while (argument[1]!=0) { 352 argument ++; 353 354 #if defined(ENABLE_LZ4C_LEGACY_OPTIONS) 355 /* Legacy arguments (-c0, -c1, -hc, -y, -s) */ 356 if ((argument[0]=='c') && (argument[1]=='0')) { cLevel=0; argument++; continue; } /* -c0 (fast compression) */ 357 if ((argument[0]=='c') && (argument[1]=='1')) { cLevel=9; argument++; continue; } /* -c1 (high compression) */ 358 if ((argument[0]=='h') && (argument[1]=='c')) { cLevel=9; argument++; continue; } /* -hc (high compression) */ 359 if (*argument=='y') { LZ4IO_setOverwrite(1); continue; } /* -y (answer 'yes' to overwrite permission) */ 360 #endif /* ENABLE_LZ4C_LEGACY_OPTIONS */ 361 362 if ((*argument>='0') && (*argument<='9')) { 363 cLevel = readU32FromChar(&argument); 364 argument--; 365 continue; 366 } 367 368 369 switch(argument[0]) 370 { 371 /* Display help */ 372 case 'V': DISPLAY(WELCOME_MESSAGE); goto _cleanup; /* Version */ 373 case 'h': usage_advanced(exeName); goto _cleanup; 374 case 'H': usage_longhelp(exeName); goto _cleanup; 375 376 case 'e': 377 argument++; 378 cLevelLast = readU32FromChar(&argument); 379 argument--; 380 break; 381 382 /* Compression (default) */ 383 case 'z': mode = om_compress; break; 384 385 /* Use Legacy format (ex : Linux kernel compression) */ 386 case 'l': legacy_format = 1; blockSize = 8 MB; break; 387 388 /* Decoding */ 389 case 'd': mode = om_decompress; break; 390 391 /* Force stdout, even if stdout==console */ 392 case 'c': forceStdout=1; output_filename=stdoutmark; break; 393 394 /* Test integrity */ 395 case 't': mode = om_test; break; 396 397 /* Overwrite */ 398 case 'f': LZ4IO_setOverwrite(1); break; 399 400 /* Verbose mode */ 401 case 'v': displayLevel++; break; 402 403 /* Quiet mode */ 404 case 'q': if (displayLevel) displayLevel--; break; 405 406 /* keep source file (default anyway, so useless) (for xz/lzma compatibility) */ 407 case 'k': LZ4IO_setRemoveSrcFile(0); break; 408 409 /* Modify Block Properties */ 410 case 'B': 411 while (argument[1]!=0) { 412 int exitBlockProperties=0; 413 switch(argument[1]) 414 { 415 case 'D': LZ4IO_setBlockMode(LZ4IO_blockLinked); argument++; break; 416 case 'X': LZ4IO_setBlockChecksumMode(1); argument ++; break; /* disabled by default */ 417 default : 418 if (argument[1] < '0' || argument[1] > '9') { 419 exitBlockProperties=1; 420 break; 421 } else { 422 unsigned B; 423 argument++; 424 B = readU32FromChar(&argument); 425 argument--; 426 if (B < 4) badusage(exeName); 427 if (B <= 7) { 428 blockSize = LZ4IO_setBlockSizeID(B); 429 BMK_SetBlockSize(blockSize); 430 DISPLAYLEVEL(2, "using blocks of size %u KB \n", (U32)(blockSize>>10)); 431 } else { 432 if (B < 32) badusage(exeName); 433 BMK_SetBlockSize(B); 434 if (B >= 1024) { 435 DISPLAYLEVEL(2, "bench: using blocks of size %u KB \n", (U32)(B>>10)); 436 } else { 437 DISPLAYLEVEL(2, "bench: using blocks of size %u bytes \n", (U32)(B)); 438 } 439 } 440 break; 441 } 442 } 443 if (exitBlockProperties) break; 444 } 445 break; 446 447 /* Benchmark */ 448 case 'b': mode = om_bench; multiple_inputs=1; 449 break; 450 451 #ifdef UTIL_HAS_CREATEFILELIST 452 /* recursive */ 453 case 'r': recursive=1; /* without break */ 454 #endif 455 /* Treat non-option args as input files. See https://code.google.com/p/lz4/issues/detail?id=151 */ 456 case 'm': multiple_inputs=1; 457 break; 458 459 /* Modify Nb Seconds (benchmark only) */ 460 case 'i': 461 { unsigned iters; 462 argument++; 463 iters = readU32FromChar(&argument); 464 argument--; 465 BMK_setNotificationLevel(displayLevel); 466 BMK_SetNbSeconds(iters); /* notification if displayLevel >= 3 */ 467 } 468 break; 469 470 /* Pause at the end (hidden option) */ 471 case 'p': main_pause=1; break; 472 473 /* Specific commands for customized versions */ 474 EXTENDED_ARGUMENTS; 475 476 /* Unrecognised command */ 477 default : badusage(exeName); 478 } 479 } 480 continue; 481 } 482 483 /* Store in *inFileNames[] if -m is used. */ 484 if (multiple_inputs) { inFileNames[ifnIdx++]=argument; continue; } 485 486 /* Store first non-option arg in input_filename to preserve original cli logic. */ 487 if (!input_filename) { input_filename=argument; continue; } 488 489 /* Second non-option arg in output_filename to preserve original cli logic. */ 490 if (!output_filename) { 491 output_filename=argument; 492 if (!strcmp (output_filename, nullOutput)) output_filename = nulmark; 493 continue; 494 } 495 496 /* 3rd non-option arg should not exist */ 497 DISPLAYLEVEL(1, "Warning : %s won't be used ! Do you want multiple input files (-m) ? \n", argument); 498 } 499 500 DISPLAYLEVEL(3, WELCOME_MESSAGE); 501 #ifdef _POSIX_C_SOURCE 502 DISPLAYLEVEL(4, "_POSIX_C_SOURCE defined: %ldL\n", (long) _POSIX_C_SOURCE); 503 #endif 504 #ifdef _POSIX_VERSION 505 DISPLAYLEVEL(4, "_POSIX_VERSION defined: %ldL\n", (long) _POSIX_VERSION); 506 #endif 507 #ifdef PLATFORM_POSIX_VERSION 508 DISPLAYLEVEL(4, "PLATFORM_POSIX_VERSION defined: %ldL\n", (long) PLATFORM_POSIX_VERSION); 509 #endif 510 #ifdef _FILE_OFFSET_BITS 511 DISPLAYLEVEL(4, "_FILE_OFFSET_BITS defined: %ldL\n", (long) _FILE_OFFSET_BITS); 512 #endif 513 if ((mode == om_compress) || (mode == om_bench)) DISPLAYLEVEL(4, "Blocks size : %i KB\n", (U32)(blockSize>>10)); 514 515 if (multiple_inputs) { 516 input_filename = inFileNames[0]; 517 #ifdef UTIL_HAS_CREATEFILELIST 518 if (recursive) { /* at this stage, filenameTable is a list of paths, which can contain both files and directories */ 519 extendedFileList = UTIL_createFileList(inFileNames, ifnIdx, &fileNamesBuf, &fileNamesNb); 520 if (extendedFileList) { 521 unsigned u; 522 for (u=0; u<fileNamesNb; u++) DISPLAYLEVEL(4, "%u %s\n", u, extendedFileList[u]); 523 free((void*)inFileNames); 524 inFileNames = extendedFileList; 525 ifnIdx = fileNamesNb; 526 } 527 } 528 #endif 529 } 530 531 /* benchmark and test modes */ 532 if (mode == om_bench) { 533 BMK_setNotificationLevel(displayLevel); 534 operationResult = BMK_benchFiles(inFileNames, ifnIdx, cLevel, cLevelLast); 535 goto _cleanup; 536 } 537 538 if (mode == om_test) { 539 LZ4IO_setTestMode(1); 540 output_filename = nulmark; 541 mode = om_decompress; /* defer to decompress */ 542 } 543 544 /* compress or decompress */ 545 if (!input_filename) input_filename = stdinmark; 546 /* Check if input is defined as console; trigger an error in this case */ 547 if (!strcmp(input_filename, stdinmark) && IS_CONSOLE(stdin) ) { 548 DISPLAYLEVEL(1, "refusing to read from a console\n"); 549 exit(1); 550 } 551 /* if input==stdin and no output defined, stdout becomes default output */ 552 if (!strcmp(input_filename, stdinmark) && !output_filename) 553 output_filename = stdoutmark; 554 555 /* No output filename ==> try to select one automatically (when possible) */ 556 while ((!output_filename) && (multiple_inputs==0)) { 557 if (!IS_CONSOLE(stdout)) { output_filename=stdoutmark; break; } /* Default to stdout whenever possible (i.e. not a console) */ 558 if (mode == om_auto) { /* auto-determine compression or decompression, based on file extension */ 559 size_t const inSize = strlen(input_filename); 560 size_t const extSize = strlen(LZ4_EXTENSION); 561 size_t const extStart= (inSize > extSize) ? inSize-extSize : 0; 562 if (!strcmp(input_filename+extStart, LZ4_EXTENSION)) mode = om_decompress; 563 else mode = om_compress; 564 } 565 if (mode == om_compress) { /* compression to file */ 566 size_t const l = strlen(input_filename); 567 dynNameSpace = (char*)calloc(1,l+5); 568 if (dynNameSpace==NULL) { perror(exeName); exit(1); } 569 strcpy(dynNameSpace, input_filename); 570 strcat(dynNameSpace, LZ4_EXTENSION); 571 output_filename = dynNameSpace; 572 DISPLAYLEVEL(2, "Compressed filename will be : %s \n", output_filename); 573 break; 574 } 575 if (mode == om_decompress) {/* decompression to file (automatic name will work only if input filename has correct format extension) */ 576 size_t outl; 577 size_t const inl = strlen(input_filename); 578 dynNameSpace = (char*)calloc(1,inl+1); 579 if (dynNameSpace==NULL) { perror(exeName); exit(1); } 580 strcpy(dynNameSpace, input_filename); 581 outl = inl; 582 if (inl>4) 583 while ((outl >= inl-4) && (input_filename[outl] == extension[outl-inl+4])) dynNameSpace[outl--]=0; 584 if (outl != inl-5) { DISPLAYLEVEL(1, "Cannot determine an output filename\n"); badusage(exeName); } 585 output_filename = dynNameSpace; 586 DISPLAYLEVEL(2, "Decoding file %s \n", output_filename); 587 } 588 break; 589 } 590 591 /* Check if output is defined as console; trigger an error in this case */ 592 if (!output_filename) output_filename = "*\\dummy^!//"; 593 if (!strcmp(output_filename,stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) { 594 DISPLAYLEVEL(1, "refusing to write to console without -c\n"); 595 exit(1); 596 } 597 /* Downgrade notification level in stdout and multiple file mode */ 598 if (!strcmp(output_filename,stdoutmark) && (displayLevel==2)) displayLevel=1; 599 if ((multiple_inputs) && (displayLevel==2)) displayLevel=1; 600 601 /* IO Stream/File */ 602 LZ4IO_setNotificationLevel(displayLevel); 603 if (ifnIdx == 0) multiple_inputs = 0; 604 if (mode == om_decompress) { 605 if (multiple_inputs) 606 operationResult = LZ4IO_decompressMultipleFilenames(inFileNames, ifnIdx, !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION); 607 else 608 operationResult = DEFAULT_DECOMPRESSOR(input_filename, output_filename); 609 } else { /* compression is default action */ 610 if (legacy_format) { 611 DISPLAYLEVEL(3, "! Generating compressed LZ4 using Legacy format (deprecated) ! \n"); 612 LZ4IO_compressFilename_Legacy(input_filename, output_filename, cLevel); 613 } else { 614 if (multiple_inputs) 615 operationResult = LZ4IO_compressMultipleFilenames(inFileNames, ifnIdx, LZ4_EXTENSION, cLevel); 616 else 617 operationResult = DEFAULT_COMPRESSOR(input_filename, output_filename, cLevel); 618 } 619 } 620 621 _cleanup: 622 if (main_pause) waitEnter(); 623 if (dynNameSpace) free(dynNameSpace); 624 #ifdef UTIL_HAS_CREATEFILELIST 625 if (extendedFileList) 626 UTIL_freeFileList(extendedFileList, fileNamesBuf); 627 else 628 #endif 629 free((void*)inFileNames); 630 return operationResult; 631 } 632