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