oodle-kraken-ruby 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,342 @@
1
+ /*
2
+ === Kraken Decompressor ===
3
+ Copyright (C) 2016, Powzix
4
+ Copyright (C) 2019, rarten
5
+ Copyright (C) 2022, Kerilk
6
+
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ */
20
+
21
+
22
+ #include "stdafx.h"
23
+ #include "kraken.h"
24
+ #include <sys/stat.h>
25
+
26
+ // The decompressor will write outside of the target buffer.
27
+ #define SAFE_SPACE 64
28
+
29
+ void error(const char *s, const char *curfile = NULL) {
30
+ if (curfile)
31
+ fprintf(stderr, "%s: ", curfile);
32
+ fprintf(stderr, "%s\n", s);
33
+ exit(1);
34
+ }
35
+
36
+
37
+ byte *load_file(const char *filename, size_t *size) {
38
+ FILE *f = fopen(filename, "rb");
39
+ if (!f) error("file open error", filename);
40
+ fseek(f, 0, SEEK_END);
41
+ ssize_t packed_size = ftell(f);
42
+ if (packed_size<0) error("file tell error", filename);
43
+ fseek(f, 0, SEEK_SET);
44
+ byte *input = new byte[packed_size];
45
+ if (!input) error("memory error", filename);
46
+ if (fread(input, 1, packed_size, f) != packed_size) error("error reading", filename);
47
+ fclose(f);
48
+ *size = (size_t)packed_size;
49
+ return input;
50
+ }
51
+
52
+ enum {
53
+ kCompressor_Kraken = 8,
54
+ kCompressor_Mermaid = 9,
55
+ kCompressor_Selkie = 11,
56
+ kCompressor_Hydra = 12,
57
+ kCompressor_Leviathan = 13,
58
+ };
59
+
60
+ bool arg_stdout, arg_force, arg_quiet, arg_dll;
61
+ int arg_compressor = kCompressor_Kraken, arg_level = 4;
62
+ char arg_direction;
63
+ const char *verifyfolder;
64
+
65
+ int ParseCmdLine(int argc, char *argv[]) {
66
+ int i;
67
+ // parse command line
68
+ for (i = 1; i < argc; i++) {
69
+ const char *s = argv[i];
70
+ char c;
71
+ if (*s != '-')
72
+ break;
73
+ if (*++s == '-') {
74
+ if (*++s == 0) {
75
+ i++;
76
+ break; // --
77
+ }
78
+ // long opts
79
+ if (!strcmp(s, "stdout")) s = "c";
80
+ else if (!strcmp(s, "decompress")) s = "d";
81
+ else if (!strcmp(s, "compress")) s = "z";
82
+ else if (!strncmp(s, "verify=",7)) {
83
+ verifyfolder = s + 7;
84
+ continue;
85
+ } else if (!strcmp(s, "verify")) {
86
+ arg_direction = 't';
87
+ continue;
88
+ } else if (!strcmp(s, "dll")) {
89
+ arg_dll = true;
90
+ continue;
91
+ } else if (!strcmp(s, "kraken")) s = "mk";
92
+ else if (!strcmp(s, "mermaid")) s = "mm";
93
+ else if (!strcmp(s, "selkie")) s = "ms";
94
+ else if (!strcmp(s, "leviathan")) s = "ml";
95
+ else if (!strcmp(s, "hydra")) s = "mh";
96
+ else if (!strncmp(s, "level=", 6)) {
97
+ arg_level = atoi(s + 6);
98
+ continue;
99
+ } else {
100
+ return -1;
101
+ }
102
+ }
103
+ // short opt
104
+ do {
105
+ switch (c = *s++) {
106
+ case 'z':
107
+ case 'd':
108
+ case 'b':
109
+ if (arg_direction)
110
+ return -1;
111
+ arg_direction = c;
112
+ break;
113
+ case 'c':
114
+ arg_stdout = true;
115
+ break;
116
+ case 'f':
117
+ arg_force = true;
118
+ break;
119
+ case 'q':
120
+ arg_quiet = true;
121
+ break;
122
+ case '1': case '2': case '3': case '4':
123
+ case '5': case '6': case '7': case '8': case '9':
124
+ arg_level = c - '0';
125
+ break;
126
+ case 'm':
127
+ c = *s++;
128
+ arg_compressor = (c == 'k') ? kCompressor_Kraken :
129
+ (c == 'm') ? kCompressor_Mermaid :
130
+ (c == 's') ? kCompressor_Selkie :
131
+ (c == 'l') ? kCompressor_Leviathan :
132
+ (c == 'h') ? kCompressor_Hydra : -1;
133
+ if (arg_compressor < 0)
134
+ return -1;
135
+ break;
136
+ default:
137
+ return -1;
138
+ }
139
+ } while (*s);
140
+ }
141
+ return i;
142
+ }
143
+
144
+ bool Verify(const char *filename, uint8 *output, size_t outbytes, const char *curfile) {
145
+ size_t test_size;
146
+ byte *test = load_file(filename, &test_size);
147
+ if (!test) {
148
+ fprintf(stderr, "file open error: %s\n", filename);
149
+ return false;
150
+ }
151
+ if (test_size != outbytes) {
152
+ fprintf(stderr, "%s: ERROR: File size difference: %zu vs %zu\n", filename, outbytes, test_size);
153
+ return false;
154
+ }
155
+ for (int i = 0; i != test_size; i++) {
156
+ if (test[i] != output[i]) {
157
+ fprintf(stderr, "%s: ERROR: File difference at 0x%x. Was %d instead of %d\n", curfile, i, output[i], test[i]);
158
+ return false;
159
+ }
160
+ }
161
+ return true;
162
+ }
163
+
164
+ #ifndef _MSC_VER
165
+ typedef uint64_t LARGE_INTEGER;
166
+ void QueryPerformanceCounter(LARGE_INTEGER *a) {
167
+ *a = 0;
168
+ }
169
+ void QueryPerformanceFrequency(LARGE_INTEGER *a) {
170
+ *a = 1;
171
+ }
172
+ #define WINAPI
173
+ typedef void* HINSTANCE;
174
+ HINSTANCE LoadLibraryA(const char *s) { return 0; }
175
+ void *GetProcAddress(HINSTANCE h, const char *s) { return 0; }
176
+ #endif
177
+
178
+ typedef ssize_t WINAPI OodLZ_CompressFunc(
179
+ int codec, uint8 *src_buf, size_t src_len, uint8 *dst_buf, int level,
180
+ void *opts, size_t offs, size_t unused, void *scratch, size_t scratch_size);
181
+ typedef ssize_t WINAPI OodLZ_DecompressFunc(uint8 *src_buf, int src_len, uint8 *dst, size_t dst_size,
182
+ int fuzz, int crc, int verbose,
183
+ uint8 *dst_base, size_t e, void *cb, void *cb_ctx, void *scratch, size_t scratch_size, int threadPhase);
184
+
185
+ OodLZ_CompressFunc *OodLZ_Compress;
186
+ OodLZ_DecompressFunc *OodLZ_Decompress;
187
+
188
+ void LoadLib() {
189
+
190
+ #if defined(_M_X64)
191
+ #define LIBNAME "oo2core_7_win64.dll"
192
+ char COMPFUNCNAME[] = "XXdleLZ_Compress";
193
+ char DECFUNCNAME[] = "XXdleLZ_Decompress";
194
+ COMPFUNCNAME[0] = DECFUNCNAME[0] = 'O';
195
+ COMPFUNCNAME[1] = DECFUNCNAME[1] = 'o';
196
+ #else
197
+ #define LIBNAME "oo2core_7_win32.dll"
198
+ char COMPFUNCNAME[] = "_XXdleLZ_Compress@40";
199
+ char DECFUNCNAME[] = "_XXdleLZ_Decompress@56";
200
+ COMPFUNCNAME[1] = DECFUNCNAME[1] = 'O';
201
+ COMPFUNCNAME[2] = DECFUNCNAME[2] = 'o';
202
+ #endif
203
+ HINSTANCE mod = LoadLibraryA(LIBNAME);
204
+ OodLZ_Compress = (OodLZ_CompressFunc*)GetProcAddress(mod, COMPFUNCNAME);
205
+ OodLZ_Decompress = (OodLZ_DecompressFunc*)GetProcAddress(mod, DECFUNCNAME);
206
+ if (!OodLZ_Compress || !OodLZ_Decompress)
207
+ error("error loading", LIBNAME);
208
+ }
209
+
210
+ int main(int argc, char *argv[]) {
211
+ int64_t start, end, freq;
212
+ int argi;
213
+
214
+ if (argc < 2 ||
215
+ (argi = ParseCmdLine(argc, argv)) < 0 ||
216
+ argi >= argc || // no files
217
+ (arg_direction != 'b' && (argc - argi) > 2) || // too many files
218
+ (arg_direction == 't' && (argc - argi) != 2) // missing argument for verify
219
+ ) {
220
+ fprintf(stderr, "ooz v7.0\n\n"
221
+ "Usage: ooz [options] input [output]\n"
222
+ " -c --stdout write to stdout\n"
223
+ " -d --decompress decompress (default)\n"
224
+ " -z --compress compress (requires oo2core_7_win64.dll)\n"
225
+ " -b just benchmark, don't overwrite anything\n"
226
+ " -f force overwrite existing file\n"
227
+ " --dll decompress with the dll\n"
228
+ " --verify decompress and verify that it matches output\n"
229
+ " --verify=<folder> verify with files in this folder\n"
230
+ " -<1-9> --level=<-4..10> compression level\n"
231
+ " -m<k> [k|m|s|l|h] compressor selection\n"
232
+ " --kraken --mermaid --selkie --leviathan --hydra compressor selection\n\n"
233
+ "(Warning! not fuzz safe, so please trust the input)\n"
234
+ );
235
+ return 1;
236
+ }
237
+ bool write_mode = (argi + 1 < argc) && (arg_direction != 't' && arg_direction != 'b');
238
+
239
+ if (!arg_force && write_mode) {
240
+ struct stat sb;
241
+ if (stat(argv[argi + 1], &sb) >= 0) {
242
+ fprintf(stderr, "file %s already exists, skipping.\n", argv[argi + 1]);
243
+ return 1;
244
+ }
245
+ }
246
+
247
+ int nverify = 0;
248
+
249
+ for (; argi < argc; argi++) {
250
+ const char *curfile = argv[argi];
251
+
252
+ size_t input_size;
253
+ byte *input = load_file(curfile, &input_size);
254
+
255
+ byte *output = NULL;
256
+ ssize_t outbytes = 0;
257
+
258
+ if (arg_direction == 'z') {
259
+ // compress using the dll
260
+ LoadLib();
261
+ output = new byte[input_size + 65536];
262
+ if (!output) error("memory error", curfile);
263
+ *(uint64*)output = input_size;
264
+ QueryPerformanceCounter((LARGE_INTEGER*)&start);
265
+ outbytes = OodLZ_Compress(arg_compressor, input, input_size, output + 8, arg_level, 0, 0, 0, 0, 0);
266
+ if (outbytes < 0) error("compress failed", curfile);
267
+ outbytes += 8;
268
+ QueryPerformanceCounter((LARGE_INTEGER*)&end);
269
+ QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
270
+ double seconds = (double)(end - start) / freq;
271
+ if (!arg_quiet)
272
+ fprintf(stderr, "%-20s: %8zu => %8zu (%.2f seconds, %.2f MB/s)\n", argv[argi], input_size, (size_t)outbytes, seconds, input_size * 1e-6 / seconds);
273
+ } else {
274
+ if (arg_dll)
275
+ LoadLib();
276
+
277
+ // stupidly attempt to autodetect if file uses 4-byte or 8-byte header,
278
+ // the previous version of this tool wrote a 4-byte header.
279
+ int hdrsize = *(uint64*)input >= 0x10000000000 ? 4 : 8;
280
+
281
+ size_t unpacked_size = (hdrsize == 8) ? *(size_t*)input : *(uint32*)input;
282
+ if (unpacked_size > (hdrsize == 4 ? 52*1024*1024 : 1024 * 1024 * 1024))
283
+ error("file too large", curfile);
284
+ output = new byte[unpacked_size + SAFE_SPACE];
285
+ if (!output) error("memory error", curfile);
286
+
287
+ QueryPerformanceCounter((LARGE_INTEGER*)&start);
288
+
289
+ if (arg_dll) {
290
+ outbytes = OodLZ_Decompress(input + hdrsize, input_size - hdrsize, output, unpacked_size, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
291
+ } else {
292
+ outbytes = Kraken_Decompress(input + hdrsize, input_size - hdrsize, output, unpacked_size);
293
+ }
294
+ if (outbytes != unpacked_size)
295
+ error("decompress error", curfile);
296
+ QueryPerformanceCounter((LARGE_INTEGER*)&end);
297
+ QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
298
+ double seconds = (double)(end - start) / freq;
299
+ if (!arg_quiet)
300
+ fprintf(stderr, "%-20s: %8zu => %8zu (%.2f seconds, %.2f MB/s)\n", argv[argi], input_size, unpacked_size, seconds, unpacked_size * 1e-6 / seconds);
301
+ }
302
+
303
+ if (verifyfolder) {
304
+ // Verify against the file in verifyfolder with the same basename excluding extension
305
+ char buf[1024];
306
+ const char *basename = curfile;
307
+ for(const char *s = curfile; *s; s++)
308
+ if (*s == '/' || *s == '\\')
309
+ basename = s + 1;
310
+ const char *ext = strrchr(basename, '.');
311
+ snprintf(buf, sizeof(buf), "%s/%.*s", verifyfolder, (int)(ext ? (ext - basename) : strlen(basename)), basename);
312
+ if (!Verify(buf, output, outbytes, curfile))
313
+ return 1;
314
+ nverify++;
315
+ }
316
+
317
+ if (arg_stdout && arg_direction != 't' && arg_direction != 'b')
318
+ fwrite(output, 1, outbytes, stdout);
319
+
320
+ if (write_mode) {
321
+ if (arg_direction == 't') {
322
+ if (!Verify(argv[argi + 1], output, outbytes, curfile))
323
+ return 1;
324
+ fprintf(stderr, "%s: Verify OK\n", curfile);
325
+ } else {
326
+ FILE *f = fopen(argv[argi + 1], "wb");
327
+ if (!f) error("file open for write error", argv[argi + 1]);
328
+ if (fwrite(output, 1, outbytes, f) != outbytes)
329
+ error("file write error", argv[argi + 1]);
330
+ fclose(f);
331
+ }
332
+ break;
333
+ }
334
+ delete[] input;
335
+ delete[] output;
336
+ }
337
+
338
+ if (nverify)
339
+ fprintf(stderr, "%d files verified OK!\n", nverify);
340
+ return 0;
341
+ }
342
+
@@ -0,0 +1,8 @@
1
+ // stdafx.cpp : source file that includes just the standard includes
2
+ // kraken.pch will be the pre-compiled header
3
+ // stdafx.obj will contain the pre-compiled type information
4
+
5
+ #include "stdafx.h"
6
+
7
+ // TODO: reference any additional headers you need in STDAFX.H
8
+ // and not in this file
@@ -0,0 +1,68 @@
1
+ /*
2
+ Copyright (C) 2016, Powzix
3
+ Copyright (C) 2019, rarten
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ // stdafx.h : includefile for standard system include files,
20
+ // or project specific include files that are used frequently, but
21
+ // are changed infrequently
22
+ //
23
+
24
+ #pragma once
25
+
26
+ #define _CRT_SECURE_NO_WARNINGS 1
27
+
28
+ #include <stdio.h>
29
+ #include <stdlib.h>
30
+ #include <string.h>
31
+ #include <assert.h>
32
+ #include <stdint.h>
33
+ #include <limits.h>
34
+ #if defined(_MSC_VER)
35
+ #include <Windows.h>
36
+ #include <intrin.h>
37
+ #undef max
38
+ #undef min
39
+ #else
40
+ #include <stddef.h>
41
+ #define __forceinline inline
42
+ #define _byteswap_ushort(x) __builtin_bswap16((uint16)(x))
43
+ #define _byteswap_ulong(x) __builtin_bswap32((uint32)(x))
44
+ #define _byteswap_uint64(x) __builtin_bswap64((uint64)(x))
45
+ #define _BitScanForward(dst, x) (*(dst) = __builtin_ctz(x))
46
+ #define _BitScanReverse(dst, x) (*(dst) = (__builtin_clz(x) ^ 31))
47
+
48
+ static inline uint32_t _rotl(uint32_t x, int n) {
49
+ return (((x) << (n)) | ((x) >> (32-(n))));
50
+ }
51
+
52
+ #include <xmmintrin.h>
53
+ #endif
54
+
55
+ #pragma warning (disable: 4244)
56
+ #pragma warning (disable: 4530) // c++ exception handler used without unwind semantics
57
+ #pragma warning (disable: 4018) // signed/unsigned mismatch
58
+
59
+ // TODO: reference additional headers your program requires here
60
+ typedef uint8_t byte;
61
+ typedef uint8_t uint8;
62
+ typedef uint32_t uint32;
63
+ typedef uint64_t uint64;
64
+ typedef int64_t int64;
65
+ typedef int32_t int32;
66
+ typedef uint16_t uint16;
67
+ typedef int16_t int16;
68
+ typedef unsigned int uint;
@@ -0,0 +1,8 @@
1
+ #pragma once
2
+
3
+ // Including SDKDDKVer.h defines the highest available Windows platform.
4
+
5
+ // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6
+ // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7
+
8
+ #include <SDKDDKVer.h>
@@ -0,0 +1,2 @@
1
+ require "oodle_kraken_c"
2
+
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oodle-kraken-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Brice Videau
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-10-29 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Uncompress files compressed with Oodle Kraken / Mermaid / Selkie / Leviathan
14
+ / LZNA / Bitknit.
15
+ email: brice.videau@gmail.com
16
+ executables: []
17
+ extensions:
18
+ - ext/oodle-kraken/extconf.rb
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE
22
+ - ext/oodle-kraken/extconf.rb
23
+ - ext/oodle-kraken/oodle_kraken_c.c
24
+ - ext/oodle-kraken/ooz/LICENSE
25
+ - ext/oodle-kraken/ooz/README.md
26
+ - ext/oodle-kraken/ooz/bitknit.cpp
27
+ - ext/oodle-kraken/ooz/kraken.cpp
28
+ - ext/oodle-kraken/ooz/kraken.h
29
+ - ext/oodle-kraken/ooz/lzna.cpp
30
+ - ext/oodle-kraken/ooz/ooz.cpp
31
+ - ext/oodle-kraken/ooz/stdafx.cpp
32
+ - ext/oodle-kraken/ooz/stdafx.h
33
+ - ext/oodle-kraken/ooz/targetver.h
34
+ - lib/oodle-kraken-ruby.rb
35
+ homepage: https://github.com/kerilk/oodle-kraken-ruby
36
+ licenses:
37
+ - GPL-3.0-or-later
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 2.0.0
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubygems_version: 3.1.2
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: Library for decrompressing Oodle compressed file
58
+ test_files: []