extlzma2 2.0.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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rspec_status +17 -0
- data/.rubocop.yml +42 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +37 -0
- data/LICENSE +26 -0
- data/README.md +9 -0
- data/Rakefile +15 -0
- data/ext/extlzma2/consts.c +66 -0
- data/ext/extlzma2/error.c +87 -0
- data/ext/extlzma2/extconf.rb +27 -0
- data/ext/extlzma2/extlzma2.c +89 -0
- data/ext/extlzma2/extlzma2.h +171 -0
- data/ext/extlzma2/filter.c +530 -0
- data/ext/extlzma2/index.c +66 -0
- data/ext/extlzma2/stream.c +440 -0
- data/ext/extlzma2/utils.c +93 -0
- data/extlzma2.gemspec +27 -0
- data/lib/extlzma2/aux.rb +42 -0
- data/lib/extlzma2/decoder.rb +73 -0
- data/lib/extlzma2/encoder.rb +82 -0
- data/lib/extlzma2/filter.rb +17 -0
- data/lib/extlzma2/stream.rb +49 -0
- data/lib/extlzma2/utils.rb +104 -0
- data/lib/extlzma2/version.rb +5 -0
- data/lib/extlzma2.rb +148 -0
- metadata +71 -0
@@ -0,0 +1,440 @@
|
|
1
|
+
#include "extlzma2.h"
|
2
|
+
|
3
|
+
VALUE extlzma_cStream;
|
4
|
+
static VALUE cEncoder;
|
5
|
+
static VALUE cDecoder;
|
6
|
+
static VALUE cAutoDecoder;
|
7
|
+
static VALUE cRawEncoder;
|
8
|
+
static VALUE cRawDecoder;
|
9
|
+
|
10
|
+
enum
|
11
|
+
{
|
12
|
+
WORK_BUFFER_SIZE = 256 * 1024, // 256 KiB
|
13
|
+
BUFFER_BLOCK_SIZE = WORK_BUFFER_SIZE,
|
14
|
+
UPDATE_TRY_MAX = 2,
|
15
|
+
};
|
16
|
+
|
17
|
+
static inline void filter_copy(lzma_filter *dest, VALUE filter)
|
18
|
+
{
|
19
|
+
memcpy(dest, extlzma_getfilter(filter), sizeof(*dest));
|
20
|
+
}
|
21
|
+
|
22
|
+
static void stream_clear(lzma_stream *stream)
|
23
|
+
{
|
24
|
+
static const lzma_stream init = LZMA_STREAM_INIT;
|
25
|
+
memcpy(stream, &init, sizeof(init));
|
26
|
+
}
|
27
|
+
|
28
|
+
static inline lzma_stream *getstream(VALUE lzma)
|
29
|
+
{
|
30
|
+
return getref(lzma);
|
31
|
+
}
|
32
|
+
|
33
|
+
static inline void stream_cleanup(void *pp)
|
34
|
+
{
|
35
|
+
if (pp)
|
36
|
+
{
|
37
|
+
lzma_stream *p = (lzma_stream *)pp;
|
38
|
+
lzma_end(p);
|
39
|
+
free(p);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
static void stream_mark(void *p)
|
44
|
+
{
|
45
|
+
}
|
46
|
+
|
47
|
+
static VALUE stream_alloc(VALUE klass)
|
48
|
+
{
|
49
|
+
lzma_stream *p;
|
50
|
+
VALUE obj = Data_Make_Struct(klass, lzma_stream, stream_mark, stream_cleanup, p);
|
51
|
+
stream_clear(p);
|
52
|
+
return obj;
|
53
|
+
}
|
54
|
+
|
55
|
+
static VALUE aux_str_reserve(VALUE str, size_t size)
|
56
|
+
{
|
57
|
+
size_t capa = rb_str_capacity(str);
|
58
|
+
if (capa < size)
|
59
|
+
{
|
60
|
+
rb_str_modify_expand(str, size - RSTRING_LEN(str));
|
61
|
+
}
|
62
|
+
else
|
63
|
+
{
|
64
|
+
rb_str_modify(str);
|
65
|
+
}
|
66
|
+
|
67
|
+
return str;
|
68
|
+
}
|
69
|
+
|
70
|
+
static inline void *aux_lzma_code_nogvl(va_list *p)
|
71
|
+
{
|
72
|
+
lzma_stream *stream = va_arg(*p, lzma_stream *);
|
73
|
+
lzma_action sync = va_arg(*p, lzma_action);
|
74
|
+
return (void *)lzma_code(stream, sync);
|
75
|
+
}
|
76
|
+
|
77
|
+
static inline lzma_ret aux_lzma_code(lzma_stream *stream, lzma_action sync)
|
78
|
+
{
|
79
|
+
return (lzma_ret)aux_thread_call_without_gvl(aux_lzma_code_nogvl, stream, sync);
|
80
|
+
}
|
81
|
+
|
82
|
+
/*
|
83
|
+
* call-seq:
|
84
|
+
* code(src, dest, maxdest, action) -> status
|
85
|
+
*
|
86
|
+
* +lzma_code+ を用いて、圧縮/伸長処理を行います。
|
87
|
+
*
|
88
|
+
* [RETURN]
|
89
|
+
* +lzma_code+ が返す整数値をそのまま返します。
|
90
|
+
*
|
91
|
+
* [src]
|
92
|
+
* 処理前のバイナリデータが格納された文字列オブジェクトを与えます。
|
93
|
+
*
|
94
|
+
* このオブジェクトは変更されます。
|
95
|
+
*
|
96
|
+
* 処理された部分が取り除かれます (処理されなかった部分が残ります)。
|
97
|
+
*
|
98
|
+
* [dest]
|
99
|
+
* 処理後のバイナリデータを格納する文字列オブジェクトを与えます。
|
100
|
+
*
|
101
|
+
* [maxdest]
|
102
|
+
* dest の最大処理バイト数を与えます。
|
103
|
+
*
|
104
|
+
* [action]
|
105
|
+
* +lzma_code+ の +action+ 引数に渡される整数値です。
|
106
|
+
*/
|
107
|
+
static VALUE stream_code(VALUE stream, VALUE src, VALUE dest, VALUE maxdest, VALUE action)
|
108
|
+
{
|
109
|
+
lzma_stream *p = getstream(stream);
|
110
|
+
|
111
|
+
if (NIL_P(src))
|
112
|
+
{
|
113
|
+
p->next_in = NULL;
|
114
|
+
p->avail_in = 0;
|
115
|
+
}
|
116
|
+
else
|
117
|
+
{
|
118
|
+
rb_check_type(src, RUBY_T_STRING);
|
119
|
+
rb_str_modify(src);
|
120
|
+
p->next_in = (uint8_t *)RSTRING_PTR(src);
|
121
|
+
p->avail_in = RSTRING_LEN(src);
|
122
|
+
}
|
123
|
+
|
124
|
+
size_t maxdestn = NUM2SIZET(maxdest);
|
125
|
+
rb_check_type(dest, RUBY_T_STRING);
|
126
|
+
aux_str_reserve(dest, maxdestn);
|
127
|
+
p->next_out = (uint8_t *)RSTRING_PTR(dest);
|
128
|
+
p->avail_out = maxdestn;
|
129
|
+
|
130
|
+
lzma_action act = NUM2INT(action);
|
131
|
+
|
132
|
+
lzma_ret s = aux_lzma_code(p, act);
|
133
|
+
|
134
|
+
if (p->next_in)
|
135
|
+
{
|
136
|
+
size_t srcrest = p->avail_in;
|
137
|
+
memmove(RSTRING_PTR(src), p->next_in, srcrest);
|
138
|
+
rb_str_set_len(src, srcrest);
|
139
|
+
}
|
140
|
+
|
141
|
+
rb_str_set_len(dest, maxdestn - p->avail_out);
|
142
|
+
|
143
|
+
return UINT2NUM(s);
|
144
|
+
}
|
145
|
+
|
146
|
+
// filter は LZMA::Filter クラスのインスタンスを与えることができる
|
147
|
+
static void filter_setup(lzma_filter filterpack[LZMA_FILTERS_MAX + 1], VALUE filter[], VALUE *filterend, VALUE encoder)
|
148
|
+
{
|
149
|
+
if ((filterend - filter) > LZMA_FILTERS_MAX)
|
150
|
+
{
|
151
|
+
rb_raise(extlzma_eFilterTooLong,
|
152
|
+
"filter chain too long (max %d, but given %d)",
|
153
|
+
LZMA_FILTERS_MAX, (int)(filterend - filter));
|
154
|
+
}
|
155
|
+
for (; filter < filterend; filter++, filterpack++)
|
156
|
+
{
|
157
|
+
VALUE f = *filter;
|
158
|
+
if (!rb_obj_is_kind_of(f, extlzma_cFilter))
|
159
|
+
{
|
160
|
+
rb_raise(rb_eTypeError,
|
161
|
+
"not a filter - #<%s:%p>",
|
162
|
+
rb_obj_classname(f), (void *)f);
|
163
|
+
}
|
164
|
+
filter_copy(filterpack, f);
|
165
|
+
}
|
166
|
+
filterpack->id = LZMA_VLI_UNKNOWN;
|
167
|
+
filterpack->options = NULL;
|
168
|
+
}
|
169
|
+
|
170
|
+
#define RETRY_NOMEM(TIMES, STMT) \
|
171
|
+
({ \
|
172
|
+
lzma_ret RETRY_NOMEM_status = 0; \
|
173
|
+
int RETRY_NOMEM_i; \
|
174
|
+
for (RETRY_NOMEM_i = (TIMES); RETRY_NOMEM_i > 0; RETRY_NOMEM_i--) \
|
175
|
+
{ \
|
176
|
+
RETRY_NOMEM_status = ({ STMT; }); \
|
177
|
+
if (RETRY_NOMEM_status == LZMA_MEM_ERROR && RETRY_NOMEM_i > 1) \
|
178
|
+
{ \
|
179
|
+
rb_gc(); \
|
180
|
+
continue; \
|
181
|
+
} \
|
182
|
+
break; \
|
183
|
+
} \
|
184
|
+
RETRY_NOMEM_status; \
|
185
|
+
})
|
186
|
+
|
187
|
+
static int conv_checkmethod(VALUE check)
|
188
|
+
{
|
189
|
+
check = rb_hash_lookup2(check, ID2SYM(extlzma_id_check), Qundef);
|
190
|
+
switch (check)
|
191
|
+
{
|
192
|
+
case Qnil:
|
193
|
+
return LZMA_CHECK_NONE;
|
194
|
+
case Qundef:
|
195
|
+
return LZMA_CHECK_CRC64;
|
196
|
+
default:
|
197
|
+
if (check == ID2SYM(extlzma_id_none))
|
198
|
+
{
|
199
|
+
return LZMA_CHECK_NONE;
|
200
|
+
}
|
201
|
+
else if (check == ID2SYM(extlzma_id_crc32))
|
202
|
+
{
|
203
|
+
return LZMA_CHECK_CRC32;
|
204
|
+
}
|
205
|
+
else if (check == ID2SYM(extlzma_id_crc64))
|
206
|
+
{
|
207
|
+
return LZMA_CHECK_CRC64;
|
208
|
+
}
|
209
|
+
else if (check == ID2SYM(extlzma_id_sha256))
|
210
|
+
{
|
211
|
+
return LZMA_CHECK_SHA256;
|
212
|
+
}
|
213
|
+
else
|
214
|
+
{
|
215
|
+
return NUM2UINT(check);
|
216
|
+
}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
static inline void ext_encoder_init_scanargs(VALUE encoder, int argc, VALUE argv[], lzma_filter filterpack[LZMA_FILTERS_MAX + 1], uint32_t *check)
|
221
|
+
{
|
222
|
+
if (check)
|
223
|
+
{
|
224
|
+
VALUE tmp;
|
225
|
+
rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &tmp);
|
226
|
+
if (NIL_P(tmp))
|
227
|
+
{
|
228
|
+
*check = LZMA_CHECK_CRC64;
|
229
|
+
}
|
230
|
+
else
|
231
|
+
{
|
232
|
+
*check = conv_checkmethod(tmp);
|
233
|
+
argc--;
|
234
|
+
}
|
235
|
+
}
|
236
|
+
else
|
237
|
+
{
|
238
|
+
rb_scan_args(argc, argv, "13", NULL, NULL, NULL, NULL);
|
239
|
+
}
|
240
|
+
memset(filterpack, 0, sizeof(lzma_filter[LZMA_FILTERS_MAX + 1]));
|
241
|
+
filter_setup(filterpack, argv, argv + argc, encoder);
|
242
|
+
}
|
243
|
+
|
244
|
+
/*
|
245
|
+
* call-seq:
|
246
|
+
* initialize(filter1, check: CHECK_CRC64) -> encoder
|
247
|
+
* initialize(filter1, filter2, check: CHECK_CRC64) -> encoder
|
248
|
+
* initialize(filter1, filter2, filter3, check: CHECK_CRC64) -> encoder
|
249
|
+
* initialize(filter1, filter2, filter3, filter4, check: CHECK_CRC64) -> encoder
|
250
|
+
*
|
251
|
+
* 圧縮器を生成します。圧縮されたデータストリームは xz ファイルフォーマットです。
|
252
|
+
*
|
253
|
+
* [RETURN]
|
254
|
+
* 生成された圧縮器
|
255
|
+
*
|
256
|
+
* [filter1, filter2, filter3, filter4]
|
257
|
+
* LZMA::Filter インスタンス。最低一つを必要とします。
|
258
|
+
*
|
259
|
+
* [check]
|
260
|
+
* チェックメソッド。
|
261
|
+
*
|
262
|
+
* CHECK_NONE CHECK_CRC32 CHECK_CRC64 CHECK_SHA256 のいずれかの定数を与えます。
|
263
|
+
*
|
264
|
+
* [EXCEPTIONS]
|
265
|
+
* (NO DOCUMENTS)
|
266
|
+
*/
|
267
|
+
static VALUE encoder_init(int argc, VALUE argv[], VALUE stream)
|
268
|
+
{
|
269
|
+
lzma_stream *p = getstream(stream);
|
270
|
+
|
271
|
+
uint32_t check;
|
272
|
+
lzma_filter filterpack[LZMA_FILTERS_MAX + 1];
|
273
|
+
ext_encoder_init_scanargs(stream, argc, argv, filterpack, &check);
|
274
|
+
|
275
|
+
AUX_LZMA_TEST(RETRY_NOMEM(2, lzma_stream_encoder(p, filterpack, check)));
|
276
|
+
|
277
|
+
return stream;
|
278
|
+
}
|
279
|
+
|
280
|
+
static inline void ext_decoder_init_scanargs(int argc, VALUE argv[], uint64_t *memlimit, uint32_t *flags)
|
281
|
+
{
|
282
|
+
switch (argc)
|
283
|
+
{
|
284
|
+
case 0:
|
285
|
+
*memlimit = UINT64_MAX;
|
286
|
+
*flags = 0;
|
287
|
+
return;
|
288
|
+
case 1:
|
289
|
+
*memlimit = NIL_P(argv[0]) ? UINT64_MAX : NUM2SIZET(argv[0]);
|
290
|
+
*flags = 0;
|
291
|
+
return;
|
292
|
+
case 2:
|
293
|
+
*memlimit = NIL_P(argv[0]) ? UINT64_MAX : NUM2SIZET(argv[0]);
|
294
|
+
*flags = NIL_P(argv[1]) ? 0 : (uint32_t)NUM2UINT(argv[1]);
|
295
|
+
return;
|
296
|
+
}
|
297
|
+
|
298
|
+
rb_error_arity(argc, 0, 2);
|
299
|
+
}
|
300
|
+
|
301
|
+
/*
|
302
|
+
* call-seq:
|
303
|
+
* initialize(memlimit = nil, flags = 0)
|
304
|
+
*
|
305
|
+
* [RETURN]
|
306
|
+
* 伸張器を返します。
|
307
|
+
*
|
308
|
+
* [memlimit]
|
309
|
+
* 作業メモリ量の最大値を指定します。単位はバイトです。
|
310
|
+
*
|
311
|
+
* [flags]
|
312
|
+
* 伸張器の挙動を変更するための整数値を指定します。定数として次のものが利用できます。
|
313
|
+
*
|
314
|
+
* - LZMA::TELL_NO_CHECK
|
315
|
+
* - LZMA::TELL_UNSUPPORTED_CHECK
|
316
|
+
* - LZMA::TELL_ANY_CHECK
|
317
|
+
* - LZMA::CONCATENATED
|
318
|
+
*
|
319
|
+
* これらの意味は xz ユーティリティに含まれる liblzma/api/lzma/container.h に記述されています。
|
320
|
+
*/
|
321
|
+
static VALUE autodecoder_init(int argc, VALUE argv[], VALUE stream)
|
322
|
+
{
|
323
|
+
lzma_stream *p = getstream(stream);
|
324
|
+
uint64_t memlimit;
|
325
|
+
uint32_t flags;
|
326
|
+
ext_decoder_init_scanargs(argc, argv, &memlimit, &flags);
|
327
|
+
|
328
|
+
AUX_LZMA_TEST(RETRY_NOMEM(2, lzma_auto_decoder(p, memlimit, flags)));
|
329
|
+
|
330
|
+
return stream;
|
331
|
+
}
|
332
|
+
|
333
|
+
/*
|
334
|
+
* call-seq:
|
335
|
+
* initialize(memlimit = nil, flags = 0)
|
336
|
+
*
|
337
|
+
* xz ストリームの伸張器を返します。
|
338
|
+
*
|
339
|
+
* 引数については AutoDecoder#initialize と同じです。
|
340
|
+
*/
|
341
|
+
static VALUE decoder_init(int argc, VALUE argv[], VALUE stream)
|
342
|
+
{
|
343
|
+
lzma_stream *p = getstream(stream);
|
344
|
+
|
345
|
+
uint64_t memlimit;
|
346
|
+
uint32_t flags;
|
347
|
+
ext_decoder_init_scanargs(argc, argv, &memlimit, &flags);
|
348
|
+
|
349
|
+
AUX_LZMA_TEST(RETRY_NOMEM(2, lzma_stream_decoder(p, memlimit, flags)));
|
350
|
+
|
351
|
+
return stream;
|
352
|
+
}
|
353
|
+
|
354
|
+
/*
|
355
|
+
* call-seq:
|
356
|
+
* initialize(filter1) -> encoder
|
357
|
+
* initialize(filter1, filter2) -> encoder
|
358
|
+
* initialize(filter1, filter2, filter3) -> encoder
|
359
|
+
* initialize(filter1, filter2, filter3, filter4) -> encoder
|
360
|
+
*
|
361
|
+
* 生の (xzヘッダなどの付かない) LZMA1/LZMA2ストリームを構成する圧縮器を生成します。
|
362
|
+
*
|
363
|
+
* [RETURN]
|
364
|
+
* 圧縮器を返します。
|
365
|
+
*
|
366
|
+
* [filter1, filter2, filter3, filter4]
|
367
|
+
* Filter インスタンスを与えます。
|
368
|
+
*
|
369
|
+
* Filter インスタンスは、例えば LZMA2 フィルタを生成する場合 Filter.lzma2 を利用します。
|
370
|
+
*/
|
371
|
+
static VALUE rawencoder_init(int argc, VALUE argv[], VALUE stream)
|
372
|
+
{
|
373
|
+
lzma_stream *p = getstream(stream);
|
374
|
+
|
375
|
+
lzma_filter filterpack[LZMA_FILTERS_MAX + 1];
|
376
|
+
ext_encoder_init_scanargs(stream, argc, argv, filterpack, NULL);
|
377
|
+
|
378
|
+
AUX_LZMA_TEST(RETRY_NOMEM(2, lzma_raw_encoder(p, filterpack)));
|
379
|
+
|
380
|
+
return stream;
|
381
|
+
}
|
382
|
+
|
383
|
+
/*
|
384
|
+
* call-seq:
|
385
|
+
* initialize(filter1) -> decoder
|
386
|
+
* initialize(filter1, filter2) -> decoder
|
387
|
+
* initialize(filter1, filter2, filter3) -> decoder
|
388
|
+
* initialize(filter1, filter2, filter3, filter4) -> decoder
|
389
|
+
*/
|
390
|
+
static VALUE rawdecoder_init(int argc, VALUE argv[], VALUE stream)
|
391
|
+
{
|
392
|
+
lzma_stream *p = getstream(stream);
|
393
|
+
|
394
|
+
lzma_filter filterpack[LZMA_FILTERS_MAX + 1];
|
395
|
+
ext_encoder_init_scanargs(stream, argc, argv, filterpack, NULL);
|
396
|
+
|
397
|
+
AUX_LZMA_TEST(RETRY_NOMEM(2, lzma_raw_decoder(p, filterpack)));
|
398
|
+
|
399
|
+
return stream;
|
400
|
+
}
|
401
|
+
|
402
|
+
void extlzma_init_Stream(void)
|
403
|
+
{
|
404
|
+
extlzma_cStream = rb_define_class_under(extlzma_mLZMA, "Stream", rb_cObject);
|
405
|
+
rb_undef_alloc_func(extlzma_cStream);
|
406
|
+
rb_define_method(extlzma_cStream, "code", stream_code, 4);
|
407
|
+
|
408
|
+
cEncoder = rb_define_class_under(extlzma_cStream, "Encoder", extlzma_cStream);
|
409
|
+
rb_define_alloc_func(cEncoder, stream_alloc);
|
410
|
+
rb_define_method(cEncoder, "initialize", RUBY_METHOD_FUNC(encoder_init), -1);
|
411
|
+
rb_define_alias(cEncoder, "encode", "code");
|
412
|
+
rb_define_alias(cEncoder, "compress", "code");
|
413
|
+
|
414
|
+
cDecoder = rb_define_class_under(extlzma_cStream, "Decoder", extlzma_cStream);
|
415
|
+
rb_define_alloc_func(cDecoder, stream_alloc);
|
416
|
+
rb_define_method(cDecoder, "initialize", RUBY_METHOD_FUNC(decoder_init), -1);
|
417
|
+
rb_define_alias(cDecoder, "decode", "code");
|
418
|
+
rb_define_alias(cDecoder, "decompress", "code");
|
419
|
+
rb_define_alias(cDecoder, "uncompress", "code");
|
420
|
+
|
421
|
+
cAutoDecoder = rb_define_class_under(extlzma_cStream, "AutoDecoder", extlzma_cStream);
|
422
|
+
rb_define_alloc_func(cAutoDecoder, stream_alloc);
|
423
|
+
rb_define_method(cAutoDecoder, "initialize", RUBY_METHOD_FUNC(autodecoder_init), -1);
|
424
|
+
rb_define_alias(cDecoder, "decode", "code");
|
425
|
+
rb_define_alias(cDecoder, "decompress", "code");
|
426
|
+
rb_define_alias(cDecoder, "uncompress", "code");
|
427
|
+
|
428
|
+
cRawEncoder = rb_define_class_under(extlzma_cStream, "RawEncoder", extlzma_cStream);
|
429
|
+
rb_define_alloc_func(cRawEncoder, stream_alloc);
|
430
|
+
rb_define_method(cRawEncoder, "initialize", RUBY_METHOD_FUNC(rawencoder_init), -1);
|
431
|
+
rb_define_alias(cEncoder, "encode", "code");
|
432
|
+
rb_define_alias(cEncoder, "compress", "code");
|
433
|
+
|
434
|
+
cRawDecoder = rb_define_class_under(extlzma_cStream, "RawDecoder", extlzma_cStream);
|
435
|
+
rb_define_alloc_func(cRawDecoder, stream_alloc);
|
436
|
+
rb_define_method(cRawDecoder, "initialize", RUBY_METHOD_FUNC(rawdecoder_init), -1);
|
437
|
+
rb_define_alias(cDecoder, "decode", "code");
|
438
|
+
rb_define_alias(cDecoder, "decompress", "code");
|
439
|
+
rb_define_alias(cDecoder, "uncompress", "code");
|
440
|
+
}
|
@@ -0,0 +1,93 @@
|
|
1
|
+
#include "extlzma2.h"
|
2
|
+
|
3
|
+
static inline VALUE crc_calc(void *(*update)(va_list *vp), int argc, VALUE argv[])
|
4
|
+
{
|
5
|
+
VALUE src, crc;
|
6
|
+
rb_scan_args(argc, argv, "11", &src, &crc);
|
7
|
+
rb_check_type(src, RUBY_T_STRING);
|
8
|
+
return (VALUE)aux_thread_call_without_gvl(update,
|
9
|
+
(const uint8_t *)RSTRING_PTR(src),
|
10
|
+
RSTRING_LEN(src),
|
11
|
+
NIL_P(crc) ? INT2FIX(0) : crc);
|
12
|
+
}
|
13
|
+
|
14
|
+
static VALUE crc32_update(va_list *vp)
|
15
|
+
{
|
16
|
+
const uint8_t *ptr = va_arg(*vp, const uint8_t *);
|
17
|
+
size_t size = va_arg(*vp, size_t);
|
18
|
+
VALUE crc = va_arg(*vp, VALUE);
|
19
|
+
return UINT2NUM(lzma_crc32(ptr, size, NUM2UINT(crc)));
|
20
|
+
}
|
21
|
+
|
22
|
+
/*
|
23
|
+
* call-seq:
|
24
|
+
* LZMA::Utils.crc32(string, crc = 0)
|
25
|
+
*
|
26
|
+
* liblzmaに含まれるlzma_crc32を呼び出します。
|
27
|
+
*/
|
28
|
+
static VALUE utils_crc32(int argc, VALUE argv[], VALUE self)
|
29
|
+
{
|
30
|
+
return crc_calc((void *(*)(va_list *))crc32_update, argc, argv);
|
31
|
+
}
|
32
|
+
|
33
|
+
static VALUE crc64_update(va_list *vp)
|
34
|
+
{
|
35
|
+
const uint8_t *ptr = va_arg(*vp, const uint8_t *);
|
36
|
+
size_t size = va_arg(*vp, size_t);
|
37
|
+
VALUE crc = va_arg(*vp, VALUE);
|
38
|
+
return ULL2NUM(lzma_crc64(ptr, size, NUM2ULL(crc)));
|
39
|
+
}
|
40
|
+
|
41
|
+
/*
|
42
|
+
* call-seq:
|
43
|
+
* LZMA::Utils.crc64(string, crc = 0)
|
44
|
+
*
|
45
|
+
* liblzmaに含まれるlzma_crc64を呼び出します。
|
46
|
+
*/
|
47
|
+
static VALUE utils_crc64(int argc, VALUE argv[], VALUE self)
|
48
|
+
{
|
49
|
+
return crc_calc((void *(*)(va_list *))crc64_update, argc, argv);
|
50
|
+
}
|
51
|
+
|
52
|
+
/*
|
53
|
+
* call-seq:
|
54
|
+
* lookup_error(lzma_ret) -> exception class
|
55
|
+
*/
|
56
|
+
static VALUE utils_lookup_error(VALUE mod, VALUE status)
|
57
|
+
{
|
58
|
+
return extlzma_lookup_error(NUM2INT(status));
|
59
|
+
}
|
60
|
+
|
61
|
+
/*
|
62
|
+
* call-seq:
|
63
|
+
* stream_buffer_bound(uncompressed_size) -> worst encoded size
|
64
|
+
*/
|
65
|
+
static VALUE utils_stream_buffer_bound(VALUE mod, VALUE size)
|
66
|
+
{
|
67
|
+
return SIZET2NUM(lzma_stream_buffer_bound(NUM2SIZET(size)));
|
68
|
+
}
|
69
|
+
|
70
|
+
/*
|
71
|
+
* call-seq:
|
72
|
+
* block_buffer_bound(uncompressed_size) -> worst encoded size
|
73
|
+
*/
|
74
|
+
static VALUE utils_block_buffer_bound(VALUE mod, VALUE size)
|
75
|
+
{
|
76
|
+
return SIZET2NUM(lzma_block_buffer_bound(NUM2SIZET(size)));
|
77
|
+
}
|
78
|
+
|
79
|
+
static VALUE mUtils;
|
80
|
+
|
81
|
+
void extlzma_init_Utils(void)
|
82
|
+
{
|
83
|
+
mUtils = rb_define_module_under(extlzma_mLZMA, "Utils");
|
84
|
+
|
85
|
+
rb_extend_object(extlzma_mLZMA, mUtils);
|
86
|
+
rb_extend_object(mUtils, mUtils); // 自分に対してもモジュールメソッドを利用できるようにする
|
87
|
+
|
88
|
+
rb_define_method(mUtils, "crc32", RUBY_METHOD_FUNC(utils_crc32), -1);
|
89
|
+
rb_define_method(mUtils, "crc64", RUBY_METHOD_FUNC(utils_crc64), -1);
|
90
|
+
rb_define_method(mUtils, "lookup_error", RUBY_METHOD_FUNC(utils_lookup_error), 1);
|
91
|
+
rb_define_method(mUtils, "stream_buffer_bound", RUBY_METHOD_FUNC(utils_stream_buffer_bound), 1);
|
92
|
+
rb_define_method(mUtils, "block_buffer_bound", RUBY_METHOD_FUNC(utils_block_buffer_bound), 1);
|
93
|
+
}
|
data/extlzma2.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/extlzma2/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'extlzma2'
|
7
|
+
spec.version = LZMA::VERSION
|
8
|
+
spec.authors = ['Ishotihadus']
|
9
|
+
spec.email = ['hanachan.pao@gmail.com']
|
10
|
+
|
11
|
+
spec.summary = 'A Ruby binding of liblzma'
|
12
|
+
spec.description = 'A Ruby binding of liblzma that is compatible with Ruby 3.2'
|
13
|
+
spec.homepage = 'https://github.com/Ishotihadus/extlzma2'
|
14
|
+
spec.required_ruby_version = '>= 2.6.0'
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
18
|
+
|
19
|
+
spec.files = Dir.chdir(__dir__) do
|
20
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
21
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
spec.require_paths = ['lib']
|
26
|
+
spec.extensions = ['ext/extlzma2/extconf.rb']
|
27
|
+
end
|
data/lib/extlzma2/aux.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module LZMA
|
6
|
+
module Aux
|
7
|
+
def self.encode(src, encoder)
|
8
|
+
if src.is_a?(String)
|
9
|
+
s = Encoder.new(encoder, String.new)
|
10
|
+
s << src
|
11
|
+
s.close
|
12
|
+
return s.outport
|
13
|
+
end
|
14
|
+
|
15
|
+
s = Encoder.new(encoder, (src || String.new))
|
16
|
+
return s unless block_given?
|
17
|
+
|
18
|
+
begin
|
19
|
+
yield(s)
|
20
|
+
ensure
|
21
|
+
s.close
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.decode(src, decoder)
|
26
|
+
return decode(StringIO.new(src), decoder, &:read) if src.is_a?(String)
|
27
|
+
|
28
|
+
s = Decoder.new(decoder, src)
|
29
|
+
return s unless block_given?
|
30
|
+
|
31
|
+
begin
|
32
|
+
yield(s)
|
33
|
+
ensure
|
34
|
+
begin
|
35
|
+
s.close
|
36
|
+
rescue StandardError
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module LZMA
|
6
|
+
Decoder = Struct.new(:context, :inport, :readbuf, :workbuf, :status) do |klass|
|
7
|
+
klass::BLOCKSIZE = 256 * 1024 # 256 KiB
|
8
|
+
|
9
|
+
def initialize(context, inport)
|
10
|
+
super(context, inport, String.new, StringIO.new(String.new), :ready)
|
11
|
+
end
|
12
|
+
|
13
|
+
def read(size = nil, buf = String.new)
|
14
|
+
buf.clear
|
15
|
+
size = size.to_i if size
|
16
|
+
return buf if size == 0
|
17
|
+
|
18
|
+
tmp = String.new
|
19
|
+
while !eof && (size.nil? || size > 0)
|
20
|
+
fetch or break if workbuf.eof?
|
21
|
+
|
22
|
+
workbuf.read(size, tmp) or break
|
23
|
+
buf << tmp
|
24
|
+
size -= tmp.bytesize if size
|
25
|
+
end
|
26
|
+
|
27
|
+
buf
|
28
|
+
end
|
29
|
+
|
30
|
+
def eof
|
31
|
+
!status && workbuf.eof?
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :eof?, :eof
|
35
|
+
|
36
|
+
def close
|
37
|
+
self.status = nil
|
38
|
+
workbuf.rewind
|
39
|
+
workbuf.string.clear
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def fetch
|
46
|
+
return nil unless status == :ready
|
47
|
+
|
48
|
+
while workbuf.eof
|
49
|
+
inport.read(self.class::BLOCKSIZE, readbuf) if readbuf.empty?
|
50
|
+
|
51
|
+
workbuf.string.clear
|
52
|
+
workbuf.rewind
|
53
|
+
s = if readbuf.empty?
|
54
|
+
context.code(nil, workbuf.string, self.class::BLOCKSIZE, LZMA::FINISH)
|
55
|
+
else
|
56
|
+
context.code(readbuf, workbuf.string, self.class::BLOCKSIZE, 0)
|
57
|
+
end
|
58
|
+
|
59
|
+
case s
|
60
|
+
when LZMA::OK
|
61
|
+
# pass
|
62
|
+
when LZMA::STREAM_END
|
63
|
+
self.status = :finished
|
64
|
+
break
|
65
|
+
else
|
66
|
+
Utils.raise_err s
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
self
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|