gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-support/gbcompress/zx0/zx0_salvador_c_UNUSED
1 /*
2 * salvador.c - command line compression utility for the salvador library
3 *
4 * Copyright (C) 2021 Emmanuel Marty
5 *
6 * This software is provided 'as-is', without any express or implied
7 * warranty. In no event will the authors be held liable for any damages
8 * arising from the use of this software.
9 *
10 * Permission is granted to anyone to use this software for any purpose,
11 * including commercial applications, and to alter it and redistribute it
12 * freely, subject to the following restrictions:
13 *
14 * 1. The origin of this software must not be misrepresented; you must not
15 * claim that you wrote the original software. If you use this software
16 * in a product, an acknowledgment in the product documentation would be
17 * appreciated but is not required.
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 * 3. This notice may not be removed or altered from any source distribution.
21 */
22
23 /*
24 * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori
25 *
26 * Implements the ZX0 encoding designed by Einar Saukas. https://github.com/einar-saukas/ZX0
27 * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/
28 *
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #ifdef _WIN32
35 #include <windows.h>
36 #include <sys/timeb.h>
37 #else
38 #include <sys/time.h>
39 #endif
40 #include "libsalvador.h"
41
42 #define OPT_VERBOSE 1
43 #define OPT_STATS 2
44 #define OPT_BACKWARD 4
45 #define OPT_CLASSIC 8
46
47 #define TOOL_VERSION "1.4.2"
48
49 /*---------------------------------------------------------------------------*/
50
51 #ifdef _WIN32
52 LARGE_INTEGER hpc_frequency;
53 BOOL hpc_available = FALSE;
54 #endif
55
56 static void do_init_time() {
57 #ifdef _WIN32
58 hpc_frequency.QuadPart = 0;
59 hpc_available = QueryPerformanceFrequency(&hpc_frequency);
60 #endif
61 }
62
63 static long long do_get_time() {
64 long long nTime;
65
66 #ifdef _WIN32
67 if (hpc_available) {
68 LARGE_INTEGER nCurTime;
69
70 /* Use HPC hardware for best precision */
71 QueryPerformanceCounter(&nCurTime);
72 nTime = (long long)(nCurTime.QuadPart * 1000000LL / hpc_frequency.QuadPart);
73 }
74 else {
75 struct _timeb tb;
76 _ftime(&tb);
77
78 nTime = ((long long)tb.time * 1000LL + (long long)tb.millitm) * 1000LL;
79 }
80 #else
81 struct timeval tm;
82 gettimeofday(&tm, NULL);
83
84 nTime = (long long)tm.tv_sec * 1000000LL + (long long)tm.tv_usec;
85 #endif
86 return nTime;
87 }
88
89 static void do_reverse_buffer(unsigned char *pBuffer, size_t nBufferSize) {
90 size_t nMidPoint = nBufferSize / 2;
91 size_t i, j;
92
93 for (i = 0, j = nBufferSize - 1; i < nMidPoint; i++, j--) {
94 unsigned char c = pBuffer[i];
95 pBuffer[i] = pBuffer[j];
96 pBuffer[j] = c;
97 }
98 }
99
100 /*---------------------------------------------------------------------------*/
101
102 static void compression_progress(long long nOriginalSize, long long nCompressedSize) {
103 if (nOriginalSize >= 512 * 1024) {
104 fprintf(stdout, "\r%lld => %lld (%g %%) \b\b\b\b\b", nOriginalSize, nCompressedSize, (double)(nCompressedSize * 100.0 / nOriginalSize));
105 fflush(stdout);
106 }
107 }
108
109 static int do_compress(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions, const unsigned int nMaxWindowSize) {
110 long long nStartTime = 0LL, nEndTime = 0LL;
111 size_t nOriginalSize = 0L, nCompressedSize = 0L, nMaxCompressedSize;
112 int nFlags = (nOptions & OPT_CLASSIC) ? 0 : FLG_IS_INVERTED;
113 salvador_stats stats;
114 unsigned char *pDecompressedData;
115 unsigned char *pCompressedData;
116
117 if (nOptions & OPT_BACKWARD)
118 nFlags |= FLG_IS_BACKWARD;
119
120 if (nOptions & OPT_VERBOSE) {
121 nStartTime = do_get_time();
122 }
123
124 FILE* f_dict = NULL;
125 size_t nDictionarySize = 0;
126 if (pszDictionaryFilename) {
127 /* Open the dictionary */
128 f_dict = fopen(pszDictionaryFilename, "rb");
129 if (!f_dict) {
130 fprintf(stderr, "error opening dictionary '%s' for reading\n", pszDictionaryFilename);
131 return 100;
132 }
133
134 /* Get dictionary size */
135 fseek(f_dict, 0, SEEK_END);
136 nDictionarySize = (size_t)ftell(f_dict);
137 fseek(f_dict, 0, SEEK_SET);
138
139 if (nDictionarySize > BLOCK_SIZE) nDictionarySize = BLOCK_SIZE;
140 }
141
142 /* Read the whole original file in memory */
143
144 FILE *f_in = fopen(pszInFilename, "rb");
145 if (!f_in) {
146 if (f_dict) fclose(f_dict);
147 fprintf(stderr, "error opening '%s' for reading\n", pszInFilename);
148 return 100;
149 }
150
151 fseek(f_in, 0, SEEK_END);
152 nOriginalSize = (size_t)ftell(f_in);
153 fseek(f_in, 0, SEEK_SET);
154
155 pDecompressedData = (unsigned char*)malloc(nDictionarySize + nOriginalSize);
156 if (!pDecompressedData) {
157 fclose(f_in);
158 if (f_dict) fclose(f_dict);
159 fprintf(stderr, "out of memory for reading '%s', %zu bytes needed\n", pszInFilename, nOriginalSize);
160 return 100;
161 }
162
163 if (f_dict) {
164 /* Read dictionary data */
165 if (fread(pDecompressedData + ((nOptions & OPT_BACKWARD) ? nOriginalSize : 0), 1, nDictionarySize, f_dict) != nDictionarySize) {
166 free(pDecompressedData);
167 fclose(f_in);
168 fclose(f_dict);
169 fprintf(stderr, "I/O error while reading dictionary '%s'\n", pszDictionaryFilename);
170 return 100;
171 }
172
173 fclose(f_dict);
174 f_dict = NULL;
175 }
176
177 /* Read input file data */
178 if (fread(pDecompressedData + ((nOptions & OPT_BACKWARD) ? 0 : nDictionarySize), 1, nOriginalSize, f_in) != nOriginalSize) {
179 free(pDecompressedData);
180 fclose(f_in);
181 fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename);
182 return 100;
183 }
184
185 fclose(f_in);
186 f_in = NULL;
187
188 if (nOptions & OPT_BACKWARD)
189 do_reverse_buffer(pDecompressedData, nDictionarySize + nOriginalSize);
190
191 /* Allocate max compressed size */
192
193 nMaxCompressedSize = salvador_get_max_compressed_size(nDictionarySize + nOriginalSize);
194
195 pCompressedData = (unsigned char*)malloc(nMaxCompressedSize);
196 if (!pCompressedData) {
197 free(pDecompressedData);
198 fprintf(stderr, "out of memory for compressing '%s', %zu bytes needed\n", pszInFilename, nMaxCompressedSize);
199 return 100;
200 }
201
202 memset(pCompressedData, 0, nMaxCompressedSize);
203
204 nCompressedSize = salvador_compress(pDecompressedData, pCompressedData, nDictionarySize + nOriginalSize, nMaxCompressedSize, nFlags, nMaxWindowSize, nDictionarySize, compression_progress, &stats);
205
206 if (nOptions & OPT_VERBOSE) {
207 nEndTime = do_get_time();
208 }
209
210 if (nCompressedSize == (size_t)-1) {
211 free(pCompressedData);
212 free(pDecompressedData);
213 fprintf(stderr, "compression error for '%s'\n", pszInFilename);
214 return 100;
215 }
216
217 if (nOptions & OPT_BACKWARD)
218 do_reverse_buffer(pCompressedData, nCompressedSize);
219
220 /* Write whole compressed file out */
221
222 FILE *f_out = fopen(pszOutFilename, "wb");
223 if (!f_out) {
224 free(pCompressedData);
225 free(pDecompressedData);
226 fprintf(stderr, "error opening '%s' for writing\n", pszOutFilename);
227 return 100;
228 }
229
230 fwrite(pCompressedData, 1, nCompressedSize, f_out);
231 fclose(f_out);
232
233 free(pCompressedData);
234 free(pDecompressedData);
235
236 if (nOptions & OPT_VERBOSE) {
237 double fDelta = ((double)(nEndTime - nStartTime)) / 1000000.0;
238 double fSpeed = ((double)nOriginalSize / 1048576.0) / fDelta;
239 fprintf(stdout, "\rCompressed '%s' in %g seconds, %.02g Mb/s, %d tokens (%g bytes/token), %zu into %zu bytes ==> %g %%\n",
240 pszInFilename, fDelta, fSpeed, stats.commands_divisor, (double)nOriginalSize / (double)stats.commands_divisor,
241 nOriginalSize, nCompressedSize, (double)(nCompressedSize * 100.0 / nOriginalSize));
242 }
243
244 if (nOptions & OPT_STATS) {
245 if (stats.literals_divisor > 0)
246 fprintf(stdout, "Literals: min: %d avg: %d max: %d count: %d\n", stats.min_literals, stats.total_literals / stats.literals_divisor, stats.max_literals, stats.literals_divisor);
247 else
248 fprintf(stdout, "Literals: none\n");
249
250 fprintf(stdout, "Normal matches: %d rep matches: %d EOD: %d\n",
251 stats.num_normal_matches, stats.num_rep_matches, stats.num_eod);
252
253 if (stats.match_divisor > 0) {
254 fprintf(stdout, "Offsets: min: %d avg: %d max: %d count: %d\n", stats.min_offset, (int)(stats.total_offsets / (long long)stats.match_divisor), stats.max_offset, stats.match_divisor);
255 fprintf(stdout, "Match lens: min: %d avg: %d max: %d count: %d\n", stats.min_match_len, stats.total_match_lens / stats.match_divisor, stats.max_match_len, stats.match_divisor);
256 }
257 else {
258 fprintf(stdout, "Offsets: none\n");
259 fprintf(stdout, "Match lens: none\n");
260 }
261 if (stats.rle1_divisor > 0) {
262 fprintf(stdout, "RLE1 lens: min: %d avg: %d max: %d count: %d\n", stats.min_rle1_len, stats.total_rle1_lens / stats.rle1_divisor, stats.max_rle1_len, stats.rle1_divisor);
263 }
264 else {
265 fprintf(stdout, "RLE1 lens: none\n");
266 }
267 if (stats.rle2_divisor > 0) {
268 fprintf(stdout, "RLE2 lens: min: %d avg: %d max: %d count: %d\n", stats.min_rle2_len, stats.total_rle2_lens / stats.rle2_divisor, stats.max_rle2_len, stats.rle2_divisor);
269 }
270 else {
271 fprintf(stdout, "RLE2 lens: none\n");
272 }
273 fprintf(stdout, "Safe distance: %d (0x%X)\n", stats.safe_dist, stats.safe_dist);
274 }
275 return 0;
276 }
277
278 /*---------------------------------------------------------------------------*/
279
280 static int do_decompress(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions) {
281 long long nStartTime = 0LL, nEndTime = 0LL;
282 size_t nCompressedSize, nMaxDecompressedSize, nOriginalSize;
283 unsigned char *pCompressedData;
284 unsigned char *pDecompressedData;
285 int nFlags = (nOptions & OPT_CLASSIC) ? 0 : FLG_IS_INVERTED;
286
287 if (nOptions & OPT_BACKWARD)
288 nFlags |= FLG_IS_BACKWARD;
289
290 /* Read the whole compressed file in memory */
291
292 FILE *f_in = fopen(pszInFilename, "rb");
293 if (!f_in) {
294 fprintf(stderr, "error opening '%s' for reading\n", pszInFilename);
295 return 100;
296 }
297
298 fseek(f_in, 0, SEEK_END);
299 nCompressedSize = (size_t)ftell(f_in);
300 fseek(f_in, 0, SEEK_SET);
301
302 pCompressedData = (unsigned char*)malloc(nCompressedSize);
303 if (!pCompressedData) {
304 fclose(f_in);
305 fprintf(stderr, "out of memory for reading '%s', %zu bytes needed\n", pszInFilename, nCompressedSize);
306 return 100;
307 }
308
309 if (fread(pCompressedData, 1, nCompressedSize, f_in) != nCompressedSize) {
310 free(pCompressedData);
311 fclose(f_in);
312 fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename);
313 return 100;
314 }
315
316 fclose(f_in);
317 f_in = NULL;
318
319 if (nOptions & OPT_BACKWARD)
320 do_reverse_buffer(pCompressedData, nCompressedSize);
321
322 /* Get max decompressed size */
323
324 nMaxDecompressedSize = salvador_get_max_decompressed_size(pCompressedData, nCompressedSize, nFlags);
325 if (nMaxDecompressedSize == (size_t)-1) {
326 free(pCompressedData);
327 fprintf(stderr, "invalid compressed format for file '%s'\n", pszInFilename);
328 return 100;
329 }
330
331 FILE* f_dict = NULL;
332 size_t nDictionarySize = 0;
333 if (pszDictionaryFilename) {
334 /* Open the dictionary */
335 f_dict = fopen(pszDictionaryFilename, "rb");
336 if (!f_dict) {
337 fprintf(stderr, "error opening dictionary '%s' for reading\n", pszDictionaryFilename);
338 return 100;
339 }
340
341 /* Get dictionary size */
342 fseek(f_dict, 0, SEEK_END);
343 nDictionarySize = (size_t)ftell(f_dict);
344 fseek(f_dict, 0, SEEK_SET);
345
346 if (nDictionarySize > BLOCK_SIZE) nDictionarySize = BLOCK_SIZE;
347 }
348
349 /* Allocate max decompressed size */
350
351 pDecompressedData = (unsigned char*)malloc(nDictionarySize + nMaxDecompressedSize);
352 if (!pDecompressedData) {
353 free(pCompressedData);
354 if (f_dict) fclose(f_dict);
355 fprintf(stderr, "out of memory for decompressing '%s', %zu bytes needed\n", pszInFilename, nMaxDecompressedSize);
356 return 100;
357 }
358
359 memset(pDecompressedData, 0, nDictionarySize + nMaxDecompressedSize);
360
361 if (f_dict) {
362 /* Read dictionary data */
363 if (fread(pDecompressedData, 1, nDictionarySize, f_dict) != nDictionarySize) {
364 free(pDecompressedData);
365 fclose(f_dict);
366 fprintf(stderr, "I/O error while reading dictionary '%s'\n", pszDictionaryFilename);
367 return 100;
368 }
369
370 fclose(f_dict);
371 f_dict = NULL;
372
373 if (nOptions & OPT_BACKWARD)
374 do_reverse_buffer(pDecompressedData, nDictionarySize);
375 }
376
377 if (nOptions & OPT_VERBOSE) {
378 nStartTime = do_get_time();
379 }
380
381 nOriginalSize = salvador_decompress(pCompressedData, pDecompressedData, nCompressedSize, nMaxDecompressedSize, nDictionarySize, nFlags);
382 if (nOriginalSize == (size_t)-1) {
383 free(pDecompressedData);
384 free(pCompressedData);
385
386 fprintf(stderr, "decompression error for '%s'\n", pszInFilename);
387 return 100;
388 }
389
390 if (nOptions & OPT_VERBOSE) {
391 nEndTime = do_get_time();
392 }
393
394 if (nOptions & OPT_BACKWARD)
395 do_reverse_buffer(pDecompressedData + nDictionarySize, nOriginalSize);
396
397 /* Write whole decompressed file out */
398
399 FILE *f_out = fopen(pszOutFilename, "wb");
400 if (!f_out) {
401 free(pDecompressedData);
402 free(pCompressedData);
403
404 fprintf(stderr, "error opening '%s' for writing\n", pszOutFilename);
405 return 100;
406 }
407
408 fwrite(pDecompressedData + nDictionarySize, 1, nOriginalSize, f_out);
409 fclose(f_out);
410
411 free(pDecompressedData);
412 free(pCompressedData);
413
414 if (nOptions & OPT_VERBOSE) {
415 double fDelta = ((double)(nEndTime - nStartTime)) / 1000000.0;
416 double fSpeed = ((double)nOriginalSize / 1048576.0) / fDelta;
417 fprintf(stdout, "Decompressed '%s' in %g seconds, %g Mb/s\n",
418 pszInFilename, fDelta, fSpeed);
419 }
420
421 return 0;
422 }
423
424 /*---------------------------------------------------------------------------*/
425
426 static int do_compare(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions) {
427 long long nStartTime = 0LL, nEndTime = 0LL;
428 size_t nCompressedSize, nMaxDecompressedSize, nOriginalSize, nDecompressedSize;
429 unsigned char *pCompressedData = NULL;
430 unsigned char *pOriginalData = NULL;
431 unsigned char *pDecompressedData = NULL;
432 int nFlags = (nOptions & OPT_CLASSIC) ? 0 : FLG_IS_INVERTED;
433
434 if (nOptions & OPT_BACKWARD)
435 nFlags |= FLG_IS_BACKWARD;
436
437 /* Read the whole compressed file in memory */
438
439 FILE *f_in = fopen(pszInFilename, "rb");
440 if (!f_in) {
441 fprintf(stderr, "error opening '%s' for reading\n", pszInFilename);
442 return 100;
443 }
444
445 fseek(f_in, 0, SEEK_END);
446 nCompressedSize = (size_t)ftell(f_in);
447 fseek(f_in, 0, SEEK_SET);
448
449 pCompressedData = (unsigned char*)malloc(nCompressedSize);
450 if (!pCompressedData) {
451 fclose(f_in);
452 fprintf(stderr, "out of memory for reading '%s', %zu bytes needed\n", pszInFilename, nCompressedSize);
453 return 100;
454 }
455
456 if (fread(pCompressedData, 1, nCompressedSize, f_in) != nCompressedSize) {
457 free(pCompressedData);
458 fclose(f_in);
459 fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename);
460 return 100;
461 }
462
463 fclose(f_in);
464 f_in = NULL;
465
466 if (nOptions & OPT_BACKWARD)
467 do_reverse_buffer(pCompressedData, nCompressedSize);
468
469 /* Read the whole original file in memory */
470
471 f_in = fopen(pszOutFilename, "rb");
472 if (!f_in) {
473 free(pCompressedData);
474 fprintf(stderr, "error opening '%s' for reading\n", pszInFilename);
475 return 100;
476 }
477
478 fseek(f_in, 0, SEEK_END);
479 nOriginalSize = (size_t)ftell(f_in);
480 fseek(f_in, 0, SEEK_SET);
481
482 pOriginalData = (unsigned char*)malloc(nOriginalSize);
483 if (!pOriginalData) {
484 fclose(f_in);
485 free(pCompressedData);
486 fprintf(stderr, "out of memory for reading '%s', %zu bytes needed\n", pszInFilename, nOriginalSize);
487 return 100;
488 }
489
490 if (fread(pOriginalData, 1, nOriginalSize, f_in) != nOriginalSize) {
491 free(pOriginalData);
492 fclose(f_in);
493 free(pCompressedData);
494 fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename);
495 return 100;
496 }
497
498 fclose(f_in);
499 f_in = NULL;
500
501 /* Get max decompressed size */
502
503 nMaxDecompressedSize = salvador_get_max_decompressed_size(pCompressedData, nCompressedSize, nFlags);
504 if (nMaxDecompressedSize == (size_t)-1) {
505 free(pOriginalData);
506 free(pCompressedData);
507 fprintf(stderr, "invalid compressed format for file '%s'\n", pszInFilename);
508 return 100;
509 }
510
511 FILE* f_dict = NULL;
512 size_t nDictionarySize = 0;
513 if (pszDictionaryFilename) {
514 /* Open the dictionary */
515 f_dict = fopen(pszDictionaryFilename, "rb");
516 if (!f_dict) {
517 free(pOriginalData);
518 free(pCompressedData);
519 fprintf(stderr, "error opening dictionary '%s' for reading\n", pszDictionaryFilename);
520 return 100;
521 }
522
523 /* Get dictionary size */
524 fseek(f_dict, 0, SEEK_END);
525 nDictionarySize = (size_t)ftell(f_dict);
526 fseek(f_dict, 0, SEEK_SET);
527
528 if (nDictionarySize > BLOCK_SIZE) nDictionarySize = BLOCK_SIZE;
529 }
530
531 /* Allocate max decompressed size */
532
533 pDecompressedData = (unsigned char*)malloc(nDictionarySize + nMaxDecompressedSize);
534 if (!pDecompressedData) {
535 free(pOriginalData);
536 free(pCompressedData);
537 if (f_dict) fclose(f_dict);
538 fprintf(stderr, "out of memory for decompressing '%s', %zu bytes needed\n", pszInFilename, nMaxDecompressedSize);
539 return 100;
540 }
541
542 memset(pDecompressedData, 0, nDictionarySize + nMaxDecompressedSize);
543
544 if (f_dict) {
545 /* Read dictionary data */
546 if (fread(pDecompressedData, 1, nDictionarySize, f_dict) != nDictionarySize) {
547 free(pDecompressedData);
548 free(pOriginalData);
549 free(pCompressedData);
550 fclose(f_dict);
551 fprintf(stderr, "I/O error while reading dictionary '%s'\n", pszDictionaryFilename);
552 return 100;
553 }
554
555 fclose(f_dict);
556 f_dict = NULL;
557
558 if (nOptions & OPT_BACKWARD)
559 do_reverse_buffer(pDecompressedData, nDictionarySize);
560 }
561
562 if (nOptions & OPT_VERBOSE) {
563 nStartTime = do_get_time();
564 }
565
566 nDecompressedSize = salvador_decompress(pCompressedData, pDecompressedData, nCompressedSize, nMaxDecompressedSize, nDictionarySize, nFlags);
567 if (nDecompressedSize == (size_t)-1) {
568 free(pDecompressedData);
569 free(pOriginalData);
570 free(pCompressedData);
571
572 fprintf(stderr, "decompression error for '%s'\n", pszInFilename);
573 return 100;
574 }
575
576 if (nOptions & OPT_VERBOSE) {
577 nEndTime = do_get_time();
578 }
579
580 if (nOptions & OPT_BACKWARD)
581 do_reverse_buffer(pDecompressedData + nDictionarySize, nDecompressedSize);
582
583 if (nDecompressedSize != nOriginalSize || memcmp(pDecompressedData + nDictionarySize, pOriginalData, nOriginalSize)) {
584 free(pDecompressedData);
585 free(pOriginalData);
586 free(pCompressedData);
587
588 fprintf(stderr, "error comparing compressed file '%s' with original '%s'\n", pszInFilename, pszOutFilename);
589 return 100;
590 }
591
592 free(pDecompressedData);
593 free(pOriginalData);
594 free(pCompressedData);
595
596 if (nOptions & OPT_VERBOSE) {
597 double fDelta = ((double)(nEndTime - nStartTime)) / 1000000.0;
598 double fSpeed = ((double)nOriginalSize / 1048576.0) / fDelta;
599 fprintf(stdout, "Compared '%s' in %g seconds, %g Mb/s\n",
600 pszInFilename, fDelta, fSpeed);
601 }
602
603 return 0;
604 }
605
606 /*---------------------------------------------------------------------------*/
607
608 static void generate_compressible_data(unsigned char *pBuffer, size_t nBufferSize, unsigned int nSeed, int nNumLiteralValues, float fMatchProbability) {
609 size_t nIndex = 0;
610 int nMatchProbability = (int)(fMatchProbability * 1023.0f);
611
612 srand(nSeed);
613
614 if (nBufferSize == 0) return;
615 pBuffer[nIndex++] = rand() % nNumLiteralValues;
616
617 while (nIndex < nBufferSize) {
618 if ((rand() & 1023) >= nMatchProbability) {
619 size_t nLiteralCount = rand() & 127;
620 if (nLiteralCount > (nBufferSize - nIndex))
621 nLiteralCount = nBufferSize - nIndex;
622
623 while (nLiteralCount--)
624 pBuffer[nIndex++] = rand() % nNumLiteralValues;
625 }
626 else {
627 size_t nMatchLength = MIN_MATCH_SIZE + (rand() & 1023);
628 size_t nMatchOffset;
629
630 if (nMatchLength > (nBufferSize - nIndex))
631 nMatchLength = nBufferSize - nIndex;
632 if (nMatchLength > nIndex)
633 nMatchLength = nIndex;
634
635 if (nMatchLength < nIndex)
636 nMatchOffset = rand() % (nIndex - nMatchLength);
637 else
638 nMatchOffset = 0;
639
640 while (nMatchLength--) {
641 pBuffer[nIndex] = pBuffer[nIndex - nMatchOffset];
642 nIndex++;
643 }
644 }
645 }
646 }
647
648 static void xor_data(unsigned char *pBuffer, size_t nBufferSize, unsigned int nSeed, float fXorProbability) {
649 size_t nIndex = 0;
650 int nXorProbability = (int)(fXorProbability * 1023.0f);
651
652 srand(nSeed);
653
654 while (nIndex < nBufferSize) {
655 if ((rand() & 1023) < nXorProbability) {
656 pBuffer[nIndex] ^= 0xff;
657 }
658 nIndex++;
659 }
660 }
661
662 static int do_self_test(const unsigned int nOptions, const unsigned int nMaxWindowSize, const int nIsQuickTest) {
663 unsigned char *pGeneratedData;
664 unsigned char *pCompressedData;
665 unsigned char *pTmpCompressedData;
666 unsigned char *pTmpDecompressedData;
667 size_t nGeneratedDataSize;
668 size_t nMaxCompressedDataSize;
669 unsigned int nSeed = 123;
670 int nFlags = FLG_IS_INVERTED;
671 int i;
672
673 if (nOptions & OPT_BACKWARD)
674 nFlags |= FLG_IS_BACKWARD;
675
676 pGeneratedData = (unsigned char*)malloc(4 * BLOCK_SIZE);
677 if (!pGeneratedData) {
678 fprintf(stderr, "out of memory, %d bytes needed\n", 4 * BLOCK_SIZE);
679 return 100;
680 }
681
682 nMaxCompressedDataSize = salvador_get_max_compressed_size(4 * BLOCK_SIZE);
683 pCompressedData = (unsigned char*)malloc(nMaxCompressedDataSize);
684 if (!pCompressedData) {
685 free(pGeneratedData);
686 pGeneratedData = NULL;
687
688 fprintf(stderr, "out of memory, %zu bytes needed\n", nMaxCompressedDataSize);
689 return 100;
690 }
691
692 pTmpCompressedData = (unsigned char*)malloc(nMaxCompressedDataSize);
693 if (!pTmpCompressedData) {
694 free(pCompressedData);
695 pCompressedData = NULL;
696 free(pGeneratedData);
697 pGeneratedData = NULL;
698
699 fprintf(stderr, "out of memory, %zu bytes needed\n", nMaxCompressedDataSize);
700 return 100;
701 }
702
703 pTmpDecompressedData = (unsigned char*)malloc(4 * BLOCK_SIZE);
704 if (!pTmpDecompressedData) {
705 free(pTmpCompressedData);
706 pTmpCompressedData = NULL;
707 free(pCompressedData);
708 pCompressedData = NULL;
709 free(pGeneratedData);
710 pGeneratedData = NULL;
711
712 fprintf(stderr, "out of memory, %d bytes needed\n", 4 * BLOCK_SIZE);
713 return 100;
714 }
715
716 memset(pGeneratedData, 0, 4 * BLOCK_SIZE);
717 memset(pCompressedData, 0, nMaxCompressedDataSize);
718 memset(pTmpCompressedData, 0, nMaxCompressedDataSize);
719
720 /* Test compressing with a too small buffer to do anything, expect to fail cleanly */
721 for (i = 0; i < 12; i++) {
722 generate_compressible_data(pGeneratedData, i, nSeed, 256, 0.5f);
723 salvador_compress(pGeneratedData, pCompressedData, i, i, nFlags, nMaxWindowSize, 0 /* dictionary size */, NULL, NULL);
724 }
725
726 size_t nDataSizeStep = 128;
727 float fProbabilitySizeStep = nIsQuickTest ? 0.005f : 0.0005f;
728
729 for (nGeneratedDataSize = 1024; nGeneratedDataSize <= (nIsQuickTest ? 1024U : (4U * BLOCK_SIZE)); nGeneratedDataSize += nDataSizeStep) {
730 float fMatchProbability;
731
732 fprintf(stdout, "size %zu", nGeneratedDataSize);
733 for (fMatchProbability = 0; fMatchProbability <= 0.995f; fMatchProbability += fProbabilitySizeStep) {
734 int nNumLiteralValues[12] = { 1, 2, 3, 15, 30, 56, 96, 137, 178, 191, 255, 256 };
735 float fXorProbability;
736
737 fputc('.', stdout);
738 fflush(stdout);
739
740 for (i = 0; i < 12; i++) {
741 /* Generate data to compress */
742 generate_compressible_data(pGeneratedData, nGeneratedDataSize, nSeed, nNumLiteralValues[i], fMatchProbability);
743
744 /* Try to compress it, expected to succeed */
745 size_t nActualCompressedSize = salvador_compress(pGeneratedData, pCompressedData, nGeneratedDataSize, salvador_get_max_compressed_size(nGeneratedDataSize),
746 nFlags, nMaxWindowSize, 0 /* dictionary size */, NULL, NULL);
747 if (nActualCompressedSize == (size_t)-1 || nActualCompressedSize < (1 + 1 + 1 /* footer */)) {
748 free(pTmpDecompressedData);
749 pTmpDecompressedData = NULL;
750 free(pTmpCompressedData);
751 pTmpCompressedData = NULL;
752 free(pCompressedData);
753 pCompressedData = NULL;
754 free(pGeneratedData);
755 pGeneratedData = NULL;
756
757 fprintf(stderr, "\nself-test: error compressing size %zu, seed %u, match probability %f, literals range %d\n", nGeneratedDataSize, nSeed, fMatchProbability, nNumLiteralValues[i]);
758 return 100;
759 }
760
761 /* Try to decompress it, expected to succeed */
762 size_t nActualDecompressedSize;
763 nActualDecompressedSize = salvador_decompress(pCompressedData, pTmpDecompressedData, nActualCompressedSize, nGeneratedDataSize, 0 /* dictionary size */, nFlags);
764 if (nActualDecompressedSize == (size_t)-1) {
765 free(pTmpDecompressedData);
766 pTmpDecompressedData = NULL;
767 free(pTmpCompressedData);
768 pTmpCompressedData = NULL;
769 free(pCompressedData);
770 pCompressedData = NULL;
771 free(pGeneratedData);
772 pGeneratedData = NULL;
773
774 fprintf(stderr, "\nself-test: error decompressing size %zu, seed %u, match probability %f, literals range %d\n", nGeneratedDataSize, nSeed, fMatchProbability, nNumLiteralValues[i]);
775 return 100;
776 }
777
778 if (memcmp(pGeneratedData, pTmpDecompressedData, nGeneratedDataSize)) {
779 free(pTmpDecompressedData);
780 pTmpDecompressedData = NULL;
781 free(pTmpCompressedData);
782 pTmpCompressedData = NULL;
783 free(pCompressedData);
784 pCompressedData = NULL;
785 free(pGeneratedData);
786 pGeneratedData = NULL;
787
788 fprintf(stderr, "\nself-test: error comparing decompressed and original data, size %zu, seed %u, match probability %f, literals range %d\n", nGeneratedDataSize, nSeed, fMatchProbability, nNumLiteralValues[i]);
789 return 100;
790 }
791
792 /* Try to decompress corrupted data, expected to fail cleanly, without crashing or corrupting memory outside the output buffer */
793 for (fXorProbability = 0.05f; fXorProbability <= 0.5f; fXorProbability += 0.05f) {
794 memcpy(pTmpCompressedData, pCompressedData, nActualCompressedSize);
795 xor_data(pTmpCompressedData, nActualCompressedSize, nSeed, fXorProbability);
796 salvador_decompress(pTmpCompressedData, pGeneratedData, nActualCompressedSize, nGeneratedDataSize, 0 /* dictionary size */, nFlags);
797 }
798 }
799
800 nSeed++;
801 }
802
803 fputc(10, stdout);
804 fflush(stdout);
805
806 nDataSizeStep <<= 1;
807 if (nDataSizeStep > (128 * 4096))
808 nDataSizeStep = 128 * 4096;
809 fProbabilitySizeStep *= 1.25;
810 if (fProbabilitySizeStep > (0.0005f * 4096))
811 fProbabilitySizeStep = 0.0005f * 4096;
812 }
813
814 free(pTmpDecompressedData);
815 pTmpDecompressedData = NULL;
816
817 free(pTmpCompressedData);
818 pTmpCompressedData = NULL;
819
820 free(pCompressedData);
821 pCompressedData = NULL;
822
823 free(pGeneratedData);
824 pGeneratedData = NULL;
825
826 fprintf(stdout, "All tests passed.\n");
827 return 0;
828 }
829
830 /*---------------------------------------------------------------------------*/
831
832 static int do_compr_benchmark(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions, const unsigned int nMaxWindowSize) {
833 size_t nFileSize, nMaxCompressedSize;
834 unsigned char *pFileData;
835 unsigned char *pCompressedData;
836 int nFlags = FLG_IS_INVERTED;
837 int i;
838
839 if (pszDictionaryFilename) {
840 fprintf(stderr, "in-memory benchmarking does not support dictionaries\n");
841 return 100;
842 }
843
844 /* Read the whole original file in memory */
845
846 FILE *f_in = fopen(pszInFilename, "rb");
847 if (!f_in) {
848 fprintf(stderr, "error opening '%s' for reading\n", pszInFilename);
849 return 100;
850 }
851
852 fseek(f_in, 0, SEEK_END);
853 nFileSize = (size_t)ftell(f_in);
854 fseek(f_in, 0, SEEK_SET);
855
856 pFileData = (unsigned char*)malloc(nFileSize);
857 if (!pFileData) {
858 fclose(f_in);
859 fprintf(stderr, "out of memory for reading '%s', %zu bytes needed\n", pszInFilename, nFileSize);
860 return 100;
861 }
862
863 if (fread(pFileData, 1, nFileSize, f_in) != nFileSize) {
864 free(pFileData);
865 fclose(f_in);
866 fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename);
867 return 100;
868 }
869
870 fclose(f_in);
871 f_in = NULL;
872
873 if (nOptions & OPT_BACKWARD)
874 do_reverse_buffer(pFileData, nFileSize);
875
876 /* Allocate max compressed size */
877
878 nMaxCompressedSize = salvador_get_max_compressed_size(nFileSize);
879
880 pCompressedData = (unsigned char*)malloc(nMaxCompressedSize + 2048);
881 if (!pCompressedData) {
882 free(pFileData);
883 fprintf(stderr, "out of memory for compressing '%s', %zu bytes needed\n", pszInFilename, nMaxCompressedSize);
884 return 100;
885 }
886
887 memset(pCompressedData + 1024, 0, nMaxCompressedSize);
888
889 long long nBestCompTime = -1;
890
891 size_t nActualCompressedSize = 0;
892 size_t nRightGuardPos = nMaxCompressedSize;
893
894 for (i = 0; i < 5; i++) {
895 unsigned char nGuard = 0x33 + i;
896 int j;
897
898 /* Write guard bytes around the output buffer, to help check for writes outside of it by the compressor */
899 memset(pCompressedData, nGuard, 1024);
900 memset(pCompressedData + 1024 + nRightGuardPos, nGuard, 1024);
901
902 long long t0 = do_get_time();
903 nActualCompressedSize = salvador_compress(pFileData, pCompressedData + 1024, nFileSize, nRightGuardPos, nFlags, nMaxWindowSize, 0 /* dictionary size */, NULL, NULL);
904 long long t1 = do_get_time();
905 if (nActualCompressedSize == (size_t)-1) {
906 free(pCompressedData);
907 free(pFileData);
908 fprintf(stderr, "compression error\n");
909 return 100;
910 }
911
912 long long nCurDecTime = t1 - t0;
913 if (nBestCompTime == -1 || nBestCompTime > nCurDecTime)
914 nBestCompTime = nCurDecTime;
915
916 /* Check guard bytes before the output buffer */
917 for (j = 0; j < 1024; j++) {
918 if (pCompressedData[j] != nGuard) {
919 free(pCompressedData);
920 free(pFileData);
921 fprintf(stderr, "error, wrote outside of output buffer at %d!\n", j - 1024);
922 return 100;
923 }
924 }
925
926 /* Check guard bytes after the output buffer */
927 for (j = 0; j < 1024; j++) {
928 if (pCompressedData[1024 + nRightGuardPos + j] != nGuard) {
929 free(pCompressedData);
930 free(pFileData);
931 fprintf(stderr, "error, wrote outside of output buffer at %d!\n", j);
932 return 100;
933 }
934 }
935
936 nRightGuardPos = nActualCompressedSize;
937 }
938
939 if (nOptions & OPT_BACKWARD)
940 do_reverse_buffer(pCompressedData + 1024, nActualCompressedSize);
941
942 if (pszOutFilename) {
943 FILE *f_out;
944
945 /* Write whole compressed file out */
946
947 f_out = fopen(pszOutFilename, "wb");
948 if (f_out) {
949 fwrite(pCompressedData + 1024, 1, nActualCompressedSize, f_out);
950 fclose(f_out);
951 }
952 }
953
954 free(pCompressedData);
955 free(pFileData);
956
957 fprintf(stdout, "compressed size: %zu bytes\n", nActualCompressedSize);
958 fprintf(stdout, "compression time: %lld microseconds (%g Mb/s)\n", nBestCompTime, ((double)nActualCompressedSize / 1024.0) / ((double)nBestCompTime / 1000.0));
959
960 return 0;
961 }
962
963 /*---------------------------------------------------------------------------*/
964
965 static int do_dec_benchmark(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions) {
966 size_t nFileSize, nMaxDecompressedSize;
967 unsigned char *pFileData;
968 unsigned char *pDecompressedData;
969 int nFlags = FLG_IS_INVERTED;
970 int i;
971
972 if (pszDictionaryFilename) {
973 fprintf(stderr, "in-memory benchmarking does not support dictionaries\n");
974 return 100;
975 }
976
977 /* Read the whole compressed file in memory */
978
979 FILE *f_in = fopen(pszInFilename, "rb");
980 if (!f_in) {
981 fprintf(stderr, "error opening '%s' for reading\n", pszInFilename);
982 return 100;
983 }
984
985 fseek(f_in, 0, SEEK_END);
986 nFileSize = (size_t)ftell(f_in);
987 fseek(f_in, 0, SEEK_SET);
988
989 pFileData = (unsigned char*)malloc(nFileSize);
990 if (!pFileData) {
991 fclose(f_in);
992 fprintf(stderr, "out of memory for reading '%s', %zu bytes needed\n", pszInFilename, nFileSize);
993 return 100;
994 }
995
996 if (fread(pFileData, 1, nFileSize, f_in) != nFileSize) {
997 free(pFileData);
998 fclose(f_in);
999 fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename);
1000 return 100;
1001 }
1002
1003 fclose(f_in);
1004 f_in = NULL;
1005
1006 if (nOptions & OPT_BACKWARD)
1007 do_reverse_buffer(pFileData, nFileSize);
1008
1009 /* Allocate max decompressed size */
1010
1011 nMaxDecompressedSize = salvador_get_max_decompressed_size(pFileData, nFileSize, nFlags);
1012 if (nMaxDecompressedSize == (size_t)-1) {
1013 free(pFileData);
1014 fprintf(stderr, "invalid compressed format for file '%s'\n", pszInFilename);
1015 return 100;
1016 }
1017
1018 pDecompressedData = (unsigned char*)malloc(nMaxDecompressedSize);
1019 if (!pDecompressedData) {
1020 free(pFileData);
1021 fprintf(stderr, "out of memory for decompressing '%s', %zu bytes needed\n", pszInFilename, nMaxDecompressedSize);
1022 return 100;
1023 }
1024
1025 memset(pDecompressedData, 0, nMaxDecompressedSize);
1026
1027 long long nBestDecTime = -1;
1028
1029 size_t nActualDecompressedSize = 0;
1030 for (i = 0; i < 50; i++) {
1031 long long t0 = do_get_time();
1032 nActualDecompressedSize = salvador_decompress(pFileData, pDecompressedData, nFileSize, nMaxDecompressedSize, 0 /* dictionary size */, nFlags);
1033 long long t1 = do_get_time();
1034 if (nActualDecompressedSize == (size_t)-1) {
1035 free(pDecompressedData);
1036 free(pFileData);
1037 fprintf(stderr, "decompression error\n");
1038 return 100;
1039 }
1040
1041 long long nCurDecTime = t1 - t0;
1042 if (nBestDecTime == -1 || nBestDecTime > nCurDecTime)
1043 nBestDecTime = nCurDecTime;
1044 }
1045
1046 if (nOptions & OPT_BACKWARD)
1047 do_reverse_buffer(pDecompressedData, nActualDecompressedSize);
1048
1049 if (pszOutFilename) {
1050 FILE *f_out;
1051
1052 /* Write whole decompressed file out */
1053
1054 f_out = fopen(pszOutFilename, "wb");
1055 if (f_out) {
1056 fwrite(pDecompressedData, 1, nActualDecompressedSize, f_out);
1057 fclose(f_out);
1058 }
1059 }
1060
1061 free(pDecompressedData);
1062 free(pFileData);
1063
1064 fprintf(stdout, "decompressed size: %zu bytes\n", nActualDecompressedSize);
1065 fprintf(stdout, "decompression time: %lld microseconds (%g Mb/s)\n", nBestDecTime, ((double)nActualDecompressedSize / 1024.0) / ((double)nBestDecTime / 1000.0));
1066
1067 return 0;
1068 }
1069
1070 /*---------------------------------------------------------------------------*/
1071
1072 int main(int argc, char **argv) {
1073 int i;
1074 const char *pszInFilename = NULL;
1075 const char *pszOutFilename = NULL;
1076 const char *pszDictionaryFilename = NULL;
1077 int nArgsError = 0;
1078 int nCommandDefined = 0;
1079 int nVerifyCompression = 0;
1080 char cCommand = 'z';
1081 unsigned int nOptions = 0;
1082 unsigned int nMaxWindowSize = 0;
1083
1084 for (i = 1; i < argc; i++) {
1085 if (!strcmp(argv[i], "-d")) {
1086 if (!nCommandDefined) {
1087 nCommandDefined = 1;
1088 cCommand = 'd';
1089 }
1090 else
1091 nArgsError = 1;
1092 }
1093 else if (!strcmp(argv[i], "-z")) {
1094 if (!nCommandDefined) {
1095 nCommandDefined = 1;
1096 cCommand = 'z';
1097 }
1098 else
1099 nArgsError = 1;
1100 }
1101 else if (!strcmp(argv[i], "-c")) {
1102 if (!nVerifyCompression) {
1103 nVerifyCompression = 1;
1104 }
1105 else
1106 nArgsError = 1;
1107 }
1108 else if (!strcmp(argv[i], "-cbench")) {
1109 if (!nCommandDefined) {
1110 nCommandDefined = 1;
1111 cCommand = 'B';
1112 }
1113 else
1114 nArgsError = 1;
1115 }
1116 else if (!strcmp(argv[i], "-dbench")) {
1117 if (!nCommandDefined) {
1118 nCommandDefined = 1;
1119 cCommand = 'b';
1120 }
1121 else
1122 nArgsError = 1;
1123 }
1124 else if (!strcmp(argv[i], "-test")) {
1125 if (!nCommandDefined) {
1126 nCommandDefined = 1;
1127 cCommand = 't';
1128 }
1129 else
1130 nArgsError = 1;
1131 }
1132 else if (!strcmp(argv[i], "-quicktest")) {
1133 if (!nCommandDefined) {
1134 nCommandDefined = 1;
1135 cCommand = 'T';
1136 }
1137 else
1138 nArgsError = 1;
1139 }
1140 else if (!strcmp(argv[i], "-D")) {
1141 if (!pszDictionaryFilename && (i + 1) < argc) {
1142 pszDictionaryFilename = argv[i + 1];
1143 i++;
1144 }
1145 else
1146 nArgsError = 1;
1147 }
1148 else if (!strncmp(argv[i], "-D", 2)) {
1149 if (!pszDictionaryFilename) {
1150 pszDictionaryFilename = argv[i] + 2;
1151 }
1152 else
1153 nArgsError = 1;
1154 }
1155 else if (!strcmp(argv[i], "-v")) {
1156 if ((nOptions & OPT_VERBOSE) == 0) {
1157 nOptions |= OPT_VERBOSE;
1158 }
1159 else
1160 nArgsError = 1;
1161 }
1162 else if (!strcmp(argv[i], "-w")) {
1163 if (!nMaxWindowSize && (i + 1) < argc) {
1164 char *pEnd = NULL;
1165 nMaxWindowSize = (int)strtol(argv[i + 1], &pEnd, 10);
1166 if (pEnd && pEnd != argv[i + 1] && (nMaxWindowSize >= 16 && nMaxWindowSize <= MAX_OFFSET)) {
1167 i++;
1168 }
1169 else {
1170 nArgsError = 1;
1171 }
1172 }
1173 else
1174 nArgsError = 1;
1175 }
1176 else if (!strncmp(argv[i], "-w", 2)) {
1177 if (!nMaxWindowSize) {
1178 char *pEnd = NULL;
1179 nMaxWindowSize = (int)strtol(argv[i] + 2, &pEnd, 10);
1180 if (!(pEnd && pEnd != (argv[i] + 2) && (nMaxWindowSize >= 16 && nMaxWindowSize <= MAX_OFFSET))) {
1181 nArgsError = 1;
1182 }
1183 }
1184 else
1185 nArgsError = 1;
1186 }
1187 else if (!strcmp(argv[i], "-stats")) {
1188 if ((nOptions & OPT_STATS) == 0) {
1189 nOptions |= OPT_STATS;
1190 }
1191 else
1192 nArgsError = 1;
1193 }
1194 else if (!strcmp(argv[i], "-b")) {
1195 if ((nOptions & OPT_BACKWARD) == 0) {
1196 nOptions |= OPT_BACKWARD;
1197 }
1198 else
1199 nArgsError = 1;
1200 }
1201 else if (!strcmp(argv[i], "-classic")) {
1202 if ((nOptions & OPT_CLASSIC) == 0) {
1203 nOptions |= OPT_CLASSIC;
1204 }
1205 else
1206 nArgsError = 1;
1207 }
1208 else {
1209 if (!pszInFilename)
1210 pszInFilename = argv[i];
1211 else {
1212 if (!pszOutFilename)
1213 pszOutFilename = argv[i];
1214 else
1215 nArgsError = 1;
1216 }
1217 }
1218 }
1219
1220 if (!nArgsError && cCommand == 't') {
1221 return do_self_test(nOptions, nMaxWindowSize, 0);
1222 }
1223 else if (!nArgsError && cCommand == 'T') {
1224 return do_self_test(nOptions, nMaxWindowSize, 1);
1225 }
1226
1227 if (nArgsError || !pszInFilename || !pszOutFilename) {
1228 fprintf(stderr, "salvador command-line tool v" TOOL_VERSION " by Emmanuel Marty\n");
1229 fprintf(stderr, "usage: %s [-c] [-d] [-v] [-b] <infile> <outfile>\n", argv[0]);
1230 fprintf(stderr, " -c: check resulting stream after compressing\n");
1231 fprintf(stderr, " -d: decompress (default: compress)\n");
1232 fprintf(stderr, " -b: backwards compression or decompression\n");
1233 fprintf(stderr, " -w <size>: maximum window size, in bytes (16..32639), defaults to maximum\n");
1234 fprintf(stderr, " -D <file>: use dictionary file\n");
1235 fprintf(stderr, " -cbench: benchmark in-memory compression\n");
1236 fprintf(stderr, " -dbench: benchmark in-memory decompression\n");
1237 fprintf(stderr, " -test: run full automated self-tests\n");
1238 fprintf(stderr, "-quicktest: run quick automated self-tests\n");
1239 fprintf(stderr, " -stats: show compressed data stats\n");
1240 fprintf(stderr, " -classic: encode and decode using classical (V1) format, defaults to modern (V2)\n");
1241 fprintf(stderr, " -v: be verbose\n");
1242 return 100;
1243 }
1244
1245 do_init_time();
1246
1247 if (cCommand == 'z') {
1248 int nResult = do_compress(pszInFilename, pszOutFilename, pszDictionaryFilename, nOptions, nMaxWindowSize);
1249 if (nResult == 0 && nVerifyCompression) {
1250 return do_compare(pszOutFilename, pszInFilename, pszDictionaryFilename, nOptions);
1251 } else {
1252 return nResult;
1253 }
1254 }
1255 else if (cCommand == 'd') {
1256 return do_decompress(pszInFilename, pszOutFilename, pszDictionaryFilename, nOptions);
1257 }
1258 else if (cCommand == 'B') {
1259 return do_compr_benchmark(pszInFilename, pszOutFilename, pszDictionaryFilename, nOptions, nMaxWindowSize);
1260 }
1261 else if (cCommand == 'b') {
1262 return do_dec_benchmark(pszInFilename, pszOutFilename, pszDictionaryFilename, nOptions);
1263 }
1264 else {
1265 return 100;
1266 }
1267 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.