Updates to Tomato RAF including NGINX && PHP
[tomato.git] / release / src / router / lzo / lzotest / lzotest.c
blob3a9874e7e92937912651f379ad822cdc6a4ba13e
1 /* lzotest.c -- very comprehensive test driver for the LZO library
3 This file is part of the LZO real-time data compression library.
5 Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
6 Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
7 Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
8 Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
9 Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
10 Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
11 Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
12 Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
13 Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
14 Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
15 Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
16 Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
17 Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
18 Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
19 Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
20 Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
21 All Rights Reserved.
23 The LZO library is free software; you can redistribute it and/or
24 modify it under the terms of the GNU General Public License as
25 published by the Free Software Foundation; either version 2 of
26 the License, or (at your option) any later version.
28 The LZO library is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
33 You should have received a copy of the GNU General Public License
34 along with the LZO library; see the file COPYING.
35 If not, write to the Free Software Foundation, Inc.,
36 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
38 Markus F.X.J. Oberhumer
39 <markus@oberhumer.com>
40 http://www.oberhumer.com/opensource/lzo/
44 #include "lzo/lzoconf.h"
47 /*************************************************************************
48 // util
49 **************************************************************************/
51 /* portability layer */
52 #define WANT_LZO_MALLOC 1
53 #define WANT_LZO_FREAD 1
54 #define WANT_LZO_WILDARGV 1
55 #define WANT_LZO_UCLOCK 1
56 #define ACC_WANT_ACCLIB_GETOPT 1
57 #include "examples/portab.h"
59 #if defined(HAVE_STRNICMP) && !defined(HAVE_STRNCASECMP)
60 # define strncasecmp(a,b,c) strnicmp(a,b,c)
61 # define HAVE_STRNCASECMP 1
62 #endif
64 #if 0
65 # define is_digit(x) (isdigit((unsigned char)(x)))
66 # define is_space(x) (isspace((unsigned char)(x)))
67 #else
68 # define is_digit(x) ((unsigned)(x) - '0' <= 9)
69 # define is_space(x) ((x)==' ' || (x)=='\t' || (x)=='\r' || (x)=='\n')
70 #endif
73 /*************************************************************************
74 // compression include section
75 **************************************************************************/
77 #define HAVE_LZO1_H 1
78 #define HAVE_LZO1A_H 1
79 #define HAVE_LZO1B_H 1
80 #define HAVE_LZO1C_H 1
81 #define HAVE_LZO1F_H 1
82 #define HAVE_LZO1X_H 1
83 #define HAVE_LZO1Y_H 1
84 #define HAVE_LZO1Z_H 1
85 #define HAVE_LZO2A_H 1
87 #if defined(NO_ZLIB_H) || (SIZEOF_INT < 4)
88 #undef HAVE_ZLIB_H
89 #endif
90 #if defined(NO_BZLIB_H) || (SIZEOF_INT != 4)
91 #undef HAVE_BZLIB_H
92 #endif
94 #if 0 && defined(LZO_OS_DOS16)
95 /* don't make this test program too big */
96 #undef HAVE_LZO1_H
97 #undef HAVE_LZO1A_H
98 #undef HAVE_LZO1C_H
99 #undef HAVE_LZO1Z_H
100 #undef HAVE_LZO2A_H
101 #undef HAVE_LZO2B_H
102 #undef HAVE_ZLIB_H
103 #endif
106 /* LZO algorithms */
107 #if defined(HAVE_LZO1_H)
108 # include "lzo/lzo1.h"
109 #endif
110 #if defined(HAVE_LZO1A_H)
111 # include "lzo/lzo1a.h"
112 #endif
113 #if defined(HAVE_LZO1B_H)
114 # include "lzo/lzo1b.h"
115 #endif
116 #if defined(HAVE_LZO1C_H)
117 # include "lzo/lzo1c.h"
118 #endif
119 #if defined(HAVE_LZO1F_H)
120 # include "lzo/lzo1f.h"
121 #endif
122 #if defined(HAVE_LZO1X_H)
123 # include "lzo/lzo1x.h"
124 # if defined(__LZO_PROFESSIONAL__)
125 # include "lzo/lzopro/lzo1x.h"
126 # endif
127 #endif
128 #if defined(HAVE_LZO1Y_H)
129 # include "lzo/lzo1y.h"
130 # if defined(__LZO_PROFESSIONAL__)
131 # include "lzo/lzopro/lzo1y.h"
132 # endif
133 #endif
134 #if defined(HAVE_LZO1Z_H)
135 # include "lzo/lzo1z.h"
136 #endif
137 #if defined(HAVE_LZO2A_H)
138 # include "lzo/lzo2a.h"
139 #endif
140 #if defined(HAVE_LZO2B_H)
141 # include "lzo/lzo2b.h"
142 #endif
143 #if defined(__LZO_PROFESSIONAL__)
144 # include "lzopro/t_config.ch"
145 #endif
146 /* other compressors */
147 #if defined(HAVE_ZLIB_H)
148 # include <zlib.h>
149 # define ALG_ZLIB 1
150 #endif
151 #if defined(HAVE_BZLIB_H)
152 # include <bzlib.h>
153 # define ALG_BZIP2 1
154 #endif
157 /*************************************************************************
158 // enumerate all methods
159 **************************************************************************/
161 enum {
162 /* compression algorithms */
163 M_LZO1B_1 = 1,
164 M_LZO1B_2, M_LZO1B_3, M_LZO1B_4, M_LZO1B_5,
165 M_LZO1B_6, M_LZO1B_7, M_LZO1B_8, M_LZO1B_9,
167 M_LZO1C_1 = 11,
168 M_LZO1C_2, M_LZO1C_3, M_LZO1C_4, M_LZO1C_5,
169 M_LZO1C_6, M_LZO1C_7, M_LZO1C_8, M_LZO1C_9,
171 M_LZO1 = 21,
172 M_LZO1A = 31,
174 M_LZO1B_99 = 901,
175 M_LZO1B_999 = 902,
176 M_LZO1C_99 = 911,
177 M_LZO1C_999 = 912,
178 M_LZO1_99 = 921,
179 M_LZO1A_99 = 931,
181 M_LZO1F_1 = 61,
182 M_LZO1F_999 = 962,
183 M_LZO1X_1 = 71,
184 M_LZO1X_1_11 = 111,
185 M_LZO1X_1_12 = 112,
186 M_LZO1X_1_15 = 115,
187 M_LZO1X_999 = 972,
188 M_LZO1Y_1 = 81,
189 M_LZO1Y_999 = 982,
190 M_LZO1Z_999 = 992,
192 M_LZO2A_999 = 942,
193 M_LZO2B_999 = 952,
195 M_LAST_LZO_COMPRESSOR = 998,
197 /* other compressors */
198 #if defined(ALG_ZLIB)
199 M_ZLIB_8_1 = 1101,
200 M_ZLIB_8_2, M_ZLIB_8_3, M_ZLIB_8_4, M_ZLIB_8_5,
201 M_ZLIB_8_6, M_ZLIB_8_7, M_ZLIB_8_8, M_ZLIB_8_9,
202 #endif
203 #if defined(ALG_BZIP2)
204 M_BZIP2_1 = 1201,
205 M_BZIP2_2, M_BZIP2_3, M_BZIP2_4, M_BZIP2_5,
206 M_BZIP2_6, M_BZIP2_7, M_BZIP2_8, M_BZIP2_9,
207 #endif
209 /* dummy compressor - for benchmarking */
210 M_MEMCPY = 999,
212 M_LAST_COMPRESSOR = 4999,
214 /* dummy algorithms - for benchmarking */
215 M_MEMSET = 5001,
217 /* checksum algorithms - for benchmarking */
218 M_ADLER32 = 6001,
219 M_CRC32 = 6002,
220 #if defined(ALG_ZLIB)
221 M_Z_ADLER32 = 6011,
222 M_Z_CRC32 = 6012,
223 #endif
225 #if defined(__LZO_PROFESSIONAL__)
226 # include "lzopro/m_enum.ch"
227 #endif
229 M_UNUSED
233 /*************************************************************************
234 // command line options
235 **************************************************************************/
237 int opt_verbose = 2;
239 long opt_c_loops = 0;
240 long opt_d_loops = 0;
241 const char *opt_corpus_path = NULL;
242 const char *opt_dump_compressed_data = NULL;
244 lzo_bool opt_use_safe_decompressor = 0;
245 lzo_bool opt_use_asm_decompressor = 0;
246 lzo_bool opt_use_asm_fast_decompressor = 0;
247 lzo_bool opt_optimize_compressed_data = 0;
249 int opt_dict = 0;
250 lzo_uint opt_max_dict_len = LZO_UINT_MAX;
251 const char *opt_dictionary_file = NULL;
253 lzo_bool opt_read_from_stdin = 0;
255 /* set these to 1 to measure the speed impact of a checksum */
256 lzo_bool opt_compute_adler32 = 0;
257 lzo_bool opt_compute_crc32 = 0;
258 static lzo_uint32 adler_in, adler_out;
259 static lzo_uint32 crc_in, crc_out;
261 lzo_bool opt_execution_time = 0;
262 int opt_uclock = -1;
263 lzo_bool opt_clear_wrkmem = 0;
265 static const lzo_bool opt_try_to_compress_0_bytes = 1;
268 /*************************************************************************
269 // misc globals
270 **************************************************************************/
272 static const char *progname = "";
273 static lzo_uclock_handle_t uch;
275 /* for statistics and benchmark */
276 int opt_totals = 0;
277 static unsigned long total_n = 0;
278 static unsigned long total_c_len = 0;
279 static unsigned long total_d_len = 0;
280 static unsigned long total_blocks = 0;
281 static double total_perc = 0.0;
282 static const char *total_method_name = NULL;
283 static unsigned total_method_names = 0;
284 /* Note: the average value of a rate (e.g. compression speed) is defined
285 * by the Harmonic Mean (and _not_ by the Arithmethic Mean ) */
286 static unsigned long total_c_mbs_n = 0;
287 static unsigned long total_d_mbs_n = 0;
288 static double total_c_mbs_harmonic = 0.0;
289 static double total_d_mbs_harmonic = 0.0;
290 static double total_c_mbs_sum = 0.0;
291 static double total_d_mbs_sum = 0.0;
294 #if defined(HAVE_LZO1X_H)
295 int default_method = M_LZO1X_1;
296 #elif defined(HAVE_LZO1B_H)
297 int default_method = M_LZO1B_1;
298 #elif defined(HAVE_LZO1C_H)
299 int default_method = M_LZO1C_1;
300 #elif defined(HAVE_LZO1F_H)
301 int default_method = M_LZO1F_1;
302 #elif defined(HAVE_LZO1Y_H)
303 int default_method = M_LZO1Y_1;
304 #else
305 int default_method = M_MEMCPY;
306 #endif
309 static const int benchmark_methods[] = {
310 M_LZO1B_1, M_LZO1B_9,
311 M_LZO1C_1, M_LZO1C_9,
312 M_LZO1F_1,
313 M_LZO1X_1,
317 static const int x1_methods[] = {
318 M_LZO1, M_LZO1A, M_LZO1B_1, M_LZO1C_1, M_LZO1F_1, M_LZO1X_1, M_LZO1Y_1,
322 static const int x99_methods[] = {
323 M_LZO1_99, M_LZO1A_99, M_LZO1B_99, M_LZO1C_99,
327 static const int x999_methods[] = {
328 M_LZO1B_999, M_LZO1C_999, M_LZO1F_999, M_LZO1X_999, M_LZO1Y_999,
329 M_LZO1Z_999,
330 M_LZO2A_999,
335 /* exit codes of this test program */
336 #define EXIT_OK 0
337 #define EXIT_USAGE 1
338 #define EXIT_FILE 2
339 #define EXIT_MEM 3
340 #define EXIT_ADLER 4
341 #define EXIT_LZO_ERROR 5
342 #define EXIT_LZO_INIT 6
343 #define EXIT_INTERNAL 7
346 /*************************************************************************
347 // memory setup
348 **************************************************************************/
350 static lzo_uint opt_block_size;
351 static lzo_uint opt_max_data_len;
353 typedef struct {
354 lzo_bytep ptr;
355 lzo_uint len;
356 lzo_uint32 adler;
357 lzo_uint32 crc;
358 lzo_bytep alloc_ptr;
359 lzo_uint alloc_len;
360 lzo_uint saved_len;
361 } mblock_t;
363 static mblock_t file_data; /* original uncompressed data */
364 static mblock_t block_c; /* compressed data */
365 static mblock_t block_d; /* decompressed data */
366 static mblock_t block_w; /* wrkmem */
367 static mblock_t dict;
370 static void mb_alloc_extra(mblock_t *mb, lzo_uint len, lzo_uint extra_bottom, lzo_uint extra_top)
372 lzo_uint align = (lzo_uint) sizeof(lzo_align_t);
374 mb->alloc_ptr = mb->ptr = NULL;
375 mb->alloc_len = mb->len = 0;
377 mb->alloc_len = extra_bottom + len + extra_top;
378 if (mb->alloc_len == 0) mb->alloc_len = 1;
379 mb->alloc_ptr = (lzo_bytep) lzo_malloc(mb->alloc_len);
381 if (mb->alloc_ptr == NULL) {
382 fprintf(stderr, "%s: out of memory (wanted %lu bytes)\n", progname, (unsigned long)mb->alloc_len);
383 exit(EXIT_MEM);
385 if (mb->alloc_len >= align && __lzo_align_gap(mb->alloc_ptr, align) != 0) {
386 fprintf(stderr, "%s: C library problem: malloc() returned misaligned pointer!\n", progname);
387 exit(EXIT_MEM);
390 mb->ptr = mb->alloc_ptr + extra_bottom;
391 mb->len = mb->saved_len = len;
392 mb->adler = 1;
393 mb->crc = 0;
397 static void mb_alloc(mblock_t *mb, lzo_uint len)
399 mb_alloc_extra(mb, len, 0, 0);
403 static void mb_free(mblock_t *mb)
405 if (!mb) return;
406 if (mb->alloc_ptr) lzo_free(mb->alloc_ptr);
407 mb->alloc_ptr = mb->ptr = NULL;
408 mb->alloc_len = mb->len = 0;
412 static lzo_uint get_max_compression_expansion(int m, lzo_uint bl)
414 if (m == M_MEMCPY || m >= M_LAST_COMPRESSOR)
415 return 0;
416 if (m == M_LZO2A_999 || m == M_LZO2B_999)
417 return bl / 8 + 256;
418 if (m > 0 && m < M_LAST_LZO_COMPRESSOR)
419 return bl / 16 + 64 + 3;
420 return bl / 8 + 256;
423 static lzo_uint get_max_decompression_overrun(int m, lzo_uint bl)
425 LZO_UNUSED(m);
426 LZO_UNUSED(bl);
427 /* may overwrite 3 bytes past the end of the decompressed block */
428 if (opt_use_asm_fast_decompressor)
429 return (lzo_uint) sizeof(lzo_voidp) - 1;
430 return 0;
434 /*************************************************************************
435 // dictionary support
436 **************************************************************************/
438 static void dict_alloc(lzo_uint max_dict_len)
440 lzo_uint l = 0xbfff; /* MAX_DICT_LEN */
441 if (max_dict_len > 0 && l > max_dict_len)
442 l = max_dict_len;
443 mb_alloc(&dict, l);
447 /* this default dictionary does not provide good contexts... */
448 static void dict_set_default(void)
450 lzo_uint d = 0;
451 unsigned i, j;
453 dict.len = 16 * 256;
454 if (dict.len > dict.alloc_len)
455 dict.len = dict.alloc_len;
457 lzo_memset(dict.ptr, 0, dict.len);
459 for (i = 0; i < 256; i++)
460 for (j = 0; j < 16; j++) {
461 if (d >= dict.len)
462 goto done;
463 dict.ptr[d++] = (unsigned char) i;
466 done:
467 dict.adler = lzo_adler32(1, dict.ptr, dict.len);
471 static void dict_load(const char *file_name)
473 FILE *fp;
475 dict.len = 0;
476 fp = fopen(file_name, "rb");
477 if (fp)
479 dict.len = (lzo_uint) lzo_fread(fp, dict.ptr, dict.alloc_len);
480 (void) fclose(fp);
481 dict.adler = lzo_adler32(1, dict.ptr, dict.len);
486 /*************************************************************************
487 // compression database
488 **************************************************************************/
490 typedef struct
492 const char * name;
493 int id;
494 lzo_uint32 mem_compress;
495 lzo_uint32 mem_decompress;
496 lzo_compress_t compress;
497 lzo_optimize_t optimize;
498 lzo_decompress_t decompress;
499 lzo_decompress_t decompress_safe;
500 lzo_decompress_t decompress_asm;
501 lzo_decompress_t decompress_asm_safe;
502 lzo_decompress_t decompress_asm_fast;
503 lzo_decompress_t decompress_asm_fast_safe;
504 lzo_compress_dict_t compress_dict;
505 lzo_decompress_dict_t decompress_dict_safe;
507 compress_t;
509 #include "asm.h"
511 #include "wrap.h"
512 #define M_PRIVATE LZO_PRIVATE
513 #define m_uint lzo_uint
514 #define m_uint32 lzo_uint32
515 #define m_voidp lzo_voidp
516 #define m_bytep lzo_bytep
517 #define m_uintp lzo_uintp
518 #include "wrapmisc.h"
520 static const compress_t compress_database[] = {
521 #include "db.h"
522 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
526 /*************************************************************************
527 // method info
528 **************************************************************************/
530 static
531 lzo_decompress_t get_decomp_info ( const compress_t *c, const char **nn )
533 lzo_decompress_t d = 0;
534 const char *n = NULL;
536 /* safe has priority over asm/fast */
537 if (!d && opt_use_safe_decompressor && opt_use_asm_fast_decompressor)
539 d = c->decompress_asm_fast_safe;
540 n = " [fs]";
542 if (!d && opt_use_safe_decompressor && opt_use_asm_decompressor)
544 d = c->decompress_asm_safe;
545 n = " [as]";
547 if (!d && opt_use_safe_decompressor)
549 d = c->decompress_safe;
550 n = " [s]";
552 if (!d && opt_use_asm_fast_decompressor)
554 d = c->decompress_asm_fast;
555 n = " [f]";
557 if (!d && opt_use_asm_decompressor)
559 d = c->decompress_asm;
560 n = " [a]";
562 if (!d)
564 d = c->decompress;
565 n = "";
567 if (!d)
568 n = "(null)";
570 if (opt_dict && c->decompress_dict_safe)
571 n = "";
573 if (nn)
574 *nn = n;
575 return d;
579 static
580 const compress_t *find_method_by_id ( int method )
582 const compress_t *db;
583 size_t size = sizeof(compress_database) / sizeof(*(compress_database));
584 size_t i;
586 db = compress_database;
587 for (i = 0; i < size && db->name != NULL; i++, db++)
589 if (method == db->id)
590 return db;
592 return NULL;
596 static
597 const compress_t *find_method_by_name ( const char *name )
599 const compress_t *db;
600 size_t size = sizeof(compress_database) / sizeof(*(compress_database));
601 size_t i;
603 db = compress_database;
604 for (i = 0; i < size && db->name != NULL; i++, db++)
606 size_t n = strlen(db->name);
608 #if defined(HAVE_STRNCASECMP)
609 if (strncasecmp(name,db->name,n) == 0 && (!name[n] || name[n] == ','))
610 return db;
611 #else
612 if (strncmp(name,db->name,n) == 0 && (!name[n] || name[n] == ','))
613 return db;
614 #endif
616 return NULL;
620 static
621 lzo_bool is_compressor ( const compress_t *c )
623 return (c->id <= M_LAST_COMPRESSOR || c->id >= 9721);
627 /*************************************************************************
628 // check that memory gets accessed within bounds
629 **************************************************************************/
631 void memchecker_init ( mblock_t *mb, lzo_xint l, unsigned char random_byte )
633 lzo_uint i;
634 lzo_uint len = (lzo_uint) l;
635 lzo_bytep p;
637 assert(len <= mb->len);
639 /* bottom */
640 p = mb->ptr;
641 for (i = 0; i < 16 && p > mb->alloc_ptr; i++)
642 *--p = random_byte++;
643 /* top */
644 p = mb->ptr + len;
645 for (i = 0; i < 16 && p < mb->alloc_ptr + mb->alloc_len; i++)
646 *p++ = random_byte++;
647 #if 0 || defined(LZO_DEBUG)
648 /* fill in garbage */
649 p = mb->ptr;
650 random_byte |= 1;
651 for (i = 0; i < len; i++, random_byte += 2)
652 *p++ = random_byte;
653 #endif
657 int memchecker_check ( mblock_t *mb, lzo_xint l, unsigned char random_byte )
659 lzo_uint i;
660 lzo_uint len = (lzo_uint) l;
661 lzo_bytep p;
663 assert(len <= mb->len);
665 /* bottom */
666 p = mb->ptr;
667 for (i = 0; i < 16 && p > mb->alloc_ptr; i++)
668 if (*--p != random_byte++)
669 return -1;
670 /* top */
671 p = mb->ptr + len;
672 for (i = 0; i < 16 && p < mb->alloc_ptr + mb->alloc_len; i++)
673 if (*p++ != random_byte++)
674 return -1;
675 return 0;
679 /*************************************************************************
680 // compress a block
681 **************************************************************************/
683 static
684 int call_compressor ( const compress_t *c,
685 const lzo_bytep src, lzo_uint src_len,
686 lzo_bytep dst, lzo_uintp dst_len )
688 int r = -100;
690 if (c && c->compress && block_w.len >= c->mem_compress)
692 unsigned char random_byte = (unsigned char) src_len;
693 memchecker_init(&block_w, c->mem_compress, random_byte);
694 if (opt_clear_wrkmem)
695 lzo_memset(block_w.ptr, 0, c->mem_compress);
697 if (opt_dict && c->compress_dict)
698 r = c->compress_dict(src,src_len,dst,dst_len,block_w.ptr,dict.ptr,dict.len);
699 else
700 r = c->compress(src,src_len,dst,dst_len,block_w.ptr);
702 if (memchecker_check(&block_w, c->mem_compress, random_byte) != 0)
703 printf("WARNING: wrkmem overwrite error (compress) !!!\n");
706 if (r == 0 && opt_compute_adler32)
708 lzo_uint32 adler;
709 adler = lzo_adler32(0, NULL, 0);
710 adler = lzo_adler32(adler, src, src_len);
711 adler_in = adler;
713 if (r == 0 && opt_compute_crc32)
715 lzo_uint32 crc;
716 crc = lzo_crc32(0, NULL, 0);
717 crc = lzo_crc32(crc, src, src_len);
718 crc_in = crc;
721 return r;
725 /*************************************************************************
726 // decompress a block
727 **************************************************************************/
729 static
730 int call_decompressor ( const compress_t *c, lzo_decompress_t d,
731 const lzo_bytep src, lzo_uint src_len,
732 lzo_bytep dst, lzo_uintp dst_len )
734 int r = -100;
736 if (c && d && block_w.len >= c->mem_decompress)
738 unsigned char random_byte = (unsigned char) src_len;
739 memchecker_init(&block_w, c->mem_decompress, random_byte);
740 if (opt_clear_wrkmem)
741 lzo_memset(block_w.ptr, 0, c->mem_decompress);
743 if (opt_dict && c->decompress_dict_safe)
744 r = c->decompress_dict_safe(src,src_len,dst,dst_len,block_w.ptr,dict.ptr,dict.len);
745 else
746 r = d(src,src_len,dst,dst_len,block_w.ptr);
748 if (memchecker_check(&block_w, c->mem_decompress, random_byte) != 0)
749 printf("WARNING: wrkmem overwrite error (decompress) !!!\n");
752 if (r == 0 && opt_compute_adler32)
753 adler_out = lzo_adler32(1, dst, *dst_len);
754 if (r == 0 && opt_compute_crc32)
755 crc_out = lzo_crc32(0, dst, *dst_len);
757 return r;
761 /*************************************************************************
762 // optimize a block
763 **************************************************************************/
765 static
766 int call_optimizer ( const compress_t *c,
767 lzo_bytep src, lzo_uint src_len,
768 lzo_bytep dst, lzo_uintp dst_len )
770 if (c && c->optimize && block_w.len >= c->mem_decompress)
771 return c->optimize(src,src_len,dst,dst_len,block_w.ptr);
772 return 0;
776 /***********************************************************************
777 // read a file
778 ************************************************************************/
780 static int load_file(const char *file_name, lzo_uint max_data_len)
782 FILE *fp;
783 #if (HAVE_FTELLO)
784 off_t ll = -1;
785 #else
786 long ll = -1;
787 #endif
788 lzo_uint l;
789 int r;
790 mblock_t *mb = &file_data;
792 mb_free(mb);
794 fp = fopen(file_name, "rb");
795 if (fp == NULL)
797 fflush(stdout); fflush(stderr);
798 fprintf(stderr, "%s: ", file_name);
799 fflush(stderr);
800 perror("fopen");
801 fflush(stdout); fflush(stderr);
802 return EXIT_FILE;
804 r = fseek(fp, 0, SEEK_END);
805 if (r == 0)
807 #if (HAVE_FTELLO)
808 ll = ftello(fp);
809 #else
810 ll = ftell(fp);
811 #endif
812 r = fseek(fp, 0, SEEK_SET);
814 if (r != 0 || ll < 0)
816 fflush(stdout); fflush(stderr);
817 fprintf(stderr, "%s: ", file_name);
818 fflush(stderr);
819 perror("fseek");
820 fflush(stdout); fflush(stderr);
821 (void) fclose(fp);
822 return EXIT_FILE;
825 l = (lzo_uint) ll;
826 if (l > max_data_len) l = max_data_len;
827 #if (HAVE_FTELLO)
828 if ((off_t) l != ll) l = max_data_len;
829 #else
830 if ((long) l != ll) l = max_data_len;
831 #endif
833 mb_alloc(mb, l);
834 mb->len = (lzo_uint) lzo_fread(fp, mb->ptr, mb->len);
836 r = ferror(fp);
837 if (fclose(fp) != 0 || r != 0)
839 mb_free(mb);
840 fflush(stdout); fflush(stderr);
841 fprintf(stderr, "%s: ", file_name);
842 fflush(stderr);
843 perror("fclose");
844 fflush(stdout); fflush(stderr);
845 return EXIT_FILE;
848 return EXIT_OK;
852 /***********************************************************************
853 // print some compression statistics
854 ************************************************************************/
856 static double t_div(double a, double b)
858 return b > 0.00001 ? a / b : 0;
861 static double set_perc_d(double perc, char *s)
863 if (perc <= 0.0) {
864 strcpy(s, "0.0");
865 return 0;
867 if (perc <= 100 - 1.0 / 16) {
868 sprintf(s, "%4.1f", perc);
870 else {
871 long p = (long) (perc + 0.5);
872 if (p < 100)
873 strcpy(s, "???");
874 else if (p >= 9999)
875 strcpy(s, "9999");
876 else
877 sprintf(s, "%ld", p);
879 return perc;
882 static double set_perc(unsigned long c_len, unsigned long d_len, char *s)
884 double perc = 0.0;
885 if (d_len > 0)
886 perc = c_len * 100.0 / d_len;
887 return set_perc_d(perc, s);
891 static
892 void print_stats ( const char *method_name, const char *file_name,
893 long t_loops, long c_loops, long d_loops,
894 double t_secs, double c_secs, double d_secs,
895 unsigned long c_len, unsigned long d_len,
896 unsigned long blocks )
898 unsigned long x_len = d_len;
899 unsigned long t_bytes, c_bytes, d_bytes;
900 double c_mbs, d_mbs, t_mbs;
901 double perc;
902 char perc_str[4+1];
904 perc = set_perc(c_len, d_len, perc_str);
906 c_bytes = x_len * c_loops * t_loops;
907 d_bytes = x_len * d_loops * t_loops;
908 t_bytes = c_bytes + d_bytes;
910 if (opt_uclock == 0)
911 c_secs = d_secs = t_secs = 0.0;
913 /* speed in uncompressed megabytes per second (1 megabyte = 1.000.000 bytes) */
914 c_mbs = (c_secs > 0.001) ? (c_bytes / c_secs) / 1000000.0 : 0;
915 d_mbs = (d_secs > 0.001) ? (d_bytes / d_secs) / 1000000.0 : 0;
916 t_mbs = (t_secs > 0.001) ? (t_bytes / t_secs) / 1000000.0 : 0;
918 total_n++;
919 total_c_len += c_len;
920 total_d_len += d_len;
921 total_blocks += blocks;
922 total_perc += perc;
923 if (c_mbs > 0) {
924 total_c_mbs_n += 1;
925 total_c_mbs_harmonic += 1.0 / c_mbs;
926 total_c_mbs_sum += c_mbs;
928 if (d_mbs > 0) {
929 total_d_mbs_n += 1;
930 total_d_mbs_harmonic += 1.0 / d_mbs;
931 total_d_mbs_sum += d_mbs;
934 if (opt_verbose >= 2)
936 printf(" compressed into %lu bytes, %s%% (%s%.3f bits/byte)\n",
937 c_len, perc_str, "", perc * 0.08);
939 #if 0
940 printf("%-15s %5ld: ","overall", t_loops);
941 printf("%10lu bytes, %8.2f secs, %8.3f MB/sec\n",
942 t_bytes, t_secs, t_mbs);
943 #else
944 LZO_UNUSED(t_mbs);
945 #endif
946 printf("%-15s %5ld: ","compress", c_loops);
947 printf("%10lu bytes, %8.2f secs, %8.3f MB/sec\n",
948 c_bytes, c_secs, c_mbs);
949 printf("%-15s %5ld: ","decompress", d_loops);
950 printf("%10lu bytes, %8.2f secs, %8.3f MB/sec\n",
951 d_bytes, d_secs, d_mbs);
952 printf("\n");
955 /* create a line for util/table.pl */
956 if (opt_verbose >= 1)
958 /* get basename */
959 const char *n, *nn, *b;
960 for (nn = n = b = file_name; *nn; nn++)
961 if (*nn == '/' || *nn == '\\' || *nn == ':')
962 b = nn + 1;
963 else
964 n = b;
966 printf("%-13s| %-14s %8lu %4lu %9lu %4s %s%8.3f %8.3f |\n",
967 method_name, n, d_len, blocks, c_len, perc_str, "", c_mbs, d_mbs);
970 if (opt_verbose >= 2)
971 printf("\n");
975 static
976 void print_totals ( void )
978 char perc_str[4+1];
980 if ((opt_verbose >= 1 && total_n > 1) || (opt_totals >= 2))
982 unsigned long n = total_n > 0 ? total_n : 1;
983 const char *t1 = "-------";
984 const char *t2 = total_method_names == 1 ? total_method_name : "";
985 #if 1 && defined(__ACCLIB_PCLOCK_CH_INCLUDED)
986 char uclock_mode[32+1];
987 sprintf(uclock_mode, "[clock=%d]", uch.mode);
988 t1 = uclock_mode;
989 if (opt_uclock == 0) t1 = t2;
990 #endif
992 #if 1
993 set_perc_d(total_perc / n, perc_str);
994 printf("%-13s %-12s %10lu %4.1f %9lu %4s %8.3f %8.3f\n",
995 t1, "***AVG***",
996 total_d_len / n, total_blocks * 1.0 / n, total_c_len / n, perc_str,
997 t_div(total_c_mbs_n, total_c_mbs_harmonic),
998 t_div(total_d_mbs_n, total_d_mbs_harmonic));
999 #endif
1000 set_perc(total_c_len, total_d_len, perc_str);
1001 printf("%-13s %-12s %10lu %4lu %9lu %4s %s%8.3f %8.3f\n",
1002 t2, "***TOTALS***",
1003 total_d_len, total_blocks, total_c_len, perc_str, "",
1004 t_div(total_c_mbs_n, total_c_mbs_harmonic),
1005 t_div(total_d_mbs_n, total_d_mbs_harmonic));
1010 /*************************************************************************
1011 // compress and decompress a file
1012 **************************************************************************/
1014 static __lzo_noinline
1015 int process_file ( const compress_t *c, lzo_decompress_t decompress,
1016 const char *method_name,
1017 const char *file_name,
1018 long t_loops, long c_loops, long d_loops )
1020 long t_i;
1021 unsigned long blocks = 0;
1022 unsigned long compressed_len = 0;
1023 double t_time = 0, c_time = 0, d_time = 0;
1024 lzo_uclock_t t_start, t_stop, x_start, x_stop;
1025 FILE *fp_dump = NULL;
1027 if (opt_dump_compressed_data)
1028 fp_dump = fopen(opt_dump_compressed_data,"wb");
1030 /* process the file */
1032 lzo_uclock_flush_cpu_cache(&uch, 0);
1033 lzo_uclock_read(&uch, &t_start);
1034 for (t_i = 0; t_i < t_loops; t_i++)
1036 lzo_uint len, c_len, c_len_max, d_len = 0;
1037 const lzo_bytep d = file_data.ptr;
1039 len = file_data.len;
1040 c_len = 0;
1041 blocks = 0;
1043 /* process blocks */
1044 if (len > 0 || opt_try_to_compress_0_bytes) do
1046 lzo_uint bl;
1047 long c_i;
1048 int r;
1049 unsigned char random_byte = (unsigned char) file_data.len;
1050 #if 1 && defined(CLOCKS_PER_SEC)
1051 random_byte = (unsigned char) (random_byte ^ clock());
1052 #endif
1053 blocks++;
1055 bl = len > opt_block_size ? opt_block_size : len;
1056 /* update lengths for memchecker_xxx() */
1057 block_c.len = bl + get_max_compression_expansion(c->id, bl);
1058 block_d.len = bl + get_max_decompression_overrun(c->id, bl);
1059 #if defined(__LZO_CHECKER)
1060 /* malloc a block of the exact size to detect any overrun */
1061 assert(block_c.alloc_ptr == NULL);
1062 assert(block_d.alloc_ptr == NULL);
1063 mb_alloc(&block_c, block_c.len);
1064 mb_alloc(&block_d, block_d.len);
1065 #endif
1066 assert(block_c.len <= block_c.saved_len);
1067 assert(block_d.len <= block_d.saved_len);
1069 memchecker_init(&block_c, block_c.len, random_byte);
1070 memchecker_init(&block_d, block_d.len, random_byte);
1072 /* compress the block */
1073 c_len = c_len_max = 0;
1074 lzo_uclock_flush_cpu_cache(&uch, 0);
1075 lzo_uclock_read(&uch, &x_start);
1076 for (r = 0, c_i = 0; c_i < c_loops; c_i++)
1078 c_len = block_c.len;
1079 r = call_compressor(c, d, bl, block_c.ptr, &c_len);
1080 if (r != 0)
1081 break;
1082 if (c_len > c_len_max)
1083 c_len_max = c_len;
1084 if (c_len > block_c.len)
1085 goto compress_overrun;
1087 lzo_uclock_read(&uch, &x_stop);
1088 c_time += lzo_uclock_get_elapsed(&uch, &x_start, &x_stop);
1089 if (r != 0)
1091 printf(" compression failed in block %lu (%d) (%lu %lu)\n",
1092 blocks, r, (unsigned long)c_len, (unsigned long)bl);
1093 return EXIT_LZO_ERROR;
1095 if (memchecker_check(&block_c, block_c.len, random_byte) != 0)
1097 compress_overrun:
1098 printf(" compression overwrite error in block %lu "
1099 "(%lu %lu %lu %lu)\n",
1100 blocks, (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl, (unsigned long)block_c.len);
1101 return EXIT_LZO_ERROR;
1104 /* optimize the compressed block */
1105 if (c_len < bl && opt_optimize_compressed_data)
1107 d_len = bl;
1108 r = call_optimizer(c, block_c.ptr, c_len, block_d.ptr, &d_len);
1109 if (r != 0 || d_len != bl)
1111 printf(" optimization failed in block %lu (%d) "
1112 "(%lu %lu %lu)\n", blocks, r,
1113 (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl);
1114 return EXIT_LZO_ERROR;
1116 if (memchecker_check(&block_c, block_c.len, random_byte) != 0 ||
1117 memchecker_check(&block_d, block_d.len, random_byte) != 0)
1119 printf(" optimize overwrite error in block %lu "
1120 "(%lu %lu %lu %lu)\n",
1121 blocks, (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl, (unsigned long)block_c.len);
1122 return EXIT_LZO_ERROR;
1126 /* dump compressed data to disk */
1127 if (fp_dump)
1129 lzo_uint l = (lzo_uint) lzo_fwrite(fp_dump, block_c.ptr, c_len);
1130 if (l != c_len || fflush(fp_dump) != 0) {
1131 /* write error */
1132 (void) fclose(fp_dump); fp_dump = NULL;
1136 /* decompress the block and verify */
1137 lzo_uclock_flush_cpu_cache(&uch, 0);
1138 lzo_uclock_read(&uch, &x_start);
1139 for (r = 0, c_i = 0; c_i < d_loops; c_i++)
1141 d_len = bl;
1142 r = call_decompressor(c, decompress, block_c.ptr, c_len, block_d.ptr, &d_len);
1143 if (r != 0 || d_len != bl)
1144 break;
1146 lzo_uclock_read(&uch, &x_stop);
1147 d_time += lzo_uclock_get_elapsed(&uch, &x_start, &x_stop);
1148 if (r != 0)
1150 printf(" decompression failed in block %lu (%d) "
1151 "(%lu %lu %lu)\n", blocks, r,
1152 (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl);
1153 return EXIT_LZO_ERROR;
1155 if (d_len != bl)
1157 printf(" decompression size error in block %lu (%lu %lu %lu)\n",
1158 blocks, (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl);
1159 return EXIT_LZO_ERROR;
1161 if (is_compressor(c))
1163 if (lzo_memcmp(d, block_d.ptr, bl) != 0)
1165 lzo_uint x = 0;
1166 while (x < bl && block_d.ptr[x] == d[x])
1167 x++;
1168 printf(" decompression data error in block %lu at offset "
1169 "%lu (%lu %lu)\n", blocks, (unsigned long)x,
1170 (unsigned long)c_len, (unsigned long)d_len);
1171 if (opt_compute_adler32)
1172 printf(" checksum: 0x%08lx 0x%08lx\n",
1173 (unsigned long)adler_in, (unsigned long)adler_out);
1174 #if 0
1175 printf("Orig: ");
1176 r = (x >= 10) ? -10 : 0 - (int) x;
1177 for (j = r; j <= 10 && x + j < bl; j++)
1178 printf(" %02x", (int)d[x+j]);
1179 printf("\nDecomp:");
1180 for (j = r; j <= 10 && x + j < bl; j++)
1181 printf(" %02x", (int)block_d.ptr[x+j]);
1182 printf("\n");
1183 #endif
1184 return EXIT_LZO_ERROR;
1186 if ((opt_compute_adler32 && adler_in != adler_out) ||
1187 (opt_compute_crc32 && crc_in != crc_out))
1189 printf(" checksum error in block %lu (%lu %lu)\n",
1190 blocks, (unsigned long)c_len, (unsigned long)d_len);
1191 printf(" adler32: 0x%08lx 0x%08lx\n",
1192 (unsigned long)adler_in, (unsigned long)adler_out);
1193 printf(" crc32: 0x%08lx 0x%08lx\n",
1194 (unsigned long)crc_in, (unsigned long)crc_out);
1195 return EXIT_LZO_ERROR;
1199 if (memchecker_check(&block_d, block_d.len, random_byte) != 0)
1201 printf(" decompression overwrite error in block %lu "
1202 "(%lu %lu %lu %lu)\n",
1203 blocks, (unsigned long)c_len, (unsigned long)d_len,
1204 (unsigned long)bl, (unsigned long)block_d.len);
1205 return EXIT_LZO_ERROR;
1208 #if defined(__LZO_CHECKER)
1209 /* free in reverse order of allocations */
1210 mb_free(&block_d);
1211 mb_free(&block_c);
1212 #endif
1214 d += bl;
1215 len -= bl;
1216 compressed_len += (unsigned long) c_len_max;
1218 while (len > 0);
1220 lzo_uclock_read(&uch, &t_stop);
1221 t_time += lzo_uclock_get_elapsed(&uch, &t_start, &t_stop);
1223 if (fp_dump) {
1224 (void) fclose(fp_dump); fp_dump = NULL;
1226 opt_dump_compressed_data = NULL; /* only dump the first file */
1228 print_stats(method_name, file_name,
1229 t_loops, c_loops, d_loops,
1230 t_time, c_time, d_time,
1231 compressed_len, (unsigned long) file_data.len, blocks);
1232 if (total_method_name != c->name) {
1233 total_method_name = c->name;
1234 total_method_names += 1;
1237 return EXIT_OK;
1242 static
1243 int do_file ( int method, const char *file_name,
1244 long c_loops, long d_loops,
1245 lzo_uint32p p_adler, lzo_uint32p p_crc )
1247 int r;
1248 const compress_t *c;
1249 lzo_decompress_t decompress;
1250 lzo_uint32 adler, crc;
1251 char method_name[256+1];
1252 const char *n;
1253 const long t_loops = 1;
1255 adler_in = adler_out = 0;
1256 crc_in = crc_out = 0;
1257 if (p_adler)
1258 *p_adler = 0;
1259 if (p_crc)
1260 *p_crc = 0;
1262 c = find_method_by_id(method);
1263 if (c == NULL || c->name == NULL || c->compress == NULL)
1264 return EXIT_INTERNAL;
1265 decompress = get_decomp_info(c,&n);
1266 if (!decompress || n == NULL || block_w.len < c->mem_decompress)
1267 return EXIT_INTERNAL;
1268 strcpy(method_name,c->name);
1269 strcat(method_name,n);
1271 if (c_loops < 1) c_loops = 1;
1272 if (d_loops < 1) d_loops = 1;
1274 fflush(stdout); fflush(stderr);
1276 /* read the whole file */
1277 r = load_file(file_name, opt_max_data_len);
1278 if (r != 0)
1279 return r;
1281 /* compute some checksums */
1282 adler = lzo_adler32(0, NULL, 0);
1283 adler = lzo_adler32(adler, file_data.ptr, file_data.len);
1284 if (p_adler)
1285 *p_adler = adler;
1286 crc = lzo_crc32(0, NULL, 0);
1287 crc = lzo_crc32(crc, file_data.ptr, file_data.len);
1288 if (p_crc)
1289 *p_crc = crc;
1291 if (opt_verbose >= 2)
1293 printf("File %s: %lu bytes (0x%08lx, 0x%08lx)\n",
1294 file_name, (unsigned long) file_data.len, (unsigned long) adler, (unsigned long) crc);
1295 printf(" compressing %lu bytes (%ld/%ld/%ld loops, %lu block-size)\n",
1296 (unsigned long) file_data.len, t_loops, c_loops, d_loops, (unsigned long) opt_block_size);
1297 printf(" %s\n", method_name);
1300 r = process_file(c, decompress, method_name, file_name,
1301 t_loops, c_loops, d_loops);
1303 return r;
1307 /*************************************************************************
1308 // Calgary Corpus and Silesia Corpus test suite driver
1309 **************************************************************************/
1311 struct corpus_entry_t
1313 const char *name;
1314 long loops;
1315 lzo_uint32 adler;
1316 lzo_uint32 crc;
1319 const struct corpus_entry_t *opt_corpus = NULL;
1321 static const struct corpus_entry_t calgary_corpus[] =
1323 { "bib", 8, 0x4bd09e98L, 0xb856ebe8L },
1324 { "book1", 1, 0xd4d3613eL, 0x24e19972L },
1325 { "book2", 1, 0x6fe14cc3L, 0xba0f3f26L },
1326 { "geo", 6, 0xf3cc5be0L, 0x4d3a6ed0L },
1327 { "news", 2, 0x2ed405b8L, 0xcafac853L },
1328 { "obj1", 35, 0x3887dd2cL, 0xc7b0cd26L },
1329 { "obj2", 4, 0xf89407c4L, 0x3ae33007L },
1330 { "paper1", 17, 0xfe65ce62L, 0x2b6baca0L },
1331 { "paper2", 11, 0x1238b7c2L, 0xf76cba72L },
1332 { "pic", 4, 0xf61a5702L, 0x4b17e59cL },
1333 { "progc", 25, 0x4c00ba45L, 0x6fb16094L },
1334 { "progl", 20, 0x4cba738eL, 0xddbf6baaL },
1335 { "progp", 28, 0x7495b92bL, 0x493a1809L },
1336 { "trans", 15, 0x52a2cec8L, 0xcdec06a6L },
1337 { NULL, 0, 0x00000000L, 0x00000000L }
1340 static const struct corpus_entry_t silesia_corpus[] =
1342 { "dickens", 1, 0x170f606fL, 0xaf3a6b76L },
1343 { "mozilla", 1, 0x1188dd4eL, 0x7fb0ab7dL },
1344 { "mr", 1, 0xaea14b97L, 0xa341883fL },
1345 { "nci", 1, 0x0af16f1fL, 0x60ff63d3L },
1346 { "ooffice", 1, 0x83c8f689L, 0xa023e1faL },
1347 { "osdb", 1, 0xb825b790L, 0xa0ca388cL },
1348 { "reymont", 1, 0xce5c82caL, 0x50d35f03L },
1349 { "samba", 1, 0x19dbb9f5L, 0x2beac5f3L },
1350 { "sao", 1, 0x7edfc4a9L, 0xfda125bfL },
1351 { "webster", 1, 0xf2962fc6L, 0x01f5a2e9L },
1352 { "xml", 1, 0xeccd03d6L, 0xff8f3051L },
1353 { "x-ray", 1, 0xc95435a0L, 0xc86a35c6L },
1354 { NULL, 0, 0x00000000L, 0x00000000L }
1358 static
1359 int do_corpus ( const struct corpus_entry_t *corpus, int method, const char *path,
1360 long c_loops, long d_loops )
1362 size_t i, n;
1363 char name[256];
1365 if (path == NULL || strlen(path) >= sizeof(name) - 12)
1366 return EXIT_USAGE;
1368 strcpy(name,path);
1369 n = strlen(name);
1370 if (n > 0 && name[n-1] != '/' && name[n-1] != '\\' && name[n-1] != ':')
1372 strcat(name,"/");
1373 n++;
1376 for (i = 0; corpus[i].name != NULL; i++)
1378 lzo_uint32 adler, crc;
1379 long c = c_loops * corpus[i].loops;
1380 long d = d_loops * corpus[i].loops;
1381 int r;
1383 strcpy(name+n,corpus[i].name);
1384 r = do_file(method, name, c, d, &adler, &crc);
1385 if (r != 0)
1386 return r;
1387 if (adler != corpus[i].adler)
1389 printf(" invalid test suite\n");
1390 return EXIT_ADLER;
1392 if (corpus[i].crc && crc != corpus[i].crc)
1394 printf(" internal checksum error !! (0x%08lx 0x%08lx)\n",
1395 (unsigned long) crc, (unsigned long) corpus[i].crc);
1396 return EXIT_INTERNAL;
1399 return EXIT_OK;
1403 /*************************************************************************
1404 // usage
1405 **************************************************************************/
1407 static
1408 void usage ( const char *name, int exit_code, lzo_bool show_methods )
1410 FILE *fp;
1411 int i;
1413 fp = stdout;
1415 fflush(stdout); fflush(stderr);
1417 fprintf(fp,"Usage: %s [option..] file...\n", name);
1418 fprintf(fp,"\n");
1419 fprintf(fp,"Options:\n");
1420 fprintf(fp," -m# compression method\n");
1421 fprintf(fp," -b# set input block size (default %lu, max %lu)\n",
1422 (unsigned long) opt_block_size, (unsigned long) opt_max_data_len);
1423 fprintf(fp," -n# number of compression/decompression runs\n");
1424 fprintf(fp," -c# number of compression runs\n");
1425 fprintf(fp," -d# number of decompression runs\n");
1426 fprintf(fp," -S use safe decompressor (if available)\n");
1427 fprintf(fp," -A use assembler decompressor (if available)\n");
1428 fprintf(fp," -F use fast assembler decompressor (if available)\n");
1429 fprintf(fp," -O optimize compressed data (if available)\n");
1430 fprintf(fp," -s DIR process Calgary Corpus test suite in directory `DIR'\n");
1431 fprintf(fp," -@ read list of files to compress from stdin\n");
1432 fprintf(fp," -q be quiet\n");
1433 fprintf(fp," -Q be very quiet\n");
1434 fprintf(fp," -v be verbose\n");
1435 fprintf(fp," -L display software license\n");
1437 if (show_methods)
1439 #if defined(__ACCLIB_PCLOCK_CH_INCLUDED)
1440 lzo_uclock_t t_dummy;
1441 lzo_uclock_read(&uch, &t_dummy);
1442 (void) lzo_uclock_get_elapsed(&uch, &t_dummy, &t_dummy);
1443 fprintf(fp,"\nAll timings are recorded using uclock mode %d %s.\n", uch.mode, uch.name);
1444 #endif
1445 fprintf(fp,"\n\n");
1446 fprintf(fp,"The following compression methods are available:\n");
1447 fprintf(fp,"\n");
1448 fprintf(fp," usage name memory available extras\n");
1449 fprintf(fp," ----- ---- ------ ----------------\n");
1451 for (i = 0; i <= M_LAST_COMPRESSOR; i++)
1453 const compress_t *c;
1454 c = find_method_by_id(i);
1455 if (c)
1457 char n[16];
1458 const char *sep = " ";
1459 unsigned long m = c->mem_compress;
1461 sprintf(n,"-m%d",i);
1462 fprintf(fp," %-6s %-13s",n,c->name);
1463 #if 1
1464 fprintf(fp,"%9lu", m);
1465 #else
1466 m = (m + 1023) / 1024;
1467 fprintf(fp,"%6lu KiB", m);
1468 #endif
1470 if (c->decompress_safe)
1471 { fprintf(fp, "%s%s", sep, "safe"); sep = ", "; }
1472 if (c->decompress_asm)
1473 { fprintf(fp, "%s%s", sep, "asm"); sep = ", "; }
1474 if (c->decompress_asm_safe)
1475 { fprintf(fp, "%s%s", sep, "asm+safe"); sep = ", "; }
1476 if (c->decompress_asm_fast)
1477 { fprintf(fp, "%s%s", sep, "fastasm"); sep = ", "; }
1478 if (c->decompress_asm_fast_safe)
1479 { fprintf(fp, "%s%s", sep, "fastasm+safe"); sep = ", "; }
1480 if (c->optimize)
1481 { fprintf(fp, "%s%s", sep, "optimize"); sep = ", "; }
1482 fprintf(fp, "\n");
1486 else
1488 fprintf(fp,"\n");
1489 fprintf(fp,"Type '%s -m' to list all available methods.\n", name);
1492 fflush(fp);
1493 if (exit_code < 0)
1494 exit_code = EXIT_USAGE;
1495 exit(exit_code);
1499 static
1500 void license(void)
1502 FILE *fp;
1504 fp = stdout;
1505 fflush(stdout); fflush(stderr);
1507 #if defined(__LZO_PROFESSIONAL__)
1508 # include "lzopro/license.ch"
1509 #else
1510 fprintf(fp,
1511 " The LZO library is free software; you can redistribute it and/or\n"
1512 " modify it under the terms of the GNU General Public License as\n"
1513 " published by the Free Software Foundation; either version 2 of\n"
1514 " the License, or (at your option) any later version.\n"
1515 "\n"
1516 " The LZO library is distributed in the hope that it will be useful,\n"
1517 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1518 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1519 " GNU General Public License for more details.\n"
1521 fprintf(fp,
1522 "\n"
1523 " You should have received a copy of the GNU General Public License\n"
1524 " along with the LZO library; see the file COPYING.\n"
1525 " If not, write to the Free Software Foundation, Inc.,\n"
1526 " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
1527 "\n"
1528 " Markus F.X.J. Oberhumer\n"
1529 " <markus@oberhumer.com>\n"
1530 " http://www.oberhumer.com/opensource/lzo/\n"
1531 "\n"
1533 #endif
1535 fflush(fp);
1536 exit(EXIT_OK);
1540 /*************************************************************************
1541 // parse method option '-m'
1542 **************************************************************************/
1544 static int methods[256+1];
1545 static int methods_n = 0;
1547 static void add_method(int m)
1549 int i;
1551 if (m > 0)
1553 if (!find_method_by_id(m)) {
1554 fprintf(stdout,"%s: invalid method %d\n",progname,m);
1555 exit(EXIT_USAGE);
1558 for (i = 0; i < methods_n; i++)
1559 if (methods[i] == m)
1560 return;
1562 if (methods_n >= 256)
1564 fprintf(stderr,"%s: too many methods\n",progname);
1565 exit(EXIT_USAGE);
1568 methods[methods_n++] = m;
1569 methods[methods_n] = 0;
1574 static void add_methods(const int *ml)
1576 while (*ml != 0)
1577 add_method(*ml++);
1581 static void add_all_methods(int first, int last)
1583 int m;
1585 for (m = first; m <= last; m++)
1586 if (find_method_by_id(m) != NULL)
1587 add_method(m);
1591 static int m_strcmp(const char *a, const char *b)
1593 size_t n;
1595 if (a[0] == 0 || b[0] == 0)
1596 return 1;
1597 n = strlen(b);
1598 if (strncmp(a,b,n) == 0 && (a[n] == 0 || a[n] == ','))
1599 return 0;
1600 return 1;
1604 static lzo_bool m_strisdigit(const char *s)
1606 for (;;)
1608 if (!is_digit(*s))
1609 return 0;
1610 s++;
1611 if (*s == 0 || *s == ',')
1612 break;
1614 return 1;
1618 static void parse_methods(const char *p)
1620 const compress_t *c;
1622 for (;;)
1624 if (p == NULL || p[0] == 0)
1625 usage(progname,-1,1);
1626 else if ((c = find_method_by_name(p)) != NULL)
1627 add_method(c->id);
1628 else if (m_strcmp(p,"all") == 0 || m_strcmp(p,"avail") == 0)
1629 add_all_methods(1,M_LAST_COMPRESSOR);
1630 else if (m_strcmp(p,"ALL") == 0)
1632 add_all_methods(1,M_LAST_COMPRESSOR);
1633 add_all_methods(9721,9729);
1634 add_all_methods(9781,9789);
1636 else if (m_strcmp(p,"lzo") == 0)
1637 add_all_methods(1,M_MEMCPY);
1638 else if (m_strcmp(p,"bench") == 0)
1639 add_methods(benchmark_methods);
1640 else if (m_strcmp(p,"m1") == 0)
1641 add_methods(x1_methods);
1642 else if (m_strcmp(p,"m99") == 0)
1643 add_methods(x99_methods);
1644 else if (m_strcmp(p,"m999") == 0)
1645 add_methods(x999_methods);
1646 else if (m_strcmp(p,"1x999") == 0)
1647 add_all_methods(9721,9729);
1648 else if (m_strcmp(p,"1y999") == 0)
1649 add_all_methods(9821,9829);
1650 #if defined(ALG_ZLIB)
1651 else if (m_strcmp(p,"zlib") == 0)
1652 add_all_methods(M_ZLIB_8_1,M_ZLIB_8_9);
1653 #endif
1654 #if defined(ALG_BZIP2)
1655 else if (m_strcmp(p,"bzip2") == 0)
1656 add_all_methods(M_BZIP2_1,M_BZIP2_9);
1657 #endif
1658 #if defined(__LZO_PROFESSIONAL__)
1659 # include "lzopro/t_opt_m.ch"
1660 #endif
1661 else if (m_strisdigit(p))
1662 add_method(atoi(p));
1663 else
1665 printf("%s: invalid method '%s'\n\n",progname,p);
1666 exit(EXIT_USAGE);
1669 while (*p && *p != ',')
1670 p++;
1671 while (*p == ',')
1672 p++;
1673 if (*p == 0)
1674 return;
1679 /*************************************************************************
1680 // options
1681 **************************************************************************/
1683 enum {
1684 OPT_LONGOPT_ONLY = 512,
1685 OPT_ADLER32,
1686 OPT_CALGARY_CORPUS,
1687 OPT_CLEAR_WRKMEM,
1688 OPT_CRC32,
1689 OPT_DICT,
1690 OPT_DUMP,
1691 OPT_EXECUTION_TIME,
1692 OPT_MAX_DATA_LEN,
1693 OPT_MAX_DICT_LEN,
1694 OPT_SILESIA_CORPUS,
1695 OPT_UCLOCK,
1696 OPT_UNUSED
1699 static const struct acc_getopt_longopt_t longopts[] =
1701 /* { name has_arg *flag val } */
1702 {"help", 0, 0, 'h'+256}, /* give help */
1703 {"license", 0, 0, 'L'}, /* display software license */
1704 {"quiet", 0, 0, 'q'}, /* quiet mode */
1705 {"verbose", 0, 0, 'v'}, /* verbose mode */
1706 {"version", 0, 0, 'V'+256}, /* display version number */
1708 {"adler32", 0, 0, OPT_ADLER32},
1709 {"calgary-corpus", 1, 0, OPT_CALGARY_CORPUS},
1710 {"clear-wrkmem", 0, 0, OPT_CLEAR_WRKMEM},
1711 {"clock", 1, 0, OPT_UCLOCK},
1712 {"corpus", 1, 0, OPT_CALGARY_CORPUS},
1713 {"crc32", 0, 0, OPT_CRC32},
1714 {"dict", 1, 0, OPT_DICT},
1715 {"dump-compressed", 1, 0, OPT_DUMP},
1716 {"execution-time", 0, 0, OPT_EXECUTION_TIME},
1717 {"max-data-length", 1, 0, OPT_MAX_DATA_LEN},
1718 {"max-dict-length", 1, 0, OPT_MAX_DICT_LEN},
1719 {"silesia-corpus", 1, 0, OPT_SILESIA_CORPUS},
1720 {"uclock", 1, 0, OPT_UCLOCK},
1721 {"methods", 1, 0, 'm'},
1722 {"totals", 0, 0, 'T'},
1724 { 0, 0, 0, 0 }
1728 static int do_option(acc_getopt_p g, int optc)
1730 #define mfx_optarg g->optarg
1731 switch (optc)
1733 case 'A':
1734 opt_use_asm_decompressor = 1;
1735 break;
1736 case 'b':
1737 opt_block_size = 0; /* set to opt_max_data_len later */
1738 if (mfx_optarg)
1740 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1741 return optc;
1742 opt_block_size = atol(mfx_optarg);
1744 break;
1745 case 'c':
1746 case 'C':
1747 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1748 return optc;
1749 opt_c_loops = atol(mfx_optarg);
1750 break;
1751 case 'd':
1752 case 'D':
1753 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1754 return optc;
1755 opt_d_loops = atol(mfx_optarg);
1756 break;
1757 case 'F':
1758 opt_use_asm_fast_decompressor = 1;
1759 break;
1760 case 'h':
1761 case 'H':
1762 case '?':
1763 case 'h'+256:
1764 usage(progname,EXIT_OK,0);
1765 break;
1766 case 'L':
1767 license();
1768 break;
1769 case 'm':
1770 parse_methods(mfx_optarg);
1771 break;
1772 case 'n':
1773 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1774 return optc;
1775 opt_c_loops = opt_d_loops = atol(mfx_optarg);
1776 break;
1777 case 'O':
1778 opt_optimize_compressed_data = 1;
1779 break;
1780 case 'q':
1781 opt_verbose -= 1;
1782 break;
1783 case 'Q':
1784 opt_verbose = 0;
1785 break;
1786 case 's':
1787 case OPT_CALGARY_CORPUS:
1788 if (!mfx_optarg || !mfx_optarg[0])
1789 return optc;
1790 opt_corpus_path = mfx_optarg;
1791 opt_corpus = calgary_corpus;
1792 break;
1793 case OPT_SILESIA_CORPUS:
1794 if (!mfx_optarg || !mfx_optarg[0])
1795 return optc;
1796 opt_corpus_path = mfx_optarg;
1797 opt_corpus = silesia_corpus;
1798 break;
1799 case 'S':
1800 opt_use_safe_decompressor = 1;
1801 break;
1802 case 'T':
1803 opt_totals += 1;
1804 break;
1805 case 'v':
1806 opt_verbose += 1;
1807 break;
1808 case 'V':
1809 case 'V'+256:
1810 exit(EXIT_OK);
1811 break;
1812 case '@':
1813 opt_read_from_stdin = 1;
1814 break;
1816 case '1': case '2': case '3': case '4': case '5':
1817 case '6': case '7': case '8': case '9':
1818 /* this is a dirty hack... */
1819 if (g->shortpos == 0) {
1820 char m[2]; m[0] = (char) optc; m[1] = 0;
1821 parse_methods(m);
1822 } else {
1823 const char *m = &g->argv[g->optind][g->shortpos-1];
1824 parse_methods(m);
1825 ++g->optind; g->shortpos = 0;
1827 break;
1829 case OPT_ADLER32:
1830 opt_compute_adler32 = 1;
1831 break;
1832 case OPT_CLEAR_WRKMEM:
1833 opt_clear_wrkmem = 1;
1834 break;
1835 case OPT_CRC32:
1836 opt_compute_crc32 = 1;
1837 break;
1838 case OPT_DICT:
1839 opt_dict = 1;
1840 opt_dictionary_file = mfx_optarg;
1841 break;
1842 case OPT_EXECUTION_TIME:
1843 opt_execution_time = 1;
1844 break;
1845 case OPT_DUMP:
1846 opt_dump_compressed_data = mfx_optarg;
1847 break;
1848 case OPT_MAX_DATA_LEN:
1849 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1850 return optc;
1851 opt_max_data_len = atol(mfx_optarg);
1852 break;
1853 case OPT_MAX_DICT_LEN:
1854 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1855 return optc;
1856 opt_max_dict_len = atol(mfx_optarg);
1857 break;
1858 case OPT_UCLOCK:
1859 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1860 return optc;
1861 opt_uclock = atoi(mfx_optarg);
1862 #if defined(__ACCLIB_PCLOCK_CH_INCLUDED)
1863 if (opt_uclock > 0)
1864 uch.mode = opt_uclock;
1865 #endif
1866 break;
1868 case '\0':
1869 return -1;
1870 case ':':
1871 return -2;
1872 default:
1873 fprintf(stderr,"%s: internal error in getopt (%d)\n",progname,optc);
1874 return -3;
1876 return 0;
1877 #undef mfx_optarg
1881 static void handle_opterr(acc_getopt_p g, const char *f, void *v)
1883 struct A { va_list ap; };
1884 struct A *a = (struct A *) v;
1885 fprintf( stderr, "%s: ", g->progname);
1886 if (a)
1887 vfprintf(stderr, f, a->ap);
1888 else
1889 fprintf( stderr, "UNKNOWN GETOPT ERROR");
1890 fprintf( stderr, "\n");
1894 static int get_options(int argc, char **argv)
1896 acc_getopt_t mfx_getopt;
1897 int optc;
1898 static const char shortopts[] =
1899 "Ab::c:C:d:D:FhHLm::n:OqQs:STvV@123456789";
1901 acc_getopt_init(&mfx_getopt, 1, argc, argv);
1902 mfx_getopt.progname = progname;
1903 mfx_getopt.opterr = handle_opterr;
1904 while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, NULL)) >= 0)
1906 if (do_option(&mfx_getopt, optc) != 0)
1907 exit(EXIT_USAGE);
1910 return mfx_getopt.optind;
1914 /*************************************************************************
1915 // main
1916 **************************************************************************/
1918 int __lzo_cdecl_main main(int argc, char *argv[])
1920 int r = EXIT_OK;
1921 int i, ii;
1922 int m;
1923 time_t t_total;
1924 const char *s;
1926 lzo_wildargv(&argc, &argv);
1927 lzo_uclock_open(&uch);
1929 progname = argv[0];
1930 for (s = progname; *s; s++)
1931 if ((*s == '/' || *s == '\\') && s[1])
1932 progname = s + 1;
1934 #if defined(__LZO_PROFESSIONAL__)
1935 printf("\nLZO Professional real-time data compression library (v%s, %s).\n",
1936 lzo_version_string(), lzo_version_date());
1937 printf("Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\nAll Rights Reserved.\n\n");
1938 #else
1939 printf("\nLZO real-time data compression library (v%s, %s).\n",
1940 lzo_version_string(), lzo_version_date());
1941 printf("Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\nAll Rights Reserved.\n\n");
1942 #endif
1946 * Step 1: initialize the LZO library
1949 if (lzo_init() != LZO_E_OK)
1951 printf("internal error - lzo_init() failed !!!\n");
1952 printf("(this usually indicates a compiler bug - try recompiling\nwithout optimizations, and enable `-DLZO_DEBUG' for diagnostics)\n");
1953 exit(1);
1958 * Step 2: setup default options
1961 opt_max_data_len = 64 * 1024L * 1024L;
1962 opt_block_size = 256 * 1024L;
1964 #if defined(LZO_ARCH_I086) && defined(ACC_MM_AHSHIFT)
1965 # if 1 && defined(LZO_ARCH_I086PM) && defined(BLX286)
1966 opt_max_data_len = 32 * 1024L * 1024L;
1967 # else
1968 opt_max_data_len = 14 * 1024L * 1024L;
1969 # endif
1970 /* reduce memory requirements for ancient 16-bit DOS 640kB real-mode */
1971 if (ACC_MM_AHSHIFT != 3) {
1972 opt_max_data_len = 16 * 1024L;
1974 #elif defined(LZO_OS_TOS)
1975 /* reduce memory requirements for 14 MB machines */
1976 opt_max_data_len = 8 * 1024L * 1024L;
1977 #endif
1982 * Step 3: parse options
1985 if (argc < 2)
1986 usage(progname,-1,0);
1987 i = get_options(argc,argv);
1989 if (methods_n == 0)
1990 add_method(default_method);
1991 if (methods_n > 1 && opt_read_from_stdin)
1993 printf("%s: cannot use multiple methods and '-@'\n", progname);
1994 exit(EXIT_USAGE);
1997 if (opt_block_size == 0)
1998 opt_block_size = opt_max_data_len;
1999 if (opt_block_size > opt_max_data_len)
2000 opt_block_size = opt_max_data_len;
2002 if (opt_c_loops < 1)
2003 opt_c_loops = 1;
2004 if (opt_d_loops < 1)
2005 opt_d_loops = 1;
2009 * Step 4: start work
2012 block_w.len = 0;
2013 for (ii = 0; ii < methods_n; ii++) {
2014 const compress_t *c = find_method_by_id(methods[ii]);
2015 assert(c != NULL);
2016 if (c->mem_compress > block_w.len)
2017 block_w.len = c->mem_compress;
2018 if (c->mem_decompress > block_w.len)
2019 block_w.len = c->mem_decompress;
2022 mb_alloc(&block_w, block_w.len);
2023 lzo_memset(block_w.ptr, 0, block_w.len);
2025 #if !defined(__LZO_CHECKER)
2026 mb_alloc_extra(&block_c, opt_block_size + get_max_compression_expansion(-1, opt_block_size), 16, 16);
2027 mb_alloc_extra(&block_d, opt_block_size + get_max_decompression_overrun(-1, opt_block_size), 16, 16);
2028 #endif
2030 if (opt_dict)
2032 opt_optimize_compressed_data = 0;
2033 dict_alloc(opt_max_dict_len);
2034 if (opt_dictionary_file)
2036 dict_load(opt_dictionary_file);
2037 if (dict.len > 0)
2038 printf("Using dictionary '%s', %lu bytes, ID 0x%08lx.\n",
2039 opt_dictionary_file,
2040 (unsigned long) dict.len, (unsigned long) dict.adler);
2042 if (dict.len == 0)
2044 dict_set_default();
2045 printf("Using default dictionary, %lu bytes, ID 0x%08lx.\n",
2046 (unsigned long) dict.len, (unsigned long) dict.adler);
2050 t_total = time(NULL);
2051 ii = i;
2052 for (m = 0; m < methods_n && r == EXIT_OK; m++)
2054 int method = methods[m];
2056 i = ii;
2057 if (i >= argc && opt_corpus_path == NULL && !opt_read_from_stdin)
2058 usage(progname,-1,0);
2059 if (m == 0 && opt_verbose >= 1)
2060 printf("%lu block-size\n\n", (unsigned long) opt_block_size);
2062 assert(find_method_by_id(method) != NULL);
2064 if (opt_corpus_path != NULL)
2065 r = do_corpus(opt_corpus, method, opt_corpus_path,
2066 opt_c_loops, opt_d_loops);
2067 else
2069 for ( ; i < argc && r == EXIT_OK; i++)
2071 r = do_file(method,argv[i],opt_c_loops,opt_d_loops,NULL,NULL);
2072 if (r == EXIT_FILE) /* ignore file errors */
2073 r = EXIT_OK;
2075 if (opt_read_from_stdin)
2077 char buf[512], *p;
2079 while (r == EXIT_OK && fgets(buf,sizeof(buf)-1,stdin) != NULL)
2081 buf[sizeof(buf)-1] = 0;
2082 p = buf + strlen(buf);
2083 while (p > buf && is_space(p[-1]))
2084 *--p = 0;
2085 p = buf;
2086 while (*p && is_space(*p))
2087 p++;
2088 if (*p)
2089 r = do_file(method,p,opt_c_loops,opt_d_loops,NULL,NULL);
2090 if (r == EXIT_FILE) /* ignore file errors */
2091 r = EXIT_OK;
2093 opt_read_from_stdin = 0;
2097 t_total = time(NULL) - t_total;
2099 if (opt_totals)
2100 print_totals();
2101 if (opt_execution_time || (methods_n > 1 && opt_verbose >= 1))
2102 printf("\n%s: execution time: %lu seconds\n", progname, (unsigned long) t_total);
2103 if (r != EXIT_OK)
2104 printf("\n%s: exit code: %d\n", progname, r);
2106 lzo_uclock_close(&uch);
2107 return r;
2112 vi:ts=4:et