extlzma 0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,517 @@
1
+ #include "extlzma.h"
2
+
3
+ VALUE extlzma_cFilter;
4
+ static VALUE cBasicLZMA;
5
+ static VALUE cLZMA1;
6
+ static VALUE cLZMA2;
7
+ static VALUE cDelta;
8
+
9
+ static void *
10
+ setup_lzma_preset(size_t preset)
11
+ {
12
+ lzma_options_lzma *lzma = xcalloc(sizeof(lzma_options_lzma), 1);
13
+ if (lzma_lzma_preset(lzma, preset)) {
14
+ free(lzma);
15
+ rb_raise(rb_eArgError,
16
+ "wrong preset level (%u for 0..9) or wrong flag bit(s) (0x%08x)",
17
+ (unsigned int)(preset & LZMA_PRESET_LEVEL_MASK),
18
+ (unsigned int)(preset & ~LZMA_PRESET_LEVEL_MASK & ~LZMA_PRESET_EXTREME));
19
+ }
20
+ return (void *)(lzma);
21
+ }
22
+
23
+ /*
24
+ * Document-method: LZMA::Filter::BasicLZMA#dict
25
+ *
26
+ * call-seq:
27
+ * dict -> string or nil
28
+ *
29
+ * 定義済み辞書を取得します。
30
+ *
31
+ * [RETURN] 定義済み辞書が定義されている場合は文字列が返ります。定義されていなければ +nil+ が返ります。
32
+ *
33
+ * エンコード情報は無視されます (常に Encoding::BINARY として扱われます)。呼び出し側で統一しておくべきです。
34
+ *
35
+ * 返される文字列は定義辞書の複成体です。変更しても定義情報には反映されません。+#dict=+ と併せて利用して下さい。
36
+ */
37
+
38
+ /*
39
+ * Document-method: LZMA::Filter::BasicLZMA#dict=
40
+ *
41
+ * call-seq:
42
+ * dict=(dict)
43
+ *
44
+ * 定義済み辞書を定義します。
45
+ *
46
+ * [dict] 定義済み辞書として文字列を与えます。定義を無効にする (定義済み辞書を利用しない) には、+nil+ を与えます。
47
+ *
48
+ * エンコード情報は無視されます (常に Encoding::BINARY として扱われます)。呼び出し側で統一しておくべきです。
49
+ *
50
+ * 与えた文字列は内部で複写され、元の文字列とは独立します。文字列の変更を反映したい場合はその都度 +#dict=+ を呼ぶ必要があります。
51
+ *
52
+ * [RETURN] 自身 (self) を返します。
53
+ */
54
+
55
+ /*
56
+ * Document-method: LZMA::Filter::BasicLZMA#dictsize
57
+ *
58
+ * call-seq:
59
+ * dictsize -> integer
60
+ *
61
+ * 辞書の大きさをバイト値として取得します。
62
+ */
63
+
64
+ /*
65
+ * Document-method: LZMA::Filter::BasicLZMA#dictsize=
66
+ *
67
+ * call-seq:
68
+ * dictsize=(size) -> self
69
+ *
70
+ * 辞書の大きさをバイト値として設定します。
71
+ */
72
+
73
+ /*
74
+ * Document-method: LZMA::Filter::BasicLZMA#lc
75
+ *
76
+ * call-seq:
77
+ * lc -> integer
78
+ *
79
+ * lc 値を取得します。
80
+ */
81
+
82
+ /*
83
+ * Document-method: LZMA::Filter::BasicLZMA#lc=
84
+ *
85
+ * call-seq:
86
+ * lc=(value) -> self
87
+ *
88
+ * lc 値を設定します。
89
+ */
90
+
91
+ /*
92
+ * Document-method: LZMA::Filter::BasicLZMA#lp
93
+ *
94
+ * call-seq:
95
+ * lp -> integer
96
+ *
97
+ * lp 値を取得します。
98
+ */
99
+
100
+ /*
101
+ * Document-method: LZMA::Filter::BasicLZMA#lp=
102
+ *
103
+ * call-seq:
104
+ * lp=(value) -> self
105
+ *
106
+ * lp 値を設定します。
107
+ */
108
+
109
+ /*
110
+ * Document-method: LZMA::Filter::BasicLZMA#pb
111
+ *
112
+ * call-seq:
113
+ * pb -> integer
114
+ *
115
+ * pb 値を取得します。
116
+ */
117
+
118
+ /*
119
+ * Document-method: LZMA::Filter::BasicLZMA#pb=
120
+ *
121
+ * call-seq:
122
+ * pb=(value) -> self
123
+ *
124
+ * pb 値を設定します。
125
+ */
126
+
127
+ /*
128
+ * Document-method: LZMA::Filter::BasicLZMA#mode
129
+ *
130
+ * call-seq:
131
+ * mode -> integer
132
+ *
133
+ * mode 値を取得します。
134
+ */
135
+
136
+ /*
137
+ * Document-method: LZMA::Filter::BasicLZMA#mode=
138
+ *
139
+ * call-seq:
140
+ * mode=(value) -> self
141
+ *
142
+ * mode 値を設定します。
143
+ */
144
+
145
+ /*
146
+ * Document-method: LZMA::Filter::BasicLZMA#nice
147
+ *
148
+ * call-seq:
149
+ * nice -> integer
150
+ *
151
+ * nice 値を取得します。
152
+ */
153
+
154
+ /*
155
+ * Document-method: LZMA::Filter::BasicLZMA#nice=
156
+ *
157
+ * call-seq:
158
+ * nice=(value) -> self
159
+ *
160
+ * nice 値を設定します。
161
+ */
162
+
163
+ /*
164
+ * Document-method: LZMA::Filter::BasicLZMA#mf
165
+ *
166
+ * call-seq:
167
+ * mf -> integer
168
+ *
169
+ * mf 値を取得します。
170
+ */
171
+
172
+ /*
173
+ * Document-method: LZMA::Filter::BasicLZMA#mf=
174
+ *
175
+ * call-seq:
176
+ * mf=(value) -> self
177
+ *
178
+ * mf 値を設定します。
179
+ */
180
+
181
+ /*
182
+ * Document-method: LZMA::Filter::BasicLZMA#depth
183
+ *
184
+ * call-seq:
185
+ * depth -> integer
186
+ *
187
+ * depth 値を取得します。
188
+ */
189
+
190
+ /*
191
+ * Document-method: LZMA::Filter::BasicLZMA#depth=
192
+ *
193
+ * call-seq:
194
+ * depth=(value) -> self
195
+ *
196
+ * depth 値を設定します。
197
+ */
198
+
199
+ #define DEFINE_ACCESSOR_ENTITY(SET0, SET, GET, MEMBER, DEFAULT) \
200
+ static inline void \
201
+ SET0(lzma_options_lzma *filter, VALUE n) \
202
+ { \
203
+ if (NIL_P(n)) { \
204
+ filter->MEMBER = DEFAULT; \
205
+ } else { \
206
+ filter->MEMBER = NUM2UINT(n); \
207
+ } \
208
+ } \
209
+ \
210
+ static VALUE \
211
+ SET(VALUE self, VALUE n) \
212
+ { \
213
+ SET0((lzma_options_lzma *)extlzma_getfilter(self)->options, n); \
214
+ return self; \
215
+ } \
216
+ \
217
+ static VALUE \
218
+ GET(VALUE self) \
219
+ { \
220
+ lzma_options_lzma *p = extlzma_getfilter(self)->options; \
221
+ return UINT2NUM(p->MEMBER); \
222
+ } \
223
+
224
+ DEFINE_ACCESSOR_ENTITY(aux_set_dictsize_0, ext_set_dictsize, ext_get_dictsize, dict_size, LZMA_DICT_SIZE_DEFAULT);
225
+ DEFINE_ACCESSOR_ENTITY(aux_set_lc_0, ext_set_lc, ext_get_lc, lc, LZMA_LC_DEFAULT);
226
+ DEFINE_ACCESSOR_ENTITY(aux_set_lp_0, ext_set_lp, ext_get_lp, lp, LZMA_LP_DEFAULT);
227
+ DEFINE_ACCESSOR_ENTITY(aux_set_pb_0, ext_set_pb, ext_get_pb, pb, LZMA_PB_DEFAULT);
228
+ DEFINE_ACCESSOR_ENTITY(aux_set_mode_0, ext_set_mode, ext_get_mode, mode, LZMA_MODE_NORMAL);
229
+ DEFINE_ACCESSOR_ENTITY(aux_set_nice_0, ext_set_nice, ext_get_nice, nice_len, 64);
230
+ DEFINE_ACCESSOR_ENTITY(aux_set_mf_0, ext_set_mf, ext_get_mf, mf, LZMA_MF_BT4);
231
+ DEFINE_ACCESSOR_ENTITY(aux_set_depth_0, ext_set_depth, ext_get_depth, depth, 0);
232
+
233
+ #undef DEFINE_ACCESSOR_ENTITY
234
+
235
+ static ID ivar_id_predict;
236
+
237
+ static inline void
238
+ aux_set_predict_nil(lzma_options_lzma *filter)
239
+ {
240
+ filter->preset_dict = NULL;
241
+ filter->preset_dict_size = 0;
242
+ }
243
+
244
+ static inline void
245
+ aux_set_predict_string(lzma_options_lzma *filter, VALUE *predict)
246
+ {
247
+ *predict = rb_str_new_frozen(*predict);
248
+ filter->preset_dict = (uint8_t *)(RSTRING_PTR(*predict));
249
+ filter->preset_dict_size = RSTRING_LEN(*predict);
250
+ }
251
+
252
+ static inline void
253
+ aux_set_predict_0(lzma_options_lzma *filter, VALUE predict, VALUE self)
254
+ {
255
+ if (NIL_P(predict)) {
256
+ aux_set_predict_nil(filter);
257
+ } else if (TYPE(predict) == T_STRING) {
258
+ if (RSTRING_LEN(predict) > 0) {
259
+ aux_set_predict_string(filter, &predict);
260
+ } else {
261
+ aux_set_predict_nil(filter);
262
+ }
263
+ } else {
264
+ rb_raise(rb_eTypeError, "%s", "predict is not a String or nil");
265
+ }
266
+
267
+ rb_obj_infect(self, predict);
268
+ rb_ivar_set(self, ivar_id_predict, predict);
269
+ }
270
+
271
+ static VALUE
272
+ ext_set_predict(VALUE self, VALUE predict)
273
+ {
274
+ aux_set_predict_0((lzma_options_lzma *)extlzma_getfilter(self)->options, predict, self);
275
+ return self;
276
+ }
277
+
278
+ static VALUE
279
+ ext_get_predict(VALUE self)
280
+ {
281
+ VALUE predict = rb_attr_get(self, ivar_id_predict);
282
+ if (!NIL_P(predict)) { predict = rb_str_new_shared(predict); }
283
+ return predict;
284
+ }
285
+
286
+ static void *
287
+ setup_lzma(VALUE obj, uint32_t preset,
288
+ VALUE dictsize, VALUE predict, VALUE lc, VALUE lp, VALUE pb,
289
+ VALUE mode, VALUE nice, VALUE mf, VALUE depth)
290
+ {
291
+ lzma_options_lzma lzma = { 0 };
292
+ if (lzma_lzma_preset(&lzma, preset) != 0) {
293
+ rb_raise(extlzma_eBadPreset, "bad preset (0x%08x)", preset);
294
+ }
295
+
296
+ if (RTEST(predict)) { aux_set_predict_0(&lzma, predict, obj); }
297
+
298
+ #define SETVAR(NAME) \
299
+ if (RTEST(NAME)) { aux_set_ ## NAME ## _0(&lzma, NAME); } \
300
+
301
+ SETVAR(dictsize);
302
+ SETVAR(lc);
303
+ SETVAR(lp);
304
+ SETVAR(pb);
305
+ SETVAR(mode);
306
+ SETVAR(nice);
307
+ SETVAR(mf);
308
+ SETVAR(depth);
309
+
310
+ #undef SETVAR
311
+
312
+ {
313
+ lzma_options_lzma *p = ALLOC(lzma_options_lzma);
314
+ memcpy(p, &lzma, sizeof(lzma));
315
+ return (void *)(p);
316
+ }
317
+ }
318
+
319
+ static void
320
+ cleanup_filter(lzma_filter *filter)
321
+ {
322
+ if (filter->options) { xfree(filter->options); }
323
+ xfree(filter);
324
+ }
325
+
326
+
327
+ static uint32_t
328
+ getpreset(VALUE preset)
329
+ {
330
+ if (NIL_P(preset)) {
331
+ return LZMA_PRESET_DEFAULT;
332
+ } else {
333
+ return NUM2UINT(preset);
334
+ }
335
+ }
336
+
337
+ static inline VALUE
338
+ filter_alloc(VALUE klass, lzma_vli id)
339
+ {
340
+ lzma_filter *filter;
341
+ VALUE obj = Data_Make_Struct(klass, lzma_filter, NULL, cleanup_filter, filter);
342
+ memset(filter, 0, sizeof(*filter));
343
+ filter->id = id;
344
+ return obj;
345
+ }
346
+
347
+ static VALUE
348
+ lzma1_alloc(VALUE klass)
349
+ {
350
+ return filter_alloc(klass, LZMA_FILTER_LZMA1);
351
+ }
352
+
353
+ static VALUE
354
+ lzma2_alloc(VALUE klass)
355
+ {
356
+ return filter_alloc(klass, LZMA_FILTER_LZMA2);
357
+ }
358
+
359
+ static VALUE
360
+ delta_alloc(VALUE klass)
361
+ {
362
+ return filter_alloc(cDelta, LZMA_FILTER_DELTA);
363
+ }
364
+
365
+ /*
366
+ * call-seq:
367
+ * initialize(dist = LZMA::DELTA_DIST_MIN)
368
+ *
369
+ * 差分フィルタ設定オブジェクトを返します。
370
+ *
371
+ * distは1要素あたりのバイト長で、1以上255以下を指定できます。
372
+ *
373
+ * NOTE::
374
+ * 使用する場合多くの場合1で十分と思われますが、音楽CDの音声データであれば1サンプル2バイトであるため2が有効でしょう。
375
+ *
376
+ * しかし元のデータによっては圧縮効率を低下させることがあるため、実際に適用するべきかはデータの特性によって検証するのが好ましいです。
377
+ */
378
+ static VALUE
379
+ delta_init(int argc, VALUE argv[], VALUE self)
380
+ {
381
+ lzma_filter *filter = extlzma_getfilter(self);
382
+ lzma_options_delta *delta = ALLOC(lzma_options_delta);
383
+ memset(delta, 0, sizeof(*delta));
384
+
385
+ VALUE preset = Qnil;
386
+ rb_scan_args(argc, argv, "01", &preset);
387
+ delta->type = LZMA_DELTA_TYPE_BYTE;
388
+ delta->dist = NIL_P(preset) ? LZMA_DELTA_DIST_MIN : NUM2UINT(preset);
389
+ filter->options = delta;
390
+ return self;
391
+ }
392
+
393
+ /*
394
+ * call-seq:
395
+ * initialize(preset = LZMA::PRESET_DEFAULT, opts = {}) -> filter
396
+ *
397
+ * LZMA フィルタ設定オブジェクトを初期化します。
398
+ *
399
+ * この段階で各値の確認を行うことはせず、*encoderに渡すときに初めて確認されます。
400
+ *
401
+ * [preset = LZMA::PRESET_DEFAULT]
402
+ * プリセット値 (≒圧縮レベル) を 0-9 の範囲で指定し、任意で LZMA::PRESET_EXTREME を論理和で組み合わせることが出来ます。
403
+ * [opts dictsize]
404
+ * 辞書の大きさをバイト値で指定します。既定値は preset によって変化します。
405
+ * [opts predict: nil]
406
+ * 定義済み辞書を指定します。既定値は nil です。
407
+ * [opts lc: nil]
408
+ * 既定値は preset によって変化します。
409
+ * [opts lp: nil]
410
+ * 既定値は preset によって変化します。
411
+ * [opts pb: nil]
412
+ * 既定値は preset によって変化します。
413
+ * [opts mode: nil]
414
+ * 既定値は preset によって変化します。
415
+ * [opts nice: nil]
416
+ * 既定値は preset によって変化します。
417
+ * [opts mf: nil]
418
+ * 既定値は preset によって変化します。
419
+ * [opts depth: nil]
420
+ * 既定値は preset によって変化します。
421
+ * [RETURN]
422
+ * フィルタオブジェクト
423
+ * [EXCEPTIONS]
424
+ * (NO DOCUMENT)
425
+ */
426
+ static VALUE
427
+ ext_lzma_init(int argc, VALUE argv[], VALUE self)
428
+ {
429
+ VALUE preset = Qnil;
430
+ VALUE opts = Qnil;
431
+ rb_scan_args(argc, argv, "01:", &preset, &opts);
432
+ lzma_filter *filter = extlzma_getfilter(self);
433
+ if (NIL_P(opts)) {
434
+ filter->options = setup_lzma_preset(getpreset(preset));
435
+ } else {
436
+ filter->options = setup_lzma(self, getpreset(preset),
437
+ rb_hash_lookup(opts, ID2SYM(extlzma_id_dictsize)),
438
+ rb_hash_lookup(opts, ID2SYM(extlzma_id_predict)),
439
+ rb_hash_lookup(opts, ID2SYM(extlzma_id_lc)),
440
+ rb_hash_lookup(opts, ID2SYM(extlzma_id_lp)),
441
+ rb_hash_lookup(opts, ID2SYM(extlzma_id_pb)),
442
+ rb_hash_lookup(opts, ID2SYM(extlzma_id_mode)),
443
+ rb_hash_lookup(opts, ID2SYM(extlzma_id_nice)),
444
+ rb_hash_lookup(opts, ID2SYM(extlzma_id_mf)),
445
+ rb_hash_lookup(opts, ID2SYM(extlzma_id_depth)));
446
+ }
447
+ return self;
448
+ }
449
+
450
+ /*
451
+ * Document-class: LZMA::Filter
452
+ *
453
+ * LZMA::Filter クラスは、各圧縮器や伸張器の生成時に用いるフィルタ情報を取り扱います。
454
+ *
455
+ * liblzma で定義されているフィルタはそれぞれ LZMA::Filter::LZMA1 /
456
+ * LZMA::Filter::LZMA2 / LZMA::Filter::Delta として定義されています。
457
+ *
458
+ * これらのクラスについてはそれぞれの文書を見てください。
459
+ */
460
+
461
+ /*
462
+ * Document-class: LZMA::Filter::BasicLZMA
463
+ *
464
+ * LZMA::Filter::LZMA1 と LZMA::Filter::LZMA2 の基本となるクラスです。
465
+ *
466
+ * allocator を持たないため、このクラス自身はインスタンスを作成することが出来ません。
467
+ */
468
+
469
+ /*
470
+ * Document-method: LZMA::Filter::BasicLZMA#dictsize -> integer
471
+ *
472
+ * call-seq:
473
+ * dictsize -> 辞書サイズ (バイト長)
474
+ *
475
+ * 様々なフィルタ値の設定・取り出しを行う
476
+ */
477
+
478
+ void
479
+ extlzma_init_Filter(void)
480
+ {
481
+ ivar_id_predict = rb_intern_const("extlzma.predict");
482
+
483
+ extlzma_cFilter = rb_define_class_under(extlzma_mLZMA, "Filter", rb_cObject);
484
+ rb_undef_alloc_func(extlzma_cFilter);
485
+
486
+ cBasicLZMA = rb_define_class_under(extlzma_cFilter, "BasicLZMA", extlzma_cFilter);
487
+ rb_define_method(cBasicLZMA, "initialize", ext_lzma_init, -1);
488
+
489
+ cLZMA1 = rb_define_class_under(extlzma_cFilter, "LZMA1", cBasicLZMA);
490
+ rb_define_alloc_func(cLZMA1, lzma1_alloc);
491
+
492
+ cLZMA2 = rb_define_class_under(extlzma_cFilter, "LZMA2", cBasicLZMA);
493
+ rb_define_alloc_func(cLZMA2, lzma2_alloc);
494
+
495
+ cDelta = rb_define_class_under(extlzma_cFilter, "Delta", extlzma_cFilter);
496
+ rb_define_alloc_func(cDelta, delta_alloc);
497
+ rb_define_method(cDelta, "initialize", delta_init, -1);
498
+
499
+ rb_define_method(cBasicLZMA, "dictsize", ext_get_dictsize, 0);
500
+ rb_define_method(cBasicLZMA, "dictsize=", ext_set_dictsize, 1);
501
+ rb_define_method(cBasicLZMA, "predict", ext_get_predict, 0);
502
+ rb_define_method(cBasicLZMA, "predict=", ext_set_predict, 1);
503
+ rb_define_method(cBasicLZMA, "lc", ext_get_lc, 0);
504
+ rb_define_method(cBasicLZMA, "lc=", ext_set_lc, 1);
505
+ rb_define_method(cBasicLZMA, "lp", ext_get_lp, 0);
506
+ rb_define_method(cBasicLZMA, "lp=", ext_set_lp, 1);
507
+ rb_define_method(cBasicLZMA, "pb", ext_get_pb, 0);
508
+ rb_define_method(cBasicLZMA, "pb=", ext_set_pb, 1);
509
+ rb_define_method(cBasicLZMA, "mode", ext_get_mode, 0);
510
+ rb_define_method(cBasicLZMA, "mode=", ext_set_mode, 1);
511
+ rb_define_method(cBasicLZMA, "nice", ext_get_nice, 0);
512
+ rb_define_method(cBasicLZMA, "nice=", ext_set_nice, 1);
513
+ rb_define_method(cBasicLZMA, "mf", ext_get_mf, 0);
514
+ rb_define_method(cBasicLZMA, "mf=", ext_set_mf, 1);
515
+ rb_define_method(cBasicLZMA, "depth", ext_get_depth, 0);
516
+ rb_define_method(cBasicLZMA, "depth=", ext_set_depth, 1);
517
+ }