extbzip3 0.0.1

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.
@@ -0,0 +1,344 @@
1
+ #include "extbzip3.h"
2
+
3
+ static inline int
4
+ aux_oneshot_encode(int format, uint32_t blocksize, const void *in, void *out, size_t insize, size_t *outsize)
5
+ {
6
+ if (blocksize < AUX_BZIP3_BLOCKSIZE_MIN) {
7
+ blocksize = AUX_BZIP3_BLOCKSIZE_MIN;
8
+ } else if (blocksize > AUX_BZIP3_BLOCKSIZE_MAX) {
9
+ return BZ3_ERR_INIT;
10
+ }
11
+
12
+ if (!outsize) {
13
+ return BZ3_ERR_INIT;
14
+ }
15
+
16
+ int headersize;
17
+ size_t blockcount;
18
+ if (format == AUX_BZIP3_V1_FILE_FORMAT) {
19
+ headersize = 9;
20
+ blockcount = 0;
21
+ } else {
22
+ headersize = 13;
23
+ blockcount = (insize / blocksize) + ((insize % blocksize != 0) ? 1 : 0);
24
+
25
+ if (blockcount > (UINT32_MAX - 1)) {
26
+ return BZ3_ERR_DATA_TOO_BIG;
27
+ }
28
+ }
29
+
30
+ if (*outsize < (size_t)headersize) {
31
+ return BZ3_ERR_INIT;
32
+ }
33
+
34
+ struct bz3_state *bz3 = bz3_new(blocksize);
35
+ if (bz3 == NULL) {
36
+ return BZ3_ERR_INIT;
37
+ }
38
+
39
+ const uint8_t *inp = (const uint8_t *)in;
40
+ const uint8_t *const inend = inp + insize;
41
+ uint8_t *outp = (uint8_t *)out + headersize;
42
+ uint8_t *const outend = outp + *outsize;
43
+
44
+ while (inend - inp > 0) {
45
+ uint32_t origsize = ((inend - inp) > blocksize) ? blocksize : (uint32_t)(inend - inp);
46
+ uint32_t packedsize = (uint32_t)bz3_bound(origsize); // TODO???: 過剰な値かも?
47
+
48
+ if (outend - outp < packedsize) {
49
+ bz3_free(bz3);
50
+ return BZ3_ERR_DATA_TOO_BIG;
51
+ }
52
+
53
+ outp += 8;
54
+
55
+ memmove(outp, inp, origsize);
56
+ int32_t ret = aux_bz3_encode_block_nogvl(bz3, outp, origsize);
57
+ if (ret < 0) {
58
+ bz3_free(bz3);
59
+ return ret;
60
+ }
61
+
62
+ storeu32le(outp - 8, ret);
63
+ storeu32le(outp - 4, origsize);
64
+
65
+ inp += origsize;
66
+ outp += ret;
67
+ }
68
+
69
+ bz3_free(bz3);
70
+
71
+ *outsize = (size_t)(outp - (const uint8_t *)out);
72
+
73
+ memmove(out, aux_bzip3_signature, sizeof(aux_bzip3_signature));
74
+ storeu32le((char *)out + 5, blocksize);
75
+
76
+ if (format == AUX_BZIP3_V1_FRAME_FORMAT) {
77
+ storeu32le((char *)out + 9, (uint32_t)blockcount);
78
+ }
79
+
80
+ return BZ3_OK;
81
+ }
82
+
83
+ struct encoder
84
+ {
85
+ struct bz3_state *bzip3;
86
+ uint32_t blocksize;
87
+ int firstwrite:1;
88
+ int closed:1;
89
+ VALUE outport;
90
+ VALUE srcbuf;
91
+ VALUE destbuf;
92
+ };
93
+
94
+ #define ENCODER_FREE_BLOCK(P) \
95
+ if ((P)->bzip3) { \
96
+ bz3_free((P)->bzip3); \
97
+ } \
98
+
99
+ #define ENCODER_VALUE_FOREACH(DEF) \
100
+ DEF(outport) \
101
+ DEF(srcbuf) \
102
+ DEF(destbuf) \
103
+
104
+ AUX_DEFINE_TYPED_DATA(encoder, encoder_allocate, ENCODER_FREE_BLOCK, ENCODER_VALUE_FOREACH)
105
+
106
+ /*
107
+ * @overload initialize(blocksize: (16 << 20))
108
+ */
109
+ static VALUE
110
+ encoder_initialize(int argc, VALUE argv[], VALUE self)
111
+ {
112
+ struct { VALUE outport, opts; } args;
113
+ rb_scan_args(argc, argv, "1:", &args.outport, &args.opts);
114
+
115
+ enum { numkw = 1 };
116
+ ID idtab[numkw] = { rb_intern("blocksize") };
117
+ union { struct { VALUE blocksize; }; VALUE vect[numkw]; } opts;
118
+ rb_get_kwargs(args.opts, idtab, 0, numkw, opts.vect);
119
+
120
+ struct encoder *p = (struct encoder *)rb_check_typeddata(self, &encoder_type);
121
+ if (p == NULL || p->bzip3) {
122
+ rb_raise(rb_eTypeError, "wrong initialized or re-initializing - %" PRIsVALUE, self);
123
+ }
124
+
125
+ p->blocksize = aux_conv_to_blocksize(opts.blocksize);
126
+ p->outport = args.outport;
127
+ p->srcbuf = Qnil;
128
+ p->destbuf = Qnil;
129
+ p->bzip3 = aux_bz3_new(p->blocksize);
130
+ p->firstwrite = 1;
131
+
132
+ return self;
133
+ }
134
+
135
+ static VALUE
136
+ encoder_outport(VALUE self)
137
+ {
138
+ return get_encoder(self)->outport;
139
+ }
140
+
141
+ static void
142
+ encoder_write_encode(VALUE self, struct encoder *p, const void *buf, size_t len)
143
+ {
144
+ size_t bufoff = 8 + (p->firstwrite ? 9 : 0);
145
+
146
+ p->destbuf = aux_str_new_recycle(p->destbuf, bufoff + bz3_bound(len));
147
+ rb_str_set_len(p->destbuf, bufoff);
148
+ rb_str_cat(p->destbuf, buf, len);
149
+
150
+ int32_t res = aux_bz3_encode_block_nogvl(p->bzip3, RSTRING_PTR(p->destbuf) + bufoff, RSTRING_LEN(p->destbuf) - bufoff);
151
+
152
+ if (res < 0) {
153
+ extbzip3_check_error(res);
154
+ }
155
+
156
+ rb_str_set_len(p->destbuf, bufoff + res);
157
+ storeu32le(RSTRING_PTR(p->destbuf) + bufoff - 8, res);
158
+ storeu32le(RSTRING_PTR(p->destbuf) + bufoff - 4, (uint32_t)len);
159
+
160
+ if (p->firstwrite) {
161
+ memcpy(RSTRING_PTR(p->destbuf), "BZ3v1", 5);
162
+ storeu32le(RSTRING_PTR(p->destbuf) + 5, p->blocksize);
163
+ p->firstwrite = 0;
164
+ }
165
+
166
+ rb_funcallv(p->outport, rb_intern("<<"), 1, &p->destbuf);
167
+ }
168
+
169
+ static VALUE
170
+ encoder_write(VALUE self, VALUE src)
171
+ {
172
+ struct encoder *p = get_encoder(self);
173
+
174
+ rb_check_type(src, RUBY_T_STRING);
175
+
176
+ size_t srclen = RSTRING_LEN(src);
177
+
178
+ if (srclen <= p->blocksize) {
179
+ if (rb_type_p(p->srcbuf, RUBY_T_STRING)) {
180
+ size_t srcbuflen = RSTRING_LEN(p->srcbuf);
181
+ size_t catlen = srclen + srcbuflen;
182
+
183
+ if (catlen >= p->blocksize) {
184
+ rb_str_cat(p->srcbuf, RSTRING_PTR(src), p->blocksize - srcbuflen);
185
+ encoder_write_encode(self, p, RSTRING_PTR(p->srcbuf), RSTRING_LEN(p->srcbuf));
186
+ rb_str_set_len(p->srcbuf, 0);
187
+ rb_str_cat(p->srcbuf, RSTRING_PTR(src) + p->blocksize - srcbuflen, srclen - (p->blocksize - srcbuflen));
188
+
189
+ return self;
190
+ }
191
+ } else {
192
+ p->srcbuf = rb_str_new(0, 0);
193
+ }
194
+
195
+ rb_str_cat(p->srcbuf, RSTRING_PTR(src), srclen);
196
+
197
+ return self;
198
+ } else {
199
+ size_t srcoff = 0;
200
+
201
+ if (rb_type_p(p->srcbuf, RUBY_T_STRING) && RSTRING_LEN(p->srcbuf) > 0) {
202
+ srcoff = p->blocksize - RSTRING_LEN(p->srcbuf);
203
+ rb_str_cat(p->srcbuf, RSTRING_PTR(src), srcoff);
204
+ encoder_write_encode(self, p, RSTRING_PTR(p->srcbuf), RSTRING_LEN(p->srcbuf));
205
+ rb_str_set_len(p->srcbuf, 0);
206
+ srclen = RSTRING_LEN(src); // maybe changed src with `outport << destbuf`
207
+ if (srclen < srcoff) {
208
+ return self;
209
+ }
210
+ }
211
+
212
+ while (srclen - srcoff > p->blocksize) {
213
+ encoder_write_encode(self, p, RSTRING_PTR(src) + srcoff, p->blocksize);
214
+ srcoff += p->blocksize;
215
+ srclen = RSTRING_LEN(src); // maybe changed src with `outport << destbuf`
216
+ if (srclen < srcoff) {
217
+ return self;
218
+ }
219
+ }
220
+
221
+ if (srcoff < srclen) {
222
+ if (!rb_type_p(p->srcbuf, RUBY_T_STRING)) {
223
+ p->srcbuf = rb_str_new(0, 0);
224
+ }
225
+
226
+ rb_str_cat(p->srcbuf, RSTRING_PTR(src), srclen - srcoff);
227
+ }
228
+
229
+ return self;
230
+ }
231
+ }
232
+
233
+ static VALUE
234
+ encoder_flush(VALUE self)
235
+ {
236
+ struct encoder *p = get_encoder(self);
237
+
238
+ if (rb_type_p(p->srcbuf, RUBY_T_STRING) && RSTRING_LEN(p->srcbuf) > 0) {
239
+ encoder_write_encode(self, p, RSTRING_PTR(p->srcbuf), RSTRING_LEN(p->srcbuf));
240
+ rb_str_set_len(p->srcbuf, 0);
241
+ }
242
+
243
+ return Qnil;
244
+ }
245
+
246
+ static VALUE
247
+ encoder_close(VALUE self)
248
+ {
249
+ struct encoder *p = get_encoder(self);
250
+
251
+ if (rb_type_p(p->srcbuf, RUBY_T_STRING) && RSTRING_LEN(p->srcbuf) > 0) {
252
+ encoder_write_encode(self, p, RSTRING_PTR(p->srcbuf), RSTRING_LEN(p->srcbuf));
253
+ rb_str_set_len(p->srcbuf, 0);
254
+ }
255
+
256
+ p->closed = 1;
257
+
258
+ return Qnil;
259
+ }
260
+
261
+ static VALUE
262
+ encoder_closed_p(VALUE self)
263
+ {
264
+ return get_encoder(self)->closed ? Qtrue : Qfalse;
265
+ }
266
+
267
+ /*
268
+ * @overload encode(src, maxdest = nil, dest = "", **opts)
269
+ * @overload encode(src, dest, **opts)
270
+ *
271
+ * @return [String]
272
+ * dest as decompression data
273
+ * @param [String] src
274
+ * @param [Integer] maxdest
275
+ * @param [String] dest
276
+ * @option opts [Integer] :blocksize ((16 << 20))
277
+ * @option opts :format (Bzip3::V1_FILE_FORMAT)
278
+ * Bzip3::V1_FILE_FORMAT, Bzip3::V1_FRAME_FORMAT
279
+ */
280
+ static VALUE
281
+ encoder_s_encode(int argc, VALUE argv[], VALUE mod)
282
+ {
283
+ size_t insize, outsize;
284
+ struct { VALUE src, maxdest, dest, opts; } args;
285
+ switch (rb_scan_args(argc, argv, "12:", &args.src, &args.maxdest, &args.dest, &args.opts)) {
286
+ case 1:
287
+ insize = RSTRING_LEN(args.src);
288
+ outsize = bz3_bound(insize);
289
+ args.dest = rb_str_buf_new(outsize);
290
+ break;
291
+ case 2:
292
+ insize = RSTRING_LEN(args.src);
293
+
294
+ if (rb_type_p(args.maxdest, RUBY_T_FIXNUM) || rb_type_p(args.maxdest, RUBY_T_BIGNUM)) {
295
+ outsize = NUM2SIZET(args.maxdest);
296
+ args.dest = rb_str_buf_new(outsize);
297
+ } else {
298
+ args.dest = args.maxdest;
299
+ outsize = bz3_bound(insize);
300
+ rb_str_modify(args.dest);
301
+ rb_str_set_len(args.dest, 0);
302
+ rb_str_modify_expand(args.dest, outsize);
303
+ }
304
+
305
+ break;
306
+ case 3:
307
+ insize = RSTRING_LEN(args.src);
308
+ outsize = NUM2SIZET(args.maxdest);
309
+ rb_str_modify(args.dest);
310
+ rb_str_set_len(args.dest, 0);
311
+ rb_str_modify_expand(args.dest, outsize);
312
+
313
+ break;
314
+ }
315
+
316
+ enum { numkw = 2 };
317
+ ID idtab[numkw] = { rb_intern("blocksize"), rb_intern("format") };
318
+ union { struct { VALUE blocksize, format; }; VALUE vect[numkw]; } opts;
319
+ rb_get_kwargs(args.opts, idtab, 0, numkw, opts.vect);
320
+
321
+ uint32_t blocksize = aux_conv_to_blocksize(opts.blocksize);
322
+ int status = aux_oneshot_encode(aux_conv_to_format(opts.format), blocksize,
323
+ RSTRING_PTR(args.src), RSTRING_PTR(args.dest),
324
+ insize, &outsize);
325
+ extbzip3_check_error(status);
326
+ rb_str_set_len(args.dest, outsize);
327
+
328
+ return args.dest;
329
+ }
330
+
331
+ void
332
+ extbzip3_init_encoder(VALUE bzip3_module)
333
+ {
334
+ VALUE encoder_class = rb_define_class_under(bzip3_module, "Encoder", rb_cObject);
335
+ rb_define_alloc_func(encoder_class, encoder_allocate);
336
+ rb_define_singleton_method(encoder_class, "encode", encoder_s_encode, -1);
337
+ rb_define_method(encoder_class, "initialize", encoder_initialize, -1);
338
+ rb_define_method(encoder_class, "outport", encoder_outport, 0);
339
+ rb_define_method(encoder_class, "write", encoder_write, 1);
340
+ rb_define_method(encoder_class, "flush", encoder_flush, 0);
341
+ rb_define_method(encoder_class, "close", encoder_close, 0);
342
+ rb_define_method(encoder_class, "closed?", encoder_closed_p, 0);
343
+ rb_define_alias(encoder_class, "<<", "write");
344
+ }
data/ext/extconf.rb ADDED
@@ -0,0 +1,43 @@
1
+ #!ruby
2
+
3
+ require "mkmf"
4
+
5
+ using Module.new {
6
+ refine Object do
7
+ def has_function_modifier?(modifier_code)
8
+ try_compile(<<~CODE)
9
+ #{modifier_code}
10
+ void
11
+ func1(void) {
12
+ }
13
+ CODE
14
+ end
15
+ end
16
+ }
17
+
18
+ MakeMakefile::CONFIG["optflags"] = "-O0 -g3" if ENV["RUBY_EXTBZIP3_DEBUG"].to_i > 0
19
+
20
+ have_header("libbz3.h") or abort "need libbz3.h header file"
21
+ have_library("bzip3") or abort "need libbzip3 library"
22
+
23
+ if RbConfig::CONFIG["arch"] =~ /mingw/i
24
+ #$LDFLAGS << " -static-libgcc" if try_ldflags("-static-libgcc")
25
+ else
26
+ if try_compile(<<~"VISIBILITY")
27
+ __attribute__((visibility("hidden"))) int conftest(void) { return 0; }
28
+ VISIBILITY
29
+
30
+ if try_cflags("-fvisibility=hidden")
31
+ $CFLAGS << " -fvisibility=hidden"
32
+ $defs << %(-DEXTBZIP3_API='__attribute__((visibility("default")))')
33
+ end
34
+ end
35
+ end
36
+
37
+ mod = %w(__attribute__((__noreturn__)) __declspec(noreturn) [[noreturn]] _Noreturn).find { |m|
38
+ has_function_modifier?(m)
39
+ }
40
+ $defs << %(-DRBEXT_NORETURN='#{mod}')
41
+
42
+ create_header
43
+ create_makefile File.join(RUBY_VERSION.slice(/\d+\.\d+/), "extbzip3")
data/gemstub.rb ADDED
@@ -0,0 +1,17 @@
1
+ require_relative "lib/extbzip3/version"
2
+
3
+ GEMSTUB = Gem::Specification.new do |s|
4
+ s.name = "extbzip3"
5
+ s.version = Bzip3::VERSION
6
+ s.summary = "ruby bindings for bzip3 (bz3)"
7
+ s.description = <<~DESCRIPT
8
+ unoficial ruby bindings for bzip3 (bz3) <https://github.com/kspalaiologos/bzip3>.
9
+ DESCRIPT
10
+ s.homepage = "https://github.com/dearblue/ruby-extbzip3"
11
+ s.licenses = %w(BSD-2-Clause LGPL-3.0+ Apache-2.0)
12
+ s.author = "dearblue"
13
+ s.email = "dearblue@users.osdn.me"
14
+
15
+ #s.required_ruby_version = ">= 2.0"
16
+ s.add_development_dependency "rake", "~> 0"
17
+ end
@@ -0,0 +1,90 @@
1
+ module Bzip3
2
+ remove_const :Decoder rescue nil
3
+
4
+ class Decoder
5
+ def initialize(inport, blocksize = 16 << 20)
6
+ @bzip3 = BlockProcessor.new(blocksize)
7
+ @inport = inport
8
+ @readbuf = nil
9
+ @destbuf = nil
10
+ @closed = false
11
+ @eof = false
12
+
13
+ self
14
+ end
15
+
16
+ def read(size = nil, buf = "".b)
17
+ buf ||= "".b
18
+ buf[0..-1] = "".b
19
+
20
+ return buf if size == 0
21
+
22
+ size &&= 0 | Integer(0 + size)
23
+
24
+ @readbuf ||= "".b
25
+
26
+ while true
27
+ if @destbuf
28
+ if size && @destbuf.bytesize >= size
29
+ buf << @destbuf.byteslice(0, size)
30
+ @destbuf[0...size] = "".b
31
+ break
32
+ else
33
+ buf << @destbuf
34
+ size -= @destbuf.bytesize if size
35
+ @destbuf[0..-1] = "".b
36
+ end
37
+ else
38
+ @destbuf = "".b
39
+
40
+ (sig, bs) = @inport.read(9)&.unpack("a5V")
41
+ raise "意図しない EOF" unless bs
42
+ raise "シグネチャが違う" unless sig == "BZ3v1"
43
+ raise "おかしなブロックサイズ" unless ((65 << 10) .. (511 << 20)).include? bs
44
+ raise "ブロックサイズがでかすぎ" unless bs <= @bzip3.blocksize
45
+ end
46
+
47
+ unless b1 = @inport.read(8)
48
+ @eof = true
49
+ break
50
+ end
51
+ raise "意図しない EOF" if b1.bytesize < 8
52
+ if b1.byteslice(0, 5) == "BZ3v1"
53
+ b2 = @inport.read(1)
54
+ if b2 && b2.bytesize > 0
55
+ b1 << b2
56
+ bs = b1.unpack1("@5V")
57
+ raise "ブロックサイズがでかすぎ" unless bs <= @bzip3.blocksize
58
+ next
59
+ end
60
+ end
61
+ (packedsize, originsize) = b1.unpack("VV")
62
+ raise "元のデータがデカすぎ" unless originsize <= @bzip3.blocksize
63
+ raise "意図しない EOF" unless @inport.read(packedsize, @readbuf)
64
+ raise "大きさがあってない" unless @readbuf.bytesize == packedsize
65
+ @bzip3.decode(@readbuf, @destbuf, originsize)
66
+ end
67
+
68
+ buf.empty? ? nil : buf
69
+ end
70
+
71
+ def close
72
+ @closed = true
73
+ @bzip3 = nil
74
+ @readbuf = nil
75
+ @destbuf = nil
76
+
77
+ self
78
+ end
79
+
80
+ def closed?
81
+ @closed
82
+ end
83
+
84
+ def eof?
85
+ @eof
86
+ end
87
+
88
+ alias :eof :eof?
89
+ end
90
+ end
@@ -0,0 +1,38 @@
1
+ # This file is for additional documents
2
+
3
+ 0 / 0
4
+
5
+ #
6
+ # Bzip3 module.
7
+ #
8
+ module Bzip3
9
+ #
10
+ # Decoder class.
11
+ #
12
+ class Decoder
13
+ end
14
+
15
+ #
16
+ # Encoder class.
17
+ #
18
+ class Encoder
19
+ end
20
+ end
21
+
22
+ class BasicObject
23
+ # 自身を出力ストリームと見立てて bzip3 を行うエンコーダオブジェクトを生成します。
24
+ def to_bzip3
25
+ end
26
+
27
+ # 自身を入力ストリームと見立てて bunzip3 を行うデコーダオブジェクトを生成します。
28
+ def bunzip3
29
+ end
30
+ end
31
+
32
+ class String
33
+ def to_bzip3
34
+ end
35
+
36
+ def bunzip3
37
+ end
38
+ end
@@ -0,0 +1,8 @@
1
+ module Bzip3
2
+ verreg = /^\s*[\-\*]\s+version:\s*(\d+(?:\.\w+)+)\s*$/i
3
+ unless File.read("#{__dir__}/../../README.md", mode: "rt") =~ verreg
4
+ raise "``version'' is not defined or bad syntax in ``README.md''"
5
+ end
6
+
7
+ VERSION = String($1)
8
+ end
data/lib/extbzip3.rb ADDED
@@ -0,0 +1,65 @@
1
+ ver = RUBY_VERSION.slice(/\d+\.\d+/)
2
+ soname = File.basename(__FILE__, ".rb") << ".so"
3
+ require File.join(ver, soname)
4
+
5
+ module Bzip3
6
+ refine String do
7
+ def to_bzip3(*args, **opts)
8
+ Bzip3::Encoder.encode(self, *args, **opts)
9
+ end
10
+
11
+ def bunzip3(*args, **opts)
12
+ Bzip3::Decoder.decode(self, *args, **opts)
13
+ end
14
+ end
15
+
16
+ refine BasicObject do
17
+ def to_bzip3(*args, **opts, &block)
18
+ Bzip3::Encoder.open(self, *args, **opts, &block)
19
+ end
20
+
21
+ def bunzip3(*args, **opts, &block)
22
+ Bzip3::Decoder.open(self, *args, **opts, &block)
23
+ end
24
+ end
25
+
26
+ class << Bzip3
27
+ using Bzip3
28
+
29
+ def encode(src, *args, **opts, &block)
30
+ src.to_bzip3(*args, **opts, &block)
31
+ end
32
+
33
+ def decode(src, *args, **opts, &block)
34
+ src.bunzip3(*args, **opts, &block)
35
+ end
36
+ end
37
+
38
+ class << Decoder
39
+ def open(*args, **opts, &block)
40
+ bz3 = new(*args, **opts)
41
+ return bz3 unless block
42
+
43
+ begin
44
+ yield bz3
45
+ ensure
46
+ bz3.close unless bz3.closed?
47
+ end
48
+ end
49
+ end
50
+
51
+ class << Encoder
52
+ def open(*args, **opts, &block)
53
+ bz3 = new(*args, **opts)
54
+ return bz3 unless block
55
+
56
+ begin
57
+ yield bz3
58
+ ensure
59
+ bz3.close unless bz3.closed?
60
+ end
61
+ end
62
+ end
63
+
64
+ Bzip3 = self
65
+ end
@@ -0,0 +1,77 @@
1
+ #!ruby
2
+
3
+ require "test-unit"
4
+ require "extbzip3"
5
+
6
+ SAMPLES = File.join(__dir__, "../sampledata")
7
+
8
+ class << SAMPLES
9
+ def load_file(path)
10
+ File.binread File.join(self, path)
11
+ end
12
+
13
+ def open_file(path, *args, **opts, &block)
14
+ File.open File.join(self, path), *args, **opts, &block
15
+ end
16
+ end
17
+
18
+ SAMPLES.freeze
19
+
20
+ class TestBzip3 < Test::Unit::TestCase
21
+ def test_oneshot
22
+ assert_equal "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\n",
23
+ Bzip3.decode(SAMPLES.load_file("single.bz3"))
24
+
25
+ assert_raise RuntimeError do
26
+ Bzip3.decode(SAMPLES.load_file("single.bz3-frame"))
27
+ end
28
+
29
+ assert_raise RuntimeError do
30
+ Bzip3.decode(SAMPLES.load_file("single.bz3-frame"), format: Bzip3::V1_FILE_FORMAT)
31
+ end
32
+
33
+ assert_equal "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\nZYXWVUTSRQPONMLKJIHGFEDCBA987654321\n",
34
+ Bzip3.decode(SAMPLES.load_file("double.bz3"))
35
+
36
+ assert_equal "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\n",
37
+ Bzip3.decode(SAMPLES.load_file("double.bz3"), concat: false)
38
+
39
+ assert_raise RuntimeError do
40
+ Bzip3.decode(SAMPLES.load_file("single+junks.bz3"))
41
+ end
42
+ end
43
+
44
+ def test_oneshot_frame
45
+ assert_equal "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\n",
46
+ Bzip3.decode(SAMPLES.load_file("single.bz3-frame"), format: Bzip3::V1_FRAME_FORMAT)
47
+
48
+ assert_raise RuntimeError do
49
+ Bzip3.decode(SAMPLES.load_file("single.bz3"), format: Bzip3::V1_FRAME_FORMAT)
50
+ end
51
+ end
52
+
53
+ def test_stream
54
+ io = SAMPLES.open_file("single.bz3")
55
+ assert_kind_of Bzip3::Decoder, Bzip3.decode(io)
56
+ assert_equal "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", Bzip3.decode(io).read
57
+ io.rewind
58
+ assert_equal "OK",
59
+ Bzip3.decode(io) { |bz3|
60
+ assert_equal "", bz3.read(0, "")
61
+ assert_equal "12345", bz3.read(5, "")
62
+ assert_equal "6789AB", bz3.read(6)
63
+ assert_equal "", bz3.read(0)
64
+ assert_equal "CDEFGHIJKLMNOPQRSTUVWXYZ\n", bz3.read
65
+ assert_equal "", bz3.read(0)
66
+ assert_equal nil, bz3.read
67
+ "OK"
68
+ }
69
+
70
+ if defined? Ractor
71
+ assert_equal "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", Ractor.new {
72
+ io2 = SAMPLES.open_file("single.bz3")
73
+ Bzip3.decode(io2).read
74
+ }.take
75
+ end
76
+ end
77
+ end