extlzma 0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,81 @@
1
+
2
+ #include "extlzma.h"
3
+
4
+ static VALUE cIndex;
5
+ static VALUE cIEncoder;
6
+ static VALUE cIDecoder;
7
+
8
+
9
+ static void
10
+ ext_index_free(lzma_index *index)
11
+ {
12
+ if (index) {
13
+ lzma_index_end(index, NULL);
14
+ }
15
+ }
16
+
17
+ static VALUE
18
+ ext_index_alloc(VALUE klass)
19
+ {
20
+ lzma_index *index = lzma_index_init(NULL);
21
+ if (!index) {
22
+ rb_raise(rb_eNoMemError, "failed allocation for lzma index structure");
23
+ }
24
+ return Data_Wrap_Struct(klass, NULL, ext_index_free, index);
25
+ }
26
+
27
+ static lzma_index *
28
+ ext_index_refp(VALUE index)
29
+ {
30
+ return getrefp(index);
31
+ }
32
+
33
+ static lzma_index *
34
+ ext_index_ref(VALUE index)
35
+ {
36
+ return getref(index);
37
+ }
38
+
39
+
40
+ static VALUE
41
+ iencoder_init(int argc, VALUE argv[], VALUE idx)
42
+ {
43
+ //RDATA_PTR(idx);
44
+
45
+ rb_raise(rb_eNotImpError, "%s", "IMPLEMENT ME!");
46
+ }
47
+
48
+ static VALUE
49
+ idecoder_init(int argc, VALUE argv[], VALUE idx)
50
+ {
51
+ rb_raise(rb_eNotImpError, "%s", "IMPLEMENT ME!");
52
+ }
53
+
54
+ static VALUE
55
+ ext_index_memused(VALUE index)
56
+ {
57
+ return ULL2NUM(lzma_index_memused(ext_index_ref(index)));
58
+ }
59
+
60
+ static VALUE
61
+ ext_index_s_memusage(VALUE index, VALUE streams, VALUE blocks)
62
+ {
63
+ return ULL2NUM(lzma_index_memusage(NUM2ULL(streams), NUM2ULL(blocks)));
64
+ }
65
+
66
+ void
67
+ extlzma_init_Index(void)
68
+ {
69
+ cIndex = rb_define_class_under(extlzma_mLZMA, "Index", rb_cObject);
70
+ rb_undef_alloc_func(cIndex);
71
+ rb_define_singleton_method(cIndex, "memusage", RUBY_METHOD_FUNC(ext_index_s_memusage), 2);
72
+ rb_define_method(cIndex, "memused", RUBY_METHOD_FUNC(ext_index_memused), 0);
73
+
74
+ cIEncoder = rb_define_class_under(cIndex, "Encoder", cIndex);
75
+ rb_define_alloc_func(cIEncoder, ext_index_alloc);
76
+ rb_define_method(cIEncoder, "initialize", RUBY_METHOD_FUNC(iencoder_init), -1);
77
+
78
+ cIDecoder = rb_define_class_under(cIndex, "Decoder", cIndex);
79
+ rb_define_alloc_func(cIDecoder, ext_index_alloc);
80
+ rb_define_method(cIDecoder, "initialize", RUBY_METHOD_FUNC(idecoder_init), -1);
81
+ }
@@ -0,0 +1,432 @@
1
+ #include "extlzma.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
+ WORK_BUFFER_SIZE = 256 * 1024, // 256 KiB
12
+ BUFFER_BLOCK_SIZE = WORK_BUFFER_SIZE,
13
+ UPDATE_TRY_MAX = 2,
14
+ };
15
+
16
+ static inline void
17
+ filter_copy(lzma_filter *dest, VALUE filter)
18
+ {
19
+ memcpy(dest, extlzma_getfilter(filter), sizeof(*dest));
20
+ }
21
+
22
+ static void
23
+ stream_clear(lzma_stream *stream)
24
+ {
25
+ static const lzma_stream init = LZMA_STREAM_INIT;
26
+ memcpy(stream, &init, sizeof(init));
27
+ }
28
+
29
+ static inline lzma_stream *
30
+ getstream(VALUE lzma)
31
+ {
32
+ return getref(lzma);
33
+ }
34
+
35
+ static inline void
36
+ stream_cleanup(void *pp)
37
+ {
38
+ if (pp) {
39
+ lzma_stream *p = (lzma_stream *)pp;
40
+ lzma_end(p);
41
+ free(p);
42
+ }
43
+ }
44
+
45
+ static void
46
+ stream_mark(void *p)
47
+ {
48
+ }
49
+
50
+ static VALUE
51
+ stream_alloc(VALUE klass)
52
+ {
53
+ lzma_stream *p;
54
+ VALUE obj = Data_Make_Struct(klass, lzma_stream, stream_mark, stream_cleanup, p);
55
+ stream_clear(p);
56
+ return obj;
57
+ }
58
+
59
+ static VALUE
60
+ aux_str_reserve(VALUE str, size_t size)
61
+ {
62
+ size_t capa = rb_str_capacity(str);
63
+ if (capa < size) {
64
+ rb_str_modify_expand(str, size - RSTRING_LEN(str));
65
+ } else {
66
+ rb_str_modify(str);
67
+ }
68
+
69
+ return str;
70
+ }
71
+
72
+ static inline void *
73
+ aux_lzma_code_nogvl(va_list *p)
74
+ {
75
+ lzma_stream *stream = va_arg(*p, lzma_stream *);
76
+ lzma_action sync = va_arg(*p, lzma_action);
77
+ return (void *)lzma_code(stream, sync);
78
+ }
79
+
80
+ static inline lzma_ret
81
+ aux_lzma_code(lzma_stream *stream, lzma_action sync)
82
+ {
83
+ return (lzma_ret)aux_thread_call_without_gvl(aux_lzma_code_nogvl, stream, sync);
84
+ }
85
+
86
+ /*
87
+ * call-seq:
88
+ * code(src, dest, maxdest, action) -> status
89
+ *
90
+ * +lzma_code+ を用いて、圧縮/伸長処理を行います。
91
+ *
92
+ * [RETURN]
93
+ * +lzma_code+ が返す整数値をそのまま返します。
94
+ *
95
+ * [src]
96
+ * 処理前のバイナリデータが格納された文字列オブジェクトを与えます。
97
+ *
98
+ * このオブジェクトは変更されます。
99
+ *
100
+ * 処理された部分が取り除かれます (処理されなかった部分が残ります)。
101
+ *
102
+ * [dest]
103
+ * 処理後のバイナリデータを格納する文字列オブジェクトを与えます。
104
+ *
105
+ * [maxdest]
106
+ * dest の最大処理バイト数を与えます。
107
+ *
108
+ * [action]
109
+ * +lzma_code+ の +action+ 引数に渡される整数値です。
110
+ */
111
+ static VALUE
112
+ stream_code(VALUE stream, VALUE src, VALUE dest, VALUE maxdest, VALUE action)
113
+ {
114
+ lzma_stream *p = getstream(stream);
115
+
116
+ if (NIL_P(src)) {
117
+ p->next_in = NULL;
118
+ p->avail_in = 0;
119
+ } else {
120
+ rb_obj_infect(stream, src);
121
+ rb_check_type(src, RUBY_T_STRING);
122
+ rb_str_modify(src);
123
+ p->next_in = (uint8_t *)RSTRING_PTR(src);
124
+ p->avail_in = RSTRING_LEN(src);
125
+ }
126
+
127
+ size_t maxdestn = NUM2SIZET(maxdest);
128
+ rb_check_type(dest, RUBY_T_STRING);
129
+ aux_str_reserve(dest, maxdestn);
130
+ rb_obj_infect(dest, stream);
131
+ p->next_out = (uint8_t *)RSTRING_PTR(dest);
132
+ p->avail_out = maxdestn;
133
+
134
+ lzma_action act = NUM2INT(action);
135
+
136
+ lzma_ret s = aux_lzma_code(p, act);
137
+
138
+ if (p->next_in) {
139
+ size_t srcrest = p->avail_in;
140
+ memmove(RSTRING_PTR(src), p->next_in, srcrest);
141
+ rb_str_set_len(src, srcrest);
142
+ }
143
+
144
+ rb_str_set_len(dest, maxdestn - p->avail_out);
145
+
146
+ return UINT2NUM(s);
147
+ }
148
+
149
+ // filter は LZMA::Filter クラスのインスタンスを与えることができる
150
+ static void
151
+ filter_setup(lzma_filter filterpack[LZMA_FILTERS_MAX + 1], VALUE filter[], VALUE *filterend, VALUE encoder)
152
+ {
153
+ if ((filterend - filter) > LZMA_FILTERS_MAX) {
154
+ rb_raise(extlzma_eFilterTooLong,
155
+ "filter chain too long (max %d, but given %d)",
156
+ LZMA_FILTERS_MAX, (int)(filterend - filter));
157
+ }
158
+ for (; filter < filterend; filter ++, filterpack ++) {
159
+ VALUE f = *filter;
160
+ if (!rb_obj_is_kind_of(f, extlzma_cFilter)) {
161
+ rb_raise(rb_eTypeError,
162
+ "not a filter - #<%s:%p>",
163
+ rb_obj_classname(f), (void *)f);
164
+ }
165
+ filter_copy(filterpack, f);
166
+ OBJ_INFECT(encoder, f);
167
+ }
168
+ filterpack->id = LZMA_VLI_UNKNOWN;
169
+ filterpack->options = NULL;
170
+ }
171
+
172
+ #define RETRY_NOMEM(TIMES, STMT) \
173
+ ({ \
174
+ lzma_ret RETRY_NOMEM_status = 0; \
175
+ int RETRY_NOMEM_i; \
176
+ for (RETRY_NOMEM_i = (TIMES); RETRY_NOMEM_i > 0; RETRY_NOMEM_i --) { \
177
+ RETRY_NOMEM_status = ({STMT;}); \
178
+ if (RETRY_NOMEM_status == LZMA_MEM_ERROR && RETRY_NOMEM_i > 1) { \
179
+ rb_gc(); \
180
+ continue; \
181
+ } \
182
+ break; \
183
+ } \
184
+ RETRY_NOMEM_status; \
185
+ }) \
186
+
187
+ static int
188
+ conv_checkmethod(VALUE check)
189
+ {
190
+ check = rb_hash_lookup2(check, ID2SYM(extlzma_id_check), Qundef);
191
+ switch (check) {
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
+ return LZMA_CHECK_NONE;
199
+ } else if (check == ID2SYM(extlzma_id_crc32)) {
200
+ return LZMA_CHECK_CRC32;
201
+ } else if (check == ID2SYM(extlzma_id_crc64)) {
202
+ return LZMA_CHECK_CRC64;
203
+ } else if (check == ID2SYM(extlzma_id_sha256)) {
204
+ return LZMA_CHECK_SHA256;
205
+ } else {
206
+ return NUM2UINT(check);
207
+ }
208
+ }
209
+ }
210
+
211
+ static inline void
212
+ ext_encoder_init_scanargs(VALUE encoder, int argc, VALUE argv[], lzma_filter filterpack[LZMA_FILTERS_MAX + 1], uint32_t *check)
213
+ {
214
+ if (check) {
215
+ VALUE tmp;
216
+ rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &tmp);
217
+ if (NIL_P(tmp)) {
218
+ *check = LZMA_CHECK_CRC64;
219
+ } else {
220
+ *check = conv_checkmethod(tmp);
221
+ argc --;
222
+ }
223
+ } else {
224
+ rb_scan_args(argc, argv, "13", NULL, NULL, NULL, NULL);
225
+ }
226
+ memset(filterpack, 0, sizeof(lzma_filter[LZMA_FILTERS_MAX + 1]));
227
+ filter_setup(filterpack, argv, argv + argc, encoder);
228
+ }
229
+
230
+ /*
231
+ * call-seq:
232
+ * initialize(filter1, check: CHECK_CRC64) -> encoder
233
+ * initialize(filter1, filter2, check: CHECK_CRC64) -> encoder
234
+ * initialize(filter1, filter2, filter3, check: CHECK_CRC64) -> encoder
235
+ * initialize(filter1, filter2, filter3, filter4, check: CHECK_CRC64) -> encoder
236
+ *
237
+ * 圧縮器を生成します。圧縮されたデータストリームは xz ファイルフォーマットです。
238
+ *
239
+ * [RETURN]
240
+ * 生成された圧縮器
241
+ *
242
+ * [filter1, filter2, filter3, filter4]
243
+ * LZMA::Filter インスタンス。最低一つを必要とします。
244
+ *
245
+ * [check]
246
+ * チェックメソッド。
247
+ *
248
+ * CHECK_NONE CHECK_CRC32 CHECK_CRC64 CHECK_SHA256 のいずれかの定数を与えます。
249
+ *
250
+ * [EXCEPTIONS]
251
+ * (NO DOCUMENTS)
252
+ */
253
+ static VALUE
254
+ encoder_init(int argc, VALUE argv[], VALUE stream)
255
+ {
256
+ lzma_stream *p = getstream(stream);
257
+
258
+ uint32_t check;
259
+ lzma_filter filterpack[LZMA_FILTERS_MAX + 1];
260
+ ext_encoder_init_scanargs(stream, argc, argv, filterpack, &check);
261
+
262
+ AUX_LZMA_TEST(RETRY_NOMEM(2, lzma_stream_encoder(p, filterpack, check)));
263
+
264
+ return stream;
265
+ }
266
+
267
+ static inline void
268
+ ext_decoder_init_scanargs(int argc, VALUE argv[], uint64_t *memlimit, uint32_t *flags)
269
+ {
270
+ switch (argc) {
271
+ case 0:
272
+ *memlimit = UINT64_MAX;
273
+ *flags = 0;
274
+ return;
275
+ case 1:
276
+ *memlimit = NIL_P(argv[0]) ? UINT64_MAX : NUM2SIZET(argv[0]);
277
+ *flags = 0;
278
+ return;
279
+ case 2:
280
+ *memlimit = NIL_P(argv[0]) ? UINT64_MAX : NUM2SIZET(argv[0]);
281
+ *flags = NIL_P(argv[1]) ? 0 : (uint32_t)NUM2UINT(argv[1]);
282
+ return;
283
+ }
284
+
285
+ rb_error_arity(argc, 0, 2);
286
+ }
287
+
288
+ /*
289
+ * call-seq:
290
+ * initialize(memlimit = nil, flags = 0)
291
+ *
292
+ * [RETURN]
293
+ * 伸張器を返します。
294
+ *
295
+ * [memlimit]
296
+ * 作業メモリ量の最大値を指定します。単位はバイトです。
297
+ *
298
+ * [flags]
299
+ * 伸張器の挙動を変更するための整数値を指定します。定数として次のものが利用できます。
300
+ *
301
+ * - LZMA::TELL_NO_CHECK
302
+ * - LZMA::TELL_UNSUPPORTED_CHECK
303
+ * - LZMA::TELL_ANY_CHECK
304
+ * - LZMA::CONCATENATED
305
+ *
306
+ * これらの意味は xz ユーティリティに含まれる liblzma/api/lzma/container.h に記述されています。
307
+ */
308
+ static VALUE
309
+ autodecoder_init(int argc, VALUE argv[], VALUE stream)
310
+ {
311
+ lzma_stream *p = getstream(stream);
312
+ uint64_t memlimit;
313
+ uint32_t flags;
314
+ ext_decoder_init_scanargs(argc, argv, &memlimit, &flags);
315
+
316
+ AUX_LZMA_TEST(RETRY_NOMEM(2, lzma_auto_decoder(p, memlimit, flags)));
317
+
318
+ return stream;
319
+ }
320
+
321
+ /*
322
+ * call-seq:
323
+ * initialize(memlimit = nil, flags = 0)
324
+ *
325
+ * xz ストリームの伸張器を返します。
326
+ *
327
+ * 引数については AutoDecoder#initialize と同じです。
328
+ */
329
+ static VALUE
330
+ decoder_init(int argc, VALUE argv[], VALUE stream)
331
+ {
332
+ lzma_stream *p = getstream(stream);
333
+
334
+ uint64_t memlimit;
335
+ uint32_t flags;
336
+ ext_decoder_init_scanargs(argc, argv, &memlimit, &flags);
337
+
338
+ AUX_LZMA_TEST(RETRY_NOMEM(2, lzma_stream_decoder(p, memlimit, flags)));
339
+
340
+ return stream;
341
+ }
342
+
343
+ /*
344
+ * call-seq:
345
+ * initialize(filter1) -> encoder
346
+ * initialize(filter1, filter2) -> encoder
347
+ * initialize(filter1, filter2, filter3) -> encoder
348
+ * initialize(filter1, filter2, filter3, filter4) -> encoder
349
+ *
350
+ * 生の (xzヘッダなどの付かない) LZMA1/LZMA2ストリームを構成する圧縮器を生成します。
351
+ *
352
+ * [RETURN]
353
+ * 圧縮器を返します。
354
+ *
355
+ * [filter1, filter2, filter3, filter4]
356
+ * Filter インスタンスを与えます。
357
+ *
358
+ * Filter インスタンスは、例えば LZMA2 フィルタを生成する場合 Filter.lzma2 を利用します。
359
+ */
360
+ static VALUE
361
+ rawencoder_init(int argc, VALUE argv[], VALUE stream)
362
+ {
363
+ lzma_stream *p = getstream(stream);
364
+
365
+ lzma_filter filterpack[LZMA_FILTERS_MAX + 1];
366
+ ext_encoder_init_scanargs(stream, argc, argv, filterpack, NULL);
367
+
368
+ AUX_LZMA_TEST(RETRY_NOMEM(2, lzma_raw_encoder(p, filterpack)));
369
+
370
+ return stream;
371
+ }
372
+
373
+ /*
374
+ * call-seq:
375
+ * initialize(filter1) -> decoder
376
+ * initialize(filter1, filter2) -> decoder
377
+ * initialize(filter1, filter2, filter3) -> decoder
378
+ * initialize(filter1, filter2, filter3, filter4) -> decoder
379
+ */
380
+ static VALUE
381
+ rawdecoder_init(int argc, VALUE argv[], VALUE stream)
382
+ {
383
+ lzma_stream *p = getstream(stream);
384
+
385
+ lzma_filter filterpack[LZMA_FILTERS_MAX + 1];
386
+ ext_encoder_init_scanargs(stream, argc, argv, filterpack, NULL);
387
+
388
+ AUX_LZMA_TEST(RETRY_NOMEM(2, lzma_raw_decoder(p, filterpack)));
389
+
390
+ return stream;
391
+ }
392
+
393
+ void
394
+ extlzma_init_Stream(void)
395
+ {
396
+ extlzma_cStream = rb_define_class_under(extlzma_mLZMA, "Stream", rb_cObject);
397
+ rb_undef_alloc_func(extlzma_cStream);
398
+ rb_define_method(extlzma_cStream, "code", stream_code, 4);
399
+
400
+ cEncoder = rb_define_class_under(extlzma_cStream, "Encoder", extlzma_cStream);
401
+ rb_define_alloc_func(cEncoder, stream_alloc);
402
+ rb_define_method(cEncoder, "initialize", RUBY_METHOD_FUNC(encoder_init), -1);
403
+ rb_define_alias(cEncoder, "encode", "code");
404
+ rb_define_alias(cEncoder, "compress", "code");
405
+
406
+ cDecoder = rb_define_class_under(extlzma_cStream, "Decoder", extlzma_cStream);
407
+ rb_define_alloc_func(cDecoder, stream_alloc);
408
+ rb_define_method(cDecoder, "initialize", RUBY_METHOD_FUNC(decoder_init), -1);
409
+ rb_define_alias(cDecoder, "decode", "code");
410
+ rb_define_alias(cDecoder, "decompress", "code");
411
+ rb_define_alias(cDecoder, "uncompress", "code");
412
+
413
+ cAutoDecoder = rb_define_class_under(extlzma_cStream, "AutoDecoder", extlzma_cStream);
414
+ rb_define_alloc_func(cAutoDecoder, stream_alloc);
415
+ rb_define_method(cAutoDecoder, "initialize", RUBY_METHOD_FUNC(autodecoder_init), -1);
416
+ rb_define_alias(cDecoder, "decode", "code");
417
+ rb_define_alias(cDecoder, "decompress", "code");
418
+ rb_define_alias(cDecoder, "uncompress", "code");
419
+
420
+ cRawEncoder = rb_define_class_under(extlzma_cStream, "RawEncoder", extlzma_cStream);
421
+ rb_define_alloc_func(cRawEncoder, stream_alloc);
422
+ rb_define_method(cRawEncoder, "initialize", RUBY_METHOD_FUNC(rawencoder_init), -1);
423
+ rb_define_alias(cEncoder, "encode", "code");
424
+ rb_define_alias(cEncoder, "compress", "code");
425
+
426
+ cRawDecoder = rb_define_class_under(extlzma_cStream, "RawDecoder", extlzma_cStream);
427
+ rb_define_alloc_func(cRawDecoder, stream_alloc);
428
+ rb_define_method(cRawDecoder, "initialize", RUBY_METHOD_FUNC(rawdecoder_init), -1);
429
+ rb_define_alias(cDecoder, "decode", "code");
430
+ rb_define_alias(cDecoder, "decompress", "code");
431
+ rb_define_alias(cDecoder, "uncompress", "code");
432
+ }