libdeflate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +1 -0
  6. data/.rubocop_todo.yml +9 -0
  7. data/.travis.yml +5 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +52 -0
  11. data/Rakefile +15 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/ext/libdeflate/extconf.rb +14 -0
  15. data/ext/libdeflate/libdeflate/.gitignore +19 -0
  16. data/ext/libdeflate/libdeflate/COPYING +21 -0
  17. data/ext/libdeflate/libdeflate/Makefile +231 -0
  18. data/ext/libdeflate/libdeflate/Makefile.msc +64 -0
  19. data/ext/libdeflate/libdeflate/NEWS +57 -0
  20. data/ext/libdeflate/libdeflate/README.md +170 -0
  21. data/ext/libdeflate/libdeflate/common/common_defs.h +351 -0
  22. data/ext/libdeflate/libdeflate/common/compiler_gcc.h +134 -0
  23. data/ext/libdeflate/libdeflate/common/compiler_msc.h +95 -0
  24. data/ext/libdeflate/libdeflate/lib/adler32.c +213 -0
  25. data/ext/libdeflate/libdeflate/lib/adler32_impl.h +281 -0
  26. data/ext/libdeflate/libdeflate/lib/aligned_malloc.c +57 -0
  27. data/ext/libdeflate/libdeflate/lib/aligned_malloc.h +13 -0
  28. data/ext/libdeflate/libdeflate/lib/bt_matchfinder.h +357 -0
  29. data/ext/libdeflate/libdeflate/lib/crc32.c +368 -0
  30. data/ext/libdeflate/libdeflate/lib/crc32_impl.h +286 -0
  31. data/ext/libdeflate/libdeflate/lib/crc32_table.h +526 -0
  32. data/ext/libdeflate/libdeflate/lib/decompress_impl.h +404 -0
  33. data/ext/libdeflate/libdeflate/lib/deflate_compress.c +2817 -0
  34. data/ext/libdeflate/libdeflate/lib/deflate_compress.h +14 -0
  35. data/ext/libdeflate/libdeflate/lib/deflate_constants.h +66 -0
  36. data/ext/libdeflate/libdeflate/lib/deflate_decompress.c +889 -0
  37. data/ext/libdeflate/libdeflate/lib/gzip_compress.c +95 -0
  38. data/ext/libdeflate/libdeflate/lib/gzip_constants.h +45 -0
  39. data/ext/libdeflate/libdeflate/lib/gzip_decompress.c +130 -0
  40. data/ext/libdeflate/libdeflate/lib/hc_matchfinder.h +405 -0
  41. data/ext/libdeflate/libdeflate/lib/lib_common.h +35 -0
  42. data/ext/libdeflate/libdeflate/lib/matchfinder_avx2.h +53 -0
  43. data/ext/libdeflate/libdeflate/lib/matchfinder_common.h +205 -0
  44. data/ext/libdeflate/libdeflate/lib/matchfinder_neon.h +61 -0
  45. data/ext/libdeflate/libdeflate/lib/matchfinder_sse2.h +53 -0
  46. data/ext/libdeflate/libdeflate/lib/unaligned.h +202 -0
  47. data/ext/libdeflate/libdeflate/lib/x86_cpu_features.c +169 -0
  48. data/ext/libdeflate/libdeflate/lib/x86_cpu_features.h +48 -0
  49. data/ext/libdeflate/libdeflate/lib/zlib_compress.c +87 -0
  50. data/ext/libdeflate/libdeflate/lib/zlib_constants.h +21 -0
  51. data/ext/libdeflate/libdeflate/lib/zlib_decompress.c +91 -0
  52. data/ext/libdeflate/libdeflate/libdeflate.h +274 -0
  53. data/ext/libdeflate/libdeflate/programs/benchmark.c +558 -0
  54. data/ext/libdeflate/libdeflate/programs/checksum.c +197 -0
  55. data/ext/libdeflate/libdeflate/programs/detect.sh +62 -0
  56. data/ext/libdeflate/libdeflate/programs/gzip.c +603 -0
  57. data/ext/libdeflate/libdeflate/programs/prog_util.c +530 -0
  58. data/ext/libdeflate/libdeflate/programs/prog_util.h +162 -0
  59. data/ext/libdeflate/libdeflate/programs/test_checksums.c +135 -0
  60. data/ext/libdeflate/libdeflate/programs/tgetopt.c +118 -0
  61. data/ext/libdeflate/libdeflate/tools/afl-fuzz/Makefile +12 -0
  62. data/ext/libdeflate/libdeflate/tools/afl-fuzz/deflate_compress/fuzz.c +40 -0
  63. data/ext/libdeflate/libdeflate/tools/afl-fuzz/deflate_compress/inputs/0 +0 -0
  64. data/ext/libdeflate/libdeflate/tools/afl-fuzz/deflate_decompress/fuzz.c +28 -0
  65. data/ext/libdeflate/libdeflate/tools/afl-fuzz/deflate_decompress/inputs/0 +3 -0
  66. data/ext/libdeflate/libdeflate/tools/afl-fuzz/gzip_decompress/fuzz.c +28 -0
  67. data/ext/libdeflate/libdeflate/tools/afl-fuzz/gzip_decompress/inputs/0 +0 -0
  68. data/ext/libdeflate/libdeflate/tools/afl-fuzz/prepare_for_fuzz.sh +14 -0
  69. data/ext/libdeflate/libdeflate/tools/afl-fuzz/zlib_decompress/fuzz.c +28 -0
  70. data/ext/libdeflate/libdeflate/tools/afl-fuzz/zlib_decompress/inputs/0 +3 -0
  71. data/ext/libdeflate/libdeflate/tools/android_build.sh +104 -0
  72. data/ext/libdeflate/libdeflate/tools/checksum_benchmarks.sh +76 -0
  73. data/ext/libdeflate/libdeflate/tools/exec_tests.sh +30 -0
  74. data/ext/libdeflate/libdeflate/tools/gen_crc32_multipliers.c +108 -0
  75. data/ext/libdeflate/libdeflate/tools/gen_crc32_table.c +100 -0
  76. data/ext/libdeflate/libdeflate/tools/gzip_tests.sh +412 -0
  77. data/ext/libdeflate/libdeflate/tools/make-windows-releases +21 -0
  78. data/ext/libdeflate/libdeflate/tools/mips_build.sh +9 -0
  79. data/ext/libdeflate/libdeflate/tools/msc_test.bat +3 -0
  80. data/ext/libdeflate/libdeflate/tools/pgo_build.sh +23 -0
  81. data/ext/libdeflate/libdeflate/tools/produce_gzip_benchmark_table.sh +37 -0
  82. data/ext/libdeflate/libdeflate/tools/run_tests.sh +305 -0
  83. data/ext/libdeflate/libdeflate/tools/windows_build.sh +10 -0
  84. data/ext/libdeflate/libdeflate_ext.c +389 -0
  85. data/ext/libdeflate/libdeflate_ext.h +8 -0
  86. data/lib/libdeflate.rb +2 -0
  87. data/lib/libdeflate/version.rb +3 -0
  88. data/libdeflate.gemspec +33 -0
  89. metadata +230 -0
@@ -0,0 +1,530 @@
1
+ /*
2
+ * prog_util.c - utility functions for programs
3
+ *
4
+ * Copyright 2016 Eric Biggers
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person
7
+ * obtaining a copy of this software and associated documentation
8
+ * files (the "Software"), to deal in the Software without
9
+ * restriction, including without limitation the rights to use,
10
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the
12
+ * Software is furnished to do so, subject to the following
13
+ * conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be
16
+ * included in all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
+ * OTHER DEALINGS IN THE SOFTWARE.
26
+ */
27
+
28
+ #include "prog_util.h"
29
+
30
+ #include <errno.h>
31
+ #include <fcntl.h>
32
+ #include <stdarg.h>
33
+ #include <time.h>
34
+ #ifdef _WIN32
35
+ # include <windows.h>
36
+ #else
37
+ # include <unistd.h>
38
+ # include <sys/mman.h>
39
+ # include <sys/time.h>
40
+ #endif
41
+
42
+ #ifndef O_BINARY
43
+ # define O_BINARY 0
44
+ #endif
45
+ #ifndef O_SEQUENTIAL
46
+ # define O_SEQUENTIAL 0
47
+ #endif
48
+ #ifndef O_NOFOLLOW
49
+ # define O_NOFOLLOW 0
50
+ #endif
51
+ #ifndef O_NONBLOCK
52
+ # define O_NONBLOCK 0
53
+ #endif
54
+ #ifndef O_NOCTTY
55
+ # define O_NOCTTY 0
56
+ #endif
57
+
58
+ /* The invocation name of the program (filename component only) */
59
+ const tchar *program_invocation_name;
60
+
61
+ static void
62
+ do_msg(const char *format, bool with_errno, va_list va)
63
+ {
64
+ int saved_errno = errno;
65
+
66
+ fprintf(stderr, "%"TS": ", program_invocation_name);
67
+ vfprintf(stderr, format, va);
68
+ if (with_errno)
69
+ fprintf(stderr, ": %s\n", strerror(saved_errno));
70
+ else
71
+ fprintf(stderr, "\n");
72
+
73
+ errno = saved_errno;
74
+ }
75
+
76
+ /* Print a message to standard error */
77
+ void
78
+ msg(const char *format, ...)
79
+ {
80
+ va_list va;
81
+
82
+ va_start(va, format);
83
+ do_msg(format, false, va);
84
+ va_end(va);
85
+ }
86
+
87
+ /* Print a message to standard error, including a description of errno */
88
+ void
89
+ msg_errno(const char *format, ...)
90
+ {
91
+ va_list va;
92
+
93
+ va_start(va, format);
94
+ do_msg(format, true, va);
95
+ va_end(va);
96
+ }
97
+
98
+ /* malloc() wrapper */
99
+ void *
100
+ xmalloc(size_t size)
101
+ {
102
+ void *p = malloc(size);
103
+ if (p == NULL && size == 0)
104
+ p = malloc(1);
105
+ if (p == NULL)
106
+ msg("Out of memory");
107
+ return p;
108
+ }
109
+
110
+ /*
111
+ * Return the number of timer ticks that have elapsed since some unspecified
112
+ * point fixed at the start of program execution
113
+ */
114
+ u64
115
+ timer_ticks(void)
116
+ {
117
+ #ifdef _WIN32
118
+ LARGE_INTEGER count;
119
+ QueryPerformanceCounter(&count);
120
+ return count.QuadPart;
121
+ #elif defined(HAVE_CLOCK_GETTIME)
122
+ struct timespec ts;
123
+ clock_gettime(CLOCK_MONOTONIC, &ts);
124
+ return (1000000000 * (u64)ts.tv_sec) + ts.tv_nsec;
125
+ #else
126
+ struct timeval tv;
127
+ gettimeofday(&tv, NULL);
128
+ return (1000000 * (u64)tv.tv_sec) + tv.tv_usec;
129
+ #endif
130
+ }
131
+
132
+ /*
133
+ * Return the number of timer ticks per second
134
+ */
135
+ static u64
136
+ timer_frequency(void)
137
+ {
138
+ #ifdef _WIN32
139
+ LARGE_INTEGER freq;
140
+ QueryPerformanceFrequency(&freq);
141
+ return freq.QuadPart;
142
+ #elif defined(HAVE_CLOCK_GETTIME)
143
+ return 1000000000;
144
+ #else
145
+ return 1000000;
146
+ #endif
147
+ }
148
+
149
+ /*
150
+ * Convert a number of elapsed timer ticks to milliseconds
151
+ */
152
+ u64 timer_ticks_to_ms(u64 ticks)
153
+ {
154
+ return ticks * 1000 / timer_frequency();
155
+ }
156
+
157
+ /*
158
+ * Convert a byte count and a number of elapsed timer ticks to MB/s
159
+ */
160
+ u64 timer_MB_per_s(u64 bytes, u64 ticks)
161
+ {
162
+ return bytes * timer_frequency() / ticks / 1000000;
163
+ }
164
+
165
+ /*
166
+ * Retrieve a pointer to the filename component of the specified path.
167
+ *
168
+ * Note: this does not modify the path. Therefore, it is not guaranteed to work
169
+ * properly for directories, since a path to a directory might have trailing
170
+ * slashes.
171
+ */
172
+ const tchar *
173
+ get_filename(const tchar *path)
174
+ {
175
+ const tchar *slash = tstrrchr(path, '/');
176
+ #ifdef _WIN32
177
+ const tchar *backslash = tstrrchr(path, '\\');
178
+ if (backslash != NULL && (slash == NULL || backslash > slash))
179
+ slash = backslash;
180
+ #endif
181
+ if (slash != NULL)
182
+ return slash + 1;
183
+ return path;
184
+ }
185
+
186
+ /* Create a copy of 'path' surrounded by double quotes */
187
+ static tchar *
188
+ quote_path(const tchar *path)
189
+ {
190
+ size_t len = tstrlen(path);
191
+ tchar *result;
192
+
193
+ result = xmalloc((1 + len + 1 + 1) * sizeof(tchar));
194
+ if (result == NULL)
195
+ return NULL;
196
+ result[0] = '"';
197
+ tmemcpy(&result[1], path, len);
198
+ result[1 + len] = '"';
199
+ result[1 + len + 1] = '\0';
200
+ return result;
201
+ }
202
+
203
+ /* Open a file for reading, or set up standard input for reading */
204
+ int
205
+ xopen_for_read(const tchar *path, bool symlink_ok, struct file_stream *strm)
206
+ {
207
+ strm->mmap_token = NULL;
208
+ strm->mmap_mem = NULL;
209
+
210
+ if (path == NULL) {
211
+ strm->is_standard_stream = true;
212
+ strm->name = T("standard input");
213
+ strm->fd = STDIN_FILENO;
214
+ #ifdef _WIN32
215
+ _setmode(strm->fd, O_BINARY);
216
+ #endif
217
+ return 0;
218
+ }
219
+
220
+ strm->is_standard_stream = false;
221
+
222
+ strm->name = quote_path(path);
223
+ if (strm->name == NULL)
224
+ return -1;
225
+
226
+ strm->fd = topen(path, O_RDONLY | O_BINARY | O_NONBLOCK | O_NOCTTY |
227
+ (symlink_ok ? 0 : O_NOFOLLOW) | O_SEQUENTIAL);
228
+ if (strm->fd < 0) {
229
+ msg_errno("Can't open %"TS" for reading", strm->name);
230
+ free(strm->name);
231
+ return -1;
232
+ }
233
+
234
+ #if defined(HAVE_POSIX_FADVISE) && (O_SEQUENTIAL == 0)
235
+ posix_fadvise(strm->fd, 0, 0, POSIX_FADV_SEQUENTIAL);
236
+ #endif
237
+
238
+ return 0;
239
+ }
240
+
241
+ /* Open a file for writing, or set up standard output for writing */
242
+ int
243
+ xopen_for_write(const tchar *path, bool overwrite, struct file_stream *strm)
244
+ {
245
+ int ret = -1;
246
+
247
+ strm->mmap_token = NULL;
248
+ strm->mmap_mem = NULL;
249
+
250
+ if (path == NULL) {
251
+ strm->is_standard_stream = true;
252
+ strm->name = T("standard output");
253
+ strm->fd = STDOUT_FILENO;
254
+ #ifdef _WIN32
255
+ _setmode(strm->fd, O_BINARY);
256
+ #endif
257
+ return 0;
258
+ }
259
+
260
+ strm->is_standard_stream = false;
261
+
262
+ strm->name = quote_path(path);
263
+ if (strm->name == NULL)
264
+ goto err;
265
+ retry:
266
+ strm->fd = topen(path, O_WRONLY | O_BINARY | O_NOFOLLOW |
267
+ O_CREAT | O_EXCL, 0644);
268
+ if (strm->fd < 0) {
269
+ if (errno != EEXIST) {
270
+ msg_errno("Can't open %"TS" for writing", strm->name);
271
+ goto err;
272
+ }
273
+ if (!overwrite) {
274
+ if (!isatty(STDERR_FILENO) || !isatty(STDIN_FILENO)) {
275
+ msg("%"TS" already exists; use -f to overwrite",
276
+ strm->name);
277
+ ret = -2; /* warning only */
278
+ goto err;
279
+ }
280
+ fprintf(stderr, "%"TS": %"TS" already exists; "
281
+ "overwrite? (y/n) ",
282
+ program_invocation_name, strm->name);
283
+ if (getchar() != 'y') {
284
+ msg("Not overwriting.");
285
+ goto err;
286
+ }
287
+ }
288
+ if (tunlink(path) != 0) {
289
+ msg_errno("Unable to delete %"TS, strm->name);
290
+ goto err;
291
+ }
292
+ goto retry;
293
+ }
294
+
295
+ return 0;
296
+
297
+ err:
298
+ free(strm->name);
299
+ return ret;
300
+ }
301
+
302
+ /* Read the full contents of a file into memory */
303
+ static int
304
+ read_full_contents(struct file_stream *strm)
305
+ {
306
+ size_t filled = 0;
307
+ size_t capacity = 4096;
308
+ char *buf;
309
+ int ret;
310
+
311
+ buf = xmalloc(capacity);
312
+ if (buf == NULL)
313
+ return -1;
314
+ do {
315
+ if (filled == capacity) {
316
+ char *newbuf;
317
+
318
+ if (capacity == SIZE_MAX)
319
+ goto oom;
320
+ capacity += MIN(SIZE_MAX - capacity, capacity);
321
+ newbuf = realloc(buf, capacity);
322
+ if (newbuf == NULL)
323
+ goto oom;
324
+ buf = newbuf;
325
+ }
326
+ ret = xread(strm, &buf[filled], capacity - filled);
327
+ if (ret < 0)
328
+ goto err;
329
+ filled += ret;
330
+ } while (ret != 0);
331
+
332
+ strm->mmap_mem = buf;
333
+ strm->mmap_size = filled;
334
+ return 0;
335
+
336
+ err:
337
+ free(buf);
338
+ return ret;
339
+ oom:
340
+ msg("Out of memory! %"TS" is too large to be processed by "
341
+ "this program as currently implemented.", strm->name);
342
+ ret = -1;
343
+ goto err;
344
+ }
345
+
346
+ /* Map the contents of a file into memory */
347
+ int
348
+ map_file_contents(struct file_stream *strm, u64 size)
349
+ {
350
+ if (size == 0) /* mmap isn't supported on empty files */
351
+ return read_full_contents(strm);
352
+
353
+ if (size > SIZE_MAX) {
354
+ msg("%"TS" is too large to be processed by this program",
355
+ strm->name);
356
+ return -1;
357
+ }
358
+ #ifdef _WIN32
359
+ strm->mmap_token = CreateFileMapping(
360
+ (HANDLE)(intptr_t)_get_osfhandle(strm->fd),
361
+ NULL, PAGE_READONLY, 0, 0, NULL);
362
+ if (strm->mmap_token == NULL) {
363
+ DWORD err = GetLastError();
364
+ if (err == ERROR_BAD_EXE_FORMAT) /* mmap unsupported */
365
+ return read_full_contents(strm);
366
+ msg("Unable create file mapping for %"TS": Windows error %u",
367
+ strm->name, (unsigned int)err);
368
+ return -1;
369
+ }
370
+
371
+ strm->mmap_mem = MapViewOfFile((HANDLE)strm->mmap_token,
372
+ FILE_MAP_READ, 0, 0, size);
373
+ if (strm->mmap_mem == NULL) {
374
+ msg("Unable to map %"TS" into memory: Windows error %u",
375
+ strm->name, (unsigned int)GetLastError());
376
+ CloseHandle((HANDLE)strm->mmap_token);
377
+ return -1;
378
+ }
379
+ #else /* _WIN32 */
380
+ strm->mmap_mem = mmap(NULL, size, PROT_READ, MAP_SHARED, strm->fd, 0);
381
+ if (strm->mmap_mem == MAP_FAILED) {
382
+ strm->mmap_mem = NULL;
383
+ if (errno == ENODEV) /* mmap isn't supported on this file */
384
+ return read_full_contents(strm);
385
+ if (errno == ENOMEM) {
386
+ msg("%"TS" is too large to be processed by this "
387
+ "program", strm->name);
388
+ } else {
389
+ msg_errno("Unable to map %"TS" into memory",
390
+ strm->name);
391
+ }
392
+ return -1;
393
+ }
394
+
395
+ #ifdef HAVE_POSIX_MADVISE
396
+ posix_madvise(strm->mmap_mem, size, POSIX_MADV_SEQUENTIAL);
397
+ #endif
398
+ strm->mmap_token = strm; /* anything that's not NULL */
399
+
400
+ #endif /* !_WIN32 */
401
+ strm->mmap_size = size;
402
+ return 0;
403
+ }
404
+
405
+ /*
406
+ * Read from a file, returning the full count to indicate all bytes were read, a
407
+ * short count (possibly 0) to indicate EOF, or -1 to indicate error.
408
+ */
409
+ ssize_t
410
+ xread(struct file_stream *strm, void *buf, size_t count)
411
+ {
412
+ char *p = buf;
413
+ size_t orig_count = count;
414
+
415
+ while (count != 0) {
416
+ ssize_t res = read(strm->fd, p, MIN(count, INT_MAX));
417
+ if (res == 0)
418
+ break;
419
+ if (res < 0) {
420
+ if (errno == EAGAIN || errno == EINTR)
421
+ continue;
422
+ msg_errno("Error reading from %"TS, strm->name);
423
+ return -1;
424
+ }
425
+ p += res;
426
+ count -= res;
427
+ }
428
+ return orig_count - count;
429
+ }
430
+
431
+ /* Write to a file, returning 0 if all bytes were written or -1 on error */
432
+ int
433
+ full_write(struct file_stream *strm, const void *buf, size_t count)
434
+ {
435
+ const char *p = buf;
436
+
437
+ while (count != 0) {
438
+ ssize_t res = write(strm->fd, p, MIN(count, INT_MAX));
439
+ if (res <= 0) {
440
+ msg_errno("Error writing to %"TS, strm->name);
441
+ return -1;
442
+ }
443
+ p += res;
444
+ count -= res;
445
+ }
446
+ return 0;
447
+ }
448
+
449
+ /* Close a file, returning 0 on success or -1 on error */
450
+ int
451
+ xclose(struct file_stream *strm)
452
+ {
453
+ int ret = 0;
454
+
455
+ if (!strm->is_standard_stream) {
456
+ if (close(strm->fd) != 0) {
457
+ msg_errno("Error closing %"TS, strm->name);
458
+ ret = -1;
459
+ }
460
+ free(strm->name);
461
+ }
462
+
463
+ if (strm->mmap_token != NULL) {
464
+ #ifdef _WIN32
465
+ UnmapViewOfFile(strm->mmap_mem);
466
+ CloseHandle((HANDLE)strm->mmap_token);
467
+ #else
468
+ munmap(strm->mmap_mem, strm->mmap_size);
469
+ #endif
470
+ strm->mmap_token = NULL;
471
+ } else {
472
+ free(strm->mmap_mem);
473
+ }
474
+ strm->mmap_mem = NULL;
475
+ strm->fd = -1;
476
+ strm->name = NULL;
477
+ return ret;
478
+ }
479
+
480
+ /*
481
+ * Parse the compression level given on the command line, returning the
482
+ * compression level on success or 0 on error
483
+ */
484
+ int
485
+ parse_compression_level(tchar opt_char, const tchar *arg)
486
+ {
487
+ unsigned long level = opt_char - '0';
488
+ const tchar *p;
489
+
490
+ if (arg == NULL)
491
+ arg = T("");
492
+
493
+ for (p = arg; *p >= '0' && *p <= '9'; p++)
494
+ level = (level * 10) + (*p - '0');
495
+
496
+ if (level < 1 || level > 12 || *p != '\0') {
497
+ msg("Invalid compression level: \"%"TC"%"TS"\". "
498
+ "Must be an integer in the range [1, 12].", opt_char, arg);
499
+ return 0;
500
+ }
501
+
502
+ return level;
503
+ }
504
+
505
+ /* Allocate a new DEFLATE compressor */
506
+ struct libdeflate_compressor *
507
+ alloc_compressor(int level)
508
+ {
509
+ struct libdeflate_compressor *c;
510
+
511
+ c = libdeflate_alloc_compressor(level);
512
+ if (c == NULL) {
513
+ msg_errno("Unable to allocate compressor with "
514
+ "compression level %d", level);
515
+ }
516
+ return c;
517
+ }
518
+
519
+ /* Allocate a new DEFLATE decompressor */
520
+ struct libdeflate_decompressor *
521
+ alloc_decompressor(void)
522
+ {
523
+ struct libdeflate_decompressor *d;
524
+
525
+ d = libdeflate_alloc_decompressor();
526
+ if (d == NULL)
527
+ msg_errno("Unable to allocate decompressor");
528
+
529
+ return d;
530
+ }