Rizin
unix-like reverse engineering framework and cli tools
lz4cli.c
Go to the documentation of this file.
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 /****************************
35 * Includes
36 *****************************/
37 #include "platform.h" /* Compiler options, IS_CONSOLE */
38 #include "util.h" /* UTIL_HAS_CREATEFILELIST, UTIL_createFileList */
39 #include <stdio.h> /* fprintf, getchar */
40 #include <stdlib.h> /* exit, calloc, free */
41 #include <string.h> /* strcmp, strlen */
42 #include "bench.h" /* BMK_benchFile, BMK_SetNbIterations, BMK_SetBlocksize, BMK_SetPause */
43 #include "lz4io.h" /* LZ4IO_compressFilename, LZ4IO_decompressFilename, LZ4IO_compressMultipleFilenames */
44 #include "lz4hc.h" /* LZ4HC_CLEVEL_MAX */
45 #include "lz4.h" /* LZ4_VERSION_STRING */
46 
47 
48 /*****************************
49 * Constants
50 ******************************/
51 #define COMPRESSOR_NAME "LZ4 command line interface"
52 #define AUTHOR "Yann Collet"
53 #define WELCOME_MESSAGE "*** %s %i-bits v%s, by %s ***\n", COMPRESSOR_NAME, (int)(sizeof(void*)*8), LZ4_versionString(), AUTHOR
54 #define LZ4_EXTENSION ".lz4"
55 #define LZ4CAT "lz4cat"
56 #define UNLZ4 "unlz4"
57 #define LZ4_LEGACY "lz4c"
58 static int g_lz4c_legacy_commands = 0;
59 
60 #define KB *(1U<<10)
61 #define MB *(1U<<20)
62 #define GB *(1U<<30)
63 
64 #define LZ4_BLOCKSIZEID_DEFAULT 7
65 
66 
67 /*-************************************
68 * Macros
69 ***************************************/
70 #define DISPLAYOUT(...) fprintf(stdout, __VA_ARGS__)
71 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
72 #define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
73 static unsigned displayLevel = 2; /* 0 : no display ; 1: errors only ; 2 : downgradable normal ; 3 : non-downgradable normal; 4 : + information */
74 
75 
76 /*-************************************
77 * Exceptions
78 ***************************************/
79 #define DEBUG 0
80 #define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);
81 #define EXM_THROW(error, ...) \
82 { \
83  DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \
84  DISPLAYLEVEL(1, "Error %i : ", error); \
85  DISPLAYLEVEL(1, __VA_ARGS__); \
86  DISPLAYLEVEL(1, "\n"); \
87  exit(error); \
88 }
89 
90 
91 /*-************************************
92 * Version modifiers
93 ***************************************/
94 #define DEFAULT_COMPRESSOR LZ4IO_compressFilename
95 #define DEFAULT_DECOMPRESSOR LZ4IO_decompressFilename
96 int LZ4IO_compressFilename_Legacy(const char* input_filename, const char* output_filename, int compressionlevel, const LZ4IO_prefs_t* prefs); /* hidden function */
98  const char** inFileNamesTable, int ifntSize,
99  const char* suffix,
100  int compressionLevel, const LZ4IO_prefs_t* prefs);
101 
102 /*-***************************
103 * Functions
104 *****************************/
105 static int usage(const char* exeName)
106 {
107  DISPLAY( "Usage : \n");
108  DISPLAY( " %s [arg] [input] [output] \n", exeName);
109  DISPLAY( "\n");
110  DISPLAY( "input : a filename \n");
111  DISPLAY( " with no FILE, or when FILE is - or %s, read standard input\n", stdinmark);
112  DISPLAY( "Arguments : \n");
113  DISPLAY( " -1 : Fast compression (default) \n");
114  DISPLAY( " -9 : High compression \n");
115  DISPLAY( " -d : decompression (default for %s extension)\n", LZ4_EXTENSION);
116  DISPLAY( " -z : force compression \n");
117  DISPLAY( " -D FILE: use FILE as dictionary \n");
118  DISPLAY( " -f : overwrite output without prompting \n");
119  DISPLAY( " -k : preserve source files(s) (default) \n");
120  DISPLAY( "--rm : remove source file(s) after successful de/compression \n");
121  DISPLAY( " -h/-H : display help/long help and exit \n");
122  return 0;
123 }
124 
125 static int usage_advanced(const char* exeName)
126 {
128  usage(exeName);
129  DISPLAY( "\n");
130  DISPLAY( "Advanced arguments :\n");
131  DISPLAY( " -V : display Version number and exit \n");
132  DISPLAY( " -v : verbose mode \n");
133  DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n");
134  DISPLAY( " -c : force write to standard output, even if it is the console\n");
135  DISPLAY( " -t : test compressed file integrity\n");
136  DISPLAY( " -m : multiple input files (implies automatic output filenames)\n");
137 #ifdef UTIL_HAS_CREATEFILELIST
138  DISPLAY( " -r : operate recursively on directories (sets also -m) \n");
139 #endif
140  DISPLAY( " -l : compress using Legacy format (Linux kernel compression)\n");
141  DISPLAY( " -B# : cut file into blocks of size # bytes [32+] \n");
142  DISPLAY( " or predefined block size [4-7] (default: 7) \n");
143  DISPLAY( " -BI : Block Independence (default) \n");
144  DISPLAY( " -BD : Block dependency (improves compression ratio) \n");
145  DISPLAY( " -BX : enable block checksum (default:disabled) \n");
146  DISPLAY( "--no-frame-crc : disable stream checksum (default:enabled) \n");
147  DISPLAY( "--content-size : compressed frame includes original size (default:not present)\n");
148  DISPLAY( "--list FILE : lists information about .lz4 files (useful for files compressed with --content-size flag)\n");
149  DISPLAY( "--[no-]sparse : sparse mode (default:enabled on file, disabled on stdout)\n");
150  DISPLAY( "--favor-decSpeed: compressed files decompress faster, but are less compressed \n");
151  DISPLAY( "--fast[=#]: switch to ultra fast compression level (default: %i)\n", 1);
152  DISPLAY( "--best : same as -%d\n", LZ4HC_CLEVEL_MAX);
153  DISPLAY( "Benchmark arguments : \n");
154  DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n");
155  DISPLAY( " -e# : test all compression levels from -bX to # (default : 1)\n");
156  DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s) \n");
158  DISPLAY( "Legacy arguments : \n");
159  DISPLAY( " -c0 : fast compression \n");
160  DISPLAY( " -c1 : high compression \n");
161  DISPLAY( " -c2,-hc: very high compression \n");
162  DISPLAY( " -y : overwrite output without prompting \n");
163  }
164  return 0;
165 }
166 
167 static int usage_longhelp(const char* exeName)
168 {
169  usage_advanced(exeName);
170  DISPLAY( "\n");
171  DISPLAY( "****************************\n");
172  DISPLAY( "***** Advanced comment *****\n");
173  DISPLAY( "****************************\n");
174  DISPLAY( "\n");
175  DISPLAY( "Which values can [output] have ? \n");
176  DISPLAY( "---------------------------------\n");
177  DISPLAY( "[output] : a filename \n");
178  DISPLAY( " '%s', or '-' for standard output (pipe mode)\n", stdoutmark);
179  DISPLAY( " '%s' to discard output (test mode) \n", NULL_OUTPUT);
180  DISPLAY( "[output] can be left empty. In this case, it receives the following value :\n");
181  DISPLAY( " - if stdout is not the console, then [output] = stdout \n");
182  DISPLAY( " - if stdout is console : \n");
183  DISPLAY( " + for compression, output to filename%s \n", LZ4_EXTENSION);
184  DISPLAY( " + for decompression, output to filename without '%s'\n", LZ4_EXTENSION);
185  DISPLAY( " > if input filename has no '%s' extension : error \n", LZ4_EXTENSION);
186  DISPLAY( "\n");
187  DISPLAY( "Compression levels : \n");
188  DISPLAY( "---------------------\n");
189  DISPLAY( "-0 ... -2 => Fast compression, all identicals\n");
190  DISPLAY( "-3 ... -%d => High compression; higher number == more compression but slower\n", LZ4HC_CLEVEL_MAX);
191  DISPLAY( "\n");
192  DISPLAY( "stdin, stdout and the console : \n");
193  DISPLAY( "--------------------------------\n");
194  DISPLAY( "To protect the console from binary flooding (bad argument mistake)\n");
195  DISPLAY( "%s will refuse to read from console, or write to console \n", exeName);
196  DISPLAY( "except if '-c' command is specified, to force output to console \n");
197  DISPLAY( "\n");
198  DISPLAY( "Simple example :\n");
199  DISPLAY( "----------------\n");
200  DISPLAY( "1 : compress 'filename' fast, using default output name 'filename.lz4'\n");
201  DISPLAY( " %s filename\n", exeName);
202  DISPLAY( "\n");
203  DISPLAY( "Short arguments can be aggregated. For example :\n");
204  DISPLAY( "----------------------------------\n");
205  DISPLAY( "2 : compress 'filename' in high compression mode, overwrite output if exists\n");
206  DISPLAY( " %s -9 -f filename \n", exeName);
207  DISPLAY( " is equivalent to :\n");
208  DISPLAY( " %s -9f filename \n", exeName);
209  DISPLAY( "\n");
210  DISPLAY( "%s can be used in 'pure pipe mode'. For example :\n", exeName);
211  DISPLAY( "-------------------------------------\n");
212  DISPLAY( "3 : compress data stream from 'generator', send result to 'consumer'\n");
213  DISPLAY( " generator | %s | consumer \n", exeName);
215  DISPLAY( "\n");
216  DISPLAY( "***** Warning ***** \n");
217  DISPLAY( "Legacy arguments take precedence. Therefore : \n");
218  DISPLAY( "--------------------------------- \n");
219  DISPLAY( " %s -hc filename \n", exeName);
220  DISPLAY( "means 'compress filename in high compression mode' \n");
221  DISPLAY( "It is not equivalent to : \n");
222  DISPLAY( " %s -h -c filename \n", exeName);
223  DISPLAY( "which displays help text and exits \n");
224  }
225  return 0;
226 }
227 
228 static int badusage(const char* exeName)
229 {
230  DISPLAYLEVEL(1, "Incorrect parameters\n");
231  if (displayLevel >= 1) usage(exeName);
232  exit(1);
233 }
234 
235 
236 static void waitEnter(void)
237 {
238  DISPLAY("Press enter to continue...\n");
239  (void)getchar();
240 }
241 
242 static const char* lastNameFromPath(const char* path)
243 {
244  const char* name = path;
245  if (strrchr(name, '/')) name = strrchr(name, '/') + 1;
246  if (strrchr(name, '\\')) name = strrchr(name, '\\') + 1; /* windows */
247  return name;
248 }
249 
253 static int exeNameMatch(const char* exeName, const char* test)
254 {
255  return !strncmp(exeName, test, strlen(test)) &&
256  (exeName[strlen(test)] == '\0' || exeName[strlen(test)] == '.');
257 }
258 
264 static unsigned readU32FromChar(const char** stringPtr)
265 {
266  unsigned result = 0;
267  while ((**stringPtr >='0') && (**stringPtr <='9')) {
268  result *= 10;
269  result += (unsigned)(**stringPtr - '0');
270  (*stringPtr)++ ;
271  }
272  if ((**stringPtr=='K') || (**stringPtr=='M')) {
273  result <<= 10;
274  if (**stringPtr=='M') result <<= 10;
275  (*stringPtr)++ ;
276  if (**stringPtr=='i') (*stringPtr)++;
277  if (**stringPtr=='B') (*stringPtr)++;
278  }
279  return result;
280 }
281 
287 static int longCommandWArg(const char** stringPtr, const char* longCommand)
288 {
289  size_t const comSize = strlen(longCommand);
290  int const result = !strncmp(*stringPtr, longCommand, comSize);
291  if (result) *stringPtr += comSize;
292  return result;
293 }
294 
296 
301 static operationMode_e determineOpMode(const char* inputFilename)
302 {
303  size_t const inSize = strlen(inputFilename);
304  size_t const extSize = strlen(LZ4_EXTENSION);
305  size_t const extStart= (inSize > extSize) ? inSize-extSize : 0;
306  if (!strcmp(inputFilename+extStart, LZ4_EXTENSION)) return om_decompress;
307  else return om_compress;
308 }
309 
310 int main(int argc, const char** argv)
311 {
312  int i,
313  cLevel=1,
314  cLevelLast=-10000,
315  legacy_format=0,
316  forceStdout=0,
317  main_pause=0,
318  multiple_inputs=0,
319  all_arguments_are_files=0,
320  operationResult=0;
322  const char* input_filename = NULL;
323  const char* output_filename= NULL;
324  const char* dictionary_filename = NULL;
325  char* dynNameSpace = NULL;
326  const char** inFileNames = (const char**)calloc((size_t)argc, sizeof(char*));
327  unsigned ifnIdx=0;
328  LZ4IO_prefs_t* const prefs = LZ4IO_defaultPreferences();
329  const char nullOutput[] = NULL_OUTPUT;
330  const char extension[] = LZ4_EXTENSION;
331  size_t blockSize = LZ4IO_setBlockSizeID(prefs, LZ4_BLOCKSIZEID_DEFAULT);
332  const char* const exeName = lastNameFromPath(argv[0]);
333 #ifdef UTIL_HAS_CREATEFILELIST
334  const char** extendedFileList = NULL;
335  char* fileNamesBuf = NULL;
336  unsigned fileNamesNb, recursive=0;
337 #endif
338 
339  /* Init */
340  if (inFileNames==NULL) {
341  DISPLAY("Allocation error : not enough memory \n");
342  return 1;
343  }
344  inFileNames[0] = stdinmark;
345  LZ4IO_setOverwrite(prefs, 0);
346 
347  /* predefined behaviors, based on binary/link name */
348  if (exeNameMatch(exeName, LZ4CAT)) {
350  LZ4IO_setOverwrite(prefs, 1);
351  LZ4IO_setPassThrough(prefs, 1);
352  LZ4IO_setRemoveSrcFile(prefs, 0);
353  forceStdout=1;
354  output_filename=stdoutmark;
355  displayLevel=1;
356  multiple_inputs=1;
357  }
358  if (exeNameMatch(exeName, UNLZ4)) { mode = om_decompress; }
359  if (exeNameMatch(exeName, LZ4_LEGACY)) { g_lz4c_legacy_commands=1; }
360 
361  /* command switches */
362  for(i=1; i<argc; i++) {
363  const char* argument = argv[i];
364 
365  if(!argument) continue; /* Protection if argument empty */
366 
367  /* Short commands (note : aggregated short commands are allowed) */
368  if (!all_arguments_are_files && argument[0]=='-') {
369  /* '-' means stdin/stdout */
370  if (argument[1]==0) {
371  if (!input_filename) input_filename=stdinmark;
372  else output_filename=stdoutmark;
373  continue;
374  }
375 
376  /* long commands (--long-word) */
377  if (argument[1]=='-') {
378  if (!strcmp(argument, "--")) { all_arguments_are_files = 1; continue; }
379  if (!strcmp(argument, "--compress")) { mode = om_compress; continue; }
380  if ((!strcmp(argument, "--decompress"))
381  || (!strcmp(argument, "--uncompress"))) { mode = om_decompress; continue; }
382  if (!strcmp(argument, "--multiple")) { multiple_inputs = 1; continue; }
383  if (!strcmp(argument, "--test")) { mode = om_test; continue; }
384  if (!strcmp(argument, "--force")) { LZ4IO_setOverwrite(prefs, 1); continue; }
385  if (!strcmp(argument, "--no-force")) { LZ4IO_setOverwrite(prefs, 0); continue; }
386  if ((!strcmp(argument, "--stdout"))
387  || (!strcmp(argument, "--to-stdout"))) { forceStdout=1; output_filename=stdoutmark; continue; }
388  if (!strcmp(argument, "--frame-crc")) { LZ4IO_setStreamChecksumMode(prefs, 1); continue; }
389  if (!strcmp(argument, "--no-frame-crc")) { LZ4IO_setStreamChecksumMode(prefs, 0); continue; }
390  if (!strcmp(argument, "--content-size")) { LZ4IO_setContentSize(prefs, 1); continue; }
391  if (!strcmp(argument, "--no-content-size")) { LZ4IO_setContentSize(prefs, 0); continue; }
392  if (!strcmp(argument, "--list")) { mode = om_list; continue; }
393  if (!strcmp(argument, "--sparse")) { LZ4IO_setSparseFile(prefs, 2); continue; }
394  if (!strcmp(argument, "--no-sparse")) { LZ4IO_setSparseFile(prefs, 0); continue; }
395  if (!strcmp(argument, "--favor-decSpeed")) { LZ4IO_favorDecSpeed(prefs, 1); continue; }
396  if (!strcmp(argument, "--verbose")) { displayLevel++; continue; }
397  if (!strcmp(argument, "--quiet")) { if (displayLevel) displayLevel--; continue; }
398  if (!strcmp(argument, "--version")) { DISPLAYOUT(WELCOME_MESSAGE); goto _cleanup; }
399  if (!strcmp(argument, "--help")) { usage_advanced(exeName); goto _cleanup; }
400  if (!strcmp(argument, "--keep")) { LZ4IO_setRemoveSrcFile(prefs, 0); continue; } /* keep source file (default) */
401  if (!strcmp(argument, "--rm")) { LZ4IO_setRemoveSrcFile(prefs, 1); continue; }
402  if (longCommandWArg(&argument, "--fast")) {
403  /* Parse optional acceleration factor */
404  if (*argument == '=') {
405  U32 fastLevel;
406  ++argument;
407  fastLevel = readU32FromChar(&argument);
408  if (fastLevel) {
409  cLevel = -(int)fastLevel;
410  } else {
411  badusage(exeName);
412  }
413  } else if (*argument != 0) {
414  /* Invalid character following --fast */
415  badusage(exeName);
416  } else {
417  cLevel = -1; /* default for --fast */
418  }
419  continue;
420  }
421 
422  /* For gzip(1) compatibility */
423  if (!strcmp(argument, "--best")) { cLevel=LZ4HC_CLEVEL_MAX; continue; }
424  }
425 
426  while (argument[1]!=0) {
427  argument ++;
428 
430  /* Legacy commands (-c0, -c1, -hc, -y) */
431  if (!strcmp(argument, "c0")) { cLevel=0; argument++; continue; } /* -c0 (fast compression) */
432  if (!strcmp(argument, "c1")) { cLevel=9; argument++; continue; } /* -c1 (high compression) */
433  if (!strcmp(argument, "c2")) { cLevel=12; argument++; continue; } /* -c2 (very high compression) */
434  if (!strcmp(argument, "hc")) { cLevel=12; argument++; continue; } /* -hc (very high compression) */
435  if (!strcmp(argument, "y")) { LZ4IO_setOverwrite(prefs, 1); continue; } /* -y (answer 'yes' to overwrite permission) */
436  }
437 
438  if ((*argument>='0') && (*argument<='9')) {
439  cLevel = (int)readU32FromChar(&argument);
440  argument--;
441  continue;
442  }
443 
444 
445  switch(argument[0])
446  {
447  /* Display help */
448  case 'V': DISPLAYOUT(WELCOME_MESSAGE); goto _cleanup; /* Version */
449  case 'h': usage_advanced(exeName); goto _cleanup;
450  case 'H': usage_longhelp(exeName); goto _cleanup;
451 
452  case 'e':
453  argument++;
454  cLevelLast = (int)readU32FromChar(&argument);
455  argument--;
456  break;
457 
458  /* Compression (default) */
459  case 'z': mode = om_compress; break;
460 
461  case 'D':
462  if (argument[1] == '\0') {
463  /* path is next arg */
464  if (i + 1 == argc) {
465  /* there is no next arg */
466  badusage(exeName);
467  }
468  dictionary_filename = argv[++i];
469  } else {
470  /* path follows immediately */
471  dictionary_filename = argument + 1;
472  }
473  /* skip to end of argument so that we jump to parsing next argument */
474  argument += strlen(argument) - 1;
475  break;
476 
477  /* Use Legacy format (ex : Linux kernel compression) */
478  case 'l': legacy_format = 1; blockSize = 8 MB; break;
479 
480  /* Decoding */
481  case 'd': mode = om_decompress; break;
482 
483  /* Force stdout, even if stdout==console */
484  case 'c':
485  forceStdout=1;
486  output_filename=stdoutmark;
487  LZ4IO_setPassThrough(prefs, 1);
488  break;
489 
490  /* Test integrity */
491  case 't': mode = om_test; break;
492 
493  /* Overwrite */
494  case 'f': LZ4IO_setOverwrite(prefs, 1); break;
495 
496  /* Verbose mode */
497  case 'v': displayLevel++; break;
498 
499  /* Quiet mode */
500  case 'q': if (displayLevel) displayLevel--; break;
501 
502  /* keep source file (default anyway, so useless) (for xz/lzma compatibility) */
503  case 'k': LZ4IO_setRemoveSrcFile(prefs, 0); break;
504 
505  /* Modify Block Properties */
506  case 'B':
507  while (argument[1]!=0) {
508  int exitBlockProperties=0;
509  switch(argument[1])
510  {
511  case 'D': LZ4IO_setBlockMode(prefs, LZ4IO_blockLinked); argument++; break;
512  case 'I': LZ4IO_setBlockMode(prefs, LZ4IO_blockIndependent); argument++; break;
513  case 'X': LZ4IO_setBlockChecksumMode(prefs, 1); argument ++; break; /* disabled by default */
514  default :
515  if (argument[1] < '0' || argument[1] > '9') {
516  exitBlockProperties=1;
517  break;
518  } else {
519  unsigned B;
520  argument++;
521  B = readU32FromChar(&argument);
522  argument--;
523  if (B < 4) badusage(exeName);
524  if (B <= 7) {
525  blockSize = LZ4IO_setBlockSizeID(prefs, B);
526  BMK_setBlockSize(blockSize);
527  DISPLAYLEVEL(2, "using blocks of size %u KB \n", (U32)(blockSize>>10));
528  } else {
529  if (B < 32) badusage(exeName);
530  blockSize = LZ4IO_setBlockSize(prefs, B);
531  BMK_setBlockSize(blockSize);
532  if (blockSize >= 1024) {
533  DISPLAYLEVEL(2, "using blocks of size %u KB \n", (U32)(blockSize>>10));
534  } else {
535  DISPLAYLEVEL(2, "using blocks of size %u bytes \n", (U32)(blockSize));
536  }
537  }
538  break;
539  }
540  }
541  if (exitBlockProperties) break;
542  }
543  break;
544 
545  /* Benchmark */
546  case 'b': mode = om_bench; multiple_inputs=1;
547  break;
548 
549  /* hidden command : benchmark files, but do not fuse result */
550  case 'S': BMK_setBenchSeparately(1);
551  break;
552 
553 #ifdef UTIL_HAS_CREATEFILELIST
554  /* recursive */
555  case 'r': recursive=1;
556 #endif
557  /* fall-through */
558  /* Treat non-option args as input files. See https://code.google.com/p/lz4/issues/detail?id=151 */
559  case 'm': multiple_inputs=1;
560  break;
561 
562  /* Modify Nb Seconds (benchmark only) */
563  case 'i':
564  { unsigned iters;
565  argument++;
566  iters = readU32FromChar(&argument);
567  argument--;
569  BMK_setNbSeconds(iters); /* notification if displayLevel >= 3 */
570  }
571  break;
572 
573  /* Pause at the end (hidden option) */
574  case 'p': main_pause=1; break;
575 
576  /* Unrecognised command */
577  default : badusage(exeName);
578  }
579  }
580  continue;
581  }
582 
583  /* Store in *inFileNames[] if -m is used. */
584  if (multiple_inputs) { inFileNames[ifnIdx++]=argument; continue; }
585 
586  /* Store first non-option arg in input_filename to preserve original cli logic. */
587  if (!input_filename) { input_filename=argument; continue; }
588 
589  /* Second non-option arg in output_filename to preserve original cli logic. */
590  if (!output_filename) {
591  output_filename=argument;
592  if (!strcmp (output_filename, nullOutput)) output_filename = nulmark;
593  continue;
594  }
595 
596  /* 3rd non-option arg should not exist */
597  DISPLAYLEVEL(1, "Warning : %s won't be used ! Do you want multiple input files (-m) ? \n", argument);
598  }
599 
601 #ifdef _POSIX_C_SOURCE
602  DISPLAYLEVEL(4, "_POSIX_C_SOURCE defined: %ldL\n", (long) _POSIX_C_SOURCE);
603 #endif
604 #ifdef _POSIX_VERSION
605  DISPLAYLEVEL(4, "_POSIX_VERSION defined: %ldL\n", (long) _POSIX_VERSION);
606 #endif
607 #ifdef PLATFORM_POSIX_VERSION
608  DISPLAYLEVEL(4, "PLATFORM_POSIX_VERSION defined: %ldL\n", (long) PLATFORM_POSIX_VERSION);
609 #endif
610 #ifdef _FILE_OFFSET_BITS
611  DISPLAYLEVEL(4, "_FILE_OFFSET_BITS defined: %ldL\n", (long) _FILE_OFFSET_BITS);
612 #endif
613  if ((mode == om_compress) || (mode == om_bench))
614  DISPLAYLEVEL(4, "Blocks size : %u KB\n", (U32)(blockSize>>10));
615 
616  if (multiple_inputs) {
617  input_filename = inFileNames[0];
618 #ifdef UTIL_HAS_CREATEFILELIST
619  if (recursive) { /* at this stage, filenameTable is a list of paths, which can contain both files and directories */
620  extendedFileList = UTIL_createFileList(inFileNames, ifnIdx, &fileNamesBuf, &fileNamesNb);
621  if (extendedFileList) {
622  unsigned u;
623  for (u=0; u<fileNamesNb; u++) DISPLAYLEVEL(4, "%u %s\n", u, extendedFileList[u]);
624  free((void*)inFileNames);
625  inFileNames = extendedFileList;
626  ifnIdx = fileNamesNb;
627  } }
628 #endif
629  }
630 
631  if (dictionary_filename) {
632  if (!strcmp(dictionary_filename, stdinmark) && IS_CONSOLE(stdin)) {
633  DISPLAYLEVEL(1, "refusing to read from a console\n");
634  exit(1);
635  }
636  LZ4IO_setDictionaryFilename(prefs, dictionary_filename);
637  }
638 
639  /* benchmark and test modes */
640  if (mode == om_bench) {
642  operationResult = BMK_benchFiles(inFileNames, ifnIdx, cLevel, cLevelLast, dictionary_filename);
643  goto _cleanup;
644  }
645 
646  if (mode == om_test) {
647  LZ4IO_setTestMode(prefs, 1);
648  output_filename = nulmark;
649  mode = om_decompress; /* defer to decompress */
650  }
651 
652  /* compress or decompress */
653  if (!input_filename) input_filename = stdinmark;
654  /* Check if input is defined as console; trigger an error in this case */
655  if (!strcmp(input_filename, stdinmark) && IS_CONSOLE(stdin) ) {
656  DISPLAYLEVEL(1, "refusing to read from a console\n");
657  exit(1);
658  }
659  if (!strcmp(input_filename, stdinmark)) {
660  /* if input==stdin and no output defined, stdout becomes default output */
661  if (!output_filename) output_filename = stdoutmark;
662  }
663  else{
664 #ifdef UTIL_HAS_CREATEFILELIST
665  if (!recursive && !UTIL_isRegFile(input_filename)) {
666 #else
667  if (!UTIL_isRegFile(input_filename)) {
668 #endif
669  DISPLAYLEVEL(1, "%s: is not a regular file \n", input_filename);
670  exit(1);
671  }
672  }
673 
674  /* No output filename ==> try to select one automatically (when possible) */
675  while ((!output_filename) && (multiple_inputs==0)) {
676  if (!IS_CONSOLE(stdout) && mode != om_list) {
677  /* Default to stdout whenever stdout is not the console.
678  * Note : this policy may change in the future, therefore don't rely on it !
679  * To ensure `stdout` is explicitly selected, use `-c` command flag.
680  * Conversely, to ensure output will not become `stdout`, use `-m` command flag */
681  DISPLAYLEVEL(1, "Warning : using stdout as default output. Do not rely on this behavior: use explicit `-c` instead ! \n");
682  output_filename=stdoutmark;
683  break;
684  }
685  if (mode == om_auto) { /* auto-determine compression or decompression, based on file extension */
686  mode = determineOpMode(input_filename);
687  }
688  if (mode == om_compress) { /* compression to file */
689  size_t const l = strlen(input_filename);
690  dynNameSpace = (char*)calloc(1,l+5);
691  if (dynNameSpace==NULL) { perror(exeName); exit(1); }
692  strcpy(dynNameSpace, input_filename);
693  strcat(dynNameSpace, LZ4_EXTENSION);
694  output_filename = dynNameSpace;
695  DISPLAYLEVEL(2, "Compressed filename will be : %s \n", output_filename);
696  break;
697  }
698  if (mode == om_decompress) {/* decompression to file (automatic name will work only if input filename has correct format extension) */
699  size_t outl;
700  size_t const inl = strlen(input_filename);
701  dynNameSpace = (char*)calloc(1,inl+1);
702  if (dynNameSpace==NULL) { perror(exeName); exit(1); }
703  strcpy(dynNameSpace, input_filename);
704  outl = inl;
705  if (inl>4)
706  while ((outl >= inl-4) && (input_filename[outl] == extension[outl-inl+4])) dynNameSpace[outl--]=0;
707  if (outl != inl-5) { DISPLAYLEVEL(1, "Cannot determine an output filename\n"); badusage(exeName); }
708  output_filename = dynNameSpace;
709  DISPLAYLEVEL(2, "Decoding file %s \n", output_filename);
710  }
711  break;
712  }
713 
714  if (mode == om_list){
715  /* Exit if trying to read from stdin as this isn't supported in this mode */
716  if(!strcmp(input_filename, stdinmark)){
717  DISPLAYLEVEL(1, "refusing to read from standard input in --list mode\n");
718  exit(1);
719  }
720  if(!multiple_inputs){
721  inFileNames[ifnIdx++] = input_filename;
722  }
723  }
724  else{
725  if (multiple_inputs==0) assert(output_filename);
726  }
727  /* when multiple_inputs==1, output_filename may simply be useless,
728  * however, output_filename must be !NULL for next strcmp() tests */
729  if (!output_filename) output_filename = "*\\dummy^!//";
730 
731  /* Check if output is defined as console; trigger an error in this case */
732  if (!strcmp(output_filename,stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) {
733  DISPLAYLEVEL(1, "refusing to write to console without -c \n");
734  exit(1);
735  }
736  /* Downgrade notification level in stdout and multiple file mode */
737  if (!strcmp(output_filename,stdoutmark) && (displayLevel==2)) displayLevel=1;
738  if ((multiple_inputs) && (displayLevel==2)) displayLevel=1;
739 
740  /* Auto-determine compression or decompression, based on file extension */
741  if (mode == om_auto) {
742  mode = determineOpMode(input_filename);
743  }
744 
745  /* IO Stream/File */
747  if (ifnIdx == 0) multiple_inputs = 0;
748  if (mode == om_decompress) {
749  if (multiple_inputs) {
750  const char* const dec_extension = !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION;
751  assert(ifnIdx <= INT_MAX);
752  operationResult = LZ4IO_decompressMultipleFilenames(inFileNames, (int)ifnIdx, dec_extension, prefs);
753  } else {
754  operationResult = DEFAULT_DECOMPRESSOR(input_filename, output_filename, prefs);
755  }
756  } else if (mode == om_list){
757  operationResult = LZ4IO_displayCompressedFilesInfo(inFileNames, ifnIdx);
758  } else { /* compression is default action */
759  if (legacy_format) {
760  DISPLAYLEVEL(3, "! Generating LZ4 Legacy format (deprecated) ! \n");
761  if(multiple_inputs){
762  const char* const leg_extension = !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION;
763  LZ4IO_compressMultipleFilenames_Legacy(inFileNames, (int)ifnIdx, leg_extension, cLevel, prefs);
764  } else {
765  LZ4IO_compressFilename_Legacy(input_filename, output_filename, cLevel, prefs);
766  }
767  } else {
768  if (multiple_inputs) {
769  const char* const comp_extension = !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION;
770  assert(ifnIdx <= INT_MAX);
771  operationResult = LZ4IO_compressMultipleFilenames(inFileNames, (int)ifnIdx, comp_extension, cLevel, prefs);
772  } else {
773  operationResult = DEFAULT_COMPRESSOR(input_filename, output_filename, cLevel, prefs);
774  } } }
775 
776 _cleanup:
777  if (main_pause) waitEnter();
778  free(dynNameSpace);
779 #ifdef UTIL_HAS_CREATEFILELIST
780  if (extendedFileList) {
781  UTIL_freeFileList(extendedFileList, fileNamesBuf);
782  inFileNames = NULL;
783  }
784 #endif
785  LZ4IO_freePreferences(prefs);
786  free((void*)inFileNames);
787  return operationResult;
788 }
lzma_index ** i
Definition: index.h:629
#define B(x)
Definition: arc.h:166
int BMK_benchFiles(const char **fileNamesTable, unsigned nbFiles, int cLevel, int cLevelLast, const char *dictFileName)
Definition: bench.c:697
void BMK_setBlockSize(size_t blockSize)
Definition: bench.c:298
void BMK_setBenchSeparately(int separate)
Definition: bench.c:300
void BMK_setNotificationLevel(unsigned level)
Definition: bench.c:288
void BMK_setNbSeconds(unsigned nbSeconds)
Definition: bench.c:292
#define _POSIX_C_SOURCE
#define INT_MAX
Definition: cp-demangle.c:131
#define NULL
Definition: cris-opc.c:27
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
unsigned char suffix[65536]
Definition: gun.c:164
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
const char int mode
Definition: ioapi.h:137
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
static void struct sockaddr socklen_t static fromlen static backlog static fork char char char static envp int struct rusage static rusage struct utsname static buf struct sembuf unsigned
Definition: sflib.h:97
#define IS_CONSOLE(stdStream)
Definition: platform.h:125
#define PLATFORM_POSIX_VERSION
Definition: platform.h:102
UTIL_STATIC int UTIL_isRegFile(const char *infilename)
Definition: util.h:368
UTIL_STATIC void UTIL_freeFileList(const char **filenameTable, char *allocatedBuffer)
Definition: util.h:639
UTIL_STATIC const char ** UTIL_createFileList(const char **inputNames, unsigned inputNamesNb, char **allocatedBuffer, unsigned *allocatedNamesNb)
Definition: util.h:584
unsigned int U32
Definition: lz4.c:288
#define LZ4_BLOCKSIZEID_DEFAULT
Definition: lz4cli.c:64
#define LZ4_EXTENSION
Definition: lz4cli.c:54
int main(int argc, const char **argv)
Definition: lz4cli.c:310
int LZ4IO_compressMultipleFilenames_Legacy(const char **inFileNamesTable, int ifntSize, const char *suffix, int compressionLevel, const LZ4IO_prefs_t *prefs)
Definition: lz4io.c:485
static int usage_longhelp(const char *exeName)
Definition: lz4cli.c:167
#define UNLZ4
Definition: lz4cli.c:56
#define WELCOME_MESSAGE
Definition: lz4cli.c:53
static int longCommandWArg(const char **stringPtr, const char *longCommand)
Definition: lz4cli.c:287
static operationMode_e determineOpMode(const char *inputFilename)
Definition: lz4cli.c:301
#define LZ4_LEGACY
Definition: lz4cli.c:57
static const char * lastNameFromPath(const char *path)
Definition: lz4cli.c:242
#define DISPLAY(...)
Definition: lz4cli.c:71
static int exeNameMatch(const char *exeName, const char *test)
Definition: lz4cli.c:253
static unsigned displayLevel
Definition: lz4cli.c:73
#define DISPLAYOUT(...)
Definition: lz4cli.c:70
static int badusage(const char *exeName)
Definition: lz4cli.c:228
#define DISPLAYLEVEL(l,...)
Definition: lz4cli.c:72
static int usage_advanced(const char *exeName)
Definition: lz4cli.c:125
#define DEFAULT_DECOMPRESSOR
Definition: lz4cli.c:95
static int g_lz4c_legacy_commands
Definition: lz4cli.c:58
#define MB
Definition: lz4cli.c:61
int LZ4IO_compressFilename_Legacy(const char *input_filename, const char *output_filename, int compressionlevel, const LZ4IO_prefs_t *prefs)
Definition: lz4io.c:399
static unsigned readU32FromChar(const char **stringPtr)
Definition: lz4cli.c:264
#define LZ4CAT
Definition: lz4cli.c:55
static void waitEnter(void)
Definition: lz4cli.c:236
#define DEFAULT_COMPRESSOR
Definition: lz4cli.c:94
static int usage(const char *exeName)
Definition: lz4cli.c:105
operationMode_e
Definition: lz4cli.c:295
@ om_auto
Definition: lz4cli.c:295
@ om_test
Definition: lz4cli.c:295
@ om_compress
Definition: lz4cli.c:295
@ om_bench
Definition: lz4cli.c:295
@ om_decompress
Definition: lz4cli.c:295
@ om_list
Definition: lz4cli.c:295
#define LZ4HC_CLEVEL_MAX
Definition: lz4hc.h:50
char int int compressionLevel
Definition: lz4hc.h:258
int LZ4IO_setPassThrough(LZ4IO_prefs_t *const prefs, int yes)
Definition: lz4io.c:195
int LZ4IO_displayCompressedFilesInfo(const char **inFileNames, size_t ifnIdx)
Definition: lz4io.c:1630
int LZ4IO_setDictionaryFilename(LZ4IO_prefs_t *const prefs, const char *dictionaryFilename)
Definition: lz4io.c:187
int LZ4IO_setBlockMode(LZ4IO_prefs_t *const prefs, LZ4IO_blockMode_t blockMode)
Definition: lz4io.c:246
void LZ4IO_favorDecSpeed(LZ4IO_prefs_t *const prefs, int favor)
Definition: lz4io.c:288
int LZ4IO_setStreamChecksumMode(LZ4IO_prefs_t *const prefs, int enable)
Definition: lz4io.c:260
size_t LZ4IO_setBlockSize(LZ4IO_prefs_t *const prefs, size_t blockSize)
Definition: lz4io.c:228
int LZ4IO_setOverwrite(LZ4IO_prefs_t *const prefs, int yes)
Definition: lz4io.c:203
int LZ4IO_compressMultipleFilenames(const char **inFileNamesTable, int ifntSize, const char *suffix, int compressionLevel, const LZ4IO_prefs_t *prefs)
Definition: lz4io.c:798
size_t LZ4IO_setBlockSizeID(LZ4IO_prefs_t *const prefs, unsigned bsid)
Definition: lz4io.c:217
int LZ4IO_setSparseFile(LZ4IO_prefs_t *const prefs, int enable)
Definition: lz4io.c:274
int LZ4IO_setBlockChecksumMode(LZ4IO_prefs_t *const prefs, int enable)
Definition: lz4io.c:253
void LZ4IO_setRemoveSrcFile(LZ4IO_prefs_t *const prefs, unsigned flag)
Definition: lz4io.c:293
LZ4IO_prefs_t * LZ4IO_defaultPreferences(void)
Definition: lz4io.c:160
int LZ4IO_setTestMode(LZ4IO_prefs_t *const prefs, int yes)
Definition: lz4io.c:210
void LZ4IO_freePreferences(LZ4IO_prefs_t *prefs)
Definition: lz4io.c:181
int LZ4IO_decompressMultipleFilenames(const char **inFileNamesTable, int ifntSize, const char *suffix, const LZ4IO_prefs_t *prefs)
Definition: lz4io.c:1308
int LZ4IO_setNotificationLevel(int level)
Definition: lz4io.c:267
int LZ4IO_setContentSize(LZ4IO_prefs_t *const prefs, int enable)
Definition: lz4io.c:281
#define stdoutmark
Definition: lz4io.h:43
#define stdinmark
Definition: lz4io.h:42
@ LZ4IO_blockLinked
Definition: lz4io.h:103
@ LZ4IO_blockIndependent
Definition: lz4io.h:103
#define NULL_OUTPUT
Definition: lz4io.h:44
#define nulmark
Definition: lz4io.h:48
assert(limit<=UINT32_MAX/2)
-lz4-versions
const char * name
Definition: op.c:541
#define _FILE_OFFSET_BITS
Definition: rz_types.h:5
static int
Definition: sfsocketcall.h:114
Definition: z80asm.h:102
Miscellaneous utility functions.