extlzma 0.4-x86-mingw32

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.
data/ext/utils.c ADDED
@@ -0,0 +1,105 @@
1
+ #include "extlzma.h"
2
+
3
+ static inline VALUE
4
+ crc_calc(void *(*update)(va_list *vp), int argc, VALUE argv[])
5
+ {
6
+ VALUE src, crc;
7
+ rb_scan_args(argc, argv, "11", &src, &crc);
8
+ rb_check_type(src, RUBY_T_STRING);
9
+ return (VALUE)aux_thread_call_without_gvl(update,
10
+ (const uint8_t *)RSTRING_PTR(src),
11
+ RSTRING_LEN(src),
12
+ NIL_P(crc) ? INT2FIX(0) : crc);
13
+ }
14
+
15
+
16
+ static VALUE
17
+ crc32_update(va_list *vp)
18
+ {
19
+ const uint8_t *ptr = va_arg(*vp, const uint8_t *);
20
+ size_t size = va_arg(*vp, size_t);
21
+ VALUE crc = va_arg(*vp, VALUE);
22
+ return UINT2NUM(lzma_crc32(ptr, size, NUM2UINT(crc)));
23
+ }
24
+
25
+ /*
26
+ * call-seq:
27
+ * LZMA::Utils.crc32(string, crc = 0)
28
+ *
29
+ * liblzmaに含まれるlzma_crc32を呼び出します。
30
+ */
31
+ static VALUE
32
+ utils_crc32(int argc, VALUE argv[], VALUE self)
33
+ {
34
+ return crc_calc((void *(*)(va_list *))crc32_update, argc, argv);
35
+ }
36
+
37
+
38
+ static VALUE
39
+ crc64_update(va_list *vp)
40
+ {
41
+ const uint8_t *ptr = va_arg(*vp, const uint8_t *);
42
+ size_t size = va_arg(*vp, size_t);
43
+ VALUE crc = va_arg(*vp, VALUE);
44
+ return ULL2NUM(lzma_crc64(ptr, size, NUM2ULL(crc)));
45
+ }
46
+
47
+ /*
48
+ * call-seq:
49
+ * LZMA::Utils.crc64(string, crc = 0)
50
+ *
51
+ * liblzmaに含まれるlzma_crc64を呼び出します。
52
+ */
53
+ static VALUE
54
+ utils_crc64(int argc, VALUE argv[], VALUE self)
55
+ {
56
+ return crc_calc((void *(*)(va_list *))crc64_update, argc, argv);
57
+ }
58
+
59
+ /*
60
+ * call-seq:
61
+ * lookup_error(lzma_ret) -> exception class
62
+ */
63
+ static VALUE
64
+ utils_lookup_error(VALUE mod, VALUE status)
65
+ {
66
+ return extlzma_lookup_error(NUM2INT(status));
67
+ }
68
+
69
+ /*
70
+ * call-seq:
71
+ * stream_buffer_bound(uncompressed_size) -> worst encoded size
72
+ */
73
+ static VALUE
74
+ utils_stream_buffer_bound(VALUE mod, VALUE size)
75
+ {
76
+ return SIZET2NUM(lzma_stream_buffer_bound(NUM2SIZET(size)));
77
+ }
78
+
79
+ /*
80
+ * call-seq:
81
+ * block_buffer_bound(uncompressed_size) -> worst encoded size
82
+ */
83
+ static VALUE
84
+ utils_block_buffer_bound(VALUE mod, VALUE size)
85
+ {
86
+ return SIZET2NUM(lzma_block_buffer_bound(NUM2SIZET(size)));
87
+ }
88
+
89
+
90
+ static VALUE mUtils;
91
+
92
+ void
93
+ extlzma_init_Utils(void)
94
+ {
95
+ mUtils = rb_define_module_under(extlzma_mLZMA, "Utils");
96
+
97
+ rb_extend_object(extlzma_mLZMA, mUtils);
98
+ rb_extend_object(mUtils, mUtils); // 自分に対してもモジュールメソッドを利用できるようにする
99
+
100
+ rb_define_method(mUtils, "crc32", RUBY_METHOD_FUNC(utils_crc32), -1);
101
+ rb_define_method(mUtils, "crc64", RUBY_METHOD_FUNC(utils_crc64), -1);
102
+ rb_define_method(mUtils, "lookup_error", RUBY_METHOD_FUNC(utils_lookup_error), 1);
103
+ rb_define_method(mUtils, "stream_buffer_bound", RUBY_METHOD_FUNC(utils_stream_buffer_bound), 1);
104
+ rb_define_method(mUtils, "block_buffer_bound", RUBY_METHOD_FUNC(utils_block_buffer_bound), 1);
105
+ }
data/gemstub.rb ADDED
@@ -0,0 +1,17 @@
1
+ require_relative "lib/extlzma/version"
2
+
3
+ GEMSTUB = Gem::Specification.new do |s|
4
+ s.name = "extlzma"
5
+ s.version = LZMA::VERSION
6
+ s.summary = "ruby bindings for liblzma in the xz utilities"
7
+ s.description = <<EOS
8
+ ruby bindings for liblzma in the xz utilities <http://tukaani.org/xz/>
9
+ EOS
10
+ s.license = "BSD-2-Clause"
11
+ s.author = "dearblue"
12
+ s.email = "dearblue@users.osdn.me"
13
+ s.homepage = "https://osdn.jp/projects/rutsubo/"
14
+
15
+ s.required_ruby_version = ">= 2.0"
16
+ s.add_development_dependency "rake", "~> 11.0"
17
+ end
Binary file
Binary file
Binary file
Binary file
data/lib/extlzma.rb ADDED
@@ -0,0 +1,529 @@
1
+ #vim: set fileencoding:utf-8
2
+
3
+ begin
4
+ libname = File.basename(__FILE__, ".rb") << ".so"
5
+ require_relative libname
6
+ rescue LoadError
7
+ ver = RUBY_VERSION.slice(/\d+\.\d+/)
8
+ require_relative "#{ver}/#{libname}"
9
+ end
10
+
11
+ require_relative "extlzma/version"
12
+ require "stringio"
13
+
14
+ module LZMA
15
+ #
16
+ # call-seq:
17
+ # encode(string_data, preset = LZMA::PRESET_DEFAULT, opts = {}) -> encoded_xz_data
18
+ # encode(string_data, filter...) -> encoded_xz_data
19
+ # encode(output_stream = nil, preset = LZMA::PRESET_DEFAULT, opts = {}) -> stream_encoder
20
+ # encode(output_stream, filter...) -> stream_encoder
21
+ # encode(output_stream = nil, preset = LZMA::PRESET_DEFAULT, opts = {}) { |encoder| ... } -> yield return value
22
+ # encode(output_stream, filter...) { |encoder| ... } -> yield return value
23
+ #
24
+ # データを圧縮、または圧縮器を生成します。
25
+ #
26
+ # 圧縮されたデータ列は xz ファイルフォーマットとなるため、コマンドラインの xz などで伸張させることが可能です。
27
+ #
28
+ # [RETURN encoded_xz_data]
29
+ # xz データストリームとしての String インスタンスです。
30
+ # [RETURN stream_encoder]
31
+ # xz データストリームを生成する圧縮器を返します。
32
+ # [RETURN output_stream]
33
+ # 引数として渡した <tt>output_stream</tt> そのものを返します。
34
+ # [string_data]
35
+ # 圧縮元となるデータを String インスタンスで渡します。
36
+ # liblzma はエンコーディング情報を無視し、そのままのバイト列をバイナリデータと見立て処理を行います。
37
+ # [preset = LZMA::PRESET_DEFAULT]
38
+ # 圧縮プリセット値を指定します (圧縮レベルのようなものです)。詳細は LZMA::Filter::LZMA2.new を見てください。
39
+ # [opts]
40
+ # LZMA::Filter::LZMA2.new に渡される可変引数です。詳細は LZMA::Filter::LZMA2.new を見てください。
41
+ # [filter]
42
+ # LZMA::Filter で定義されているクラスのインスタンスを指定します。最大4つまで指定することが出来ます。
43
+ # [output_stream]
44
+ # 圧縮データの受け皿となるオブジェクトを指定します。
45
+ #
46
+ # <tt>.<<</tt> メソッドが呼ばれます。
47
+ # [YIELD RETURN]
48
+ # 無視されます。
49
+ # [YIELD encoder]
50
+ # 圧縮器が渡されます。
51
+ #
52
+ # [EXCEPTIONS]
53
+ # (NO DOCUMENT)
54
+ #
55
+ def self.encode(src = nil, *args, &block)
56
+ Aux.encode(src, Stream.encoder(*args), &block)
57
+ end
58
+
59
+ #
60
+ # call-seq:
61
+ # decode(string_data) -> decoded data
62
+ # decode(string_data, filter...) -> decoded data
63
+ # decode(input_stream) -> decoder
64
+ # decode(input_stream, filter...) -> decoder
65
+ # decode(input_stream) { |decoder| ... }-> yield return value
66
+ # decode(input_stream, filter...) { |decoder| ... }-> yield return value
67
+ #
68
+ # 圧縮されたデータを伸張します。
69
+ #
70
+ # [RETURN decoded data]
71
+ # xz データストリームとしての String インスタンスです。
72
+ # [RETURN decoder]
73
+ # [RETURN yield return value]
74
+ # [string_data]
75
+ # 圧縮されたデータを与えます。圧縮されたデータの形式は xz と lzma です。これらはあらかじめ区別する必要なく与えることが出来ます。
76
+ # [options]
77
+ # LZMA::Filter::LZMA2.new に渡される可変引数です。詳細は LZMA::Filter::LZMA2.new を見てください。
78
+ # [EXCEPTIONS]
79
+ # (NO DOCUMENT)
80
+ #
81
+ def self.decode(src, *args, &block)
82
+ Aux.decode(src, Stream.auto_decoder(*args), &block)
83
+ end
84
+
85
+ #
86
+ # call-seq:
87
+ # LZMA.raw_encode(src) -> encoded data
88
+ # LZMA.raw_encode(src, filter...) -> encoded data
89
+ # LZMA.raw_encode(outport = nil) -> encoder
90
+ # LZMA.raw_encode(outport, filter...) -> encoder
91
+ # LZMA.raw_encode(outport = nil) { |encoder| ... } -> yield return value
92
+ # LZMA.raw_encode(outport, filter...) { |encoder| ... } -> yield return value
93
+ #
94
+ # データを圧縮します。圧縮されたデータ列は生の lzma1/lzma2 のデータ列であるため、伸張する際に適切なフィルタを与える必要があります。
95
+ #
96
+ # xz ファイルフォーマットヘッダや整合値を持たないため、これらが不要な場合は有用かもしれません。
97
+ #
98
+ # [RETURN encoded data]
99
+ # 生の lzma1/lzma2 のデータ列となる String インスタンスです。
100
+ # [src]
101
+ # 圧縮元となるデータを String インスタンスで渡します。
102
+ # [filter]
103
+ # LZMA::Filter のインスタンスを与えます。最大4つまで指定可能です。
104
+ #
105
+ # 省略時は lzma2 フィルタが指定されたとみなします。
106
+ # [EXCEPTIONS]
107
+ # (NO DOCUMENT)
108
+ #
109
+ def self.raw_encode(src, *args, &block)
110
+ Aux.encode(src, Stream.raw_encoder(*args), &block)
111
+ end
112
+
113
+ #
114
+ # call-seq:
115
+ # LZMA.raw_decode(encoded_data) -> decoded data
116
+ # LZMA.raw_decode(encoded_data, filter...) -> decoded data
117
+ # LZMA.raw_decode(inport) -> raw decoder
118
+ # LZMA.raw_decode(inport, filter...) -> raw decoder
119
+ # LZMA.raw_decode(inport) { |decoder| ... } -> yield return value
120
+ # LZMA.raw_decode(inport, filter...) { |decoder| ... } -> yield return value
121
+ #
122
+ # 圧縮されたデータを伸張します。圧縮した際に用いたフィルタをそのままの順番・数で与える必要があります。
123
+ #
124
+ # [RETURN decoded data]
125
+ # 伸張されたデータ列となる String インスタンスです。
126
+ # [src]
127
+ # 圧縮された生の lzma1/lzma2 の String インスタンスを渡します。
128
+ # [options]
129
+ # LZMA::Filter のインスタンスを与えます。最大4つまで指定可能です。
130
+ #
131
+ # 省略時は lzma2 フィルタが指定されたとみなします。
132
+ # [EXCEPTIONS]
133
+ # (NO DOCUMENT)
134
+ #
135
+ def self.raw_decode(src, *args, &block)
136
+ Aux.decode(src, Stream.raw_decoder(*args), &block)
137
+ end
138
+
139
+ def self.lzma1(*args)
140
+ LZMA::Filter::LZMA1.new(*args)
141
+ end
142
+
143
+ def self.lzma2(*args)
144
+ LZMA::Filter::LZMA2.new(*args)
145
+ end
146
+
147
+ def self.delta(*args)
148
+ LZMA::Filter::Delta.new(*args)
149
+ end
150
+
151
+ class Encoder < Struct.new(:context, :outport, :writebuf, :workbuf, :status)
152
+ BLOCKSIZE = 256 * 1024 # 256 KiB
153
+
154
+ def initialize(context, outport)
155
+ super(context, outport,
156
+ StringIO.new("".force_encoding(Encoding::BINARY)),
157
+ "".force_encoding(Encoding::BINARY), [1])
158
+ self.class.method(:finalizer_regist).(self, context, outport, writebuf, workbuf, status)
159
+ end
160
+
161
+ def write(buf)
162
+ writebuf.rewind
163
+ writebuf.string.clear
164
+ writebuf << buf
165
+ until writebuf.string.empty?
166
+ s = context.code(writebuf.string, workbuf, BLOCKSIZE, 0)
167
+ unless s == 0
168
+ Utils.raise_err s
169
+ end
170
+ outport << workbuf
171
+ workbuf.clear
172
+ end
173
+
174
+ self
175
+ end
176
+
177
+ alias << write
178
+
179
+ def close
180
+ if eof?
181
+ raise "already closed stream - #{inspect}"
182
+ end
183
+
184
+ self.class.method(:finalizer_close).(context, outport, workbuf)
185
+
186
+ status[0] = nil
187
+
188
+ nil
189
+ end
190
+
191
+ def eof
192
+ !status[0]
193
+ end
194
+
195
+ alias eof? eof
196
+
197
+ class << self
198
+ private
199
+ def finalizer_regist(obj, context, outport, writebuf, workbuf, status)
200
+ ObjectSpace.define_finalizer(obj, finalizer_make(context, outport, writebuf, workbuf, status))
201
+ end
202
+
203
+ private
204
+ def finalizer_make(context, outport, writebuf, workbuf, status)
205
+ proc do
206
+ if status[0]
207
+ until writebuf.string.empty?
208
+ s = context.code(writebuf.string, workbuf, BLOCKSIZE, 0)
209
+ Utils.raise_err s unless s == LZMA::OK
210
+ outport << workbuf
211
+ workbuf.clear
212
+ end
213
+
214
+ finalizer_close(context, outport, workbuf)
215
+
216
+ status[0] = nil
217
+ end
218
+ end
219
+ end
220
+
221
+ private
222
+ def finalizer_close(context, outport, workbuf)
223
+ while true
224
+ workbuf.clear
225
+ s = context.code(nil, workbuf, BLOCKSIZE, LZMA::FINISH)
226
+ outport << workbuf
227
+ break if s == LZMA::STREAM_END
228
+ Utils.raise_err s unless s == LZMA::OK
229
+ end
230
+ end
231
+ end
232
+ end
233
+
234
+ class Decoder < Struct.new(:context, :inport, :readbuf, :workbuf, :status)
235
+ BLOCKSIZE = 256 * 1024 # 256 KiB
236
+
237
+ def initialize(context, inport)
238
+ super context, inport,
239
+ "".force_encoding(Encoding::BINARY),
240
+ StringIO.new("".force_encoding(Encoding::BINARY)),
241
+ :ready
242
+ end
243
+
244
+ def read(size = nil, buf = "".force_encoding(Encoding::BINARY))
245
+ buf.clear
246
+ size = size.to_i if size
247
+ return buf if size == 0
248
+
249
+ tmp = "".force_encoding(Encoding::BINARY)
250
+ while !eof && (size.nil? || size > 0)
251
+ if workbuf.eof?
252
+ fetch or break
253
+ end
254
+
255
+ workbuf.read(size, tmp) or break
256
+ buf << tmp
257
+ size -= tmp.bytesize if size
258
+ end
259
+
260
+ (buf.empty? ? nil : buf)
261
+ end
262
+
263
+ def eof
264
+ !status && workbuf.eof?
265
+ end
266
+
267
+ alias eof? eof
268
+
269
+ def close
270
+ self.status = nil
271
+ workbuf.rewind
272
+ workbuf.string.clear
273
+ nil
274
+ end
275
+
276
+ private
277
+ def fetch
278
+ return nil unless status == :ready
279
+
280
+ while workbuf.eof
281
+ if readbuf.empty?
282
+ inport.read(BLOCKSIZE, readbuf)
283
+ end
284
+
285
+ workbuf.string.clear
286
+ workbuf.rewind
287
+ if readbuf.empty?
288
+ s = context.code(nil, workbuf.string, BLOCKSIZE, LZMA::FINISH)
289
+ else
290
+ s = context.code(readbuf, workbuf.string, BLOCKSIZE, 0)
291
+ end
292
+
293
+ case s
294
+ when LZMA::OK
295
+ when LZMA::STREAM_END
296
+ self.status = :finished
297
+ break
298
+ else
299
+ Utils.raise_err s
300
+ end
301
+ end
302
+
303
+ self
304
+ end
305
+ end
306
+
307
+ class Stream
308
+ def self.encoder(*args, **opts)
309
+ case
310
+ when args.empty?
311
+ Encoder.new(Filter::LZMA2.new(LZMA::PRESET_DEFAULT), **opts)
312
+ when args.size == 1 && args[0].kind_of?(Numeric)
313
+ Encoder.new(Filter::LZMA2.new(args[0]), **opts)
314
+ else
315
+ Encoder.new(*args, **opts)
316
+ end
317
+ end
318
+
319
+ def self.decoder(*args)
320
+ case
321
+ when args.empty?
322
+ Decoder.new(Filter::LZMA2.new(LZMA::PRESET_DEFAULT))
323
+ when args.size == 1 && args[0].kind_of?(Numeric)
324
+ Decoder.new(Filter::LZMA2.new(args[0]))
325
+ else
326
+ Decoder.new(*args)
327
+ end
328
+ end
329
+
330
+ def self.auto_decoder(*args)
331
+ AutoDecoder.new(*args)
332
+ end
333
+
334
+ def self.raw_encoder(*args)
335
+ case
336
+ when args.size == 0
337
+ RawEncoder.new(Filter::LZMA2.new(LZMA::PRESET_DEFAULT))
338
+ when args.size == 1 && args[0].kind_of?(Numeric)
339
+ RawEncoder.new(Filter::LZMA2.new(args[0]))
340
+ else
341
+ RawEncoder.new(*args)
342
+ end
343
+ end
344
+
345
+ def self.raw_decoder(*args)
346
+ case
347
+ when args.size == 0
348
+ RawDecoder.new(Filter::LZMA2.new(LZMA::PRESET_DEFAULT))
349
+ when args.size == 1 && args[0].kind_of?(Numeric)
350
+ RawDecoder.new(Filter::LZMA2.new(args[0]))
351
+ else
352
+ RawDecoder.new(*args)
353
+ end
354
+ end
355
+ end
356
+
357
+ class Filter
358
+ def self.lzma1(*args)
359
+ LZMA1.new(*args)
360
+ end
361
+
362
+ def self.lzma2(*args)
363
+ LZMA2.new(*args)
364
+ end
365
+
366
+ def self.delta(*args)
367
+ Delta.new(*args)
368
+ end
369
+ end
370
+
371
+ module Utils
372
+ extend self
373
+
374
+ def crc32_digest(seq, init = 0)
375
+ [Utils.crc32(seq, init)].pack("N")
376
+ end
377
+
378
+ def crc32_hexdigest(seq, init = 0)
379
+ "%08X" % Utils.crc32(seq, init)
380
+ end
381
+
382
+ def crc64_digest(seq, init = 0)
383
+ [Utils.crc64(seq, init)].pack("Q>")
384
+ end
385
+
386
+ def crc64_hexdigest(seq, init = 0)
387
+ "%016X" % Utils.crc64(seq, init)
388
+ end
389
+
390
+ #
391
+ # CRC32 を Digest のように生成できるようになります。
392
+ #
393
+ class CRC32 < Struct.new(:state, :init)
394
+ def initialize(state = 0)
395
+ state = state.to_i
396
+ super(state, state)
397
+ end
398
+
399
+ #
400
+ # call-seq:
401
+ # LZMA::Utils::CRC32#update(data) -> self
402
+ #
403
+ def update(data)
404
+ self.state = Utils.crc32(data, state)
405
+ self
406
+ end
407
+
408
+ alias << update
409
+
410
+ def finish
411
+ self
412
+ end
413
+
414
+ def reset
415
+ self.state = init
416
+ self
417
+ end
418
+
419
+ def digest
420
+ [state].pack("N")
421
+ end
422
+
423
+ def hexdigest
424
+ "%08x" % state
425
+ end
426
+
427
+ alias to_s hexdigest
428
+
429
+ def to_str
430
+ "CRC32 <#{hexdigest}>"
431
+ end
432
+
433
+ alias inspect to_str
434
+ end
435
+
436
+ #
437
+ # CRC64 を Digest のように生成できるようになります。
438
+ #
439
+ class CRC64 < Struct.new(:state, :init)
440
+ def initialize(state = 0)
441
+ state = state.to_i
442
+ super(state, state)
443
+ end
444
+
445
+ #
446
+ # call-seq:
447
+ # LZMA::Utils::CRC64#update(data) -> self
448
+ #
449
+ def update(data)
450
+ self.state = Utils.crc64(data, state)
451
+ self
452
+ end
453
+
454
+ alias << update
455
+
456
+ def finish
457
+ self
458
+ end
459
+
460
+ def reset
461
+ self.state = init
462
+ self
463
+ end
464
+
465
+ def digest
466
+ [state].pack("Q>")
467
+ end
468
+
469
+ def hexdigest
470
+ "%016x" % state
471
+ end
472
+
473
+ alias to_s hexdigest
474
+
475
+ def to_str
476
+ "CRC64 <#{hexdigest}>"
477
+ end
478
+
479
+ alias inspect to_str
480
+ end
481
+
482
+ def raise_err(lzma_ret, mesg = nil)
483
+ et = Utils.lookup_error(lzma_ret)
484
+ raise et, mesg, caller
485
+ end
486
+ end
487
+
488
+ extend Utils
489
+
490
+ #
491
+ # extlzma の内部で利用される補助モジュールです。
492
+ #
493
+ # extlzma の利用者が直接利用することは想定していません。
494
+ #
495
+ module Aux
496
+ def self.encode(src, encoder)
497
+ if src.kind_of?(String)
498
+ s = Encoder.new(encoder, "".force_encoding(Encoding::BINARY))
499
+ s << src
500
+ s.close
501
+ return s.outport
502
+ end
503
+
504
+ s = Encoder.new(encoder, (src || "".force_encoding(Encoding::BINARY)))
505
+ return s unless block_given?
506
+
507
+ begin
508
+ yield(s)
509
+ ensure
510
+ s.close
511
+ end
512
+ end
513
+
514
+ def self.decode(src, decoder)
515
+ if src.kind_of?(String)
516
+ return decode(StringIO.new(src), decoder) { |s| s.read }
517
+ end
518
+
519
+ s = Decoder.new(decoder, src)
520
+ return s unless block_given?
521
+
522
+ begin
523
+ yield(s)
524
+ ensure
525
+ s.close rescue nil
526
+ end
527
+ end
528
+ end
529
+ end