CMSIS2000  0.0.7
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lz4demo.c
Go to the documentation of this file.
1 /*
2  LZ4Demo - Demo CLI program using LZ4 compression
3  Copyright (C) Yann Collet 2011-2012
4  GPL v2 License
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License along
17  with this program; if not, write to the Free Software Foundation, Inc.,
18  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20  You can contact the author at :
21  - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
22  - LZ4 source repository : http://code.google.com/p/lz4/
23 */
24 /*
25  Note : this is *only* a demo program, an example to show how LZ4 can be used.
26  It is not considered part of LZ4 compression library.
27  The license of LZ4 is BSD.
28  The license of the demo program is GPL.
29 */
30 
31 //**************************************
32 // Compiler Options
33 //**************************************
34 // Disable some Visual warning messages
35 #define _CRT_SECURE_NO_WARNINGS
36 #define _CRT_SECURE_NO_DEPRECATE // VS2005
37 
38 
39 //****************************
40 // Includes
41 //****************************
42 #include <stdio.h> // fprintf, fopen, fread, _fileno(?)
43 #include <stdlib.h> // malloc
44 #include <string.h> // strcmp
45 #include <time.h> // clock
46 #ifdef _WIN32
47 #include <io.h> // _setmode
48 #include <fcntl.h> // _O_BINARY
49 #endif
50 #include "lz4.h"
51 #include "lz4hc.h"
52 #include "bench.h"
53 
54 
55 //**************************************
56 // Compiler-specific functions
57 //**************************************
58 #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
59 
60 #if defined(_MSC_VER) // Visual Studio
61 #define swap32 _byteswap_ulong
62 #elif GCC_VERSION >= 403
63 #define swap32 __builtin_bswap32
64 #else
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 );
70  }
71 #endif
72 
73 
74 //****************************
75 // Constants
76 //****************************
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
83 
84 #define CHUNKSIZE (8<<20) // 8 MB
85 #define CACHELINE 64
86 #define ARCHIVE_MAGICNUMBER 0x184C2102
87 #define ARCHIVE_MAGICNUMBER_SIZE 4
88 
89 
90 //**************************************
91 // Architecture Macros
92 //**************************************
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); }
97 
98 
99 //**************************************
100 // Macros
101 //**************************************
102 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
103 
104 
105 //****************************
106 // Functions
107 //****************************
108 int usage(char* exename)
109 {
110  DISPLAY( "Usage :\n");
111  DISPLAY( " %s [arg] input output\n", exename);
112  DISPLAY( "Arguments :\n");
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");
121  return 0;
122 }
123 
124 
125 int badusage(char* exename)
126 {
127  DISPLAY("Wrong parameters\n");
128  usage(exename);
129  return 0;
130 }
131 
132 
133 
134 int get_fileHandle(char* input_filename, char* output_filename, FILE** pfinput, FILE** pfoutput)
135 {
136  char stdinmark[] = "stdin";
137  char stdoutmark[] = "stdout";
138 
139  if (!strcmp (input_filename, stdinmark)) {
140  DISPLAY( "Using stdin for input\n");
141  *pfinput = stdin;
142 #ifdef _WIN32 // Need to set stdin/stdout to binary mode specifically for windows
143  _setmode( _fileno( stdin ), _O_BINARY );
144 #endif
145  } else {
146  *pfinput = fopen( input_filename, "rb" );
147  }
148 
149  if (!strcmp (output_filename, stdoutmark)) {
150  DISPLAY( "Using stdout for output\n");
151  *pfoutput = stdout;
152 #ifdef _WIN32 // Need to set stdin/stdout to binary mode specifically for windows
153  _setmode( _fileno( stdout ), _O_BINARY );
154 #endif
155  } else {
156  *pfoutput = fopen( output_filename, "wb" );
157  }
158 
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; }
161 
162  return 0;
163 }
164 
165 
166 
167 int compress_file(char* input_filename, char* output_filename, int compressionlevel)
168 {
169  int (*compressionFunction)(const char*, char*, int);
170  unsigned long long filesize = 0;
171  unsigned long long compressedfilesize = ARCHIVE_MAGICNUMBER_SIZE;
172  unsigned int u32var;
173  char* in_buff;
174  char* out_buff;
175  FILE* finput;
176  FILE* foutput;
177  int r;
178  int displayLevel = (compressionlevel>0);
179  clock_t start, end;
180  size_t sizeCheck;
181 
182 
183  // Init
184  switch (compressionlevel)
185  {
186  case 0 : compressionFunction = LZ4_compress; break;
187  case 1 : compressionFunction = LZ4_compressHC; break;
188  default : compressionFunction = LZ4_compress;
189  }
190  start = clock();
191  r = get_fileHandle(input_filename, output_filename, &finput, &foutput);
192  if (r) return r;
193 
194  // Allocate Memory
195  in_buff = (char*)malloc(CHUNKSIZE);
196  out_buff = (char*)malloc(LZ4_compressBound(CHUNKSIZE));
197  if (!in_buff || !out_buff) { DISPLAY("Allocation error : not enough memory\n"); return 8; }
198 
199  // Write Archive Header
200  u32var = ARCHIVE_MAGICNUMBER;
201  LITTLE_ENDIAN32(u32var);
202  *(unsigned int*)out_buff = u32var;
203  sizeCheck = fwrite(out_buff, 1, ARCHIVE_MAGICNUMBER_SIZE, foutput);
204  if (sizeCheck!=ARCHIVE_MAGICNUMBER_SIZE) { DISPLAY("write error\n"); return 10; }
205 
206  // Main Loop
207  while (1)
208  {
209  int outSize;
210  // Read Block
211  int inSize = (int) fread(in_buff, (size_t)1, (size_t)CHUNKSIZE, finput);
212  if( inSize<=0 ) break;
213  filesize += inSize;
214  if (displayLevel) DISPLAY("Read : %i MB \r", (int)(filesize>>20));
215 
216  // Compress Block
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);
220 
221  // Write Block
222  LITTLE_ENDIAN32(outSize);
223  * (unsigned int*) out_buff = outSize;
224  LITTLE_ENDIAN32(outSize);
225  sizeCheck = fwrite(out_buff, 1, outSize+4, foutput);
226  if (sizeCheck!=(size_t)(outSize+4)) { DISPLAY("write error\n"); return 11; }
227  }
228 
229  // Status
230  end = clock();
231  DISPLAY( "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",
232  (unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);
233  {
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);
236  }
237 
238  // Close & Free
239  free(in_buff);
240  free(out_buff);
241  fclose(finput);
242  fclose(foutput);
243 
244  return 0;
245 }
246 
247 
248 int decode_file(char* input_filename, char* output_filename)
249 {
250  unsigned long long filesize = 0;
251  char* in_buff;
252  char* out_buff;
253  size_t uselessRet;
254  int sinkint;
255  unsigned int chunkSize;
256  FILE* finput;
257  FILE* foutput;
258  clock_t start, end;
259  int r;
260  size_t sizeCheck;
261 
262 
263  // Init
264  start = clock();
265  r = get_fileHandle(input_filename, output_filename, &finput, &foutput);
266  if (r) return r;
267 
268  // Allocate Memory
269  in_buff = (char*)malloc(LZ4_compressBound(CHUNKSIZE));
270  out_buff = (char*)malloc(CHUNKSIZE);
271  if (!in_buff || !out_buff) { DISPLAY("Allocation error : not enough memory\n"); return 7; }
272 
273  // Check Archive Header
274  chunkSize = 0;
275  uselessRet = fread(&chunkSize, 1, ARCHIVE_MAGICNUMBER_SIZE, finput);
276  LITTLE_ENDIAN32(chunkSize);
277  if (chunkSize != ARCHIVE_MAGICNUMBER) { DISPLAY("Unrecognized header : file cannot be decoded\n"); return 6; }
278 
279  // Main Loop
280  while (1)
281  {
282  // Block Size
283  uselessRet = fread(&chunkSize, 1, 4, finput);
284  if( uselessRet==0 ) break; // Nothing to read : file read is completed
285  LITTLE_ENDIAN32(chunkSize);
286  if (chunkSize == ARCHIVE_MAGICNUMBER)
287  continue; // appended compressed stream
288 
289  // Read Block
290  uselessRet = fread(in_buff, 1, chunkSize, finput);
291 
292  // Decode Block
293  sinkint = LZ4_uncompress_unknownOutputSize(in_buff, out_buff, chunkSize, CHUNKSIZE);
294  if (sinkint < 0) { DISPLAY("Decoding Failed ! Corrupted input !\n"); return 9; }
295  filesize += sinkint;
296 
297  // Write Block
298  sizeCheck = fwrite(out_buff, 1, sinkint, foutput);
299  if (sizeCheck != (size_t)sinkint) { DISPLAY("write error\n"); return 12; }
300  }
301 
302  // Status
303  end = clock();
304  DISPLAY( "Successfully decoded %llu bytes \n", (unsigned long long)filesize);
305  {
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);
308  }
309 
310  // Close & Free
311  free(in_buff);
312  free(out_buff);
313  fclose(finput);
314  fclose(foutput);
315 
316  return 0;
317 }
318 
319 
320 int main(int argc, char** argv)
321 {
322  int i,
323  cLevel=0,
324  decode=0,
325  bench=0,
326  filenamesStart=2;
327  char* exename=argv[0];
328  char* input_filename=0;
329  char* output_filename=0;
330 #ifdef _WIN32
331  char nulmark[] = "nul";
332 #else
333  char nulmark[] = "/dev/null";
334 #endif
335  char nullinput[] = "null";
336 
337  // Welcome message
339 
340  if (argc<2) { badusage(exename); return 1; }
341 
342  for(i=1; i<argc; i++)
343  {
344  char* argument = argv[i];
345 
346  if(!argument) continue; // Protection if argument empty
347 
348  // Select command
349  if (argument[0]=='-')
350  {
351  argument ++;
352 
353  // Display help on usage
354  if ( argument[0] =='h' ) { usage(exename); return 0; }
355 
356  // Compression (default)
357  if ( argument[0] =='c' ) { if (argument[1] >='0') cLevel=argument[1] - '0'; continue; }
358 
359  // Decoding
360  if ( argument[0] =='d' ) { decode=1; continue; }
361 
362  // Bench
363  if ( argument[0] =='b' ) { bench=1; if (argument[1] >= '0') cLevel=argument[1] - '0'; continue; }
364 
365  // Modify Block Size (benchmark only)
366  if ( argument[0] =='B' ) { int B = argument[1] - '0'; int S = 1 << (10 + 2*B); BMK_SetBlocksize(S); continue; }
367 
368  // Modify Nb Iterations (benchmark only)
369  if ( argument[0] =='i' ) { int iters = argument[1] - '0'; BMK_SetNbIterations(iters); continue; }
370 
371  // Pause at the end (benchmark only)
372  if ( argument[0] =='p' ) { BMK_SetPause(); continue; }
373 
374  // Test
375  if ( argument[0] =='t' ) { decode=1; output_filename=nulmark; continue; }
376  }
377 
378  // first provided filename is input
379  if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }
380 
381  // second provided filename is output
382  if (!output_filename)
383  {
384  output_filename=argument;
385  if (!strcmp (output_filename, nullinput)) output_filename = nulmark;
386  continue;
387  }
388  }
389 
390  // No input filename ==> Error
391  if(!input_filename) { badusage(exename); return 1; }
392 
393  if (bench) return BMK_benchFile(argv+filenamesStart, argc-filenamesStart, cLevel);
394 
395  // No output filename ==> Error
396  if (!output_filename) { badusage(exename); return 1; }
397 
398  if (decode) return decode_file(input_filename, output_filename);
399 
400  return compress_file(input_filename, output_filename, cLevel); // Compression is 'default' action
401 
402 }