1 /* lzotest.c -- very comprehensive test driver for the LZO library
2
3 This file is part of the LZO real-time data compression library.
4
5 Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
6 All Rights Reserved.
7
8 The LZO library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of
11 the License, or (at your option) any later version.
12
13 The LZO library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with the LZO library; see the file COPYING.
20 If not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
23 Markus F.X.J. Oberhumer
24 <markus@oberhumer.com>
25 http://www.oberhumer.com/opensource/lzo/
26 */
27
28
29 #include <lzo/lzoconf.h>
30
31
32 /*************************************************************************
33 // util
34 **************************************************************************/
35
36 /* portability layer */
37 #define WANT_LZO_MALLOC 1
38 #define WANT_LZO_FREAD 1
39 #define WANT_LZO_WILDARGV 1
40 #define WANT_LZO_PCLOCK 1
41 #define LZO_WANT_ACCLIB_GETOPT 1
42 #include "examples/portab.h"
43
44 #if defined(HAVE_STRNICMP) && !defined(HAVE_STRNCASECMP)
45 # define strncasecmp(a,b,c) strnicmp(a,b,c)
46 # define HAVE_STRNCASECMP 1
47 #endif
48
49 #if 0
50 # define is_digit(x) (isdigit((unsigned char)(x)))
51 # define is_space(x) (isspace((unsigned char)(x)))
52 #else
53 # define is_digit(x) ((unsigned)(x) - '0' <= 9)
54 # define is_space(x) ((x)==' ' || (x)=='\t' || (x)=='\r' || (x)=='\n')
55 #endif
56
57
58 /*************************************************************************
59 // compression include section
60 **************************************************************************/
61
62 #define HAVE_LZO1_H 1
63 #define HAVE_LZO1A_H 1
64 #define HAVE_LZO1B_H 1
65 #define HAVE_LZO1C_H 1
66 #define HAVE_LZO1F_H 1
67 #define HAVE_LZO1X_H 1
68 #define HAVE_LZO1Y_H 1
69 #define HAVE_LZO1Z_H 1
70 #define HAVE_LZO2A_H 1
71
72 #if defined(NO_ZLIB_H) || (SIZEOF_INT < 4)
73 #undef HAVE_ZLIB_H
74 #endif
75 #if defined(NO_BZLIB_H) || (SIZEOF_INT != 4)
76 #undef HAVE_BZLIB_H
77 #endif
78
79 #if 0 && defined(LZO_OS_DOS16)
80 /* don't make this test program too big */
81 #undef HAVE_LZO1_H
82 #undef HAVE_LZO1A_H
83 #undef HAVE_LZO1C_H
84 #undef HAVE_LZO1Z_H
85 #undef HAVE_LZO2A_H
86 #undef HAVE_LZO2B_H
87 #undef HAVE_ZLIB_H
88 #endif
89
90
91 /* LZO algorithms */
92 #if defined(HAVE_LZO1_H)
93 # include <lzo/lzo1.h>
94 #endif
95 #if defined(HAVE_LZO1A_H)
96 # include <lzo/lzo1a.h>
97 #endif
98 #if defined(HAVE_LZO1B_H)
99 # include <lzo/lzo1b.h>
100 #endif
101 #if defined(HAVE_LZO1C_H)
102 # include <lzo/lzo1c.h>
103 #endif
104 #if defined(HAVE_LZO1F_H)
105 # include <lzo/lzo1f.h>
106 #endif
107 #if defined(HAVE_LZO1X_H)
108 # include <lzo/lzo1x.h>
109 #endif
110 #if defined(HAVE_LZO1Y_H)
111 # include <lzo/lzo1y.h>
112 #endif
113 #if defined(HAVE_LZO1Z_H)
114 # include <lzo/lzo1z.h>
115 #endif
116 #if defined(HAVE_LZO2A_H)
117 # include <lzo/lzo2a.h>
118 #endif
119 #if defined(HAVE_LZO2B_H)
120 # include <lzo/lzo2b.h>
121 #endif
122 /* other compressors */
123 #if defined(HAVE_ZLIB_H)
124 # include <zlib.h>
125 # define ALG_ZLIB 1
126 #endif
127 #if defined(HAVE_BZLIB_H)
128 # include <bzlib.h>
129 # define ALG_BZIP2 1
130 #endif
131
132
133 /*************************************************************************
134 // enumerate all methods
135 **************************************************************************/
136
137 enum {
138 /* compression algorithms */
139 M_LZO1B_1 = 1,
140 M_LZO1B_2, M_LZO1B_3, M_LZO1B_4, M_LZO1B_5,
141 M_LZO1B_6, M_LZO1B_7, M_LZO1B_8, M_LZO1B_9,
142
143 M_LZO1C_1 = 11,
144 M_LZO1C_2, M_LZO1C_3, M_LZO1C_4, M_LZO1C_5,
145 M_LZO1C_6, M_LZO1C_7, M_LZO1C_8, M_LZO1C_9,
146
147 M_LZO1 = 21,
148 M_LZO1A = 31,
149
150 M_LZO1B_99 = 901,
151 M_LZO1B_999 = 902,
152 M_LZO1C_99 = 911,
153 M_LZO1C_999 = 912,
154 M_LZO1_99 = 921,
155 M_LZO1A_99 = 931,
156
157 M_LZO1F_1 = 61,
158 M_LZO1F_999 = 962,
159 M_LZO1X_1 = 71,
160 M_LZO1X_1_11 = 111,
161 M_LZO1X_1_12 = 112,
162 M_LZO1X_1_15 = 115,
163 M_LZO1X_999 = 972,
164 M_LZO1Y_1 = 81,
165 M_LZO1Y_999 = 982,
166 M_LZO1Z_999 = 992,
167
168 M_LZO2A_999 = 942,
169 M_LZO2B_999 = 952,
170
171 M_LAST_LZO_COMPRESSOR = 998,
172
173 /* other compressors */
174 #if defined(ALG_ZLIB)
175 M_ZLIB_8_1 = 1101,
176 M_ZLIB_8_2, M_ZLIB_8_3, M_ZLIB_8_4, M_ZLIB_8_5,
177 M_ZLIB_8_6, M_ZLIB_8_7, M_ZLIB_8_8, M_ZLIB_8_9,
178 #endif
179 #if defined(ALG_BZIP2)
180 M_BZIP2_1 = 1201,
181 M_BZIP2_2, M_BZIP2_3, M_BZIP2_4, M_BZIP2_5,
182 M_BZIP2_6, M_BZIP2_7, M_BZIP2_8, M_BZIP2_9,
183 #endif
184
185 /* dummy compressor - for benchmarking */
186 M_MEMCPY = 999,
187
188 M_LAST_COMPRESSOR = 4999,
189
190 /* dummy algorithms - for benchmarking */
191 M_MEMSET = 5001,
192
193 /* checksum algorithms - for benchmarking */
194 M_ADLER32 = 6001,
195 M_CRC32 = 6002,
196 #if defined(ALG_ZLIB)
197 M_Z_ADLER32 = 6011,
198 M_Z_CRC32 = 6012,
199 #endif
200
201 M_UNUSED
202 };
203
204
205 /*************************************************************************
206 // command line options
207 **************************************************************************/
208
209 int opt_verbose = 1;
210
211 long opt_c_loops = 0;
212 long opt_d_loops = 0;
213 const char *opt_corpus_path = NULL;
214 const char *opt_dump_compressed_data = NULL;
215
216 lzo_bool opt_use_safe_decompressor = 0;
217 lzo_bool opt_use_asm_decompressor = 0;
218 lzo_bool opt_use_asm_fast_decompressor = 0;
219 lzo_bool opt_optimize_compressed_data = 0;
220
221 int opt_dict = 0;
222 lzo_uint opt_max_dict_len = LZO_UINT_MAX;
223 const char *opt_dictionary_file = NULL;
224
225 lzo_bool opt_read_from_stdin = 0;
226
227 /* set these to 1 to measure the speed impact of a checksum */
228 lzo_bool opt_compute_adler32 = 0;
229 lzo_bool opt_compute_crc32 = 0;
230 static lzo_uint32_t adler_in, adler_out;
231 static lzo_uint32_t crc_in, crc_out;
232
233 lzo_bool opt_execution_time = 0;
234 int opt_pclock = -1;
235 lzo_bool opt_clear_wrkmem = 0;
236
237 static const lzo_bool opt_try_to_compress_0_bytes = 1;
238
239
240 /*************************************************************************
241 // misc globals
242 **************************************************************************/
243
244 static const char *progname = "";
245 static lzo_pclock_handle_t pch;
246
247 /* for statistics and benchmark */
248 int opt_totals = 0;
249 static unsigned long total_n = 0;
250 static unsigned long total_c_len = 0;
251 static unsigned long total_d_len = 0;
252 static unsigned long total_blocks = 0;
253 static double total_perc = 0.0;
254 static const char *total_method_name = NULL;
255 static unsigned total_method_names = 0;
256 /* Note: the average value of a rate (e.g. compression speed) is defined
257 * by the Harmonic Mean (and _not_ by the Arithmethic Mean ) */
258 static unsigned long total_c_mbs_n = 0;
259 static unsigned long total_d_mbs_n = 0;
260 static double total_c_mbs_harmonic = 0.0;
261 static double total_d_mbs_harmonic = 0.0;
262 static double total_c_mbs_sum = 0.0;
263 static double total_d_mbs_sum = 0.0;
264
265
266 #if defined(HAVE_LZO1X_H)
267 int default_method = M_LZO1X_1;
268 #elif defined(HAVE_LZO1B_H)
269 int default_method = M_LZO1B_1;
270 #elif defined(HAVE_LZO1C_H)
271 int default_method = M_LZO1C_1;
272 #elif defined(HAVE_LZO1F_H)
273 int default_method = M_LZO1F_1;
274 #elif defined(HAVE_LZO1Y_H)
275 int default_method = M_LZO1Y_1;
276 #else
277 int default_method = M_MEMCPY;
278 #endif
279
280
281 static const int benchmark_methods[] = {
282 M_LZO1B_1, M_LZO1B_9,
283 M_LZO1C_1, M_LZO1C_9,
284 M_LZO1F_1,
285 M_LZO1X_1,
286 0
287 };
288
289 static const int x1_methods[] = {
290 M_LZO1, M_LZO1A, M_LZO1B_1, M_LZO1C_1, M_LZO1F_1, M_LZO1X_1, M_LZO1Y_1,
291 0
292 };
293
294 static const int x99_methods[] = {
295 M_LZO1_99, M_LZO1A_99, M_LZO1B_99, M_LZO1C_99,
296 0
297 };
298
299 static const int x999_methods[] = {
300 M_LZO1B_999, M_LZO1C_999, M_LZO1F_999, M_LZO1X_999, M_LZO1Y_999,
301 M_LZO1Z_999,
302 M_LZO2A_999,
303 0
304 };
305
306
307 /* exit codes of this test program */
308 #define EXIT_OK 0
309 #define EXIT_USAGE 1
310 #define EXIT_FILE 2
311 #define EXIT_MEM 3
312 #define EXIT_ADLER 4
313 #define EXIT_LZO_ERROR 5
314 #define EXIT_LZO_INIT 6
315 #define EXIT_INTERNAL 7
316
317
318 /*************************************************************************
319 // memory setup
320 **************************************************************************/
321
322 static lzo_uint opt_block_size;
323 static lzo_uint opt_max_data_len;
324
325 typedef struct {
326 lzo_bytep ptr;
327 lzo_uint len;
328 lzo_uint32_t adler;
329 lzo_uint32_t crc;
330 lzo_bytep alloc_ptr;
331 lzo_uint alloc_len;
332 lzo_uint saved_len;
333 } mblock_t;
334
335 static mblock_t file_data; /* original uncompressed data */
336 static mblock_t block_c; /* compressed data */
337 static mblock_t block_d; /* decompressed data */
338 static mblock_t block_w; /* wrkmem */
339 static mblock_t dict;
340
341
mb_alloc_extra(mblock_t * mb,lzo_uint len,lzo_uint extra_bottom,lzo_uint extra_top)342 static void mb_alloc_extra(mblock_t *mb, lzo_uint len, lzo_uint extra_bottom, lzo_uint extra_top)
343 {
344 lzo_uint align = (lzo_uint) sizeof(lzo_align_t);
345
346 mb->alloc_ptr = mb->ptr = NULL;
347 mb->alloc_len = mb->len = 0;
348
349 mb->alloc_len = extra_bottom + len + extra_top;
350 if (mb->alloc_len == 0) mb->alloc_len = 1;
351 mb->alloc_ptr = (lzo_bytep) lzo_malloc(mb->alloc_len);
352
353 if (mb->alloc_ptr == NULL) {
354 fprintf(stderr, "%s: out of memory (wanted %lu bytes)\n", progname, (unsigned long)mb->alloc_len);
355 exit(EXIT_MEM);
356 }
357 if (mb->alloc_len >= align && __lzo_align_gap(mb->alloc_ptr, align) != 0) {
358 fprintf(stderr, "%s: C library problem: malloc() returned misaligned pointer!\n", progname);
359 exit(EXIT_MEM);
360 }
361
362 mb->ptr = mb->alloc_ptr + extra_bottom;
363 mb->len = mb->saved_len = len;
364 mb->adler = 1;
365 mb->crc = 0;
366 }
367
368
mb_alloc(mblock_t * mb,lzo_uint len)369 static void mb_alloc(mblock_t *mb, lzo_uint len)
370 {
371 mb_alloc_extra(mb, len, 0, 0);
372 }
373
374
mb_free(mblock_t * mb)375 static void mb_free(mblock_t *mb)
376 {
377 if (!mb) return;
378 if (mb->alloc_ptr) lzo_free(mb->alloc_ptr);
379 mb->alloc_ptr = mb->ptr = NULL;
380 mb->alloc_len = mb->len = 0;
381 }
382
383
get_max_compression_expansion(int m,lzo_uint bl)384 static lzo_uint get_max_compression_expansion(int m, lzo_uint bl)
385 {
386 if (m == M_MEMCPY || m >= M_LAST_COMPRESSOR)
387 return 0;
388 if (m == M_LZO2A_999 || m == M_LZO2B_999)
389 return bl / 8 + 256;
390 if (m > 0 && m < M_LAST_LZO_COMPRESSOR)
391 return bl / 16 + 64 + 3;
392 return bl / 8 + 256;
393 }
394
get_max_decompression_overrun(int m,lzo_uint bl)395 static lzo_uint get_max_decompression_overrun(int m, lzo_uint bl)
396 {
397 LZO_UNUSED(m);
398 LZO_UNUSED(bl);
399 /* may overwrite 3 bytes past the end of the decompressed block */
400 if (opt_use_asm_fast_decompressor)
401 return (lzo_uint) sizeof(lzo_voidp) - 1;
402 return 0;
403 }
404
405
406 /*************************************************************************
407 // dictionary support
408 **************************************************************************/
409
dict_alloc(lzo_uint max_dict_len)410 static void dict_alloc(lzo_uint max_dict_len)
411 {
412 lzo_uint l = 0xbfff; /* MAX_DICT_LEN */
413 if (max_dict_len > 0 && l > max_dict_len)
414 l = max_dict_len;
415 mb_alloc(&dict, l);
416 }
417
418
419 /* this default dictionary does not provide good contexts... */
dict_set_default(void)420 static void dict_set_default(void)
421 {
422 lzo_uint d = 0;
423 unsigned i, j;
424
425 dict.len = 16 * 256;
426 if (dict.len > dict.alloc_len)
427 dict.len = dict.alloc_len;
428
429 lzo_memset(dict.ptr, 0, dict.len);
430
431 for (i = 0; i < 256; i++)
432 for (j = 0; j < 16; j++) {
433 if (d >= dict.len)
434 goto done;
435 dict.ptr[d++] = (unsigned char) i;
436 }
437
438 done:
439 dict.adler = lzo_adler32(1, dict.ptr, dict.len);
440 }
441
442
dict_load(const char * file_name)443 static void dict_load(const char *file_name)
444 {
445 FILE *fp;
446
447 dict.len = 0;
448 fp = fopen(file_name, "rb");
449 if (fp)
450 {
451 dict.len = (lzo_uint) lzo_fread(fp, dict.ptr, dict.alloc_len);
452 (void) fclose(fp);
453 dict.adler = lzo_adler32(1, dict.ptr, dict.len);
454 }
455 }
456
457
458 /*************************************************************************
459 // compression database
460 **************************************************************************/
461
462 typedef struct
463 {
464 const char * name;
465 int id;
466 lzo_uint32_t mem_compress;
467 lzo_uint32_t mem_decompress;
468 lzo_compress_t compress;
469 lzo_optimize_t optimize;
470 lzo_decompress_t decompress;
471 lzo_decompress_t decompress_safe;
472 lzo_decompress_t decompress_asm;
473 lzo_decompress_t decompress_asm_safe;
474 lzo_decompress_t decompress_asm_fast;
475 lzo_decompress_t decompress_asm_fast_safe;
476 lzo_compress_dict_t compress_dict;
477 lzo_decompress_dict_t decompress_dict_safe;
478 }
479 compress_t;
480
481 #include "asm.h"
482
483 #ifdef __cplusplus
484 extern "C" {
485 #endif
486 #include "wrap.h"
487 #define M_PRIVATE LZO_PRIVATE
488 #define m_uint lzo_uint
489 #define m_uint32_t lzo_uint32_t
490 #define m_voidp lzo_voidp
491 #define m_bytep lzo_bytep
492 #define m_uintp lzo_uintp
493 #include "wrapmisc.h"
494 #ifdef __cplusplus
495 } /* extern "C" */
496 #endif
497
498 static const compress_t compress_database[] = {
499 #include "db.h"
500 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
501 };
502
503
504 /*************************************************************************
505 // method info
506 **************************************************************************/
507
508 static
get_decomp_info(const compress_t * c,const char ** nn)509 lzo_decompress_t get_decomp_info ( const compress_t *c, const char **nn )
510 {
511 lzo_decompress_t d = 0;
512 const char *n = NULL;
513
514 /* safe has priority over asm/fast */
515 if (!d && opt_use_safe_decompressor && opt_use_asm_fast_decompressor)
516 {
517 d = c->decompress_asm_fast_safe;
518 n = " [fs]";
519 }
520 if (!d && opt_use_safe_decompressor && opt_use_asm_decompressor)
521 {
522 d = c->decompress_asm_safe;
523 n = " [as]";
524 }
525 if (!d && opt_use_safe_decompressor)
526 {
527 d = c->decompress_safe;
528 n = " [s]";
529 }
530 if (!d && opt_use_asm_fast_decompressor)
531 {
532 d = c->decompress_asm_fast;
533 n = " [f]";
534 }
535 if (!d && opt_use_asm_decompressor)
536 {
537 d = c->decompress_asm;
538 n = " [a]";
539 }
540 if (!d)
541 {
542 d = c->decompress;
543 n = "";
544 }
545 if (!d)
546 n = "(null)";
547
548 if (opt_dict && c->decompress_dict_safe)
549 n = "";
550
551 if (nn)
552 *nn = n;
553 return d;
554 }
555
556
557 static
find_method_by_id(int method)558 const compress_t *find_method_by_id ( int method )
559 {
560 const compress_t *db;
561 size_t size = sizeof(compress_database) / sizeof(*(compress_database));
562 size_t i;
563
564 db = compress_database;
565 for (i = 0; i < size && db->name != NULL; i++, db++)
566 {
567 if (method == db->id)
568 return db;
569 }
570 return NULL;
571 }
572
573
574 static
find_method_by_name(const char * name)575 const compress_t *find_method_by_name ( const char *name )
576 {
577 const compress_t *db;
578 size_t size = sizeof(compress_database) / sizeof(*(compress_database));
579 size_t i;
580
581 db = compress_database;
582 for (i = 0; i < size && db->name != NULL; i++, db++)
583 {
584 size_t n = strlen(db->name);
585
586 #if defined(HAVE_STRNCASECMP)
587 if (strncasecmp(name,db->name,n) == 0 && (!name[n] || name[n] == ','))
588 return db;
589 #else
590 if (strncmp(name,db->name,n) == 0 && (!name[n] || name[n] == ','))
591 return db;
592 #endif
593 }
594 return NULL;
595 }
596
597
598 static
is_compressor(const compress_t * c)599 lzo_bool is_compressor ( const compress_t *c )
600 {
601 return (c->id <= M_LAST_COMPRESSOR || c->id >= 9721);
602 }
603
604
605 /*************************************************************************
606 // check that memory gets accessed within bounds
607 **************************************************************************/
608
memchecker_init(mblock_t * mb,lzo_uint l,unsigned char random_byte)609 static void memchecker_init ( mblock_t *mb, lzo_uint l, unsigned char random_byte )
610 {
611 lzo_uint i;
612 lzo_uint len = (lzo_uint) l;
613 lzo_bytep p;
614
615 assert(len <= mb->len);
616
617 /* bottom */
618 p = mb->ptr;
619 for (i = 0; i < 16 && p > mb->alloc_ptr; i++)
620 *--p = random_byte++;
621 /* top */
622 p = mb->ptr + len;
623 for (i = 0; i < 16 && p < mb->alloc_ptr + mb->alloc_len; i++)
624 *p++ = random_byte++;
625 #if 0 || defined(LZO_DEBUG)
626 /* fill in garbage */
627 p = mb->ptr;
628 random_byte |= 1;
629 for (i = 0; i < len; i++, random_byte += 2)
630 *p++ = random_byte;
631 #endif
632 }
633
634
memchecker_check(mblock_t * mb,lzo_uint l,unsigned char random_byte)635 static int memchecker_check ( mblock_t *mb, lzo_uint l, unsigned char random_byte )
636 {
637 lzo_uint i;
638 lzo_uint len = (lzo_uint) l;
639 lzo_bytep p;
640
641 assert(len <= mb->len);
642
643 /* bottom */
644 p = mb->ptr;
645 for (i = 0; i < 16 && p > mb->alloc_ptr; i++)
646 if (*--p != random_byte++)
647 return -1;
648 /* top */
649 p = mb->ptr + len;
650 for (i = 0; i < 16 && p < mb->alloc_ptr + mb->alloc_len; i++)
651 if (*p++ != random_byte++)
652 return -1;
653 return 0;
654 }
655
656
657 /*************************************************************************
658 // compress a block
659 **************************************************************************/
660
661 static
call_compressor(const compress_t * c,const lzo_bytep src,lzo_uint src_len,lzo_bytep dst,lzo_uintp dst_len)662 int call_compressor ( const compress_t *c,
663 const lzo_bytep src, lzo_uint src_len,
664 lzo_bytep dst, lzo_uintp dst_len )
665 {
666 int r = -100;
667
668 if (c && c->compress && block_w.len >= c->mem_compress)
669 {
670 unsigned char random_byte = (unsigned char) src_len;
671 memchecker_init(&block_w, c->mem_compress, random_byte);
672 if (opt_clear_wrkmem)
673 lzo_memset(block_w.ptr, 0, c->mem_compress);
674
675 if (opt_dict && c->compress_dict)
676 r = c->compress_dict(src,src_len,dst,dst_len,block_w.ptr,dict.ptr,dict.len);
677 else
678 r = c->compress(src,src_len,dst,dst_len,block_w.ptr);
679
680 if (memchecker_check(&block_w, c->mem_compress, random_byte) != 0)
681 printf("WARNING: wrkmem overwrite error (compress) !!!\n");
682 }
683
684 if (r == 0 && opt_compute_adler32)
685 {
686 lzo_uint32_t adler;
687 adler = lzo_adler32(0, NULL, 0);
688 adler = lzo_adler32(adler, src, src_len);
689 adler_in = adler;
690 }
691 if (r == 0 && opt_compute_crc32)
692 {
693 lzo_uint32_t crc;
694 crc = lzo_crc32(0, NULL, 0);
695 crc = lzo_crc32(crc, src, src_len);
696 crc_in = crc;
697 }
698
699 return r;
700 }
701
702
703 /*************************************************************************
704 // decompress a block
705 **************************************************************************/
706
707 static
call_decompressor(const compress_t * c,lzo_decompress_t d,const lzo_bytep src,lzo_uint src_len,lzo_bytep dst,lzo_uintp dst_len)708 int call_decompressor ( const compress_t *c, lzo_decompress_t d,
709 const lzo_bytep src, lzo_uint src_len,
710 lzo_bytep dst, lzo_uintp dst_len )
711 {
712 int r = -100;
713
714 if (c && d && block_w.len >= c->mem_decompress)
715 {
716 unsigned char random_byte = (unsigned char) src_len;
717 memchecker_init(&block_w, c->mem_decompress, random_byte);
718 if (opt_clear_wrkmem)
719 lzo_memset(block_w.ptr, 0, c->mem_decompress);
720
721 if (opt_dict && c->decompress_dict_safe)
722 r = c->decompress_dict_safe(src,src_len,dst,dst_len,block_w.ptr,dict.ptr,dict.len);
723 else
724 r = d(src,src_len,dst,dst_len,block_w.ptr);
725
726 if (memchecker_check(&block_w, c->mem_decompress, random_byte) != 0)
727 printf("WARNING: wrkmem overwrite error (decompress) !!!\n");
728 }
729
730 if (r == 0 && opt_compute_adler32)
731 adler_out = lzo_adler32(1, dst, *dst_len);
732 if (r == 0 && opt_compute_crc32)
733 crc_out = lzo_crc32(0, dst, *dst_len);
734
735 return r;
736 }
737
738
739 /*************************************************************************
740 // optimize a block
741 **************************************************************************/
742
743 static
call_optimizer(const compress_t * c,lzo_bytep src,lzo_uint src_len,lzo_bytep dst,lzo_uintp dst_len)744 int call_optimizer ( const compress_t *c,
745 lzo_bytep src, lzo_uint src_len,
746 lzo_bytep dst, lzo_uintp dst_len )
747 {
748 if (c && c->optimize && block_w.len >= c->mem_decompress)
749 return c->optimize(src,src_len,dst,dst_len,block_w.ptr);
750 return 0;
751 }
752
753
754 /***********************************************************************
755 // read a file
756 ************************************************************************/
757
load_file(const char * file_name,lzo_uint max_data_len)758 static int load_file(const char *file_name, lzo_uint max_data_len)
759 {
760 FILE *fp;
761 #if (HAVE_FTELLO)
762 off_t ll = -1;
763 #else
764 long ll = -1;
765 #endif
766 lzo_uint l;
767 int r;
768 mblock_t *mb = &file_data;
769
770 mb_free(mb);
771
772 fp = fopen(file_name, "rb");
773 if (fp == NULL)
774 {
775 fflush(stdout); fflush(stderr);
776 fprintf(stderr, "%s: ", file_name);
777 fflush(stderr);
778 perror("fopen");
779 fflush(stdout); fflush(stderr);
780 return EXIT_FILE;
781 }
782 r = fseek(fp, 0, SEEK_END);
783 if (r == 0)
784 {
785 #if (HAVE_FTELLO)
786 ll = ftello(fp);
787 #else
788 ll = ftell(fp);
789 #endif
790 r = fseek(fp, 0, SEEK_SET);
791 }
792 if (r != 0 || ll < 0)
793 {
794 fflush(stdout); fflush(stderr);
795 fprintf(stderr, "%s: ", file_name);
796 fflush(stderr);
797 perror("fseek");
798 fflush(stdout); fflush(stderr);
799 (void) fclose(fp);
800 return EXIT_FILE;
801 }
802
803 l = (lzo_uint) ll;
804 if (l > max_data_len) l = max_data_len;
805 #if (HAVE_FTELLO)
806 if ((off_t) l != ll) l = max_data_len;
807 #else
808 if ((long) l != ll) l = max_data_len;
809 #endif
810
811 mb_alloc(mb, l);
812 mb->len = (lzo_uint) lzo_fread(fp, mb->ptr, mb->len);
813
814 r = ferror(fp);
815 if (fclose(fp) != 0 || r != 0)
816 {
817 mb_free(mb);
818 fflush(stdout); fflush(stderr);
819 fprintf(stderr, "%s: ", file_name);
820 fflush(stderr);
821 perror("fclose");
822 fflush(stdout); fflush(stderr);
823 return EXIT_FILE;
824 }
825
826 return EXIT_OK;
827 }
828
829
830 /***********************************************************************
831 // print some compression statistics
832 ************************************************************************/
833
t_div(double a,double b)834 static double t_div(double a, double b)
835 {
836 return b > 0.00001 ? a / b : 0;
837 }
838
set_perc_d(double perc,char * s)839 static double set_perc_d(double perc, char *s)
840 {
841 if (perc <= 0.0) {
842 strcpy(s, "0.0");
843 return 0;
844 }
845 if (perc <= 100 - 1.0 / 16) {
846 sprintf(s, "%4.1f", perc);
847 }
848 else {
849 long p = (long) (perc + 0.5);
850 if (p < 100)
851 strcpy(s, "???");
852 else if (p >= 9999)
853 strcpy(s, "9999");
854 else
855 sprintf(s, "%ld", p);
856 }
857 return perc;
858 }
859
set_perc(unsigned long c_len,unsigned long d_len,char * s)860 static double set_perc(unsigned long c_len, unsigned long d_len, char *s)
861 {
862 double perc = 0.0;
863 if (d_len > 0)
864 perc = c_len * 100.0 / d_len;
865 return set_perc_d(perc, s);
866 }
867
868
869 static
print_stats(const char * method_name,const char * file_name,long t_loops,long c_loops,long d_loops,double t_secs,double c_secs,double d_secs,unsigned long c_len,unsigned long d_len,unsigned long blocks)870 void print_stats ( const char *method_name, const char *file_name,
871 long t_loops, long c_loops, long d_loops,
872 double t_secs, double c_secs, double d_secs,
873 unsigned long c_len, unsigned long d_len,
874 unsigned long blocks )
875 {
876 unsigned long x_len = d_len;
877 unsigned long t_bytes, c_bytes, d_bytes;
878 double c_mbs, d_mbs, t_mbs;
879 double perc;
880 char perc_str[4+1];
881
882 perc = set_perc(c_len, d_len, perc_str);
883
884 c_bytes = x_len * c_loops * t_loops;
885 d_bytes = x_len * d_loops * t_loops;
886 t_bytes = c_bytes + d_bytes;
887
888 if (opt_pclock == 0)
889 c_secs = d_secs = t_secs = 0.0;
890
891 /* speed in uncompressed megabytes per second (1 megabyte = 1.000.000 bytes) */
892 c_mbs = (c_secs > 0.001) ? (c_bytes / c_secs) / 1000000.0 : 0;
893 d_mbs = (d_secs > 0.001) ? (d_bytes / d_secs) / 1000000.0 : 0;
894 t_mbs = (t_secs > 0.001) ? (t_bytes / t_secs) / 1000000.0 : 0;
895
896 total_n++;
897 total_c_len += c_len;
898 total_d_len += d_len;
899 total_blocks += blocks;
900 total_perc += perc;
901 if (c_mbs > 0) {
902 total_c_mbs_n += 1;
903 total_c_mbs_harmonic += 1.0 / c_mbs;
904 total_c_mbs_sum += c_mbs;
905 }
906 if (d_mbs > 0) {
907 total_d_mbs_n += 1;
908 total_d_mbs_harmonic += 1.0 / d_mbs;
909 total_d_mbs_sum += d_mbs;
910 }
911
912 if (opt_verbose >= 2)
913 {
914 printf(" compressed into %lu bytes, %s%% (%s%.3f bits/byte)\n",
915 c_len, perc_str, "", perc * 0.08);
916
917 #if 0
918 printf("%-15s %5ld: ","overall", t_loops);
919 printf("%10lu bytes, %8.2f secs, %8.3f MB/sec\n",
920 t_bytes, t_secs, t_mbs);
921 #else
922 LZO_UNUSED(t_mbs);
923 #endif
924 printf("%-15s %5ld: ","compress", c_loops);
925 printf("%10lu bytes, %8.2f secs, %8.3f MB/sec\n",
926 c_bytes, c_secs, c_mbs);
927 printf("%-15s %5ld: ","decompress", d_loops);
928 printf("%10lu bytes, %8.2f secs, %8.3f MB/sec\n",
929 d_bytes, d_secs, d_mbs);
930 printf("\n");
931 }
932
933 /* create a line for util/table.pl */
934 if (opt_verbose >= 1)
935 {
936 /* get basename */
937 const char *n, *nn, *b;
938 for (nn = n = b = file_name; *nn; nn++)
939 if (*nn == '/' || *nn == '\\' || *nn == ':')
940 b = nn + 1;
941 else
942 n = b;
943
944 printf("%-13s| %-14s %8lu %4lu %9lu %4s %s%8.3f %8.3f |\n",
945 method_name, n, d_len, blocks, c_len, perc_str, "", c_mbs, d_mbs);
946 }
947
948 if (opt_verbose >= 2)
949 printf("\n");
950 }
951
952
953 static
print_totals(void)954 void print_totals ( void )
955 {
956 char perc_str[4+1];
957
958 if ((opt_verbose >= 1 && total_n > 1) || (opt_totals >= 2))
959 {
960 unsigned long n = total_n > 0 ? total_n : 1;
961 const char *t1 = "-------";
962 const char *t2 = total_method_names == 1 ? total_method_name : "";
963 #if 1 && defined(__LZOLIB_PCLOCK_CH_INCLUDED)
964 char pclock_mode[32+1];
965 sprintf(pclock_mode, "[clock=%d]", pch.mode);
966 t1 = pclock_mode;
967 if (opt_pclock == 0) t1 = t2;
968 #endif
969
970 #if 1
971 set_perc_d(total_perc / n, perc_str);
972 printf("%-13s %-12s %10lu %4.1f %9lu %4s %8.3f %8.3f\n",
973 t1, "***AVG***",
974 total_d_len / n, total_blocks * 1.0 / n, total_c_len / n, perc_str,
975 t_div((double)total_c_mbs_n, total_c_mbs_harmonic),
976 t_div((double)total_d_mbs_n, total_d_mbs_harmonic));
977 #endif
978 set_perc(total_c_len, total_d_len, perc_str);
979 printf("%-13s %-12s %10lu %4lu %9lu %4s %s%8.3f %8.3f\n",
980 t2, "***TOTALS***",
981 total_d_len, total_blocks, total_c_len, perc_str, "",
982 t_div((double)total_c_mbs_n, total_c_mbs_harmonic),
983 t_div((double)total_d_mbs_n, total_d_mbs_harmonic));
984 }
985 }
986
987
988 /*************************************************************************
989 // compress and decompress a file
990 **************************************************************************/
991
992 static __lzo_noinline
process_file(const compress_t * c,lzo_decompress_t decompress,const char * method_name,const char * file_name,long t_loops,long c_loops,long d_loops)993 int process_file ( const compress_t *c, lzo_decompress_t decompress,
994 const char *method_name,
995 const char *file_name,
996 long t_loops, long c_loops, long d_loops )
997 {
998 long t_i;
999 unsigned long blocks = 0;
1000 unsigned long compressed_len = 0;
1001 double t_time = 0, c_time = 0, d_time = 0;
1002 lzo_pclock_t t_start, t_stop, x_start, x_stop;
1003 FILE *fp_dump = NULL;
1004
1005 if (opt_dump_compressed_data)
1006 fp_dump = fopen(opt_dump_compressed_data,"wb");
1007
1008 /* process the file */
1009
1010 lzo_pclock_flush_cpu_cache(&pch, 0);
1011 lzo_pclock_read(&pch, &t_start);
1012 for (t_i = 0; t_i < t_loops; t_i++)
1013 {
1014 lzo_uint len, c_len, c_len_max, d_len = 0;
1015 const lzo_bytep d = file_data.ptr;
1016
1017 len = file_data.len;
1018 c_len = 0;
1019 blocks = 0;
1020
1021 /* process blocks */
1022 if (len > 0 || opt_try_to_compress_0_bytes) do
1023 {
1024 lzo_uint bl;
1025 long c_i;
1026 int r;
1027 unsigned char random_byte = (unsigned char) file_data.len;
1028 #if 1 && defined(CLOCKS_PER_SEC)
1029 random_byte = (unsigned char) (random_byte ^ clock());
1030 #endif
1031 blocks++;
1032
1033 bl = len > opt_block_size ? opt_block_size : len;
1034 /* update lengths for memchecker_xxx() */
1035 block_c.len = bl + get_max_compression_expansion(c->id, bl);
1036 block_d.len = bl + get_max_decompression_overrun(c->id, bl);
1037 #if defined(__LZO_CHECKER)
1038 /* malloc a block of the exact size to detect any overrun */
1039 assert(block_c.alloc_ptr == NULL);
1040 assert(block_d.alloc_ptr == NULL);
1041 mb_alloc(&block_c, block_c.len);
1042 mb_alloc(&block_d, block_d.len);
1043 #endif
1044 assert(block_c.len <= block_c.saved_len);
1045 assert(block_d.len <= block_d.saved_len);
1046
1047 memchecker_init(&block_c, block_c.len, random_byte);
1048 memchecker_init(&block_d, block_d.len, random_byte);
1049
1050 /* compress the block */
1051 c_len = c_len_max = 0;
1052 lzo_pclock_flush_cpu_cache(&pch, 0);
1053 lzo_pclock_read(&pch, &x_start);
1054 for (r = 0, c_i = 0; c_i < c_loops; c_i++)
1055 {
1056 c_len = block_c.len;
1057 r = call_compressor(c, d, bl, block_c.ptr, &c_len);
1058 if (r != 0)
1059 break;
1060 if (c_len > c_len_max)
1061 c_len_max = c_len;
1062 if (c_len > block_c.len)
1063 goto compress_overrun;
1064 }
1065 lzo_pclock_read(&pch, &x_stop);
1066 c_time += lzo_pclock_get_elapsed(&pch, &x_start, &x_stop);
1067 if (r != 0)
1068 {
1069 printf(" compression failed in block %lu (%d) (%lu %lu)\n",
1070 blocks, r, (unsigned long)c_len, (unsigned long)bl);
1071 return EXIT_LZO_ERROR;
1072 }
1073 if (memchecker_check(&block_c, block_c.len, random_byte) != 0)
1074 {
1075 compress_overrun:
1076 printf(" compression overwrite error in block %lu "
1077 "(%lu %lu %lu %lu)\n",
1078 blocks, (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl, (unsigned long)block_c.len);
1079 return EXIT_LZO_ERROR;
1080 }
1081
1082 /* optimize the compressed block */
1083 if (c_len < bl && opt_optimize_compressed_data)
1084 {
1085 d_len = bl;
1086 r = call_optimizer(c, block_c.ptr, c_len, block_d.ptr, &d_len);
1087 if (r != 0 || d_len != bl)
1088 {
1089 printf(" optimization failed in block %lu (%d) "
1090 "(%lu %lu %lu)\n", blocks, r,
1091 (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl);
1092 return EXIT_LZO_ERROR;
1093 }
1094 if (memchecker_check(&block_c, block_c.len, random_byte) != 0 ||
1095 memchecker_check(&block_d, block_d.len, random_byte) != 0)
1096 {
1097 printf(" optimize overwrite error in block %lu "
1098 "(%lu %lu %lu %lu)\n",
1099 blocks, (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl, (unsigned long)block_c.len);
1100 return EXIT_LZO_ERROR;
1101 }
1102 }
1103
1104 /* dump compressed data to disk */
1105 if (fp_dump)
1106 {
1107 lzo_uint l = (lzo_uint) lzo_fwrite(fp_dump, block_c.ptr, c_len);
1108 if (l != c_len || fflush(fp_dump) != 0) {
1109 /* write error */
1110 (void) fclose(fp_dump); fp_dump = NULL;
1111 }
1112 }
1113
1114 /* decompress the block and verify */
1115 lzo_pclock_flush_cpu_cache(&pch, 0);
1116 lzo_pclock_read(&pch, &x_start);
1117 for (r = 0, c_i = 0; c_i < d_loops; c_i++)
1118 {
1119 d_len = bl;
1120 r = call_decompressor(c, decompress, block_c.ptr, c_len, block_d.ptr, &d_len);
1121 if (r != 0 || d_len != bl)
1122 break;
1123 }
1124 lzo_pclock_read(&pch, &x_stop);
1125 d_time += lzo_pclock_get_elapsed(&pch, &x_start, &x_stop);
1126 if (r != 0)
1127 {
1128 printf(" decompression failed in block %lu (%d) "
1129 "(%lu %lu %lu)\n", blocks, r,
1130 (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl);
1131 return EXIT_LZO_ERROR;
1132 }
1133 if (d_len != bl)
1134 {
1135 printf(" decompression size error in block %lu (%lu %lu %lu)\n",
1136 blocks, (unsigned long)c_len, (unsigned long)d_len, (unsigned long)bl);
1137 return EXIT_LZO_ERROR;
1138 }
1139 if (is_compressor(c))
1140 {
1141 if (lzo_memcmp(d, block_d.ptr, bl) != 0)
1142 {
1143 lzo_uint x = 0;
1144 while (x < bl && block_d.ptr[x] == d[x])
1145 x++;
1146 printf(" decompression data error in block %lu at offset "
1147 "%lu (%lu %lu)\n", blocks, (unsigned long)x,
1148 (unsigned long)c_len, (unsigned long)d_len);
1149 if (opt_compute_adler32)
1150 printf(" checksum: 0x%08lx 0x%08lx\n",
1151 (unsigned long)adler_in, (unsigned long)adler_out);
1152 #if 0
1153 printf("Orig: ");
1154 r = (x >= 10) ? -10 : 0 - (int) x;
1155 for (j = r; j <= 10 && x + j < bl; j++)
1156 printf(" %02x", (int)d[x+j]);
1157 printf("\nDecomp:");
1158 for (j = r; j <= 10 && x + j < bl; j++)
1159 printf(" %02x", (int)block_d.ptr[x+j]);
1160 printf("\n");
1161 #endif
1162 return EXIT_LZO_ERROR;
1163 }
1164 if ((opt_compute_adler32 && adler_in != adler_out) ||
1165 (opt_compute_crc32 && crc_in != crc_out))
1166 {
1167 printf(" checksum error in block %lu (%lu %lu)\n",
1168 blocks, (unsigned long)c_len, (unsigned long)d_len);
1169 printf(" adler32: 0x%08lx 0x%08lx\n",
1170 (unsigned long)adler_in, (unsigned long)adler_out);
1171 printf(" crc32: 0x%08lx 0x%08lx\n",
1172 (unsigned long)crc_in, (unsigned long)crc_out);
1173 return EXIT_LZO_ERROR;
1174 }
1175 }
1176
1177 if (memchecker_check(&block_d, block_d.len, random_byte) != 0)
1178 {
1179 printf(" decompression overwrite error in block %lu "
1180 "(%lu %lu %lu %lu)\n",
1181 blocks, (unsigned long)c_len, (unsigned long)d_len,
1182 (unsigned long)bl, (unsigned long)block_d.len);
1183 return EXIT_LZO_ERROR;
1184 }
1185
1186 #if defined(__LZO_CHECKER)
1187 /* free in reverse order of allocations */
1188 mb_free(&block_d);
1189 mb_free(&block_c);
1190 #endif
1191
1192 d += bl;
1193 len -= bl;
1194 compressed_len += (unsigned long) c_len_max;
1195 }
1196 while (len > 0);
1197 }
1198 lzo_pclock_read(&pch, &t_stop);
1199 t_time += lzo_pclock_get_elapsed(&pch, &t_start, &t_stop);
1200
1201 if (fp_dump) {
1202 (void) fclose(fp_dump); fp_dump = NULL;
1203 }
1204 opt_dump_compressed_data = NULL; /* only dump the first file */
1205
1206 print_stats(method_name, file_name,
1207 t_loops, c_loops, d_loops,
1208 t_time, c_time, d_time,
1209 compressed_len, (unsigned long) file_data.len, blocks);
1210 if (total_method_name != c->name) {
1211 total_method_name = c->name;
1212 total_method_names += 1;
1213 }
1214
1215 return EXIT_OK;
1216 }
1217
1218
1219
1220 static
do_file(int method,const char * file_name,long c_loops,long d_loops,lzo_uint32_tp p_adler,lzo_uint32_tp p_crc)1221 int do_file ( int method, const char *file_name,
1222 long c_loops, long d_loops,
1223 lzo_uint32_tp p_adler, lzo_uint32_tp p_crc )
1224 {
1225 int r;
1226 const compress_t *c;
1227 lzo_decompress_t decompress;
1228 lzo_uint32_t adler, crc;
1229 char method_name[256+1];
1230 const char *n;
1231 const long t_loops = 1;
1232
1233 adler_in = adler_out = 0;
1234 crc_in = crc_out = 0;
1235 if (p_adler)
1236 *p_adler = 0;
1237 if (p_crc)
1238 *p_crc = 0;
1239
1240 c = find_method_by_id(method);
1241 if (c == NULL || c->name == NULL || c->compress == NULL)
1242 return EXIT_INTERNAL;
1243 decompress = get_decomp_info(c,&n);
1244 if (!decompress || n == NULL || block_w.len < c->mem_decompress)
1245 return EXIT_INTERNAL;
1246 strcpy(method_name,c->name);
1247 strcat(method_name,n);
1248
1249 if (c_loops < 1) c_loops = 1;
1250 if (d_loops < 1) d_loops = 1;
1251
1252 fflush(stdout); fflush(stderr);
1253
1254 /* read the whole file */
1255 r = load_file(file_name, opt_max_data_len);
1256 if (r != 0)
1257 return r;
1258
1259 /* compute some checksums */
1260 adler = lzo_adler32(0, NULL, 0);
1261 adler = lzo_adler32(adler, file_data.ptr, file_data.len);
1262 if (p_adler)
1263 *p_adler = adler;
1264 crc = lzo_crc32(0, NULL, 0);
1265 crc = lzo_crc32(crc, file_data.ptr, file_data.len);
1266 if (p_crc)
1267 *p_crc = crc;
1268
1269 if (opt_verbose >= 2)
1270 {
1271 printf("File %s: %lu bytes (0x%08lx, 0x%08lx)\n",
1272 file_name, (unsigned long) file_data.len, (unsigned long) adler, (unsigned long) crc);
1273 printf(" compressing %lu bytes (%ld/%ld/%ld loops, %lu block-size)\n",
1274 (unsigned long) file_data.len, t_loops, c_loops, d_loops, (unsigned long) opt_block_size);
1275 printf(" %s\n", method_name);
1276 }
1277
1278 r = process_file(c, decompress, method_name, file_name,
1279 t_loops, c_loops, d_loops);
1280
1281 return r;
1282 }
1283
1284
1285 /*************************************************************************
1286 // Calgary Corpus and Silesia Corpus test suite driver
1287 **************************************************************************/
1288
1289 struct corpus_entry_t
1290 {
1291 const char *name;
1292 long loops;
1293 lzo_uint32_t adler;
1294 lzo_uint32_t crc;
1295 };
1296
1297 const struct corpus_entry_t *opt_corpus = NULL;
1298
1299 static const struct corpus_entry_t calgary_corpus[] =
1300 {
1301 { "bib", 8, 0x4bd09e98L, 0xb856ebe8L },
1302 { "book1", 1, 0xd4d3613eL, 0x24e19972L },
1303 { "book2", 1, 0x6fe14cc3L, 0xba0f3f26L },
1304 { "geo", 6, 0xf3cc5be0L, 0x4d3a6ed0L },
1305 { "news", 2, 0x2ed405b8L, 0xcafac853L },
1306 { "obj1", 35, 0x3887dd2cL, 0xc7b0cd26L },
1307 { "obj2", 4, 0xf89407c4L, 0x3ae33007L },
1308 { "paper1", 17, 0xfe65ce62L, 0x2b6baca0L },
1309 { "paper2", 11, 0x1238b7c2L, 0xf76cba72L },
1310 { "pic", 4, 0xf61a5702L, 0x4b17e59cL },
1311 { "progc", 25, 0x4c00ba45L, 0x6fb16094L },
1312 { "progl", 20, 0x4cba738eL, 0xddbf6baaL },
1313 { "progp", 28, 0x7495b92bL, 0x493a1809L },
1314 { "trans", 15, 0x52a2cec8L, 0xcdec06a6L },
1315 { NULL, 0, 0x00000000L, 0x00000000L }
1316 };
1317
1318 static const struct corpus_entry_t silesia_corpus[] =
1319 {
1320 { "dickens", 1, 0x170f606fL, 0xaf3a6b76L },
1321 { "mozilla", 1, 0x1188dd4eL, 0x7fb0ab7dL },
1322 { "mr", 1, 0xaea14b97L, 0xa341883fL },
1323 { "nci", 1, 0x0af16f1fL, 0x60ff63d3L },
1324 { "ooffice", 1, 0x83c8f689L, 0xa023e1faL },
1325 { "osdb", 1, 0xb825b790L, 0xa0ca388cL },
1326 { "reymont", 1, 0xce5c82caL, 0x50d35f03L },
1327 { "samba", 1, 0x19dbb9f5L, 0x2beac5f3L },
1328 { "sao", 1, 0x7edfc4a9L, 0xfda125bfL },
1329 { "webster", 1, 0xf2962fc6L, 0x01f5a2e9L },
1330 { "xml", 1, 0xeccd03d6L, 0xff8f3051L },
1331 { "x-ray", 1, 0xc95435a0L, 0xc86a35c6L },
1332 { NULL, 0, 0x00000000L, 0x00000000L }
1333 };
1334
1335
1336 static
do_corpus(const struct corpus_entry_t * corpus,int method,const char * path,long c_loops,long d_loops)1337 int do_corpus ( const struct corpus_entry_t *corpus, int method, const char *path,
1338 long c_loops, long d_loops )
1339 {
1340 size_t i, n;
1341 char name[256];
1342
1343 if (path == NULL || strlen(path) >= sizeof(name) - 12)
1344 return EXIT_USAGE;
1345
1346 strcpy(name,path);
1347 n = strlen(name);
1348 if (n > 0 && name[n-1] != '/' && name[n-1] != '\\' && name[n-1] != ':')
1349 {
1350 strcat(name,"/");
1351 n++;
1352 }
1353
1354 for (i = 0; corpus[i].name != NULL; i++)
1355 {
1356 lzo_uint32_t adler, crc;
1357 long c = c_loops * corpus[i].loops;
1358 long d = d_loops * corpus[i].loops;
1359 int r;
1360
1361 strcpy(name+n,corpus[i].name);
1362 r = do_file(method, name, c, d, &adler, &crc);
1363 if (r != 0)
1364 return r;
1365 if (adler != corpus[i].adler)
1366 {
1367 printf(" invalid test suite\n");
1368 return EXIT_ADLER;
1369 }
1370 if (corpus[i].crc && crc != corpus[i].crc)
1371 {
1372 printf(" internal checksum error !! (0x%08lx 0x%08lx)\n",
1373 (unsigned long) crc, (unsigned long) corpus[i].crc);
1374 return EXIT_INTERNAL;
1375 }
1376 }
1377 return EXIT_OK;
1378 }
1379
1380
1381 /*************************************************************************
1382 // usage
1383 **************************************************************************/
1384
1385 static
usage(const char * name,int exit_code,lzo_bool show_methods)1386 void usage ( const char *name, int exit_code, lzo_bool show_methods )
1387 {
1388 FILE *fp;
1389 int i;
1390
1391 fp = stdout;
1392
1393 fflush(stdout); fflush(stderr);
1394
1395 fprintf(fp,"Usage: %s [option..] file...\n", name);
1396 fprintf(fp,"\n");
1397 fprintf(fp,"Options:\n");
1398 fprintf(fp," -m# compression method\n");
1399 fprintf(fp," -b# set input block size (default %lu, max %lu)\n",
1400 (unsigned long) opt_block_size, (unsigned long) opt_max_data_len);
1401 fprintf(fp," -n# number of compression/decompression runs\n");
1402 fprintf(fp," -c# number of compression runs\n");
1403 fprintf(fp," -d# number of decompression runs\n");
1404 fprintf(fp," -S use safe decompressor (if available)\n");
1405 fprintf(fp," -A use assembler decompressor (if available)\n");
1406 fprintf(fp," -F use fast assembler decompressor (if available)\n");
1407 fprintf(fp," -O optimize compressed data (if available)\n");
1408 fprintf(fp," -s DIR process Calgary Corpus test suite in directory `DIR'\n");
1409 fprintf(fp," -@ read list of files to compress from stdin\n");
1410 fprintf(fp," -q be quiet\n");
1411 fprintf(fp," -Q be very quiet\n");
1412 fprintf(fp," -v be verbose\n");
1413 fprintf(fp," -L display software license\n");
1414
1415 if (show_methods)
1416 {
1417 #if defined(__LZOLIB_PCLOCK_CH_INCLUDED)
1418 lzo_pclock_t t_dummy;
1419 lzo_pclock_read(&pch, &t_dummy);
1420 (void) lzo_pclock_get_elapsed(&pch, &t_dummy, &t_dummy);
1421 fprintf(fp,"\nAll timings are recorded using pclock mode %d %s.\n", pch.mode, pch.name);
1422 #endif
1423 fprintf(fp,"\n\n");
1424 fprintf(fp,"The following compression methods are available:\n");
1425 fprintf(fp,"\n");
1426 fprintf(fp," usage name memory available extras\n");
1427 fprintf(fp," ----- ---- ------ ----------------\n");
1428
1429 for (i = 0; i <= M_LAST_COMPRESSOR; i++)
1430 {
1431 const compress_t *c;
1432 c = find_method_by_id(i);
1433 if (c)
1434 {
1435 char n[16];
1436 const char *sep = " ";
1437 unsigned long m = c->mem_compress;
1438
1439 sprintf(n,"-m%d",i);
1440 fprintf(fp," %-6s %-13s",n,c->name);
1441 #if 1
1442 fprintf(fp,"%9lu", m);
1443 #else
1444 m = (m + 1023) / 1024;
1445 fprintf(fp,"%6lu KiB", m);
1446 #endif
1447
1448 if (c->decompress_safe)
1449 { fprintf(fp, "%s%s", sep, "safe"); sep = ", "; }
1450 if (c->decompress_asm)
1451 { fprintf(fp, "%s%s", sep, "asm"); sep = ", "; }
1452 if (c->decompress_asm_safe)
1453 { fprintf(fp, "%s%s", sep, "asm+safe"); sep = ", "; }
1454 if (c->decompress_asm_fast)
1455 { fprintf(fp, "%s%s", sep, "fastasm"); sep = ", "; }
1456 if (c->decompress_asm_fast_safe)
1457 { fprintf(fp, "%s%s", sep, "fastasm+safe"); sep = ", "; }
1458 if (c->optimize)
1459 { fprintf(fp, "%s%s", sep, "optimize"); /*sep = ", ";*/ }
1460 fprintf(fp, "\n");
1461 }
1462 }
1463 }
1464 else
1465 {
1466 fprintf(fp,"\n");
1467 fprintf(fp,"Type '%s -m' to list all available methods.\n", name);
1468 }
1469
1470 fflush(fp);
1471 if (exit_code < 0)
1472 exit_code = EXIT_USAGE;
1473 exit(exit_code);
1474 }
1475
1476
1477 static
license(void)1478 void license(void)
1479 {
1480 FILE *fp;
1481
1482 fp = stdout;
1483 fflush(stdout); fflush(stderr);
1484
1485 fprintf(fp,
1486 " The LZO library is free software; you can redistribute it and/or\n"
1487 " modify it under the terms of the GNU General Public License as\n"
1488 " published by the Free Software Foundation; either version 2 of\n"
1489 " the License, or (at your option) any later version.\n"
1490 "\n"
1491 " The LZO library is distributed in the hope that it will be useful,\n"
1492 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1493 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1494 " GNU General Public License for more details.\n"
1495 );
1496 fprintf(fp,
1497 "\n"
1498 " You should have received a copy of the GNU General Public License\n"
1499 " along with the LZO library; see the file COPYING.\n"
1500 " If not, write to the Free Software Foundation, Inc.,\n"
1501 " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
1502 "\n"
1503 " Markus F.X.J. Oberhumer\n"
1504 " <markus@oberhumer.com>\n"
1505 " http://www.oberhumer.com/opensource/lzo/\n"
1506 "\n"
1507 );
1508
1509 fflush(fp);
1510 exit(EXIT_OK);
1511 }
1512
1513
1514 /*************************************************************************
1515 // parse method option '-m'
1516 **************************************************************************/
1517
1518 static int methods[256+1];
1519 static int methods_n = 0;
1520
add_method(int m)1521 static void add_method(int m)
1522 {
1523 int i;
1524
1525 if (m > 0)
1526 {
1527 if (!find_method_by_id(m)) {
1528 fprintf(stdout,"%s: invalid method %d\n",progname,m);
1529 exit(EXIT_USAGE);
1530 }
1531
1532 for (i = 0; i < methods_n; i++)
1533 if (methods[i] == m)
1534 return;
1535
1536 if (methods_n >= 256)
1537 {
1538 fprintf(stderr,"%s: too many methods\n",progname);
1539 exit(EXIT_USAGE);
1540 }
1541
1542 methods[methods_n++] = m;
1543 methods[methods_n] = 0;
1544 }
1545 }
1546
1547
add_methods(const int * ml)1548 static void add_methods(const int *ml)
1549 {
1550 while (*ml != 0)
1551 add_method(*ml++);
1552 }
1553
1554
add_all_methods(int first,int last)1555 static void add_all_methods(int first, int last)
1556 {
1557 int m;
1558
1559 for (m = first; m <= last; m++)
1560 if (find_method_by_id(m) != NULL)
1561 add_method(m);
1562 }
1563
1564
m_strcmp(const char * a,const char * b)1565 static int m_strcmp(const char *a, const char *b)
1566 {
1567 size_t n;
1568
1569 if (a[0] == 0 || b[0] == 0)
1570 return 1;
1571 n = strlen(b);
1572 if (strncmp(a,b,n) == 0 && (a[n] == 0 || a[n] == ','))
1573 return 0;
1574 return 1;
1575 }
1576
1577
m_strisdigit(const char * s)1578 static lzo_bool m_strisdigit(const char *s)
1579 {
1580 for (;;)
1581 {
1582 if (!is_digit(*s))
1583 return 0;
1584 s++;
1585 if (*s == 0 || *s == ',')
1586 break;
1587 }
1588 return 1;
1589 }
1590
1591
parse_methods(const char * p)1592 static void parse_methods(const char *p)
1593 {
1594 const compress_t *c;
1595
1596 for (;;)
1597 {
1598 if (p == NULL || p[0] == 0)
1599 usage(progname,-1,1);
1600 else if ((c = find_method_by_name(p)) != NULL)
1601 add_method(c->id);
1602 else if (m_strcmp(p,"all") == 0 || m_strcmp(p,"avail") == 0)
1603 add_all_methods(1,M_LAST_COMPRESSOR);
1604 else if (m_strcmp(p,"ALL") == 0)
1605 {
1606 add_all_methods(1,M_LAST_COMPRESSOR);
1607 add_all_methods(9721,9729);
1608 add_all_methods(9781,9789);
1609 }
1610 else if (m_strcmp(p,"lzo") == 0)
1611 add_all_methods(1,M_MEMCPY);
1612 else if (m_strcmp(p,"bench") == 0)
1613 add_methods(benchmark_methods);
1614 else if (m_strcmp(p,"m1") == 0)
1615 add_methods(x1_methods);
1616 else if (m_strcmp(p,"m99") == 0)
1617 add_methods(x99_methods);
1618 else if (m_strcmp(p,"m999") == 0)
1619 add_methods(x999_methods);
1620 else if (m_strcmp(p,"1x999") == 0)
1621 add_all_methods(9721,9729);
1622 else if (m_strcmp(p,"1y999") == 0)
1623 add_all_methods(9821,9829);
1624 #if defined(ALG_ZLIB)
1625 else if (m_strcmp(p,"zlib") == 0)
1626 add_all_methods(M_ZLIB_8_1,M_ZLIB_8_9);
1627 #endif
1628 #if defined(ALG_BZIP2)
1629 else if (m_strcmp(p,"bzip2") == 0)
1630 add_all_methods(M_BZIP2_1,M_BZIP2_9);
1631 #endif
1632 else if (m_strisdigit(p))
1633 add_method(atoi(p));
1634 else
1635 {
1636 printf("%s: invalid method '%s'\n\n",progname,p);
1637 exit(EXIT_USAGE);
1638 }
1639
1640 while (*p && *p != ',')
1641 p++;
1642 while (*p == ',')
1643 p++;
1644 if (*p == 0)
1645 return;
1646 }
1647 }
1648
1649
1650 /*************************************************************************
1651 // options
1652 **************************************************************************/
1653
1654 enum {
1655 OPT_LONGOPT_ONLY = 512,
1656 OPT_ADLER32,
1657 OPT_CALGARY_CORPUS,
1658 OPT_CLEAR_WRKMEM,
1659 OPT_CRC32,
1660 OPT_DICT,
1661 OPT_DUMP,
1662 OPT_EXECUTION_TIME,
1663 OPT_MAX_DATA_LEN,
1664 OPT_MAX_DICT_LEN,
1665 OPT_SILESIA_CORPUS,
1666 OPT_PCLOCK,
1667 OPT_UNUSED
1668 };
1669
1670 static const struct lzo_getopt_longopt_t longopts[] =
1671 {
1672 /* { name has_arg *flag val } */
1673 {"help", 0, 0, 'h'+256}, /* give help */
1674 {"license", 0, 0, 'L'}, /* display software license */
1675 {"quiet", 0, 0, 'q'}, /* quiet mode */
1676 {"verbose", 0, 0, 'v'}, /* verbose mode */
1677 {"version", 0, 0, 'V'+256}, /* display version number */
1678
1679 {"adler32", 0, 0, OPT_ADLER32},
1680 {"calgary-corpus", 1, 0, OPT_CALGARY_CORPUS},
1681 {"clear-wrkmem", 0, 0, OPT_CLEAR_WRKMEM},
1682 {"clock", 1, 0, OPT_PCLOCK},
1683 {"corpus", 1, 0, OPT_CALGARY_CORPUS},
1684 {"crc32", 0, 0, OPT_CRC32},
1685 {"dict", 1, 0, OPT_DICT},
1686 {"dump-compressed", 1, 0, OPT_DUMP},
1687 {"execution-time", 0, 0, OPT_EXECUTION_TIME},
1688 {"max-data-length", 1, 0, OPT_MAX_DATA_LEN},
1689 {"max-dict-length", 1, 0, OPT_MAX_DICT_LEN},
1690 {"silesia-corpus", 1, 0, OPT_SILESIA_CORPUS},
1691 {"uclock", 1, 0, OPT_PCLOCK},
1692 {"methods", 1, 0, 'm'},
1693 {"totals", 0, 0, 'T'},
1694
1695 { 0, 0, 0, 0 }
1696 };
1697
1698
do_option(lzo_getopt_p g,int optc)1699 static int do_option(lzo_getopt_p g, int optc)
1700 {
1701 #define mfx_optarg g->optarg
1702 switch (optc)
1703 {
1704 case 'A':
1705 opt_use_asm_decompressor = 1;
1706 break;
1707 case 'b':
1708 opt_block_size = 0; /* set to opt_max_data_len later */
1709 if (mfx_optarg)
1710 {
1711 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1712 return optc;
1713 opt_block_size = atol(mfx_optarg);
1714 }
1715 break;
1716 case 'c':
1717 case 'C':
1718 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1719 return optc;
1720 opt_c_loops = atol(mfx_optarg);
1721 break;
1722 case 'd':
1723 case 'D':
1724 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1725 return optc;
1726 opt_d_loops = atol(mfx_optarg);
1727 break;
1728 case 'F':
1729 opt_use_asm_fast_decompressor = 1;
1730 break;
1731 case 'h':
1732 case 'H':
1733 case '?':
1734 case 'h'+256:
1735 usage(progname,EXIT_OK,0);
1736 break;
1737 case 'L':
1738 license();
1739 break;
1740 case 'm':
1741 parse_methods(mfx_optarg);
1742 break;
1743 case 'n':
1744 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1745 return optc;
1746 opt_c_loops = opt_d_loops = atol(mfx_optarg);
1747 break;
1748 case 'O':
1749 opt_optimize_compressed_data = 1;
1750 break;
1751 case 'q':
1752 opt_verbose -= 1;
1753 break;
1754 case 'Q':
1755 opt_verbose = 0;
1756 break;
1757 case 's':
1758 case OPT_CALGARY_CORPUS:
1759 if (!mfx_optarg || !mfx_optarg[0])
1760 return optc;
1761 opt_corpus_path = mfx_optarg;
1762 opt_corpus = calgary_corpus;
1763 break;
1764 case OPT_SILESIA_CORPUS:
1765 if (!mfx_optarg || !mfx_optarg[0])
1766 return optc;
1767 opt_corpus_path = mfx_optarg;
1768 opt_corpus = silesia_corpus;
1769 break;
1770 case 'S':
1771 opt_use_safe_decompressor = 1;
1772 break;
1773 case 'T':
1774 opt_totals += 1;
1775 break;
1776 case 'v':
1777 opt_verbose += 1;
1778 break;
1779 case 'V':
1780 case 'V'+256:
1781 exit(EXIT_OK);
1782 break;
1783 case '@':
1784 opt_read_from_stdin = 1;
1785 break;
1786
1787 case '1': case '2': case '3': case '4': case '5':
1788 case '6': case '7': case '8': case '9':
1789 /* this is a dirty hack... */
1790 if (g->shortpos == 0) {
1791 char m[2]; m[0] = (char) optc; m[1] = 0;
1792 parse_methods(m);
1793 } else {
1794 const char *m = &g->argv[g->optind][g->shortpos-1];
1795 parse_methods(m);
1796 ++g->optind; g->shortpos = 0;
1797 }
1798 break;
1799
1800 case OPT_ADLER32:
1801 opt_compute_adler32 = 1;
1802 break;
1803 case OPT_CLEAR_WRKMEM:
1804 opt_clear_wrkmem = 1;
1805 break;
1806 case OPT_CRC32:
1807 opt_compute_crc32 = 1;
1808 break;
1809 case OPT_DICT:
1810 opt_dict = 1;
1811 opt_dictionary_file = mfx_optarg;
1812 break;
1813 case OPT_EXECUTION_TIME:
1814 opt_execution_time = 1;
1815 break;
1816 case OPT_DUMP:
1817 opt_dump_compressed_data = mfx_optarg;
1818 break;
1819 case OPT_MAX_DATA_LEN:
1820 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1821 return optc;
1822 opt_max_data_len = atol(mfx_optarg);
1823 break;
1824 case OPT_MAX_DICT_LEN:
1825 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1826 return optc;
1827 opt_max_dict_len = atol(mfx_optarg);
1828 break;
1829 case OPT_PCLOCK:
1830 if (!mfx_optarg || !is_digit(mfx_optarg[0]))
1831 return optc;
1832 opt_pclock = atoi(mfx_optarg);
1833 #if defined(__LZOLIB_PCLOCK_CH_INCLUDED)
1834 if (opt_pclock > 0)
1835 pch.mode = opt_pclock;
1836 #endif
1837 break;
1838
1839 case '\0':
1840 return -1;
1841 case ':':
1842 return -2;
1843 default:
1844 fprintf(stderr,"%s: internal error in getopt (%d)\n",progname,optc);
1845 return -3;
1846 }
1847 return 0;
1848 #undef mfx_optarg
1849 }
1850
1851
handle_opterr(lzo_getopt_p g,const char * f,void * v)1852 static void handle_opterr(lzo_getopt_p g, const char *f, void *v)
1853 {
1854 struct A { va_list ap; };
1855 struct A *a = (struct A *) v;
1856 fprintf( stderr, "%s: ", g->progname);
1857 if (a)
1858 vfprintf(stderr, f, a->ap);
1859 else
1860 fprintf( stderr, "UNKNOWN GETOPT ERROR");
1861 fprintf( stderr, "\n");
1862 }
1863
1864
get_options(int argc,char ** argv)1865 static int get_options(int argc, char **argv)
1866 {
1867 lzo_getopt_t mfx_getopt;
1868 int optc;
1869 static const char shortopts[] =
1870 "Ab::c:C:d:D:FhHLm::n:OqQs:STvV@123456789";
1871
1872 lzo_getopt_init(&mfx_getopt, 1, argc, argv);
1873 mfx_getopt.progname = progname;
1874 mfx_getopt.opterr = handle_opterr;
1875 while ((optc = lzo_getopt(&mfx_getopt, shortopts, longopts, NULL)) >= 0)
1876 {
1877 if (do_option(&mfx_getopt, optc) != 0)
1878 exit(EXIT_USAGE);
1879 }
1880
1881 return mfx_getopt.optind;
1882 }
1883
1884
1885 /*************************************************************************
1886 // main
1887 **************************************************************************/
1888
main(int argc,char * argv[])1889 int __lzo_cdecl_main main(int argc, char *argv[])
1890 {
1891 int r = EXIT_OK;
1892 int i, ii;
1893 int m;
1894 time_t t_total;
1895 const char *s;
1896
1897 lzo_wildargv(&argc, &argv);
1898 lzo_pclock_open_default(&pch);
1899
1900 progname = argv[0];
1901 for (s = progname; *s; s++)
1902 if ((*s == '/' || *s == '\\') && s[1])
1903 progname = s + 1;
1904
1905 #if 0
1906 printf("\nLZO real-time data compression library (v%s, %s).\n",
1907 lzo_version_string(), lzo_version_date());
1908 printf("Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer\nAll Rights Reserved.\n\n");
1909 #endif
1910
1911
1912 /*
1913 * Step 1: initialize the LZO library
1914 */
1915
1916 if (lzo_init() != LZO_E_OK)
1917 {
1918 printf("internal error - lzo_init() failed !!!\n");
1919 printf("(this usually indicates a compiler bug - try recompiling\nwithout optimizations, and enable `-DLZO_DEBUG' for diagnostics)\n");
1920 exit(1);
1921 }
1922
1923
1924 /*
1925 * Step 2: setup default options
1926 */
1927
1928 opt_max_data_len = 64 * 1024L * 1024L;
1929 opt_block_size = 256 * 1024L;
1930
1931 #if (LZO_ARCH_M68K && LZO_OS_TOS)
1932 /* reduce memory requirements for 14 MB machines */
1933 opt_max_data_len = 8 * 1024L * 1024L;
1934 #endif
1935
1936
1937
1938 /*
1939 * Step 3: parse options
1940 */
1941
1942 if (argc < 2)
1943 usage(progname,-1,0);
1944 i = get_options(argc,argv);
1945
1946 if (methods_n == 0)
1947 add_method(default_method);
1948 if (methods_n > 1 && opt_read_from_stdin)
1949 {
1950 printf("%s: cannot use multiple methods and '-@'\n", progname);
1951 exit(EXIT_USAGE);
1952 }
1953
1954 if (opt_block_size == 0)
1955 opt_block_size = opt_max_data_len;
1956 if (opt_block_size > opt_max_data_len)
1957 opt_block_size = opt_max_data_len;
1958
1959 if (opt_c_loops < 1)
1960 opt_c_loops = 1;
1961 if (opt_d_loops < 1)
1962 opt_d_loops = 1;
1963
1964
1965 /*
1966 * Step 4: start work
1967 */
1968
1969 block_w.len = 0;
1970 for (ii = 0; ii < methods_n; ii++) {
1971 const compress_t *c = find_method_by_id(methods[ii]);
1972 assert(c != NULL);
1973 if (c->mem_compress > block_w.len)
1974 block_w.len = c->mem_compress;
1975 if (c->mem_decompress > block_w.len)
1976 block_w.len = c->mem_decompress;
1977 }
1978
1979 mb_alloc(&block_w, block_w.len);
1980 lzo_memset(block_w.ptr, 0, block_w.len);
1981
1982 #if !defined(__LZO_CHECKER)
1983 mb_alloc_extra(&block_c, opt_block_size + get_max_compression_expansion(-1, opt_block_size), 16, 16);
1984 mb_alloc_extra(&block_d, opt_block_size + get_max_decompression_overrun(-1, opt_block_size), 16, 16);
1985 #endif
1986
1987 if (opt_dict)
1988 {
1989 opt_optimize_compressed_data = 0;
1990 dict_alloc(opt_max_dict_len);
1991 if (opt_dictionary_file)
1992 {
1993 dict_load(opt_dictionary_file);
1994 if (dict.len > 0)
1995 printf("Using dictionary '%s', %lu bytes, ID 0x%08lx.\n",
1996 opt_dictionary_file,
1997 (unsigned long) dict.len, (unsigned long) dict.adler);
1998 }
1999 if (dict.len == 0)
2000 {
2001 dict_set_default();
2002 printf("Using default dictionary, %lu bytes, ID 0x%08lx.\n",
2003 (unsigned long) dict.len, (unsigned long) dict.adler);
2004 }
2005 }
2006
2007 t_total = time(NULL);
2008 ii = i;
2009 for (m = 0; m < methods_n && r == EXIT_OK; m++)
2010 {
2011 int method = methods[m];
2012
2013 i = ii;
2014 if (i >= argc && opt_corpus_path == NULL && !opt_read_from_stdin)
2015 usage(progname,-1,0);
2016 if (m == 0 && opt_verbose >= 1)
2017 printf("%lu block-size\n\n", (unsigned long) opt_block_size);
2018
2019 assert(find_method_by_id(method) != NULL);
2020
2021 if (opt_corpus_path != NULL)
2022 r = do_corpus(opt_corpus, method, opt_corpus_path,
2023 opt_c_loops, opt_d_loops);
2024 else
2025 {
2026 for ( ; i < argc && r == EXIT_OK; i++)
2027 {
2028 r = do_file(method,argv[i],opt_c_loops,opt_d_loops,NULL,NULL);
2029 if (r == EXIT_FILE) /* ignore file errors */
2030 r = EXIT_OK;
2031 }
2032 if (opt_read_from_stdin)
2033 {
2034 char buf[512], *p;
2035
2036 while (r == EXIT_OK && fgets(buf,sizeof(buf)-1,stdin) != NULL)
2037 {
2038 buf[sizeof(buf)-1] = 0;
2039 p = buf + strlen(buf);
2040 while (p > buf && is_space(p[-1]))
2041 *--p = 0;
2042 p = buf;
2043 while (*p && is_space(*p))
2044 p++;
2045 if (*p)
2046 r = do_file(method,p,opt_c_loops,opt_d_loops,NULL,NULL);
2047 if (r == EXIT_FILE) /* ignore file errors */
2048 r = EXIT_OK;
2049 }
2050 opt_read_from_stdin = 0;
2051 }
2052 }
2053 }
2054 t_total = time(NULL) - t_total;
2055
2056 if (opt_totals)
2057 print_totals();
2058 if (opt_execution_time || (methods_n > 1 && opt_verbose >= 1))
2059 printf("\n%s: execution time: %lu seconds\n", progname, (unsigned long) t_total);
2060 if (r != EXIT_OK)
2061 printf("\n%s: exit code: %d\n", progname, r);
2062
2063 lzo_pclock_close(&pch);
2064 return r;
2065 }
2066
2067
2068 /* vim:set ts=4 sw=4 et: */
2069