liblzma 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
1
+ # encoding:utf-8
2
+
3
+ = liblzma for Ruby
4
+
5
+ - AUTHOR : dearblue
6
+ - MAIL : dearblue@users.sourceforge.jp
7
+ - LICENSE : 2-clause BSD License (二条項BSDライセンス)
8
+ - PROJECTPAGE : http://sourceforge.jp/projects/rutsubo/
9
+
10
+ This document is written in Japanese.
11
+
12
+
13
+ == はじめに
14
+
15
+ xzユーティリティに含まれるliblzmaのRubyバインディングです。
16
+
17
+ gemパッケージになっており、『gem install liblzma-0.2.gem』でビルド、インストールが完了します。
18
+
19
+ MinGW32およびFreeBSD 9.0R i386で動作確認を行っています。
20
+
21
+ MinGW32向けにはバイナリパッケージも用意してあります (もしかしたらruby-mswin32でも動作するかもしれません)。
22
+
23
+ FreeBSD 9.0R i386 上では標準コンパイラであるGCCのほかにllvm clangでもビルド可能なことを確認してあります。
24
+
25
+
26
+ == 利用できる主な機能
27
+
28
+ ※カッコ内は、本来のliblzmaが提供する関数を示す
29
+
30
+ * LZMA::Stream::Encoder/Decoder (lzma_stream_encoder / lzma_stream_decoder)
31
+ * LZMA::Stream::RawEncoder/RawDecoder (lzma_raw_encoder / lzma_raw_decoder)
32
+ * LZMA::Utils.crc32/crc64 (lzma_crc32 / lzma_crc64)
33
+ * LZMA::Filter::LZMA1/LZMA2/Delta
34
+
35
+
36
+ == 実際に利用するには
37
+
38
+ まともな文書化が出来ていないため、gemパッケージ内の『samples』ディレクトリに含まれる各サンプルを頼りにして下さい。
39
+
40
+
41
+ == ライセンスについて
42
+
43
+ liblzma for Ruby は、二条項BSDライセンスの下で利用できます。
@@ -0,0 +1,11 @@
1
+ require "mkmf"
2
+
3
+ have_header "lzma.h" or raise "need lzma.h"
4
+ have_library "lzma" or raise "need liblzma.a"
5
+ create_makefile "liblzma"
6
+
7
+ # Makefile から、『-L.』を取り除く
8
+ # (本来のliblzma.aではなく、これから作成するliblzma.soへの結合を抑止するため)
9
+ mf = File.read("Makefile", mode: "r:binary")
10
+ mf.gsub!(/(?<=\s)-L\.(?=\s|$)/, " ")
11
+ File.write("Makefile", mf, mode: "wb")
@@ -0,0 +1,1027 @@
1
+ /*
2
+ * liblzma.c -
3
+ * Author:: dearblue <dearblue@sourceforge.jp>
4
+ * Copyright:: Copyright (c) 2010 dearblue
5
+ * License:: Distributed under the 2-clause BSD License
6
+ */
7
+
8
+ #include <ruby.h>
9
+ #include <ruby/intern.h>
10
+ #include <lzma.h>
11
+
12
+
13
+ static VALUE mLZMA;
14
+
15
+
16
+ static VALUE symDICTSIZE;
17
+ static VALUE symPRESETDICT;
18
+ static VALUE symLC;
19
+ static VALUE symLP;
20
+ static VALUE symPB;
21
+ static VALUE symMODE;
22
+ static VALUE symNICE;
23
+ static VALUE symMF;
24
+ static VALUE symDEPTH;
25
+ static VALUE symCHECK;
26
+
27
+
28
+ static inline int
29
+ lzma_isfailed(lzma_ret status)
30
+ {
31
+ return status != 0;
32
+ }
33
+
34
+
35
+ // SECTION: LZMA::Constants
36
+
37
+ static VALUE mConstants;
38
+
39
+ static void
40
+ setup_constants(void)
41
+ {
42
+ mConstants = rb_define_module_under(mLZMA, "Constants");
43
+ rb_include_module(mLZMA, mConstants);
44
+
45
+ #define DEFINE_CONSTANT(NAME, VALUE) \
46
+ { \
47
+ rb_define_const(mConstants, #NAME, VALUE); \
48
+ rb_define_const(mConstants, "LZMA_" #NAME, VALUE); \
49
+ } \
50
+
51
+ DEFINE_CONSTANT(NICE_DEFAULT, SIZET2NUM(64));
52
+ DEFINE_CONSTANT(DEPTH_DEFAULT, SIZET2NUM(0));
53
+
54
+ DEFINE_CONSTANT(PRESET_DEFAULT, UINT2NUM(LZMA_PRESET_DEFAULT));
55
+ DEFINE_CONSTANT(PRESET_LEVEL_MASK, UINT2NUM(LZMA_PRESET_LEVEL_MASK));
56
+ DEFINE_CONSTANT(PRESET_EXTREME, UINT2NUM(LZMA_PRESET_EXTREME));
57
+ DEFINE_CONSTANT(DICT_SIZE_MIN, UINT2NUM(LZMA_DICT_SIZE_MIN));
58
+ DEFINE_CONSTANT(DICT_SIZE_DEFAULT, UINT2NUM(LZMA_DICT_SIZE_DEFAULT));
59
+ DEFINE_CONSTANT(LCLP_MIN, UINT2NUM(LZMA_LCLP_MIN));
60
+ DEFINE_CONSTANT(LCLP_MAX, UINT2NUM(LZMA_LCLP_MAX));
61
+ DEFINE_CONSTANT(LC_DEFAULT, UINT2NUM(LZMA_LC_DEFAULT));
62
+ DEFINE_CONSTANT(LP_DEFAULT, UINT2NUM(LZMA_LP_DEFAULT));
63
+ DEFINE_CONSTANT(PB_MIN, UINT2NUM(LZMA_PB_MIN));
64
+ DEFINE_CONSTANT(PB_MAX, UINT2NUM(LZMA_PB_MAX));
65
+ DEFINE_CONSTANT(PB_DEFAULT, UINT2NUM(LZMA_PB_DEFAULT));
66
+ DEFINE_CONSTANT(MODE_FAST, UINT2NUM(LZMA_MODE_FAST));
67
+ DEFINE_CONSTANT(MODE_NORMAL, UINT2NUM(LZMA_MODE_NORMAL));
68
+ DEFINE_CONSTANT(MF_HC3, UINT2NUM(LZMA_MF_HC3));
69
+ DEFINE_CONSTANT(MF_HC4, UINT2NUM(LZMA_MF_HC4));
70
+ DEFINE_CONSTANT(MF_BT2, UINT2NUM(LZMA_MF_BT2));
71
+ DEFINE_CONSTANT(MF_BT3, UINT2NUM(LZMA_MF_BT3));
72
+ DEFINE_CONSTANT(MF_BT4, UINT2NUM(LZMA_MF_BT4));
73
+
74
+ DEFINE_CONSTANT(CHECK_NONE, UINT2NUM(LZMA_CHECK_NONE));
75
+ DEFINE_CONSTANT(CHECK_CRC32, UINT2NUM(LZMA_CHECK_CRC32));
76
+ DEFINE_CONSTANT(CHECK_CRC64, UINT2NUM(LZMA_CHECK_CRC64));
77
+ DEFINE_CONSTANT(CHECK_SHA256, UINT2NUM(LZMA_CHECK_SHA256));
78
+
79
+ DEFINE_CONSTANT(RUN, UINT2NUM(LZMA_RUN));
80
+ DEFINE_CONSTANT(FULL_FLUSH, UINT2NUM(LZMA_FULL_FLUSH));
81
+ DEFINE_CONSTANT(SYNC_FLUSH, UINT2NUM(LZMA_SYNC_FLUSH));
82
+ DEFINE_CONSTANT(FINISH, UINT2NUM(LZMA_FINISH));
83
+
84
+ #undef DEFINE_CONSTANT
85
+ }
86
+
87
+
88
+ // SECTION: LZMA::Exceptions
89
+
90
+ static VALUE mExceptions;
91
+
92
+ static VALUE eBasicException;
93
+ static VALUE eStreamEnd;
94
+ static VALUE eNoCheck;
95
+ static VALUE eUnsupportedCheck;
96
+ static VALUE eGetCheck;
97
+ static VALUE eMemError;
98
+ static VALUE eMemlimitError;
99
+ static VALUE eFormatError;
100
+ static VALUE eOptionsError;
101
+ static VALUE eDataError;
102
+ static VALUE eBufError;
103
+ static VALUE eProgError;
104
+ static VALUE eFilterTooLong;
105
+ static VALUE eBadPreset;
106
+
107
+ static inline VALUE
108
+ lookup_exception(lzma_ret status)
109
+ {
110
+ switch (status) {
111
+ case LZMA_OK: return Qnil;
112
+ case LZMA_STREAM_END: return eStreamEnd;
113
+ case LZMA_NO_CHECK: return eNoCheck;
114
+ case LZMA_UNSUPPORTED_CHECK: return eUnsupportedCheck;
115
+ case LZMA_GET_CHECK: return eGetCheck;
116
+ case LZMA_MEM_ERROR: return eMemError;
117
+ case LZMA_MEMLIMIT_ERROR: return eMemlimitError;
118
+ case LZMA_FORMAT_ERROR: return eFormatError;
119
+ case LZMA_OPTIONS_ERROR: return eOptionsError;
120
+ case LZMA_DATA_ERROR: return eDataError;
121
+ case LZMA_BUF_ERROR: return eBufError;
122
+ case LZMA_PROG_ERROR: return eProgError;
123
+ default: return rb_eRuntimeError;
124
+ }
125
+ }
126
+
127
+ static void
128
+ setup_exceptions(void)
129
+ {
130
+ mExceptions = rb_define_module_under(mLZMA, "Exceptions");
131
+ rb_include_module(mLZMA, mExceptions);
132
+
133
+ eBasicException = rb_define_class_under(mExceptions, "BasicException", rb_eStandardError);
134
+ rb_define_class_under(mExceptions, "FilterTooLong", eBasicException);
135
+ rb_define_class_under(mExceptions, "BadPreset", eBasicException);
136
+
137
+ #define DEFINE_EXCEPTION(CLASS, STATUS) \
138
+ { \
139
+ e ## CLASS = rb_define_class_under(mExceptions, #CLASS, eBasicException); \
140
+ rb_define_const(e ## CLASS, "STATUS", SIZET2NUM(STATUS)); \
141
+ } \
142
+
143
+ DEFINE_EXCEPTION(StreamEnd, LZMA_STREAM_END);
144
+ DEFINE_EXCEPTION(NoCheck, LZMA_NO_CHECK);
145
+ DEFINE_EXCEPTION(UnsupportedCheck, LZMA_UNSUPPORTED_CHECK);
146
+ DEFINE_EXCEPTION(GetCheck, LZMA_GET_CHECK);
147
+ DEFINE_EXCEPTION(MemError, LZMA_MEM_ERROR);
148
+ DEFINE_EXCEPTION(MemlimitError, LZMA_MEMLIMIT_ERROR);
149
+ DEFINE_EXCEPTION(FormatError, LZMA_FORMAT_ERROR);
150
+ DEFINE_EXCEPTION(OptionsError, LZMA_OPTIONS_ERROR);
151
+ DEFINE_EXCEPTION(DataError, LZMA_DATA_ERROR);
152
+ DEFINE_EXCEPTION(BufError, LZMA_BUF_ERROR);
153
+ DEFINE_EXCEPTION(ProgError, LZMA_PROG_ERROR);
154
+ #undef DEFINE_EXCEPTION
155
+ }
156
+
157
+
158
+ // SECTION: LZMA::Filter
159
+
160
+ static VALUE cFilter;
161
+ static VALUE cBasicLZMA;
162
+ static VALUE cLZMA1;
163
+ static VALUE cLZMA2;
164
+ static VALUE cDelta;
165
+
166
+
167
+ static inline lzma_filter *
168
+ getfilter(VALUE obj)
169
+ {
170
+ lzma_filter *filter;
171
+ Data_Get_Struct(obj, lzma_filter, filter);
172
+ return filter;
173
+ }
174
+
175
+ static void *
176
+ setup_lzma_preset(size_t preset)
177
+ {
178
+ lzma_options_lzma *lzma = xcalloc(sizeof(lzma_options_lzma), 1);
179
+ if (lzma_lzma_preset(lzma, preset)) {
180
+ rb_raise(rb_eArgError,
181
+ "wrong preset level (%d for 0..9) or wrong flag bit(s) (%08x)",
182
+ preset & LZMA_PRESET_LEVEL_MASK,
183
+ preset & ~LZMA_PRESET_LEVEL_MASK & ~LZMA_PRESET_EXTREME);
184
+ }
185
+ return (void *)(lzma);
186
+ }
187
+
188
+ static const char PRIVATE_DICTPRESET[] = "dict_preset";
189
+
190
+ static inline void
191
+ lzma_set_dict_0(lzma_options_lzma *filter, VALUE dict, VALUE self)
192
+ {
193
+ if (NIL_P(dict)) {
194
+ filter->preset_dict = NULL;
195
+ filter->preset_dict_size = 0;
196
+ } else {
197
+ if (TYPE(dict) != T_STRING) {
198
+ rb_raise(rb_eTypeError, "%s", "dict is not a String or nil");
199
+ }
200
+ dict = rb_str_new_frozen(dict);
201
+ filter->preset_dict = (uint8_t *)(RSTRING_PTR(dict));
202
+ filter->preset_dict_size = RSTRING_LEN(dict);
203
+ }
204
+ rb_iv_set(self, PRIVATE_DICTPRESET, dict);
205
+ }
206
+
207
+ static VALUE
208
+ lzma_set_dict(VALUE self, VALUE dict)
209
+ {
210
+ lzma_set_dict_0((lzma_options_lzma *)getfilter(self)->options, dict, self);
211
+ return self;
212
+ }
213
+
214
+ static VALUE
215
+ lzma_get_dict(VALUE self)
216
+ {
217
+ return rb_str_new_shared(rb_iv_get(self, PRIVATE_DICTPRESET));
218
+ }
219
+
220
+
221
+ #define DEFINE_ACCESSOR_ENTITY(NAME, MEMBER, DEFAULT) \
222
+ static inline void \
223
+ lzma_set_ ## NAME ## _0(lzma_options_lzma *filter, VALUE n) \
224
+ { \
225
+ if (NIL_P(n)) { \
226
+ filter->MEMBER = DEFAULT; \
227
+ } else { \
228
+ filter->MEMBER = NUM2UINT(n); \
229
+ } \
230
+ } \
231
+ \
232
+ static VALUE \
233
+ lzma_set_ ## NAME(VALUE self, VALUE n) \
234
+ { \
235
+ lzma_set_ ## NAME ## _0((lzma_options_lzma *)getfilter(self)->options, n); \
236
+ return self; \
237
+ } \
238
+ \
239
+ static VALUE \
240
+ lzma_get_ ## NAME(VALUE self) \
241
+ { \
242
+ return UINT2NUM(((lzma_options_lzma *)getfilter(self)->options)->MEMBER); \
243
+ } \
244
+
245
+ DEFINE_ACCESSOR_ENTITY(dictsize, dict_size, LZMA_DICT_SIZE_DEFAULT) // lzma_set_dictsize_0, lzma_set_dictsize, lzma_set_lc
246
+ DEFINE_ACCESSOR_ENTITY(lc, lc, LZMA_LC_DEFAULT)
247
+ DEFINE_ACCESSOR_ENTITY(lp, lp, LZMA_LP_DEFAULT)
248
+ DEFINE_ACCESSOR_ENTITY(pb, pb, LZMA_PB_DEFAULT)
249
+ DEFINE_ACCESSOR_ENTITY(mode, mode, LZMA_MODE_NORMAL)
250
+ DEFINE_ACCESSOR_ENTITY(nice, nice_len, 64)
251
+ DEFINE_ACCESSOR_ENTITY(mf, mf, LZMA_MF_BT4)
252
+ DEFINE_ACCESSOR_ENTITY(depth, depth, 0)
253
+
254
+ #undef DEFINE_ACCESSOR_ENTITY
255
+
256
+ static void *
257
+ setup_lzma(VALUE obj, uint32_t preset,
258
+ VALUE dictsize, VALUE dictpreset, VALUE lc, VALUE lp, VALUE pb,
259
+ VALUE mode, VALUE nice, VALUE mf, VALUE depth)
260
+ {
261
+ lzma_options_lzma lzma = { 0 };
262
+ if (lzma_lzma_preset(&lzma, preset) != 0) {
263
+ rb_raise(eBadPreset, "bad preset (%08x)", preset);
264
+ }
265
+
266
+ if (RTEST(dictpreset)) { lzma_set_dict_0(&lzma, dictpreset, obj); }
267
+
268
+ #define SETVAR(NAME) \
269
+ if (RTEST(NAME)) { lzma_set_ ## NAME ## _0(&lzma, NAME); } \
270
+
271
+ SETVAR(dictsize);
272
+ SETVAR(lc);
273
+ SETVAR(lp);
274
+ SETVAR(pb);
275
+ SETVAR(mode);
276
+ SETVAR(nice);
277
+ SETVAR(mf);
278
+ SETVAR(depth);
279
+
280
+ #undef SETVAR
281
+
282
+ {
283
+ lzma_options_lzma *p = ALLOC(lzma_options_lzma);
284
+ memcpy(p, &lzma, sizeof(lzma));
285
+ return (void *)(p);
286
+ }
287
+ }
288
+
289
+ static void
290
+ cleanup_filter(lzma_filter *filter)
291
+ {
292
+ if (filter->options) { xfree(filter->options); }
293
+ xfree(filter);
294
+ }
295
+
296
+
297
+ static uint32_t
298
+ getpreset(VALUE preset)
299
+ {
300
+ if (NIL_P(preset)) {
301
+ return LZMA_PRESET_DEFAULT;
302
+ } else {
303
+ return NUM2UINT(preset);
304
+ }
305
+ }
306
+
307
+ /*
308
+ * call-seq:
309
+ * LZMA::Filter.lzma1(....)
310
+ *
311
+ * LZMA::Filter::LZMA1.newを呼ぶための補助機構である
312
+ *
313
+ * LZMA::Filter::LZMA1クラスの .new や #initialize を書き換えた場合はそれに従う
314
+ * (あくまで .new を呼ぶだけである)
315
+ */
316
+ static VALUE
317
+ lzma1_new(int argc, VALUE argv[], VALUE self)
318
+ {
319
+ return rb_class_new_instance(argc, argv, cLZMA1);
320
+ }
321
+
322
+ /*
323
+ * call-seq:
324
+ * LZMA::Filter.lzma2(...)
325
+ *
326
+ * LZMA::Filter::LZMA2.new を呼ぶための補助機構である
327
+ *
328
+ * LZMA::Filter::LZMA2クラスの .new や #initialize を書き換えた場合はそれに従う
329
+ * (あくまで .new を呼ぶだけである)
330
+ */
331
+ static VALUE
332
+ lzma2_new(int argc, VALUE argv[], VALUE self)
333
+ {
334
+ return rb_class_new_instance(argc, argv, cLZMA2);
335
+ }
336
+
337
+ /*
338
+ * call-seq:
339
+ * LZMA::Filter.delta(....)
340
+ *
341
+ * LZMA::Filter::Delta.newを呼ぶための補助機構である
342
+ *
343
+ * LZMA::Filter::Deltaクラスの .new や #initialize を書き換えた場合はそれに従う
344
+ * (あくまで .new を呼ぶだけである)
345
+ */
346
+ static VALUE
347
+ delta_new(int argc, VALUE argv[], VALUE self)
348
+ {
349
+ return rb_class_new_instance(argc, argv, cDelta);
350
+ }
351
+
352
+
353
+
354
+ static inline VALUE
355
+ filter_alloc(VALUE klass, lzma_vli id)
356
+ {
357
+ lzma_filter *filter;
358
+ VALUE obj = Data_Make_Struct(klass, lzma_filter, NULL, cleanup_filter, filter);
359
+ memset(filter, 0, sizeof(*filter));
360
+ filter->id = id;
361
+ return obj;
362
+ }
363
+
364
+ static VALUE
365
+ lzma1_alloc(VALUE klass)
366
+ {
367
+ return filter_alloc(klass, LZMA_FILTER_LZMA1);
368
+ }
369
+
370
+ static VALUE
371
+ lzma2_alloc(VALUE klass)
372
+ {
373
+ return filter_alloc(klass, LZMA_FILTER_LZMA2);
374
+ }
375
+
376
+ static VALUE
377
+ delta_alloc(VALUE klass)
378
+ {
379
+ return filter_alloc(cDelta, LZMA_FILTER_DELTA);
380
+ }
381
+
382
+ /*
383
+ * call-seq:
384
+ * LZMA::Filter::Delta.new(dist = LZMA::DELTA_DIST_MIN)
385
+ *
386
+ * 差分フィルタ設定オブジェクトを返す。
387
+ *
388
+ * distは1要素あたりのバイト長で、1以上を指定する。
389
+ *
390
+ * 使用する場合多くの場合1で十分だろうし、音楽CDの音声データであれば2を指定するのがいいだろう。
391
+ *
392
+ * しかし元のデータによっては圧縮効率を低下させることがあるため、常に適用することはしないほうがいい。
393
+ */
394
+ static VALUE
395
+ delta_init(int argc, VALUE argv[], VALUE self)
396
+ {
397
+ lzma_filter *filter = getfilter(self);
398
+ lzma_options_delta *delta = ALLOC(lzma_options_delta);
399
+ memset(delta, 0, sizeof(*delta));
400
+
401
+ VALUE preset = Qnil;
402
+ rb_scan_args(argc, argv, "01", &preset);
403
+ delta->type = LZMA_DELTA_TYPE_BYTE;
404
+ delta->dist = NIL_P(preset) ? LZMA_DELTA_DIST_MIN : NUM2UINT(preset);
405
+ filter->options = delta;
406
+ return self;
407
+ }
408
+
409
+ /*
410
+ * call-seq:
411
+ * LZMA::Filter::BasicLZMA.new(preset = LZMA::PRESET_DEFAULT, opts = { .... } ) -> filter
412
+ *
413
+ * フィルタ設定オブジェクトを返す。
414
+ *
415
+ * この段階で各値の確認を行うことはせず、*encoderに渡すときに初めて確認される
416
+ *
417
+ * 引数::
418
+ * 引数は、presetは整数で、続くoptsはハッシュであり、細かい調整を行う場合に指定する。
419
+ *
420
+ * どちらも任意に省略可能であり、presetを省略してoptsを指定することも可能である。
421
+ *
422
+ * preset:: プリセット値 (≒圧縮レベル) を0-9の範囲で指定する。既定値はLZMA::PRESET_DEFAULTである。
423
+ * dictsize:: 既定値はLZMA::DICT_SIZE_DEFAULT
424
+ * presetdict:: 既定値はnil
425
+ * lc:: 既定値はLZMA::LC_DEFAULT
426
+ * lp:: 既定値はLZMA::LP_DEFAULT
427
+ * pb:: 既定値はLZMA::PB_DEFAULT
428
+ * mode:: 既定値はLZMA::MODE_NORMAL
429
+ * nice:: 既定値はLZMA::NICE_DEFAULT
430
+ * mf:: 既定値はLZMA::MF_BT4
431
+ * depth:: 既定値はLZMA::DEPTH_DEFAULT
432
+ */
433
+ static VALUE
434
+ lzma_init(int argc, VALUE argv[], VALUE self)
435
+ {
436
+ VALUE preset = Qnil;
437
+ VALUE opts = Qnil;
438
+ rb_scan_args(argc, argv, "01:", &preset, &opts);
439
+ lzma_filter *filter = getfilter(self);
440
+ if (NIL_P(opts)) {
441
+ filter->options = setup_lzma_preset(getpreset(preset));
442
+ } else {
443
+ filter->options = setup_lzma(self, getpreset(preset),
444
+ rb_hash_lookup(opts, symDICTSIZE),
445
+ rb_hash_lookup(opts, symPRESETDICT),
446
+ rb_hash_lookup(opts, symLC),
447
+ rb_hash_lookup(opts, symLP),
448
+ rb_hash_lookup(opts, symPB),
449
+ rb_hash_lookup(opts, symMODE),
450
+ rb_hash_lookup(opts, symNICE),
451
+ rb_hash_lookup(opts, symMF),
452
+ rb_hash_lookup(opts, symDEPTH));
453
+ }
454
+ return self;
455
+ }
456
+
457
+ /*
458
+ * Document-method: LZMA::Filter::BasicLZMA#dictsize
459
+ *
460
+ * call-seq:
461
+ * LZMA::Filter::BasicLZMA#dictsize -> 辞書サイズ (バイト長)
462
+ *
463
+ * 様々なフィルタ値の設定・取り出しを行う
464
+ */
465
+ static void
466
+ setup_filter(void)
467
+ {
468
+ cFilter = rb_define_class_under(mLZMA, "Filter", rb_cObject);
469
+ rb_undef_alloc_func(cFilter);
470
+ rb_define_singleton_method(cFilter, "lzma1", RUBY_METHOD_FUNC(lzma1_new), -1);
471
+ rb_define_singleton_method(cFilter, "lzma2", RUBY_METHOD_FUNC(lzma2_new), -1);
472
+ rb_define_singleton_method(cFilter, "delta", RUBY_METHOD_FUNC(delta_new), -1);
473
+
474
+ cBasicLZMA = rb_define_class_under(cFilter, "BasicLZMA", cFilter);
475
+ rb_define_method(cBasicLZMA, "initialize", lzma_init, -1);
476
+
477
+ cLZMA1 = rb_define_class_under(cFilter, "LZMA1", cBasicLZMA);
478
+ rb_define_alloc_func(cLZMA1, lzma1_alloc);
479
+
480
+ cLZMA2 = rb_define_class_under(cFilter, "LZMA2", cBasicLZMA);
481
+ rb_define_alloc_func(cLZMA2, lzma2_alloc);
482
+
483
+ cDelta = rb_define_class_under(cFilter, "Delta", cFilter);
484
+ rb_define_alloc_func(cDelta, delta_alloc);
485
+ rb_define_method(cDelta, "initialize", delta_init, -1);
486
+
487
+ #define DEF_ACCESSOR(CLASS, NAME) \
488
+ rb_define_method(CLASS, #NAME, lzma_get_ ## NAME, 0); \
489
+ rb_define_method(CLASS, #NAME "=", lzma_set_ ## NAME, 1); \
490
+
491
+ DEF_ACCESSOR(cBasicLZMA, dictsize);
492
+ DEF_ACCESSOR(cBasicLZMA, dict);
493
+ DEF_ACCESSOR(cBasicLZMA, lc);
494
+ DEF_ACCESSOR(cBasicLZMA, lp);
495
+ DEF_ACCESSOR(cBasicLZMA, pb);
496
+ DEF_ACCESSOR(cBasicLZMA, mode);
497
+ DEF_ACCESSOR(cBasicLZMA, nice);
498
+ DEF_ACCESSOR(cBasicLZMA, mf);
499
+ DEF_ACCESSOR(cBasicLZMA, depth);
500
+
501
+ #undef DEF_ACCESSOR
502
+ }
503
+
504
+
505
+ // SECTION: LZMA::Stream
506
+
507
+ static VALUE cStream;
508
+ static VALUE cEncoder;
509
+ static VALUE cDecoder;
510
+ static VALUE cAutoDecoder;
511
+ static VALUE cRawEncoder;
512
+ static VALUE cRawDecoder;
513
+
514
+
515
+ #define LZMA_TEST(STATUS) \
516
+ { \
517
+ lzma_ret _status = (STATUS); \
518
+ if (lzma_isfailed(_status)) { \
519
+ VALUE exc = lookup_exception(_status); \
520
+ rb_exc_raise(rb_exc_new3(exc, rb_class_name(exc))); \
521
+ } \
522
+ } \
523
+
524
+ static inline void
525
+ filter_copy(lzma_filter *dest, VALUE filter)
526
+ {
527
+ memcpy(dest, getfilter(filter), sizeof(*dest));
528
+ }
529
+
530
+ static void
531
+ stream_clear(lzma_stream *stream)
532
+ {
533
+ const lzma_stream init = LZMA_STREAM_INIT;
534
+ memcpy(stream, &init, sizeof(init));
535
+ }
536
+
537
+ static inline lzma_stream *
538
+ getstream(VALUE lzma)
539
+ {
540
+ lzma_stream *stream;
541
+ Data_Get_Struct(lzma, lzma_stream, stream);
542
+ return stream;
543
+ }
544
+
545
+ static inline void
546
+ stream_cleanup(lzma_stream *stream)
547
+ {
548
+ lzma_end(stream);
549
+ xfree(stream);
550
+ }
551
+
552
+
553
+ static inline int
554
+ is_sync(size_t sync)
555
+ {
556
+ return (sync == LZMA_SYNC_FLUSH || sync == LZMA_FULL_FLUSH || sync == LZMA_FINISH);
557
+ }
558
+
559
+
560
+ struct stream_update_args
561
+ {
562
+ lzma_stream *stream;
563
+ lzma_action action;
564
+ const uint8_t *src;
565
+ size_t srclen;
566
+ };
567
+
568
+ static VALUE
569
+ stream_update_1(struct stream_update_args *args)
570
+ {
571
+ VALUE dest = rb_str_new("", 0);
572
+ uint8_t buf[4 * 1024];
573
+ args->stream->next_in = args->src;
574
+ args->stream->avail_in = args->srclen;
575
+ while (args->stream->avail_in > 0 || is_sync(args->action)) {
576
+ do {
577
+ rb_thread_check_ints();
578
+ args->stream->next_out = buf;
579
+ args->stream->avail_out = sizeof(buf);
580
+ lzma_ret status = lzma_code(args->stream, args->action);
581
+ if (status == LZMA_STREAM_END) {
582
+ rb_str_buf_cat(dest, (const char *)buf, args->stream->next_out - buf);
583
+ return dest;
584
+ }
585
+
586
+ LZMA_TEST(status);
587
+ rb_str_buf_cat(dest, (const char *)buf, args->stream->next_out - buf);
588
+ } while (args->stream->next_out - buf > 0);
589
+ }
590
+ return dest;
591
+ }
592
+
593
+ static inline VALUE
594
+ stream_update_2(struct stream_update_args *args)
595
+ {
596
+ return rb_thread_blocking_region((VALUE (*)(void *))stream_update_1, args, RUBY_UBF_IO, NULL);
597
+ }
598
+
599
+ static inline VALUE
600
+ stream_update_3(VALUE src)
601
+ {
602
+ rb_str_unlocktmp(src);
603
+ return Qnil;
604
+ }
605
+
606
+ static inline VALUE
607
+ stream_update_0(lzma_stream *stream, lzma_action action, VALUE src)
608
+ {
609
+ if (RTEST(src)) {
610
+ StringValue(src);
611
+ rb_str_locktmp(src);
612
+ struct stream_update_args args = {
613
+ stream, action,
614
+ (const uint8_t *)RSTRING_PTR(src), RSTRING_LEN(src),
615
+ };
616
+ return rb_ensure(stream_update_2, (VALUE)&args, stream_update_3, src);
617
+ } else {
618
+ struct stream_update_args args = {
619
+ stream, action, NULL, 0,
620
+ };
621
+ return stream_update_2(&args);
622
+ }
623
+ }
624
+
625
+ /*
626
+ * call-seq:
627
+ * LZMA::Stream#update(src, flush = LZMA::RUN)
628
+ *
629
+ * データストリームとして渡されたsrcを圧縮/伸張します。
630
+ *
631
+ * [RETURN] Stringインスタンス
632
+ * [EXCEPTION] LZMA::Exceptions::BasicException
633
+ */
634
+ static VALUE
635
+ stream_update(int argc, VALUE argv[], VALUE self)
636
+ {
637
+ VALUE src, flush1;
638
+ int flush;
639
+ if (rb_scan_args(argc, argv, "11", &src, &flush1) == 1) {
640
+ flush = LZMA_RUN;
641
+ } else {
642
+ flush = NUM2INT(flush1);
643
+ }
644
+ lzma_stream *stream = getstream(self);
645
+ return stream_update_0(stream, flush, src);
646
+ }
647
+
648
+ /*
649
+ * call-seq:
650
+ * LZMA::Stream#flush(fullsync = false)
651
+ */
652
+ static VALUE
653
+ stream_flush(int argc, VALUE argv[], VALUE self)
654
+ {
655
+ VALUE fullsync = Qfalse;
656
+ rb_scan_args(argc, argv, "01", &fullsync);
657
+ lzma_stream *stream = getstream(self);
658
+ size_t sync = RTEST(fullsync) ? LZMA_FULL_FLUSH : LZMA_SYNC_FLUSH;
659
+ return stream_update_0(stream, sync, Qnil);
660
+ }
661
+
662
+ /*
663
+ * call-seq:
664
+ * LZMA::Stream#finish
665
+ */
666
+ static VALUE
667
+ stream_finish(VALUE self)
668
+ {
669
+ lzma_stream *stream = getstream(self);
670
+ VALUE dest = stream_update_0(stream, LZMA_FINISH, Qnil);
671
+
672
+ lzma_end(stream);
673
+ stream_clear(stream);
674
+
675
+ return dest;
676
+ }
677
+
678
+
679
+
680
+ static VALUE
681
+ stream_alloc(VALUE klass)
682
+ {
683
+ lzma_stream *stream;
684
+ VALUE obj = Data_Make_Struct(klass, lzma_stream, NULL, stream_cleanup, stream);
685
+ stream_clear(stream);
686
+ return obj;
687
+ }
688
+
689
+ // filters0はLZMA::Filterクラスのinstanceを与えることができる
690
+ static void
691
+ filter_setup(lzma_filter filter[LZMA_FILTERS_MAX + 1], VALUE filters0[], VALUE *filters0end)
692
+ {
693
+ if ((filters0end - filters0) > LZMA_FILTERS_MAX) {
694
+ rb_raise(eFilterTooLong, "filter chain too long (max %d, but given %d)",
695
+ LZMA_FILTERS_MAX, filters0end - filters0);
696
+ }
697
+ for (; filters0 < filters0end; filters0 ++, filter ++) {
698
+ VALUE f = *filters0;
699
+ if (!rb_obj_is_kind_of(f, cFilter)) {
700
+ rb_raise(rb_eTypeError, "%s", "not a filter");
701
+ }
702
+ filter_copy(filter, f);
703
+ }
704
+ filter->id = LZMA_VLI_UNKNOWN;
705
+ filter->options = NULL;
706
+ }
707
+
708
+
709
+ // LZMA::Stream.encoder(filter1, filter2, ...., filterN, check: CRC64)
710
+ static VALUE
711
+ encoder_init(int argc, VALUE argv[], VALUE self)
712
+ {
713
+ VALUE vcheck;
714
+ rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &vcheck);
715
+ uint32_t check;
716
+ if (NIL_P(vcheck)) {
717
+ check = LZMA_CHECK_CRC64;
718
+ } else {
719
+ check = NUM2UINT(vcheck);
720
+ argc --;
721
+ }
722
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
723
+ memset(filters, 0, sizeof(filters));
724
+ filter_setup(filters, argv, argv + argc);
725
+
726
+ lzma_stream *stream = getstream(self);
727
+ LZMA_TEST(lzma_stream_encoder(stream, filters, check));
728
+
729
+ return self;
730
+ }
731
+
732
+ /*
733
+ * call-seq:
734
+ * LZMA::Stream::AutoDecoder.initialize(memlimit = nil, flags = nil)
735
+ */
736
+ static VALUE
737
+ autodecoder_init(int argc, VALUE argv[], VALUE self)
738
+ {
739
+ VALUE memlimit0 = Qnil;
740
+ VALUE flags0 = Qnil;
741
+ uint64_t memlimit = UINT64_MAX;
742
+ uint32_t flags = 0;
743
+ rb_scan_args(argc, argv, "02", &memlimit0, &flags0);
744
+ if (!NIL_P(flags0)) { flags = NUM2SIZET(flags0); }
745
+ if (!NIL_P(memlimit0)) { memlimit = NUM2SIZET(memlimit0); }
746
+
747
+ lzma_stream *stream = getstream(self);
748
+ LZMA_TEST(lzma_auto_decoder(stream, memlimit, flags));
749
+
750
+ return self;
751
+ }
752
+
753
+ /*
754
+ * call-seq:
755
+ * LZMA::Stream::Decoder.initialize(memlimit = nil, flags = nil)
756
+ */
757
+ static VALUE
758
+ decoder_init(int argc, VALUE argv[], VALUE self)
759
+ {
760
+ VALUE memlimit0 = Qnil;
761
+ VALUE flags0 = Qnil;
762
+ uint64_t memlimit = UINT64_MAX;
763
+ uint32_t flags = 0;
764
+ rb_scan_args(argc, argv, "02", &memlimit0, &flags0);
765
+ if (!NIL_P(flags0)) { flags = NUM2SIZET(flags0); }
766
+ if (!NIL_P(memlimit0)) { memlimit = NUM2SIZET(memlimit0); }
767
+
768
+ lzma_stream *stream = getstream(self);
769
+ LZMA_TEST(lzma_stream_decoder(stream, memlimit, flags));
770
+
771
+ return self;
772
+ }
773
+
774
+ /*
775
+ * call-seq:
776
+ * LZMA::Stream::RawEncoder.initialize(filter1 [ , filter2 [ , .... ] ]) -> encoder
777
+ *
778
+ * 生の (xzヘッダなどの付かない) LZMA1/2ストリームを構成する圧縮器機を生成する。
779
+ *
780
+ * filterは1つ以上4つまでを与える。
781
+ */
782
+ static VALUE
783
+ rawencoder_init(int argc, VALUE argv[], VALUE self)
784
+ {
785
+ if (argc < 1 || argc > 4) {
786
+ rb_scan_args(argc, argv, "13", NULL, NULL, NULL, NULL);
787
+ }
788
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
789
+ memset(filters, 0, sizeof(filters));
790
+ filter_setup(filters, argv, argv + argc);
791
+
792
+ lzma_stream *stream = getstream(self);
793
+ LZMA_TEST(lzma_raw_encoder(stream, filters));
794
+
795
+ return self;
796
+ }
797
+
798
+ /*
799
+ * call-seq:
800
+ * LZMA::Stream::RawDecoder.initialize(filter1 [ , filter2 [ , .... ] ])
801
+ */
802
+ static VALUE
803
+ rawdecoder_init(int argc, VALUE argv[], VALUE self)
804
+ {
805
+ if (argc < 1 || argc > 4) {
806
+ rb_scan_args(argc, argv, "13", NULL, NULL, NULL, NULL);
807
+ }
808
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
809
+ memset(filters, 0, sizeof(filters));
810
+ filter_setup(filters, argv, argv + argc);
811
+
812
+ lzma_stream *stream = getstream(self);
813
+ LZMA_TEST(lzma_raw_decoder(stream, filters));
814
+
815
+ return self;
816
+ }
817
+
818
+ static void
819
+ setup_stream(void)
820
+ {
821
+ cStream = rb_define_class_under(mLZMA, "Stream", rb_cObject);
822
+ rb_undef_alloc_func(cStream);
823
+ rb_define_method(cStream, "update", stream_update, -1);
824
+ rb_define_method(cStream, "flush", stream_flush, -1);
825
+ rb_define_method(cStream, "finish", stream_finish, 0);
826
+
827
+ cEncoder = rb_define_class_under(cStream, "Encoder", cStream);
828
+ rb_define_alloc_func(cEncoder, stream_alloc);
829
+ rb_define_method(cEncoder, "initialize", RUBY_METHOD_FUNC(encoder_init), -1);
830
+
831
+ cDecoder = rb_define_class_under(cStream, "Decoder", cStream);
832
+ rb_define_alloc_func(cDecoder, stream_alloc);
833
+ rb_define_method(cDecoder, "initialize", RUBY_METHOD_FUNC(decoder_init), -1);
834
+
835
+ cAutoDecoder = rb_define_class_under(cStream, "AutoDecoder", cStream);
836
+ rb_define_alloc_func(cAutoDecoder, stream_alloc);
837
+ rb_define_method(cAutoDecoder, "initialize", RUBY_METHOD_FUNC(autodecoder_init), -1);
838
+
839
+ cRawEncoder = rb_define_class_under(cStream, "RawEncoder", cStream);
840
+ rb_define_alloc_func(cRawEncoder, stream_alloc);
841
+ rb_define_method(cRawEncoder, "initialize", RUBY_METHOD_FUNC(rawencoder_init), -1);
842
+
843
+ cRawDecoder = rb_define_class_under(cStream, "RawDecoder", cStream);
844
+ rb_define_alloc_func(cRawDecoder, stream_alloc);
845
+ rb_define_method(cRawDecoder, "initialize", RUBY_METHOD_FUNC(rawdecoder_init), -1);
846
+ }
847
+
848
+
849
+ // SECTION: LZMA::Index
850
+
851
+
852
+ static VALUE cIndex;
853
+ static VALUE cIEncoder;
854
+ static VALUE cIDecoder;
855
+
856
+ static VALUE
857
+ iencoder_alloc(VALUE klass)
858
+ {
859
+ rb_raise(rb_eNotImpError, "%s", "IMPLEMENT ME!");
860
+ }
861
+
862
+ static VALUE
863
+ iencoder_init(int argc, VALUE argv[], VALUE self)
864
+ {
865
+ rb_raise(rb_eNotImpError, "%s", "IMPLEMENT ME!");
866
+ }
867
+
868
+ static VALUE
869
+ idecoder_alloc(VALUE klass)
870
+ {
871
+ rb_raise(rb_eNotImpError, "%s", "IMPLEMENT ME!");
872
+ }
873
+
874
+ static VALUE
875
+ idecoder_init(int argc, VALUE argv[], VALUE self)
876
+ {
877
+ rb_raise(rb_eNotImpError, "%s", "IMPLEMENT ME!");
878
+ }
879
+
880
+
881
+ static void
882
+ setup_index(void)
883
+ {
884
+ cIndex = rb_define_class_under(mLZMA, "Index", rb_cObject);
885
+ rb_undef_alloc_func(cIndex);
886
+
887
+ cIEncoder = rb_define_class_under(cIndex, "Encoder", cIndex);
888
+ rb_define_alloc_func(cIEncoder, iencoder_alloc);
889
+ rb_define_method(cIEncoder, "initialize", RUBY_METHOD_FUNC(iencoder_init), -1);
890
+
891
+ cIDecoder = rb_define_class_under(cIndex, "Decoder", cIndex);
892
+ rb_define_alloc_func(cIDecoder, idecoder_alloc);
893
+ rb_define_method(cIDecoder, "initialize", RUBY_METHOD_FUNC(idecoder_init), -1);
894
+ }
895
+
896
+
897
+ // SECTION: LZMA::Utils
898
+
899
+ struct utils_crc32_args
900
+ {
901
+ const uint8_t *ptr;
902
+ size_t len;
903
+ uint32_t crc;
904
+ };
905
+
906
+ static VALUE
907
+ utils_crc32_update(struct utils_crc32_args *args)
908
+ {
909
+ return UINT2NUM(lzma_crc32(args->ptr, args->len, args->crc));
910
+ }
911
+
912
+ /*
913
+ * call-seq:
914
+ * LZMA::Utils.crc32(string, crc = 0)
915
+ *
916
+ * liblzmaに含まれるlzma_crc32を呼び出します。
917
+ */
918
+ static VALUE
919
+ utils_crc32(int argc, VALUE argv[], VALUE self)
920
+ {
921
+ VALUE src, crc;
922
+ rb_scan_args(argc, argv, "11", &src, &crc);
923
+
924
+ StringValue(src);
925
+ rb_str_locktmp(src);
926
+
927
+ struct utils_crc32_args args = {
928
+ (const uint8_t *)RSTRING_PTR(src),
929
+ RSTRING_LEN(src),
930
+ NIL_P(crc) ? 0 : NUM2UINT(crc),
931
+ };
932
+
933
+ crc = rb_thread_blocking_region((VALUE (*)(void *))utils_crc32_update, &args, RUBY_UBF_IO, NULL);
934
+
935
+ rb_str_unlocktmp(src);
936
+
937
+ return crc;
938
+ }
939
+
940
+
941
+
942
+ struct utils_crc64_args
943
+ {
944
+ const uint8_t *ptr;
945
+ size_t len;
946
+ uint64_t crc;
947
+ };
948
+
949
+ static VALUE
950
+ utils_crc64_update(struct utils_crc64_args *args)
951
+ {
952
+ return ULL2NUM(lzma_crc64(args->ptr, args->len, args->crc));
953
+ }
954
+
955
+ /*
956
+ * call-seq:
957
+ * LZMA::Utils.crc64(string, crc = 0)
958
+ *
959
+ * liblzmaに含まれるlzma_crc64を呼び出します。
960
+ */
961
+ static VALUE
962
+ utils_crc64(int argc, VALUE argv[], VALUE self)
963
+ {
964
+ VALUE src, crc;
965
+ rb_scan_args(argc, argv, "11", &src, &crc);
966
+
967
+ StringValue(src);
968
+ rb_str_locktmp(src);
969
+
970
+ struct utils_crc64_args args = {
971
+ (const uint8_t *)RSTRING_PTR(src),
972
+ RSTRING_LEN(src),
973
+ NIL_P(crc) ? 0 : NUM2ULL(crc),
974
+ };
975
+
976
+ crc = rb_thread_blocking_region((VALUE (*)(void *))utils_crc64_update, &args, RUBY_UBF_IO, NULL);
977
+
978
+ rb_str_unlocktmp(src);
979
+
980
+ return crc;
981
+ }
982
+
983
+
984
+ static VALUE mUtils;
985
+
986
+ static void
987
+ setup_utils(void)
988
+ {
989
+ mUtils = rb_define_module_under(mLZMA, "Utils");
990
+ rb_include_module(mLZMA, mUtils);
991
+ rb_extend_object(mLZMA, mUtils);
992
+
993
+ // rb_define_module_functionを使わない理由は、rb_define_module_functionで定義すると
994
+ // インスタンスメソッドがprivateで定義されるため、その対策。
995
+
996
+ rb_extend_object(mUtils, mUtils);
997
+
998
+ rb_define_method(mUtils, "crc32", RUBY_METHOD_FUNC(utils_crc32), -1);
999
+ rb_define_method(mUtils, "crc64", RUBY_METHOD_FUNC(utils_crc64), -1);
1000
+ }
1001
+
1002
+
1003
+ // SECTION: LZMA
1004
+
1005
+ void
1006
+ Init_liblzma(void)
1007
+ {
1008
+ symDICTSIZE = ID2SYM(rb_intern("dict_size"));
1009
+ symPRESETDICT = ID2SYM(rb_intern("preset_dict"));
1010
+ symLC = ID2SYM(rb_intern("lc"));
1011
+ symLP = ID2SYM(rb_intern("lp"));
1012
+ symPB = ID2SYM(rb_intern("pb"));
1013
+ symMODE = ID2SYM(rb_intern("mode"));
1014
+ symNICE = ID2SYM(rb_intern("nice"));
1015
+ symMF = ID2SYM(rb_intern("mf"));
1016
+ symDEPTH = ID2SYM(rb_intern("depth"));
1017
+ symCHECK = ID2SYM(rb_intern("check"));
1018
+
1019
+ mLZMA = rb_define_module("LZMA");
1020
+
1021
+ setup_utils();
1022
+ setup_constants();
1023
+ setup_exceptions();
1024
+ setup_filter();
1025
+ setup_stream();
1026
+ setup_index();
1027
+ }