• R/O
  • SSH
  • HTTPS

rutsubo: コミット


コミットメタ情報

リビジョン71 (tree)
日時2015-04-19 23:05:37
作者dearblue

ログメッセージ

extlz4:

* セーフレベルを確認して例外を発生させる方針をやめ、汚染の伝搬のみとするように変更
* Raw API を Block API に名称変更
* LZ4::BlockEncoder#predict メソッドを追加
* LZ4::BlockEncoder#inspect メソッドを追加
* LZ4::BlockDecoder.linksize メソッドを追加
* 互換性のため以前の rawXXX で始まるメソッドをそのまま利用できる事を目的とした lib/extlz4/compat.rb を追加
* ext/frameapi.c の処理でオブジェクトの汚染状態を伝搬させるように修正
* ext/frameapi.c から predict の痕跡を削除
* LZ4::Encoder#initialize の引数解析処理を修正

  • outport を省略可能となるように変更
  • キーワード引数 level を削除し、第二引数として与えるように変更
  • キーワード引数 blocksize を追加
  • キーワード引数 blocklink を追加
  • キーワード引数 streamsum を checksum に変更

* LZ4::Encoder#outport、LZ4::Encoder#outport= メソッドを追加
* LZ4::Encoder#prefs_XXX メソッドによる圧縮設定値を確認できる機能を追加
* LZ4::Encoder#inspect メソッドを追加
* LZ4::Decoder#inport メソッドを追加
* LZ4::Decoder#prefs_XXX メソッドによる圧縮設定値を確認できる機能を追加
* LZ4::Decoder#inspect メソッドを追加
* いくつかの試験項目の追加と修正
* その他の修正

変更サマリ

差分

--- trunk/extlz4/README.md (revision 70)
+++ trunk/extlz4/README.md (revision 71)
@@ -6,7 +6,9 @@
66
77 LZ4 データストリームを圧縮・伸張できます。lz4-cli で扱うことが出来ます。
88
9- $ dmesg | ruby -r extlz4 -e 'LZ4.encode_file($stdin.binmode, $stdout.binmode)' | lz4c -d | more
9+``` shell:shell
10+$ dmesg | ruby -r extlz4 -e 'LZ4.encode_file($stdin.binmode, $stdout.binmode)' | lz4c -d | more
11+```
1012
1113 ほかの ruby 向けの lz4 バインディングライブラリとしては KOMIYA Atsushi さんによる [lz4-ruby (http://rubygems.org/gems/lz4-ruby)](http://rubygems.org/gems/lz4-ruby) があります。
1214
@@ -13,24 +15,25 @@
1315
1416 ## SUMMARY (概要)
1517
16-- PACKAGE NAME (名称): extlz4
17-- AUTHOR (制作者): dearblue <dearblue@users.sourceforge.jp>
18-- HOW TO INSTALL (インストール手順): `gem install extlz4`
19-- VERSION (バージョン情報): 0.2
20-- RELEASE QUALITY (品質): alpha
21-- LICENSING (ライセンス): 2-clause BSD License (二条項 BSD ライセンス)
22-- DEPENDENCY GEMS (依存する gem パッケージ):
23- - none (なし)
24-- DEPENDENCY EXTERNAL C LIBRARIES (依存する外部 C ライブラリ):
25- - none (なし)
26-- BUNDLED EXTERNAL C LIBRARIES (同梱される外部 C ライブラリ):
27- - lz4 (Yann Collet さんによる) <http://code.google.com/p/lz4/> (r127)
28-- REPORT ISSUE TO (問題の報告先): <http://sourceforge.jp/projects/rutsubo/ticket/>
18+ * PACKAGE NAME (名称): extlz4
19+ * AUTHOR (制作者): dearblue <dearblue@users.sourceforge.jp>
20+ * REPORT ISSUE TO (問題の報告先): <http://sourceforge.jp/projects/rutsubo/ticket/>
21+ * HOW TO INSTALL (インストール手順): `gem install extlz4`
22+ * VERSION (バージョン情報): 0.2
23+ * RELEASE QUALITY (品質): alpha
24+ * LICENSING (ライセンス): 2-clause BSD License (二条項 BSD ライセンス)
25+ * DEPENDENCY GEMS (依存する gem パッケージ):
26+ * none (なし)
27+ * DEPENDENCY EXTERNAL C LIBRARIES (依存する外部 C ライブラリ):
28+ * none (なし)
29+ * BUNDLED EXTERNAL C LIBRARIES (同梱される外部 C ライブラリ):
30+ * lz4 (Yann Collet さんによる) <http://code.google.com/p/lz4/> (r127)
2931
3032
3133 ## ATTENTIONS (注意事項)
3234
33-- Many documents are written in japanese.
35+ * Many documents are written in japanese.
36+
3437 (ドキュメントの多くは日本語で記述されています)
3538
3639
@@ -59,31 +62,29 @@
5962
6063 ## FEATURES (機能)
6164
62-- Generic LZ4 streaming data process
63- - Decode LZ4 streaming data: ``LZ4.decode``
64- - Encode LZ4 streaming data: ``LZ4.encode``
65-- Generic LZ4 streaming data file process
66- - Decode LZ4 streaming data file: ``LZ4.decode_file``
67- - Encode LZ4 streaming data file: ``LZ4.encode_file``
68-- Primitive LZ4 data process
69- - Decode LZ4 data: ``LZ4.raw_decode``
70- - Encode LZ4 data: ``LZ4.raw_encode`` (supporting high compression level)
71- - Streaming Decode LZ4 data: ``LZ4.raw_stream_decode`` and ``LZ4::RawStreamDecoder#update``
72- - Streaming Encode LZ4 data: ``LZ4.raw_stream_encode`` and ``LZ4::RawStreamEncoder#update`` (supporting high compression level)
65+ * Generic LZ4 frame data process
66+ * Decode LZ4 Frame data : LZ4.decode
67+ * Encode LZ4 Frame data : LZ4.encode
68+ * Generic LZ4 frame data file process
69+ * Decode LZ4 Frame data file : LZ4.decode\_file
70+ * Encode LZ4 Frame data file : LZ4.encode\_file
71+ * LZ4 block data process
72+ * Decode LZ4 block data : LZ4.block\_decode
73+ * Encode LZ4 block data : LZ4.block\_encode (supporting high compression level)
74+ * Streaming Decode LZ4 block data : LZ4.block\_stream\_decode and LZ4::BlockDecoder#update
75+ * Streaming Encode LZ4 block data : LZ4.block\_stream\_encode and LZ4::BlockEncoder#update (supporting high compression level)
7376
7477
75-## ABOUT SECURITY (セキュリティについて)
78+## ABOUT TAINT STATE AND SECURITY (汚染状態とセキュリティについて)
7679
77-extlz4 はセキュリティレベルとオブジェクトの汚染状態を確認し、禁止される処理を決定します。
80+extlz4 はオブジェクト間での汚染状態を一方向伝播します。
7881
79-セーフレベルが3未満であれば、禁止される処理はありません。
82+オブジェクトの汚染伝播については『入力 -> 出力』となり、
83+ストリーム処理の場合は『入力 -> 圧縮器・伸張器 -> 出力』というようになります。
8084
81-セーフレベルが3以上の場合、入力と出力 (ストリーム処理の場合はストリーム処理器が含まれる) のすべてが汚染状態でなければ禁止されます。
85+セキュリティレベルによる処理の拒否は行いません。
8286
83-いずれのセーフレベルにおいても、オブジェクト間で汚染状態が一方向伝播されます。
84-オブジェクトの汚染伝播については『入力 -> 出力』となり、ストリーム処理の場合は『入力 -> 圧縮器・伸張器 -> 出力』というようになります。
8587
86-
8788 ## EXAMPLES (用例)
8889
8990 First, load extlz4. (最初に extlz4 を読み込んでください)
@@ -104,13 +105,13 @@
104105 compressed_data_string = LZ4.encode(uncompressed_data_string)
105106 ```
106107
107-### High compression encoding (高効率圧縮処理)
108+### High compression encoding (高圧縮処理)
108109
109110 ``` ruby:ruby
110111 compressed_data_string = LZ4.encode(uncompressed_data_string, 9)
111112 ```
112113
113-### Stream decoding
114+### Frame decoding
114115
115116 ``` ruby:ruby
116117 File.open("sample.txt.lz4", "rb") do |file|
@@ -122,7 +123,7 @@
122123 end
123124 ```
124125
125-### Stream encoding by high compression
126+### Frame encoding by high compression
126127
127128 ``` ruby:ruby
128129 File.open("sample.txt.lz4", "wb") do |file|
@@ -133,7 +134,7 @@
133134 end
134135 ```
135136
136-### Stream encoding without block
137+### Frame encoding without block
137138
138139 ``` ruby:ruby
139140 file = File.open("sample.txt.lz4", "wb")
@@ -142,39 +143,54 @@
142143 lz4.close # VERY IMPORTANT!
143144 ```
144145
145-### Raw data processing (high compression encoding and decoding)
146+### Block data processing (fast compression encoding and decoding)
146147
147- src = "abcdefg" * 100
148- lz4data = LZ4.raw_encode(16, src)
149- data = LZ4.raw_decode(lz4data)
150- p src == data # => true
148+``` ruby:ruby
149+src = "abcdefg" * 100
150+lz4data = LZ4.block_encode(src)
151+data = LZ4.block_decode(lz4data)
152+p src == data # => true
153+```
151154
152-### Raw stream data processing (high compression encoding and decoding)
155+### Block data processing (high compression encoding and decoding)
153156
154- blocksize = 4 * 1024 # 4 KiB (REQEUIRED PARAMETER)
155- ishighcompress = true # use high compression method (OPTIONAL PARAMETER)
156- encoder = LZ4.raw_stream_encode(blocksize, ishighcompress)
157+``` ruby:ruby
158+src = "abcdefg" * 100
159+level = 8
160+lz4data = LZ4.block_encode(level, src)
161+data = LZ4.block_decode(lz4data)
162+p src == data # => true
163+```
157164
158- src = "abcdefg" * 100
159- lz4data1 = encoder.update(16, src)
165+### Block stream data processing (high compression encoding and decoding)
160166
161- decoder = LZ4.raw_stream_decode # not required blocksize
167+``` ruby:ruby
168+level = 8 # (OPTIONAL PARAMETER)
169+predict = "abcdefg" # with preset dictionary (OPTIONAL PARAMETER)
170+encoder = LZ4.block_stream_encode(level, predict)
162171
163- data = decoder.update(lz4data1)
164- p src == data # => true
172+src = "abcdefg" * 100
173+lz4data1 = encoder.update(src)
165174
166- lz4data2 = encoder.update(src) # default high compression level
167- p "lz4data1.bytesize" => lz4data1.bytesize,
168- "lz4data2.bytesize" => lz4data2.bytesize
175+decoder = LZ4.block_stream_decode(predict)
169176
170- data = decoder.update(lz4data2)
171- p src == data # => true
177+data = decoder.update(lz4data1)
178+p src == data # => true
172179
180+src2 = "ABCDEFG" * 100
181+lz4data2 = encoder.update(src2)
182+p "lz4data1.bytesize" => lz4data1.bytesize,
183+ "lz4data2.bytesize" => lz4data2.bytesize
173184
174-## おまけ
185+data = decoder.update(lz4data2)
186+p src2 == data # => true
187+```
175188
176-コマンドラインプログラムとして `extlz4` が追加されます。
177189
190+## BONUS (おまけ)
191+
192+コマンドラインプログラムとして ``extlz4`` が追加されます。
193+
178194 これは lz4 と同程度の機能を持ちます (車輪の再発明とも言う)。
179195
180196 とはいえ、引数のとり方を変えてあり、gzip のような形で利用できます。
--- trunk/extlz4/test/sampledata.rb (nonexistent)
+++ trunk/extlz4/test/sampledata.rb (revision 71)
@@ -0,0 +1,15 @@
1+SMALLSIZE = 400
2+BIGSIZE = 12000000
3+
4+SAMPLES = {
5+ "empty" => "",
6+ "\\0 (small size)" => "\0".b * SMALLSIZE,
7+ "\\0 (big size)" => "\0".b * BIGSIZE,
8+ "\\xaa (small size)" => "\xaa".b * SMALLSIZE,
9+ "\\xaa (big size)" => "\xaa".b * BIGSIZE,
10+ "random (small size)" => OpenSSL::Random.random_bytes(SMALLSIZE),
11+ "random (big size)" => OpenSSL::Random.random_bytes(BIGSIZE),
12+}
13+
14+SAMPLES["freebsd ports index"] = File.read("/usr/ports/INDEX-10", mode: "rb") rescue nil # if on FreeBSD
15+SAMPLES["freebsd kernel"] = File.read("/boot/kernel/kernel", mode: "rb") rescue nil # if on FreeBSD
--- trunk/extlz4/test/test_blockapi.rb (revision 70)
+++ trunk/extlz4/test/test_blockapi.rb (revision 71)
@@ -1,36 +1,71 @@
11 #!ruby
22
33 require "test-unit"
4+require "openssl" # for OpenSSL::Random.random_bytes
45 require "extlz4"
5-require "openssl" # for OpenSSL::Random.random_bytes
66
7-SMALLSIZE = 400
8-BIGSIZE = 12000000
7+require_relative "sampledata"
98
10-SAMPLES = [
11- "",
12- "\0".b * SMALLSIZE,
13- "\0".b * BIGSIZE,
14- "\xaa".b * SMALLSIZE,
15- "\xaa".b * BIGSIZE,
16- OpenSSL::Random.random_bytes(SMALLSIZE),
17- OpenSSL::Random.random_bytes(BIGSIZE),
18-]
9+class TestBlockAPI < Test::Unit::TestCase
10+ SAMPLES.each_pair do |name, data|
11+ define_method("test_block_encode_decode_sample:#{name}", -> {
12+ assert(data, LZ4.block_decode(LZ4.block_encode(data)))
13+ })
14+ end
1915
20-SAMPLES << File.read("/usr/ports/INDEX-10", mode: "rb") rescue nil # if on FreeBSD
21-SAMPLES << File.read("/boot/kernel/kernel", mode: "rb") rescue nil # if on FreeBSD
16+ def test_block_encode
17+ buf = ""
18+ assert_kind_of(String, LZ4.block_encode(SAMPLES["\\0 (small size)"]))
19+ assert_kind_of(String, LZ4.block_encode(SAMPLES["\\0 (small size)"], 1000))
20+ assert_same(buf, LZ4.block_encode(SAMPLES["\\0 (small size)"], buf))
21+ assert_same(buf, LZ4.block_encode(SAMPLES["\\0 (small size)"], 1000, buf))
22+ assert_same(buf, LZ4.block_encode(nil, SAMPLES["\\0 (small size)"], 1000, buf))
2223
23-$stderr.puts "%s:%d: prepaired sample data (%d samples)\n" % [__FILE__, __LINE__, SAMPLES.size]
24+ # high compression
25+ assert_kind_of(String, LZ4.block_encode(0, SAMPLES["\\0 (small size)"]))
26+ assert_kind_of(String, LZ4.block_encode(0, SAMPLES["\\0 (small size)"], 1000))
27+ assert_same(buf, LZ4.block_encode(0, SAMPLES["\\0 (small size)"], buf))
28+ assert_same(buf, LZ4.block_encode(0, SAMPLES["\\0 (small size)"], 1000, buf))
29+ end
2430
25-class TestRawAPI < Test::Unit::TestCase
26- def test_encode_decode
27- assert { LZ4.raw_decode(LZ4.raw_encode(SAMPLES[0])) == SAMPLES[0] }
28- assert { LZ4.raw_decode(LZ4.raw_encode(SAMPLES[2])) == SAMPLES[2] }
29- assert { LZ4.raw_decode(LZ4.raw_encode(SAMPLES[3])) == SAMPLES[3] }
30- assert { LZ4.raw_decode(LZ4.raw_encode(SAMPLES[4])) == SAMPLES[4] }
31- assert { LZ4.raw_decode(LZ4.raw_encode(SAMPLES[5])) == SAMPLES[5] }
32- assert { LZ4.raw_decode(LZ4.raw_encode(SAMPLES[6])) == SAMPLES[6] }
33- assert { LZ4.raw_decode(LZ4.raw_encode(SAMPLES[7])) == SAMPLES[7] } if SAMPLES.size > 7
34- assert { LZ4.raw_decode(LZ4.raw_encode(SAMPLES[8])) == SAMPLES[8] } if SAMPLES.size > 8
31+ def test_block_encode_invalid_args
32+ src = SAMPLES["\\0 (small size)"]
33+ buf = ""
34+ assert_raise(ArgumentError) { LZ4.block_encode } # no arguments
35+ assert_raise(ArgumentError) { LZ4.block_encode(-1, src) } # wrong level
36+ assert_raise(TypeError) { LZ4.block_encode(100) } # source is not string
37+ assert_raise(TypeError) { LZ4.block_encode(nil) } # source is not string
38+ assert_raise(TypeError) { LZ4.block_encode(:bad_input) } # source is not string
39+ assert_raise(TypeError) { LZ4.block_encode(/bad-input/) } # source is not string
40+ assert_raise(RuntimeError) { LZ4.block_encode(src, "bad-destbuf".freeze) } # can't modify frozen String
41+ assert_raise(LZ4::Error) { LZ4.block_encode(src, 1) } # maxdest is too small
42+ assert_raise(LZ4::Error) { LZ4.block_encode(src, 1, buf) } # maxdest is too small
43+ assert_raise(TypeError) { LZ4.block_encode(src, "bad-maxsize", "a") } # "bad-maxsize" is not integer
3544 end
45+
46+ def test_block_decode
47+ src = LZ4.block_encode(SAMPLES["\\0 (small size)"])
48+ buf = ""
49+ assert_kind_of(String, LZ4.block_decode(src))
50+ assert_kind_of(String, LZ4.block_decode(src, 1000))
51+ assert_same(buf, LZ4.block_decode(src, buf))
52+ assert_same(buf, LZ4.block_decode(src, 1000, buf))
53+ end
54+
55+ def test_block_decode_invalid_args
56+ src = LZ4.block_encode(SAMPLES["\\0 (small size)"])
57+ buf = ""
58+ assert_raise(ArgumentError) { LZ4.block_decode } # no arguments
59+ assert_raise(TypeError) { LZ4.block_decode(-1, src) } # do not given level
60+ assert_raise(TypeError) { LZ4.block_decode(100) } # source is not string
61+ assert_raise(TypeError) { LZ4.block_decode(nil) } # source is not string
62+ assert_raise(TypeError) { LZ4.block_decode(:bad_input) } # source is not string
63+ assert_raise(TypeError) { LZ4.block_decode(/bad-input/) } # source is not string
64+ assert_raise(RuntimeError) { LZ4.block_decode(src, "bad-destbuf".freeze) } # can't modify frozen String
65+ assert_raise(TypeError) { LZ4.block_decode(src, "bad-maxsize", "a") } # "bad-maxsize" is not integer
66+
67+ src2 = SAMPLES["\\xaa (small size)"]
68+ assert_raise(LZ4::Error) { LZ4.block_decode(src2) } # encounted invalid end of sequence
69+ assert_raise(LZ4::Error) { LZ4.block_decode(src2, 100000) } # max_dest_size is too small, or data is corrupted
70+ end
3671 end
--- trunk/extlz4/test/test_frameapi.rb (revision 70)
+++ trunk/extlz4/test/test_frameapi.rb (revision 71)
@@ -1,66 +1,60 @@
11 #!ruby
22
3+=begin
34 # 必要と思われる試験項目
4-#
5-# * frameapi の圧縮処理
6-# * LZ4.encode
7-# * LZ4.decode で伸長できるか
8-# * lz4-cli で伸長できるか
9-# * 汚染状態の伝搬
10-# * security level
11-# * LZ4.encode_file
12-# * LZ4.decode_file で伸長できるか
13-# * lz4-cli で伸長できるか
14-# * frameapi の伸長処理
15-# * LZ4.decode
16-# * LZ4.decode_file
17-# * LZ4.test_file
18-#
19-# * 試験で用いる試料
20-# * /usr/ports/INDEX-10
21-# * /boot/kernel/kernel
22-# * 長さ 0 の空データ
23-# * 0 で埋められた小さなデータ
24-# * 0 で埋められたでかいデータ
25-# * 0xaa で埋められた小さなデータ
26-# * 0xaa で埋められたでかいデータ
27-# * /dev/random (4000 bytes)
28-# * /dev/random (12000000 bytes)
29-# * 可能であれば数十 GB レベルのファイル
305
6+* LZ4.encode
7+ * LZ4.decode で伸長できるか
8+ * lz4-cli で伸長できるか
9+ * 汚染状態の伝搬
10+ * security level
11+* LZ4.encode_file
12+ * LZ4.decode_file で伸長できるか
13+ * lz4-cli で伸長できるか
14+* LZ4.decode
15+* LZ4.decode_file
16+* LZ4.test_file
17+
18+* 試験で用いる試料
19+ * /usr/ports/INDEX-10
20+ * /boot/kernel/kernel
21+ * 長さ 0 の空データ
22+ * 0 で埋められた小さなデータ
23+ * 0 で埋められたでかいデータ
24+ * 0xaa で埋められた小さなデータ
25+ * 0xaa で埋められたでかいデータ
26+ * /dev/random (4000 bytes)
27+ * /dev/random (12000000 bytes)
28+ * 可能であれば数十 GB レベルのファイル
29+=end
30+
3131 require "test-unit"
32+require "openssl" # for OpenSSL::Random.random_bytes
3233 require "extlz4"
33-require "openssl" # for OpenSSL::Random.random_bytes
34-#require "zlib" # for Zlib.crc32
3534
36-SMALLSIZE = 400
37-BIGSIZE = 12000000
35+require_relative "sampledata"
3836
39-SAMPLES = [
40- "",
41- "\0".b * SMALLSIZE,
42- "\0".b * BIGSIZE,
43- "\xaa".b * SMALLSIZE,
44- "\xaa".b * BIGSIZE,
45- OpenSSL::Random.random_bytes(SMALLSIZE),
46- OpenSSL::Random.random_bytes(BIGSIZE),
47-]
37+class TestFrameAPI < Test::Unit::TestCase
38+ SAMPLES.each_pair do |name, data|
39+ define_method("test_encode_decode_sample:#{name}", -> {
40+ assert(data, LZ4.decode(LZ4.encode(data)))
41+ })
42+ end
4843
49-SAMPLES << File.read("/usr/ports/INDEX-10", mode: "rb") rescue nil # if on FreeBSD
50-SAMPLES << File.read("/boot/kernel/kernel", mode: "rb") rescue nil # if on FreeBSD
44+ def test_encode_args
45+ assert_kind_of(LZ4::Encoder, LZ4.encode)
46+ assert_kind_of(LZ4::Encoder, LZ4.encode(StringIO.new("")))
47+ assert_kind_of(String, LZ4.encode {})
48+ io = StringIO.new("")
49+ assert_same(io, LZ4.encode(io) {})
50+ assert_kind_of(LZ4::Encoder, LZ4.encode(io, 16))
51+ assert_kind_of(LZ4::Encoder, LZ4::Encoder.new)
52+ end
5153
52-$stderr.puts "%s:%d: prepaired sample data (%d samples)\n" % [__FILE__, __LINE__, SAMPLES.size]
53-
54-class TestFrameAPI < Test::Unit::TestCase
55- def test_encode_decode
56- assert { LZ4.decode(LZ4.encode(SAMPLES[0])) == SAMPLES[0] }
57- assert { LZ4.decode(LZ4.encode(SAMPLES[1])) == SAMPLES[1] }
58- assert { LZ4.decode(LZ4.encode(SAMPLES[2])) == SAMPLES[2] }
59- assert { LZ4.decode(LZ4.encode(SAMPLES[3])) == SAMPLES[3] }
60- assert { LZ4.decode(LZ4.encode(SAMPLES[4])) == SAMPLES[4] }
61- assert { LZ4.decode(LZ4.encode(SAMPLES[5])) == SAMPLES[5] }
62- assert { LZ4.decode(LZ4.encode(SAMPLES[6])) == SAMPLES[6] }
63- assert { LZ4.decode(LZ4.encode(SAMPLES[7])) == SAMPLES[7] } if SAMPLES.size > 7
64- assert { LZ4.decode(LZ4.encode(SAMPLES[8])) == SAMPLES[8] } if SAMPLES.size > 8
54+ def test_decode_args
55+ assert_raise(ArgumentError) { LZ4.decode }
56+ assert_raise(NoMethodError) { LZ4.decode(nil) } # undefined method `read' for nil:NilClass
57+ assert_raise(LZ4::Error) { LZ4.decode("") } # read error (or already EOF)
58+ assert_raise(ArgumentError) { LZ4.decode(nil, nil) } # wrong number of arguments (2 for 1)
6559 end
6660 end
--- trunk/extlz4/ext/blockapi.c (revision 70)
+++ trunk/extlz4/ext/blockapi.c (revision 71)
@@ -2,7 +2,11 @@
22 #include <lz4.h>
33 #include <lz4hc.h>
44
5-#if __GNUC__ || __clang__
5+#define RDOCFAKE(code)
6+
7+RDOCFAKE(mLZ4 = rb_define_module("LZ4"));
8+
9+#if __GNUC__ || __clang__ || EXTLZ4_FORCE_EXPECT
610 #define AUX_LIKELY(x) __builtin_expect(!!(x), 1)
711 #define AUX_UNLIKELY(x) __builtin_expect(!!(x), 0)
812 #else
@@ -10,50 +14,63 @@
1014 #define AUX_UNLIKELY(x) (x)
1115 #endif
1216
13-static inline const char *
14-aux_lz4_expandsize(const char *p, const char *end, size_t *size)
17+static inline size_t
18+aux_lz4_expandsize(const char **p, const char *end, size_t size)
1519 {
16- while (AUX_LIKELY(p < end)) {
17- int s = (uint8_t)*p ++;
18- *size += s;
19- if (AUX_LIKELY(s != 255)) { return p; }
20+ while (AUX_LIKELY(*p < end)) {
21+ int s = (uint8_t)*(*p) ++;
22+ size += s;
23+ if (AUX_LIKELY(s != 255)) {
24+ return size;
25+ }
2026 }
2127
2228 rb_raise(eError, "encounted invalid end of sequence");
2329 }
2430
25-static inline const char *
26-aux_lz4_scanseq(const char *p, const char *end, size_t *size)
31+static inline size_t
32+aux_lz4_scanseq(const char *p, const char *end, size_t *linksize)
2733 {
34+ size_t size = 0;
2835 while (AUX_LIKELY(p < end)) {
2936 uint8_t token = (uint8_t)*p ++;
3037 size_t s = token >> 4;
3138 if (AUX_LIKELY(s == 15)) {
32- p = aux_lz4_expandsize(p, end, &s);
39+ s = aux_lz4_expandsize(&p, end, s);
3340 }
34- *size += s;
41+ size += s;
3542 p += s;
3643
37- s = token & 0x0f;
38- if (AUX_UNLIKELY(s == 0 && p == end)) {
39- return p;
40- }
41-
4244 if (AUX_UNLIKELY(p + 2 >= end)) {
45+ if (p == end) {
46+#if 0
47+ s = token & 0x0f;
48+ if (s != 0) {
49+ // TODO: raise? or do nothing?
50+ }
51+#endif
52+ return size;
53+ }
4354 break;
4455 }
4556 size_t offset = (uint8_t)*p ++;
4657 offset |= ((size_t)((uint8_t)*p ++)) << 8;
58+ if (linksize) {
59+ ssize_t n = offset - size;
60+ if (AUX_UNLIKELY(n > 0 && n > (ssize_t)*linksize)) {
61+ *linksize = n;
62+ }
63+ }
4764 #if 0
4865 if (AUX_UNLIKELY(offset == 0)) {
4966 rb_raise(eError, "offset is zero");
5067 }
5168 #endif
69+ s = token & 0x0f;
5270 if (AUX_LIKELY(s == 15)) {
53- p = aux_lz4_expandsize(p, end, &s);
71+ s = aux_lz4_expandsize(&p, end, s);
5472 }
55- s += 4;
56- *size += s;
73+ size += s + 4;
5774 }
5875
5976 rb_raise(eError, "encounted invalid end of sequence");
@@ -67,13 +84,31 @@
6784 static size_t
6885 aux_lz4_scansize(VALUE str)
6986 {
70- const char *p = RSTRING_PTR(str);
71- const char *end = p + RSTRING_LEN(str);
87+ const char *p;
88+ size_t size;
89+ RSTRING_GETMEM(str, p, size);
7290
73- size_t total = 0;
74- aux_lz4_scanseq(p, end, &total);
91+ return aux_lz4_scanseq(p, p + size, NULL);
92+}
7593
76- return total;
94+/*
95+ * offset トークンがバッファの負の数を表しているか確認する。
96+ *
97+ * 戻り値はその最大距離を返す (負の数として見るならば最小値だが、絶対値に変換する)。
98+ *
99+ * 名称の link は LZ4 frame からとった。
100+ */
101+static size_t
102+aux_lz4_linksize(VALUE str)
103+{
104+ const char *p;
105+ size_t size;
106+ RSTRING_GETMEM(str, p, size);
107+
108+ size_t linksize = 0;
109+ aux_lz4_scanseq(p, p + size, &linksize);
110+
111+ return linksize;
77112 }
78113
79114 static inline VALUE
@@ -83,25 +118,6 @@
83118 return obj;
84119 }
85120
86-/*
87- * Check the object and security
88- *
89- * - $SAFE < 3: Pass always
90- * - $SAFE >= 3: Pass if all arguments, otherwise prevention
91- */
92-static inline void
93-check_security(VALUE processor, VALUE src, VALUE dest)
94-{
95- if (rb_safe_level() < 3 ||
96- ((NIL_P(processor) || OBJ_TAINTED(processor)) &&
97- OBJ_TAINTED(src) && OBJ_TAINTED(dest))) {
98-
99- return;
100- }
101-
102- rb_insecure_operation();
103-}
104-
105121 static inline size_t
106122 aux_lz4_compressbound(VALUE src)
107123 {
@@ -108,35 +124,31 @@
108124 return LZ4_compressBound(RSTRING_LEN(src));
109125 }
110126
111-/*
112- * call-seq:
113- * compressbound(src) -> size
114- *
115- * Calcuration maximum size of encoded data in worst case.
116- */
117-static VALUE
118-rawenc_s_compressbound(VALUE mod, VALUE src)
127+enum {
128+ MAX_PREDICT_SIZE = 65536,
129+};
130+
131+static inline VALUE
132+make_predict(VALUE predict)
119133 {
120- return SIZET2NUM(aux_lz4_compressbound(src));
121-}
134+ if (NIL_P(predict)) {
135+ return Qnil;
136+ }
122137
123-/*
124- * call-seq:
125- * scansize(lz4_rawencoded_data) -> integer
126- *
127- * Scan raw lz4 data, and get decoded byte size.
128- *
129- * このメソッドは、raw_decode メソッドに max_dest_size なしで利用する場合の検証目的で利用できるようにしてあります。
130- *
131- * その他の有用な使い方があるのかは不明です。
132- */
133-static VALUE
134-rawdec_s_scansize(VALUE mod, VALUE str)
135-{
136- Check_Type(str, RUBY_T_STRING);
137- return SIZET2NUM(aux_lz4_scansize(str));
138+ rb_check_type(predict, RUBY_T_STRING);
139+ size_t size = RSTRING_LEN(predict);
140+ if (size == 0) {
141+ return Qnil;
142+ }
143+ if (size > MAX_PREDICT_SIZE) {
144+ predict = rb_str_subseq(predict, size - MAX_PREDICT_SIZE, MAX_PREDICT_SIZE);
145+ } else {
146+ predict = rb_str_dup(predict);
147+ }
148+ return rb_str_freeze(predict);
138149 }
139150
151+
140152 /*
141153 * calculate destination size from source data
142154 */
@@ -143,7 +155,7 @@
143155 typedef size_t aux_calc_destsize_f(VALUE src);
144156
145157 static inline void
146-rawprocess_args(int argc, VALUE argv[], VALUE *src, VALUE *dest, size_t *maxsize, int *level, aux_calc_destsize_f *calcsize)
158+blockprocess_args(int argc, VALUE argv[], VALUE *src, VALUE *dest, size_t *maxsize, int *level, aux_calc_destsize_f *calcsize)
147159 {
148160 const VALUE *argend = argv + argc;
149161 VALUE tmp;
@@ -194,149 +206,29 @@
194206 rb_error_arity(argc, 1, (level ? 4 : 3));
195207 }
196208
197-/***********/
198-
199-typedef int aux_lz4_encoder_f(const char *src, char *dest, int srcsize, int maxsize, int level);
200-
201-static int
202-aux_LZ4_compress_limitedOutput(const char *src, char *dest, int srcsize, int maxsize, int level)
203-{
204- return LZ4_compress_limitedOutput(src, dest, srcsize, maxsize);
205-}
206-
207209 /*
208- * call-seq:
209- * encode(src) -> compressed string data
210- * encode(src, max_dest_size) -> compressed string data
211- * encode(src, dest) -> dest with compressed string data
212- * encode(src, max_dest_size, dest) -> dest with compressed string data
213- * encode(level, src) -> compressed string data
214- * encode(level, src, max_dest_size) -> compressed string data
215- * encode(level, src, dest) -> dest with compressed string data
216- * encode(level, src, max_dest_size, dest) -> dest with compressed string data
210+ * Document-class: LZ4::BlockEncoder
217211 *
218- * Encode to raw LZ4 data.
219- *
220- * level を指定した場合、より圧縮処理に時間を掛けて圧縮効率を高めることが出来ます。
221- *
222- * 実装の都合上、圧縮関数は LZ4_compress_limitedOutput / LZ4_compressHC2_limitedOutput が使われます。
223- *
224- * [RETURN]
225- * 圧縮されたデータが文字列として返ります。dest を指定した場合は、圧縮データを格納した dest を返します。
226- *
227- * 圧縮データには自身の終わりやデータ長が含まれていないため、伸張する際には余計なデータが付随していると正常に伸張できません。
228- *
229- * [src]
230- * 圧縮対象となる文字列オブジェクトを指定します。
231- *
232- * [max_dest_size]
233- * 出力バッファの最大バイト数を指定します。圧縮時にこれよりも多くのバッファ長が必要になった場合は例外が発生します。
234- *
235- * 省略時は src 長から最悪値が計算されます。dest が最初に確保できれば圧縮処理中に例外が発生することがありません。
236- *
237- * [dest]
238- * 出力先とする文字列オブジェクトを指定します。
239- *
240- * max_dest_size が同時に指定されない場合、出力バッファの最大バイト長は src 長から最悪値が求められて調整されます。
241- *
242- * [level]
243- * 圧縮レベルとして 0 から 16 までの整数で指定すると、高効率圧縮処理が行われます。
244- *
245- * 0 を指定した場合、LZ4 の規定値による高効率圧縮処理が行われます。
246- *
247- * nil を与えるか省略した場合、通常の圧縮処理が行われます。
212+ * このクラスは LZ4 Block API を扱うためのものです。
248213 */
249-static VALUE
250-rawenc_s_encode(int argc, VALUE argv[], VALUE lz4)
251-{
252- VALUE src, dest;
253- size_t maxsize;
254- int level;
255- rawprocess_args(argc, argv, &src, &dest, &maxsize, &level, aux_lz4_compressbound);
256- check_security(Qnil, src, dest);
257214
258- aux_lz4_encoder_f *encoder;
259- if (level < 0) {
260- encoder = aux_LZ4_compress_limitedOutput;
261- } else {
262- encoder = LZ4_compressHC2_limitedOutput;
263- }
215+typedef void blockencoder_reset_f(void *context, int level);
216+typedef void *blockencoder_create_f(int level);
217+typedef int blockencoder_free_f(void *context);
218+typedef int blockencoder_loaddict_f(void *context, const char *dict, int dictsize);
219+typedef int blockencoder_savedict_f(void *context, char *dict, int dictsize);
220+typedef int blockencoder_update_f(void *context, const char *src, char *dest, int srcsize, int destsize);
221+typedef int blockencoder_update_unlinked_f(void *context, const char *src, char *dest, int srcsize, int destsize);
264222
265- size_t srcsize = RSTRING_LEN(src);
266- if (srcsize > LZ4_MAX_INPUT_SIZE) {
267- rb_raise(eError,
268- "source size is too big for lz4 encode (given %zu, but max %zu bytes)",
269- srcsize, (size_t)LZ4_MAX_INPUT_SIZE);
270- }
271- aux_str_reserve(dest, maxsize);
272- rb_str_set_len(dest, 0);
273- rb_obj_infect(dest, src);
274-
275- int size = encoder(RSTRING_PTR(src), RSTRING_PTR(dest), srcsize, maxsize, level);
276- if (size <= 0) {
277- rb_raise(eError,
278- "failed LZ4 compress - maxsize is too small, or out of memory");
279- }
280-
281- rb_str_set_len(dest, size);
282-
283- return dest;
284-}
285-
286-/*
287- * call-seq:
288- * decode(src) -> decoded string data
289- * decode(src, max_dest_size) -> decoded string data
290- * decode(src, dest) -> dest with decoded string data
291- * decode(src, max_dest_size, dest) -> dest with decoded string data
292- *
293- * Decode raw LZ4 data.
294- *
295- * 出力先は、max_dest_size が与えられていない場合、必要に応じて自動的に拡張されます。
296- * この場合、いったん圧縮された LZ4 データを走査するため、事前に僅かな CPU 時間を必要とします。
297- */
298-static VALUE
299-rawdec_s_decode(int argc, VALUE argv[], VALUE lz4)
223+struct blockencoder_traits
300224 {
301- VALUE src, dest;
302- size_t maxsize;
303- rawprocess_args(argc, argv, &src, &dest, &maxsize, NULL, aux_lz4_scansize);
304- check_security(Qnil, src, dest);
305-
306- aux_str_reserve(dest, maxsize);
307- rb_str_set_len(dest, 0);
308- rb_obj_infect(dest, src);
309-
310- int size = LZ4_decompress_safe(RSTRING_PTR(src), RSTRING_PTR(dest), RSTRING_LEN(src), maxsize);
311- if (size < 0) {
312- rb_raise(eError,
313- "failed LZ4_decompress_safe - max_dest_size is too small, or data is corrupted");
314- }
315-
316- rb_str_set_len(dest, size);
317-
318- return dest;
319-}
320-
321-/***********/
322-
323-typedef void rawencoder_reset_f(void *context, int level);
324-typedef void *rawencoder_create_f(int level);
325-typedef int rawencoder_free_f(void *context);
326-typedef int rawencoder_loaddict_f(void *context, const char *dict, int dictsize);
327-typedef int rawencoder_savedict_f(void *context, char *dict, int dictsize);
328-typedef int rawencoder_update_f(void *context, const char *src, char *dest, int srcsize, int destsize);
329-typedef int rawencoder_update_unlinked_f(void *context, const char *src, char *dest, int srcsize, int destsize);
330-
331-struct rawencoder_traits
332-{
333- rawencoder_reset_f *reset;
334- rawencoder_create_f *create;
335- rawencoder_free_f *free;
336- rawencoder_loaddict_f *loaddict;
337- rawencoder_savedict_f *savedict;
338- rawencoder_update_f *update;
339- rawencoder_update_unlinked_f *update_unlinked;
225+ blockencoder_reset_f *reset;
226+ blockencoder_create_f *create;
227+ blockencoder_free_f *free;
228+ blockencoder_loaddict_f *loaddict;
229+ blockencoder_savedict_f *savedict;
230+ blockencoder_update_f *update;
231+ blockencoder_update_unlinked_f *update_unlinked;
340232 };
341233
342234 static void
@@ -346,60 +238,50 @@
346238 LZ4_resetStream(context);
347239 }
348240
349-static const struct rawencoder_traits rawencoder_traits_std = {
350- .reset = (rawencoder_reset_f *)aux_LZ4_resetStream,
351- .create = (rawencoder_create_f *)LZ4_createStream,
352- .free = (rawencoder_free_f *)LZ4_freeStream,
353- .loaddict = (rawencoder_loaddict_f *)LZ4_loadDict,
354- .savedict = (rawencoder_savedict_f *)LZ4_saveDict,
355- .update = (rawencoder_update_f *)LZ4_compress_limitedOutput_continue,
356- .update_unlinked = (rawencoder_update_f *)LZ4_compress_limitedOutput_withState,
241+static const struct blockencoder_traits blockencoder_traits_std = {
242+ .reset = (blockencoder_reset_f *)aux_LZ4_resetStream,
243+ .create = (blockencoder_create_f *)LZ4_createStream,
244+ .free = (blockencoder_free_f *)LZ4_freeStream,
245+ .loaddict = (blockencoder_loaddict_f *)LZ4_loadDict,
246+ .savedict = (blockencoder_savedict_f *)LZ4_saveDict,
247+ .update = (blockencoder_update_f *)LZ4_compress_limitedOutput_continue,
248+ .update_unlinked = (blockencoder_update_f *)LZ4_compress_limitedOutput_withState,
357249 };
358250
359-static const struct rawencoder_traits rawencoder_traits_hc = {
360- .reset = (rawencoder_reset_f *)LZ4_resetStreamHC,
361- .create = (rawencoder_create_f *)LZ4_createStreamHC,
362- .free = (rawencoder_free_f *)LZ4_freeStreamHC,
363- .loaddict = (rawencoder_loaddict_f *)LZ4_loadDictHC,
364- .savedict = (rawencoder_savedict_f *)LZ4_saveDictHC,
365- .update = (rawencoder_update_f *)LZ4_compressHC_limitedOutput_continue,
366- .update_unlinked = (rawencoder_update_f *)LZ4_compressHC_limitedOutput_withStateHC,
251+static const struct blockencoder_traits blockencoder_traits_hc = {
252+ .reset = (blockencoder_reset_f *)LZ4_resetStreamHC,
253+ .create = (blockencoder_create_f *)LZ4_createStreamHC,
254+ .free = (blockencoder_free_f *)LZ4_freeStreamHC,
255+ .loaddict = (blockencoder_loaddict_f *)LZ4_loadDictHC,
256+ .savedict = (blockencoder_savedict_f *)LZ4_saveDictHC,
257+ .update = (blockencoder_update_f *)LZ4_compressHC_limitedOutput_continue,
258+ .update_unlinked = (blockencoder_update_f *)LZ4_compressHC_limitedOutput_withStateHC,
367259 };
368260
369-struct rawencoder
261+struct blockencoder
370262 {
371263 void *context;
372- const struct rawencoder_traits *traits;
264+ const struct blockencoder_traits *traits;
373265 VALUE predict;
266+ int level;
374267 int prefixsize;
375- char prefix[1 + (1 << 16)]; /* 64 KiB; LZ4_loadDict, LZ4_saveDict */
376-
377-////////
378-// VALUE predict; /* preset-dictionary (used when next reset) */
379-// VALUE buffer; /* entity of input buffer */
380-// char *inoff; /* current offset of buffer */
381-// const char *intail; /* end offset of buffer */
382-// void *lz4; /* lz4 stream context */
383-// size_t blocksize; /* stream block size (maximum size) */
384-// struct rawencoder_traits *traits;
385-// VALUE ishc; /* false: not hc / true: hc */
386-////////
268+ char prefix[1 << 16]; /* 64 KiB; LZ4_loadDict, LZ4_saveDict */
387269 };
388270
389271 static void
390-rawenc_mark(void *pp)
272+blkenc_mark(void *pp)
391273 {
392274 if (pp) {
393- struct rawencoder *p = pp;
275+ struct blockencoder *p = pp;
394276 rb_gc_mark(p->predict);
395277 }
396278 }
397279
398280 static void
399-rawenc_free(void *pp)
281+blkenc_free(void *pp)
400282 {
401283 if (pp) {
402- struct rawencoder *p = pp;
284+ struct blockencoder *p = pp;
403285 if (p->context && p->traits) {
404286 p->traits->free(p->context);
405287 }
@@ -408,36 +290,36 @@
408290 }
409291 }
410292
411-static const rb_data_type_t rawencoder_type = {
412- .wrap_struct_name = "extlz4.LZ4.RawEncoder",
413- .function.dmark = rawenc_mark,
414- .function.dfree = rawenc_free,
415- /* .function.dsize = rawenc_size, */
293+static const rb_data_type_t blockencoder_type = {
294+ .wrap_struct_name = "extlz4.LZ4.BlockEncoder",
295+ .function.dmark = blkenc_mark,
296+ .function.dfree = blkenc_free,
297+ /* .function.dsize = blkenc_size, */
416298 };
417299
418300 static VALUE
419-rawenc_alloc(VALUE klass)
301+blkenc_alloc(VALUE klass)
420302 {
421- struct rawencoder *p;
422- VALUE v = TypedData_Make_Struct(klass, struct rawencoder, &rawencoder_type, p);
303+ struct blockencoder *p;
304+ VALUE v = TypedData_Make_Struct(klass, struct blockencoder, &blockencoder_type, p);
423305 p->predict = Qnil;
424306 return v;
425307 }
426308
427-static inline struct rawencoder *
309+static inline struct blockencoder *
428310 getencoderp(VALUE enc)
429311 {
430- return getrefp(enc, &rawencoder_type);
312+ return getrefp(enc, &blockencoder_type);
431313 }
432314
433-static inline struct rawencoder *
315+static inline struct blockencoder *
434316 getencoder(VALUE enc)
435317 {
436- return getref(enc, &rawencoder_type);
318+ return getref(enc, &blockencoder_type);
437319 }
438320
439321 static inline void
440-rawenc_setup(int argc, VALUE argv[], int *level, struct rawencoder *p)
322+blkenc_setup(int argc, VALUE argv[], struct blockencoder *p)
441323 {
442324 if (p->context) {
443325 void *cx = p->context;
@@ -449,25 +331,23 @@
449331 rb_scan_args(argc, argv, "02", &level1, &p->predict);
450332
451333 if (NIL_P(level1)) {
452- *level = -1;
453- p->traits = &rawencoder_traits_std;
334+ p->level = -1;
335+ p->traits = &blockencoder_traits_std;
454336 } else {
455- *level = NUM2UINT(level1);
456- p->traits = &rawencoder_traits_hc;
337+ p->level = NUM2UINT(level1);
338+ p->traits = &blockencoder_traits_hc;
457339 }
458340
459341 if (argc < 2) {
460342 p->predict = Qundef;
461343 } else {
462- if (!NIL_P(p->predict)) {
463- rb_check_type(p->predict, RUBY_T_STRING);
464- }
344+ p->predict = make_predict(p->predict);
465345 }
466346
467- p->context = p->traits->create(*level);
347+ p->context = p->traits->create(p->level);
468348 if (!p->context) {
469349 rb_gc();
470- p->context = p->traits->create(*level);
350+ p->context = p->traits->create(p->level);
471351 if (!p->context) {
472352 errno = ENOMEM;
473353 rb_sys_fail("failed context allocation by LZ4_createStream()");
@@ -479,6 +359,9 @@
479359 * call-seq:
480360 * initialize(level = nil, predict = nil)
481361 *
362+ * [INFECTION]
363+ * +self+ < +predict+
364+ *
482365 * [RETURN]
483366 * self
484367 *
@@ -488,12 +371,12 @@
488371 * When given +0+ .. +15+, encode high compression.
489372 *
490373 * [predict]
491- * Pre load dictionary.
374+ * Preset dictionary.
492375 */
493376 static VALUE
494-rawenc_init(int argc, VALUE argv[], VALUE enc)
377+blkenc_init(int argc, VALUE argv[], VALUE enc)
495378 {
496- struct rawencoder *p = getencoder(enc);
379+ struct blockencoder *p = getencoder(enc);
497380 if (p->context) {
498381 rb_raise(eError,
499382 "already initialized - #<%s:%p>",
@@ -500,8 +383,7 @@
500383 rb_obj_classname(enc), (void *)enc);
501384 }
502385
503- int level;
504- rawenc_setup(argc, argv, &level, p);
386+ blkenc_setup(argc, argv, p);
505387 p->prefixsize = p->traits->savedict(p->context, p->prefix, sizeof(p->prefix));
506388 if (p->predict == Qundef) {
507389 p->predict = Qnil;
@@ -513,16 +395,20 @@
513395 }
514396
515397 /*
516- * update(src [, max_dest_size] [, dest]) -> dest
398+ * call-seq:
399+ * update(src, dest = "") -> dest
400+ * update(src, max_dest_size, dest = "") -> dest
401+ *
402+ * [INFECTION]
403+ * +dest+ < +self+ < +src+
517404 */
518405 static VALUE
519-rawenc_update(int argc, VALUE argv[], VALUE enc)
406+blkenc_update(int argc, VALUE argv[], VALUE enc)
520407 {
521- struct rawencoder *p = getencoder(enc);
408+ struct blockencoder *p = getencoder(enc);
522409 VALUE src, dest;
523410 size_t maxsize;
524- rawprocess_args(argc, argv, &src, &dest, &maxsize, NULL, aux_lz4_compressbound);
525- check_security(enc, src, dest);
411+ blockprocess_args(argc, argv, &src, &dest, &maxsize, NULL, aux_lz4_compressbound);
526412 rb_obj_infect(enc, src);
527413 rb_obj_infect(dest, enc);
528414 char *srcp;
@@ -535,7 +421,6 @@
535421 rb_str_capacity(dest));
536422 }
537423 p->prefixsize = p->traits->savedict(p->context, p->prefix, sizeof(p->prefix));
538-//fprintf(stderr, "%s:%d:%s: rawencoder.prefixsize=%d\n", __FILE__, __LINE__, __func__, p->prefixsize);
539424 rb_str_set_len(dest, s);
540425 return dest;
541426 }
@@ -545,12 +430,15 @@
545430 * reset(level = nil) -> self
546431 * reset(level, predict) -> self
547432 *
548- * Reset raw stream encoder.
433+ * [INFECTION]
434+ * +self+ < +predict+
435+ *
436+ * Reset block stream encoder.
549437 */
550438 static VALUE
551-rawenc_reset(int argc, VALUE argv[], VALUE enc)
439+blkenc_reset(int argc, VALUE argv[], VALUE enc)
552440 {
553- struct rawencoder *p = getencoder(enc);
441+ struct blockencoder *p = getencoder(enc);
554442 if (!p->context) {
555443 rb_raise(eError,
556444 "not initialized yet - #<%s:%p>",
@@ -558,8 +446,7 @@
558446 }
559447
560448 VALUE predict = p->predict;
561- int level;
562- rawenc_setup(argc, argv, &level, p);
449+ blkenc_setup(argc, argv, p);
563450 if (p->predict == Qundef) {
564451 p->predict = predict;
565452 }
@@ -572,9 +459,9 @@
572459 }
573460
574461 static VALUE
575-rawenc_release(VALUE enc)
462+blkenc_release(VALUE enc)
576463 {
577- struct rawencoder *p = getencoder(enc);
464+ struct blockencoder *p = getencoder(enc);
578465 if (p->traits && p->context) {
579466 p->traits->free(p->context);
580467 }
@@ -585,32 +472,173 @@
585472 return Qnil;
586473 }
587474
475+static VALUE
476+blkenc_predict(VALUE enc)
477+{
478+ return getencoder(enc)->predict;
479+}
480+
481+static VALUE
482+blkenc_inspect(VALUE enc)
483+{
484+ struct blockencoder *p = getencoderp(enc);
485+ if (p && p->context) {
486+ if (p->level < 0) {
487+ return rb_sprintf("#<%s:%p (fast compression)%s>",
488+ rb_obj_classname(enc), (void *)enc,
489+ (NIL_P(p->predict)) ? "" : " (with predict)");
490+ } else {
491+ return rb_sprintf("#<%s:%p (high compression %d)%s>",
492+ rb_obj_classname(enc), (void *)enc, p->level,
493+ (NIL_P(p->predict)) ? "" : " (with predict)");
494+ }
495+ } else {
496+ return rb_sprintf("#<%s:%p **NOT INITIALIZED**>",
497+ rb_obj_classname(enc), (void *)enc);
498+ }
499+}
500+
588501 /*
589- * class LZ4::RawDecoder
502+ * call-seq:
503+ * compressbound(src) -> size
504+ *
505+ * Calcuration maximum size of encoded data in worst case.
590506 */
507+static VALUE
508+blkenc_s_compressbound(VALUE mod, VALUE src)
509+{
510+ return SIZET2NUM(aux_lz4_compressbound(src));
511+}
591512
592-struct rawdecoder
513+typedef int aux_lz4_encoder_f(const char *src, char *dest, int srcsize, int maxsize, int level);
514+
515+static int
516+aux_LZ4_compress_limitedOutput(const char *src, char *dest, int srcsize, int maxsize, int level)
593517 {
518+ return LZ4_compress_limitedOutput(src, dest, srcsize, maxsize);
519+}
520+
521+/*
522+ * call-seq:
523+ * encode(src, dest = "") -> dest with compressed string data
524+ * encode(src, max_dest_size, dest = "") -> dest with compressed string data
525+ * encode(level, src, dest = "") -> dest with compressed string data
526+ * encode(level, src, max_dest_size, dest = "") -> dest with compressed string data
527+ *
528+ * Encode to block LZ4 data.
529+ *
530+ * level を指定した場合、より圧縮処理に時間を掛けて圧縮効率を高めることが出来ます。
531+ *
532+ * 実装の都合上、圧縮関数は LZ4_compress_limitedOutput / LZ4_compressHC2_limitedOutput が使われます。
533+ *
534+ * [INFECTION]
535+ * +dest+ < +src+
536+ *
537+ * [RETURN]
538+ * 圧縮されたデータが文字列として返ります。dest を指定した場合は、圧縮データを格納した dest を返します。
539+ *
540+ * 圧縮データには自身の終わりやデータ長が含まれていないため、伸張する際には余計なデータが付随していると正常に伸張できません。
541+ *
542+ * [src]
543+ * 圧縮対象となる文字列オブジェクトを指定します。
544+ *
545+ * [max_dest_size]
546+ * 出力バッファの最大バイト数を指定します。圧縮時にこれよりも多くのバッファ長が必要になった場合は例外が発生します。
547+ *
548+ * 省略時は src 長から最悪値が計算されます。dest が最初に確保できれば圧縮処理中に例外が発生することがありません。
549+ *
550+ * [dest]
551+ * 出力先とする文字列オブジェクトを指定します。
552+ *
553+ * max_dest_size が同時に指定されない場合、出力バッファの最大バイト長は src 長から最悪値が求められて調整されます。
554+ *
555+ * [level]
556+ * 圧縮レベルとして 0 から 16 までの整数で指定すると、高効率圧縮処理が行われます。
557+ *
558+ * 0 を指定した場合、LZ4 の規定値による高効率圧縮処理が行われます。
559+ *
560+ * nil を与えるか省略した場合、通常の圧縮処理が行われます。
561+ */
562+static VALUE
563+blkenc_s_encode(int argc, VALUE argv[], VALUE lz4)
564+{
565+ VALUE src, dest;
566+ size_t maxsize;
567+ int level;
568+ blockprocess_args(argc, argv, &src, &dest, &maxsize, &level, aux_lz4_compressbound);
569+
570+ aux_lz4_encoder_f *encoder;
571+ if (level < 0) {
572+ encoder = aux_LZ4_compress_limitedOutput;
573+ } else {
574+ encoder = LZ4_compressHC2_limitedOutput;
575+ }
576+
577+ size_t srcsize = RSTRING_LEN(src);
578+ if (srcsize > LZ4_MAX_INPUT_SIZE) {
579+ rb_raise(eError,
580+ "source size is too big for lz4 encode (given %zu, but max %zu bytes)",
581+ srcsize, (size_t)LZ4_MAX_INPUT_SIZE);
582+ }
583+ aux_str_reserve(dest, maxsize);
584+ rb_str_set_len(dest, 0);
585+ rb_obj_infect(dest, src);
586+
587+ int size = encoder(RSTRING_PTR(src), RSTRING_PTR(dest), srcsize, maxsize, level);
588+ if (size <= 0) {
589+ rb_raise(eError,
590+ "failed LZ4 compress - maxsize is too small, or out of memory");
591+ }
592+
593+ rb_str_set_len(dest, size);
594+
595+ return dest;
596+}
597+
598+static void
599+init_blockencoder(void)
600+{
601+ VALUE cBlockEncoder = rb_define_class_under(mLZ4, "BlockEncoder", rb_cObject);
602+ rb_define_alloc_func(cBlockEncoder, blkenc_alloc);
603+ rb_define_method(cBlockEncoder, "initialize", RUBY_METHOD_FUNC(blkenc_init), -1);
604+ rb_define_method(cBlockEncoder, "reset", RUBY_METHOD_FUNC(blkenc_reset), -1);
605+ rb_define_method(cBlockEncoder, "update", RUBY_METHOD_FUNC(blkenc_update), -1);
606+ rb_define_method(cBlockEncoder, "release", RUBY_METHOD_FUNC(blkenc_release), 0);
607+ rb_define_method(cBlockEncoder, "predict", RUBY_METHOD_FUNC(blkenc_predict), 0);
608+ rb_define_method(cBlockEncoder, "inspect", RUBY_METHOD_FUNC(blkenc_inspect), 0);
609+ rb_define_alias(cBlockEncoder, "encode", "update");
610+ rb_define_alias(cBlockEncoder, "compress", "update");
611+ rb_define_alias(cBlockEncoder, "free", "release");
612+
613+ rb_define_singleton_method(cBlockEncoder, "compressbound", blkenc_s_compressbound, 1);
614+ rb_define_singleton_method(cBlockEncoder, "encode", blkenc_s_encode, -1);
615+ rb_define_alias(rb_singleton_class(cBlockEncoder), "compress", "encode");
616+}
617+
618+/*
619+ * class LZ4::BlockDecoder
620+ */
621+
622+struct blockdecoder
623+{
594624 void *context;
595625 VALUE predict;
596- //int prefixsize;
597- //char prefix[1 + (1 << 16)]; /* 64 KiB; LZ4_loadDict, LZ4_saveDict */
598626 };
599627
600628 static void
601-rawdec_mark(void *pp)
629+blkdec_mark(void *pp)
602630 {
603631 if (pp) {
604- struct rawdecoder *p = pp;
632+ struct blockdecoder *p = pp;
605633 rb_gc_mark(p->predict);
606634 }
607635 }
608636
609637 static void
610-rawdec_free(void *pp)
638+blkdec_free(void *pp)
611639 {
612640 if (pp) {
613- struct rawdecoder *p = pp;
641+ struct blockdecoder *p = pp;
614642 if (p->context) {
615643 LZ4_freeStreamDecode(p->context);
616644 }
@@ -618,36 +646,36 @@
618646 }
619647 }
620648
621-static const rb_data_type_t rawdecoder_type = {
622- .wrap_struct_name = "extlz4.LZ4.RawDecoder",
623- .function.dmark = rawdec_mark,
624- .function.dfree = rawdec_free,
625- /* .function.dsize = rawdec_size, */
649+static const rb_data_type_t blockdecoder_type = {
650+ .wrap_struct_name = "extlz4.LZ4.BlockDecoder",
651+ .function.dmark = blkdec_mark,
652+ .function.dfree = blkdec_free,
653+ /* .function.dsize = blkdec_size, */
626654 };
627655
628656 static VALUE
629-rawdec_alloc(VALUE klass)
657+blkdec_alloc(VALUE klass)
630658 {
631- struct rawdecoder *p;
632- VALUE v = TypedData_Make_Struct(klass, struct rawdecoder, &rawdecoder_type, p);
659+ struct blockdecoder *p;
660+ VALUE v = TypedData_Make_Struct(klass, struct blockdecoder, &blockdecoder_type, p);
633661 p->predict = Qnil;
634662 return v;
635663 }
636664
637-static inline struct rawdecoder *
665+static inline struct blockdecoder *
638666 getdecoderp(VALUE dec)
639667 {
640- return getrefp(dec, &rawdecoder_type);
668+ return getrefp(dec, &blockdecoder_type);
641669 }
642670
643-static inline struct rawdecoder *
671+static inline struct blockdecoder *
644672 getdecoder(VALUE dec)
645673 {
646- return getref(dec, &rawdecoder_type);
674+ return getref(dec, &blockdecoder_type);
647675 }
648676
649677 static inline void
650-rawdec_setup(int argc, VALUE argv[], VALUE predict, struct rawdecoder *p)
678+blkdec_setup(int argc, VALUE argv[], VALUE predict, struct blockdecoder *p)
651679 {
652680 VALUE predict1;
653681 rb_scan_args(argc, argv, "01", &predict1);
@@ -677,10 +705,13 @@
677705 if (!NIL_P(predict)) {
678706 if (LZ4_setStreamDecode(p->context, RSTRING_PTR(predict), RSTRING_LEN(predict)) == 0) {
679707 rb_raise(eError,
680- "failed set preset dictionary - LZ4_setStreamDecode()");
708+ "failed LZ4_setStreamDecode() with preset dictionary");
681709 }
682710 } else {
683- LZ4_setStreamDecode(p->context, NULL, 0);
711+ if (LZ4_setStreamDecode(p->context, NULL, 0) == 0) {
712+ rb_raise(eError,
713+ "failed LZ4_setStreamDecode()");
714+ }
684715 }
685716 }
686717
@@ -688,13 +719,16 @@
688719 * call-seq:
689720 * initialize
690721 * initialize(preset_dictionary)
722+ *
723+ * [INFECTION]
724+ * +self+ < +preset_dictionary+
691725 */
692726 static VALUE
693-rawdec_init(int argc, VALUE argv[], VALUE dec)
727+blkdec_init(int argc, VALUE argv[], VALUE dec)
694728 {
695- struct rawdecoder *p = getdecoder(dec);
729+ struct blockdecoder *p = getdecoder(dec);
696730
697- rawdec_setup(argc, argv, Qnil, p);
731+ blkdec_setup(argc, argv, Qnil, p);
698732 rb_obj_infect(p->predict, dec);
699733
700734 return dec;
@@ -704,13 +738,16 @@
704738 * call-seq:
705739 * reset
706740 * reset(preset_dictionary)
741+ *
742+ * [INFECTION]
743+ * +self+ < +preset_dictionary+
707744 */
708745 static VALUE
709-rawdec_reset(int argc, VALUE argv[], VALUE dec)
746+blkdec_reset(int argc, VALUE argv[], VALUE dec)
710747 {
711- struct rawdecoder *p = getdecoder(dec);
748+ struct blockdecoder *p = getdecoder(dec);
712749
713- rawdec_setup(argc, argv, p->predict, p);
750+ blkdec_setup(argc, argv, p->predict, p);
714751 rb_obj_infect(p->predict, dec);
715752
716753 return dec;
@@ -718,31 +755,28 @@
718755
719756 /*
720757 * call-seq:
721- * update(src) -> decoded string data
722- * update(src, max_dest_size) -> decoded string data
723- * update(src, dest) -> dest for decoded string data
724- * update(src, max_dest_size, dest) -> dest for decoded string data
758+ * update(src, dest = "") -> dest for decoded string data
759+ * update(src, max_dest_size, dest = "") -> dest for decoded string data
725760 *
726- * Decode raw lz4 data of stream block.
761+ * Decode block lz4 data of stream block.
727762 *
728- * Given arguments and return values are same as LZ4#raw_decode.
729- * See LZ4#raw_decode for about its.
763+ * Given arguments and return values are same as LZ4#block_decode.
764+ * See LZ4#block_decode for about its.
730765 *
731766 * 出力先は、max_dest_size が与えられていない場合、必要に応じて自動的に拡張されます。
732767 * この場合、いったん圧縮された LZ4 データを走査するため、事前に僅かな CPU 時間を必要とします。
733768 *
734769 * [INFECTION]
735- * +src+ -> +self+ -> +dest+
770+ * +dest+ < +self+ < +src+
736771 */
737772 static VALUE
738-rawdec_update(int argc, VALUE argv[], VALUE dec)
773+blkdec_update(int argc, VALUE argv[], VALUE dec)
739774 {
740- struct rawdecoder *p = getdecoder(dec);
775+ struct blockdecoder *p = getdecoder(dec);
741776 if (!p->context) { rb_raise(eError, "need reset (context not initialized)"); }
742777 VALUE src, dest;
743778 size_t maxsize;
744- rawprocess_args(argc, argv, &src, &dest, &maxsize, NULL, aux_lz4_scansize);
745- check_security(dec, src, dest);
779+ blockprocess_args(argc, argv, &src, &dest, &maxsize, NULL, aux_lz4_scansize);
746780 rb_obj_infect(dec, src);
747781 rb_obj_infect(dest, dec);
748782 const char *srcp;
@@ -764,9 +798,9 @@
764798 * Release allocated internal heap memory.
765799 */
766800 static VALUE
767-rawdec_release(VALUE lz4)
801+blkdec_release(VALUE lz4)
768802 {
769- struct rawdecoder *p = getdecoderp(lz4);
803+ struct blockdecoder *p = getdecoderp(lz4);
770804 if (!p) { return Qnil; }
771805 if (p->context) {
772806 LZ4_freeStreamDecode(p->context);
@@ -778,36 +812,97 @@
778812 }
779813
780814 /*
781- * initializer rawapi.c
815+ * call-seq:
816+ * scansize(lz4_blockencoded_data) -> integer
817+ *
818+ * Scan block lz4 data, and get decoded byte size.
819+ *
820+ * このメソッドは、block_decode メソッドに max_dest_size なしで利用する場合の検証目的で利用できるようにしてあります。
821+ *
822+ * その他の有用な使い方があるのかは不明です。
782823 */
824+static VALUE
825+blkdec_s_scansize(VALUE mod, VALUE str)
826+{
827+ rb_check_type(str, RUBY_T_STRING);
828+ return SIZET2NUM(aux_lz4_scansize(str));
829+}
783830
784-void
785-extlz4_init_rawapi(void)
831+/*
832+ * call-seq:
833+ * linksize(lz4_blockencoded_data) -> prefix size as integer
834+ *
835+ * Scan block lz4 data, and get prefix byte size.
836+ */
837+static VALUE
838+blkdec_s_linksize(VALUE mod, VALUE str)
786839 {
787- VALUE cRawEncoder = rb_define_class_under(mLZ4, "RawEncoder", rb_cObject);
788- rb_define_singleton_method(cRawEncoder, "compressbound", rawenc_s_compressbound, 1);
789- rb_define_singleton_method(cRawEncoder, "encode", rawenc_s_encode, -1);
790- rb_define_alias(rb_singleton_class(cRawEncoder), "compress", "encode");
791- rb_define_alloc_func(cRawEncoder, rawenc_alloc);
792- rb_define_method(cRawEncoder, "initialize", RUBY_METHOD_FUNC(rawenc_init), -1);
793- rb_define_method(cRawEncoder, "reset", RUBY_METHOD_FUNC(rawenc_reset), -1);
794- rb_define_method(cRawEncoder, "update", RUBY_METHOD_FUNC(rawenc_update), -1);
795- rb_define_method(cRawEncoder, "release", RUBY_METHOD_FUNC(rawenc_release), 0);
796- rb_define_alias(cRawEncoder, "encode", "update");
797- rb_define_alias(cRawEncoder, "compress", "update");
798- rb_define_alias(cRawEncoder, "free", "release");
840+ rb_check_type(str, RUBY_T_STRING);
841+ return SIZET2NUM(aux_lz4_linksize(str));
842+}
799843
800- VALUE cRawDecoder = rb_define_class_under(mLZ4, "RawDecoder", rb_cObject);
801- rb_define_singleton_method(cRawDecoder, "scansize", rawdec_s_scansize, 1);
802- rb_define_singleton_method(cRawDecoder, "decode", rawdec_s_decode, -1);
803- rb_define_alias(rb_singleton_class(cRawDecoder), "decompress", "decode");
804- rb_define_alias(rb_singleton_class(cRawDecoder), "uncompress", "decode");
805- rb_define_alloc_func(cRawDecoder, rawdec_alloc);
806- rb_define_method(cRawDecoder, "initialize", RUBY_METHOD_FUNC(rawdec_init), -1);
807- rb_define_method(cRawDecoder, "reset", RUBY_METHOD_FUNC(rawdec_reset), -1);
808- rb_define_method(cRawDecoder, "update", RUBY_METHOD_FUNC(rawdec_update), -1);
809- rb_define_method(cRawDecoder, "release", RUBY_METHOD_FUNC(rawdec_release), 0);
810- rb_define_alias(cRawDecoder, "decode", "update");
811- rb_define_alias(cRawDecoder, "decompress", "update");
812- rb_define_alias(cRawDecoder, "uncompress", "update");
844+/*
845+ * call-seq:
846+ * decode(src, dest = "") -> dest with decoded string data
847+ * decode(src, max_dest_size, dest = "") -> dest with decoded string data
848+ *
849+ * Decode block LZ4 data.
850+ *
851+ * 出力先は、max_dest_size が与えられていない場合、必要に応じて自動的に拡張されます。
852+ * この場合、いったん圧縮された LZ4 データを走査するため、事前に僅かな CPU 時間を必要とします。
853+ *
854+ * [INFECTION]
855+ * +dest+ < +src+
856+ */
857+static VALUE
858+blkdec_s_decode(int argc, VALUE argv[], VALUE lz4)
859+{
860+ VALUE src, dest;
861+ size_t maxsize;
862+ blockprocess_args(argc, argv, &src, &dest, &maxsize, NULL, aux_lz4_scansize);
863+
864+ aux_str_reserve(dest, maxsize);
865+ rb_str_set_len(dest, 0);
866+ rb_obj_infect(dest, src);
867+
868+ int size = LZ4_decompress_safe(RSTRING_PTR(src), RSTRING_PTR(dest), RSTRING_LEN(src), maxsize);
869+ if (size < 0) {
870+ rb_raise(eError,
871+ "failed LZ4_decompress_safe - max_dest_size is too small, or data is corrupted");
872+ }
873+
874+ rb_str_set_len(dest, size);
875+
876+ return dest;
813877 }
878+
879+static void
880+init_blockdecoder(void)
881+{
882+ VALUE cBlockDecoder = rb_define_class_under(mLZ4, "BlockDecoder", rb_cObject);
883+ rb_define_alloc_func(cBlockDecoder, blkdec_alloc);
884+ rb_define_method(cBlockDecoder, "initialize", RUBY_METHOD_FUNC(blkdec_init), -1);
885+ rb_define_method(cBlockDecoder, "reset", RUBY_METHOD_FUNC(blkdec_reset), -1);
886+ rb_define_method(cBlockDecoder, "update", RUBY_METHOD_FUNC(blkdec_update), -1);
887+ rb_define_method(cBlockDecoder, "release", RUBY_METHOD_FUNC(blkdec_release), 0);
888+ rb_define_alias(cBlockDecoder, "decode", "update");
889+ rb_define_alias(cBlockDecoder, "decompress", "update");
890+ rb_define_alias(cBlockDecoder, "uncompress", "update");
891+
892+ rb_define_singleton_method(cBlockDecoder, "scansize", blkdec_s_scansize, 1);
893+ rb_define_singleton_method(cBlockDecoder, "linksize", blkdec_s_linksize, 1);
894+ rb_define_singleton_method(cBlockDecoder, "decode", blkdec_s_decode, -1);
895+ rb_define_alias(rb_singleton_class(cBlockDecoder), "decompress", "decode");
896+ rb_define_alias(rb_singleton_class(cBlockDecoder), "uncompress", "decode");
897+}
898+
899+/*
900+ * initializer blockapi.c
901+ */
902+
903+void
904+extlz4_init_blockapi(void)
905+{
906+ init_blockencoder();
907+ init_blockdecoder();
908+}
--- trunk/extlz4/ext/frameapi.c (revision 70)
+++ trunk/extlz4/ext/frameapi.c (revision 71)
@@ -1,7 +1,9 @@
11 #include "extlz4.h"
2+#include <stdarg.h>
23 #include <lz4frame.h>
34 #include <lz4frame_static.h>
45 #include "hashargs.h"
6+#include <ruby/thread.h>
57
68 static ID id_op_lshift;
79 static ID id_read;
@@ -32,6 +34,69 @@
3234 }
3335 }
3436
37+static inline void *
38+aux_thread_call_without_gvl(void *(*func)(void *), void (*cancel)(void *), ...)
39+{
40+ va_list va1, va2;
41+ va_start(va1, cancel);
42+ va_start(va2, cancel);
43+ void *s = rb_thread_call_without_gvl(func, &va1, cancel, &va2);
44+ va_end(va1);
45+ va_end(va2);
46+ return s;
47+}
48+
49+static void *
50+aux_LZ4F_compressUpdate_nogvl(void *pp)
51+{
52+ va_list *p = pp;
53+ LZ4F_compressionContext_t *encoder = va_arg(*p, LZ4F_compressionContext_t *);
54+ char *dest = va_arg(*p, char *);
55+ size_t destsize = va_arg(*p, size_t);
56+ const char *src = va_arg(*p, const char *);
57+ size_t srcsize = va_arg(*p, size_t);
58+ LZ4F_compressOptions_t *opts = va_arg(*p, LZ4F_compressOptions_t *);
59+
60+ return (void *)LZ4F_compressUpdate(encoder, dest, destsize, src, srcsize, opts);
61+}
62+
63+static size_t
64+aux_LZ4F_compressUpdate(LZ4F_compressionContext_t *encoder,
65+ char *dest, size_t destsize, const char *src, size_t srcsize,
66+ LZ4F_compressOptions_t *opts)
67+{
68+ return (size_t)aux_thread_call_without_gvl(aux_LZ4F_compressUpdate_nogvl, NULL,
69+ encoder, dest, destsize, src, srcsize, opts);
70+}
71+
72+static int
73+aux_frame_level(const LZ4F_preferences_t *p)
74+{
75+ return p->compressionLevel;
76+}
77+
78+static int
79+aux_frame_blocksize(const LZ4F_frameInfo_t *info)
80+{
81+ int bsid = info->blockSizeID;
82+ if (bsid == 0) {
83+ bsid = max4MB;
84+ }
85+ return 1 << (bsid * 2 + 8);
86+}
87+
88+static int
89+aux_frame_blocklink(const LZ4F_frameInfo_t *info)
90+{
91+ return info->blockMode == blockLinked;
92+}
93+
94+static int
95+aux_frame_checksum(const LZ4F_frameInfo_t *info)
96+{
97+ return info->contentChecksumFlag == contentChecksumEnabled;
98+}
99+
35100 /*** class LZ4::Encoder ***/
36101
37102 struct encoder
@@ -38,7 +103,6 @@
38103 {
39104 VALUE outport;
40105 VALUE workbuf;
41- VALUE predict;
42106 LZ4F_preferences_t prefs;
43107 LZ4F_compressionContext_t encoder;
44108 };
@@ -50,7 +114,6 @@
50114 struct encoder *p = pp;
51115 rb_gc_mark(p->outport);
52116 rb_gc_mark(p->workbuf);
53- rb_gc_mark(p->predict);
54117 }
55118 }
56119
@@ -79,41 +142,76 @@
79142 VALUE obj = TypedData_Make_Struct(mod, struct encoder, &encoder_type, p);
80143 p->outport = Qnil;
81144 p->workbuf = Qnil;
82- p->predict = Qnil;
83145 return obj;
84146 }
85147
148+static inline int
149+fenc_init_args_blocksize(size_t size)
150+{
151+ if (size == 0) {
152+ return max4MB;
153+ } else if (size <= 64 * 1024) {
154+ return max64KB;
155+ } else if (size <= 256 * 1024) {
156+ return max256KB;
157+ } else if (size <= 1 * 1024 * 1024) {
158+ return max1MB;
159+ } else {
160+ return max4MB;
161+ }
162+}
163+
86164 static inline void
87165 fenc_init_args(int argc, VALUE argv[], VALUE *outport, LZ4F_preferences_t *prefs)
88166 {
89167 VALUE level, opts;
90- rb_scan_args(argc, argv, "11:", outport, &level, &opts);
168+ rb_scan_args(argc, argv, "02:", outport, &level, &opts);
91169
170+ memset(prefs, 0, sizeof(*prefs));
171+
172+ if (NIL_P(*outport)) {
173+ *outport = rb_str_buf_new(0);
174+ }
175+
176+ prefs->compressionLevel = NIL_P(level) ? 1 : NUM2INT(level);
177+
92178 if (!NIL_P(opts)) {
93- VALUE blocklink, streamsum;
179+ VALUE blocksize, blocklink, checksum;
94180 RBX_SCANHASH(opts, Qnil,
95- RBX_SCANHASH_ARGS("level", &level, INT2FIX(1)),
181+ RBX_SCANHASH_ARGS("blocksize", &blocksize, Qnil),
96182 RBX_SCANHASH_ARGS("blocklink", &blocklink, Qfalse),
97- RBX_SCANHASH_ARGS("streamsum", &streamsum, Qtrue));
98- memset(prefs, 0, sizeof(*prefs));
99- // prefs->autoFlush = ????;
100- //prefs->frameInfo.blockSizeID = ; /* max64KB, max256KB, max1MB, max4MB ; 0 == default */
183+ RBX_SCANHASH_ARGS("checksum", &checksum, Qtrue));
184+ // prefs->autoFlush = TODO;
185+ prefs->frameInfo.blockSizeID = NIL_P(blocksize) ? max4MB : fenc_init_args_blocksize(NUM2INT(blocksize));
101186 prefs->frameInfo.blockMode = RTEST(blocklink) ? blockLinked : blockIndependent;
102- prefs->frameInfo.contentChecksumFlag = RTEST(streamsum) ? contentChecksumEnabled : noContentChecksum;
187+ prefs->frameInfo.contentChecksumFlag = RTEST(checksum) ? contentChecksumEnabled : noContentChecksum;
103188 } else {
104- memset(prefs, 0, sizeof(*prefs));
189+ prefs->frameInfo.blockSizeID = max4MB;
190+ prefs->frameInfo.blockMode = blockIndependent;
191+ prefs->frameInfo.contentChecksumFlag = contentChecksumEnabled;
105192 }
106- prefs->compressionLevel = NUM2INT(level);
107193 }
108194
195+static struct encoder *
196+getencoderp(VALUE enc)
197+{
198+ return getrefp(enc, &encoder_type);
199+}
200+
201+static struct encoder *
202+getencoder(VALUE enc)
203+{
204+ return getref(enc, &encoder_type);
205+}
206+
109207 /*
110208 * call-seq:
111- * initialize(outport, level = 1, blocklinked: false, streamsum: true)
209+ * initialize(outport = "".b, level = 1, blocksize: nil, blocklink: false, checksum: true)
112210 */
113211 static VALUE
114212 fenc_init(int argc, VALUE argv[], VALUE enc)
115213 {
116- struct encoder *p = getref(enc, &encoder_type);
214+ struct encoder *p = getencoder(enc);
117215 VALUE outport;
118216 fenc_init_args(argc, argv, &outport, &p->prefs);
119217
@@ -126,6 +224,7 @@
126224 rb_str_set_len(p->workbuf, s);
127225 rb_funcall2(outport, id_op_lshift, 1, &p->workbuf);
128226 p->outport = outport;
227+ rb_obj_infect(p->outport, enc);
129228 return enc;
130229 }
131230
@@ -141,7 +240,7 @@
141240 size_t destsize = LZ4F_compressBound(srcsize, &p->prefs);
142241 aux_str_reserve(p->workbuf, destsize);
143242 char *destp = RSTRING_PTR(p->workbuf);
144- size_t size = LZ4F_compressUpdate(p->encoder, destp, destsize, srcp, srcsize, opts);
243+ size_t size = aux_LZ4F_compressUpdate(p->encoder, destp, destsize, srcp, srcsize, opts);
145244 aux_lz4f_check_error(size);
146245 rb_str_set_len(p->workbuf, size);
147246 rb_funcall2(p->outport, id_op_lshift, 1, &p->workbuf);
@@ -156,9 +255,12 @@
156255 static VALUE
157256 fenc_write(int argc, VALUE argv[], VALUE enc)
158257 {
159- struct encoder *p = getref(enc, &encoder_type);
258+ struct encoder *p = getencoder(enc);
160259 VALUE src;
161260 rb_scan_args(argc, argv, "1", &src);
261+ rb_obj_infect(enc, src);
262+ rb_obj_infect(enc, p->workbuf);
263+ rb_obj_infect(p->outport, enc);
162264 fenc_update(p, src, NULL);
163265 return enc;
164266 }
@@ -166,21 +268,22 @@
166268 static VALUE
167269 fenc_push(VALUE enc, VALUE src)
168270 {
169- struct encoder *p = getref(enc, &encoder_type);
271+ struct encoder *p = getencoder(enc);
272+ rb_obj_infect(enc, src);
273+ rb_obj_infect(enc, p->workbuf);
274+ rb_obj_infect(p->outport, enc);
170275 fenc_update(p, src, NULL);
171276 return enc;
172277 }
173278
174279 static VALUE
175-fenc_flush(int argc, VALUE argv[], VALUE enc)
280+fenc_flush(VALUE enc)
176281 {
177- struct encoder *p = getref(enc, &encoder_type);
282+ struct encoder *p = getencoder(enc);
178283 size_t destsize = AUX_LZ4F_BLOCK_SIZE_MAX + AUX_LZ4F_FINISH_SIZE;
179284 aux_str_reserve(p->workbuf, destsize);
180- //rb_str_locktmp(p->workbuf);
181285 char *destp = RSTRING_PTR(p->workbuf);
182286 size_t size = LZ4F_flush(p->encoder, destp, destsize, NULL);
183- //rb_str_unlocktmp(p->workbuf);
184287 aux_lz4f_check_error(size);
185288 rb_str_set_len(p->workbuf, size);
186289 rb_funcall2(p->outport, id_op_lshift, 1, &p->workbuf);
@@ -191,13 +294,11 @@
191294 static VALUE
192295 fenc_close(VALUE enc)
193296 {
194- struct encoder *p = getref(enc, &encoder_type);
297+ struct encoder *p = getencoder(enc);
195298 size_t destsize = AUX_LZ4F_BLOCK_SIZE_MAX + AUX_LZ4F_FINISH_SIZE;
196299 aux_str_reserve(p->workbuf, destsize);
197- //rb_str_locktmp(p->workbuf);
198300 char *destp = RSTRING_PTR(p->workbuf);
199301 size_t size = LZ4F_compressEnd(p->encoder, destp, destsize, NULL);
200- //rb_str_unlocktmp(p->workbuf);
201302 aux_lz4f_check_error(size);
202303 rb_str_set_len(p->workbuf, size);
203304 rb_funcall2(p->outport, id_op_lshift, 1, &p->workbuf);
@@ -205,6 +306,65 @@
205306 return enc;
206307 }
207308
309+static VALUE
310+fenc_getoutport(VALUE enc)
311+{
312+ return getencoder(enc)->outport;
313+}
314+
315+static VALUE
316+fenc_setoutport(VALUE enc, VALUE outport)
317+{
318+ return getencoder(enc)->outport = outport;
319+}
320+
321+static VALUE
322+fenc_prefs_level(VALUE enc)
323+{
324+ return INT2NUM(aux_frame_level(&getencoder(enc)->prefs));
325+}
326+
327+static int
328+fenc_blocksize(struct encoder *p)
329+{
330+ return aux_frame_blocksize(&p->prefs.frameInfo);
331+}
332+
333+static VALUE
334+fenc_prefs_blocksize(VALUE enc)
335+{
336+ return INT2NUM(fenc_blocksize(getencoder(enc)));
337+}
338+
339+static VALUE
340+fenc_prefs_blocklink(VALUE enc)
341+{
342+ return aux_frame_blocklink(&getencoder(enc)->prefs.frameInfo) ? Qtrue : Qfalse;
343+}
344+
345+static VALUE
346+fenc_prefs_checksum(VALUE enc)
347+{
348+ return aux_frame_checksum(&getencoder(enc)->prefs.frameInfo) ? Qtrue : Qfalse;
349+}
350+
351+static VALUE
352+fenc_inspect(VALUE enc)
353+{
354+ struct encoder *p = getencoderp(enc);
355+ if (p) {
356+ return rb_sprintf("#<%s:%p outport=#<%s:%p>, level=%d, blocksize=%d, blocklink=%s, checksum=%s>",
357+ rb_obj_classname(enc), (void *)enc,
358+ rb_obj_classname(p->outport), (void *)p->outport,
359+ p->prefs.compressionLevel, fenc_blocksize(p),
360+ aux_frame_blocklink(&p->prefs.frameInfo) ? "true" : "false",
361+ aux_frame_checksum(&p->prefs.frameInfo) ? "true" : "false");
362+ } else {
363+ return rb_sprintf("#<%s:%p **INVALID REFERENCE**>",
364+ rb_obj_classname(enc), (void *)enc);
365+ }
366+}
367+
208368 /*** class LZ4::Decoder ***/
209369
210370 struct decoder
@@ -211,10 +371,11 @@
211371 {
212372 VALUE inport;
213373 VALUE readbuf; /* read buffer from inport */
214- VALUE blockbuf; /* decoded lz4 frame block buffer */
215- VALUE predict; /* preset dictionary (OBSOLUTE) */ /* FIXME: DELETE ME */
216- size_t readsize; /* readblocksize in initialize */
217- size_t status; /* status code of LZ4F_decompress */
374+ char *blockbuf; /* decoded lz4 frame block buffer */
375+ const char *blockend; /* end of blockbuf */
376+ char *blockhead;
377+ const char *blocktail;
378+ size_t status; /* status code of LZ4F_decompress */
218379 LZ4F_frameInfo_t info;
219380 LZ4F_decompressionContext_t decoder;
220381 };
@@ -226,8 +387,6 @@
226387 struct decoder *p = pp;
227388 rb_gc_mark(p->inport);
228389 rb_gc_mark(p->readbuf);
229- rb_gc_mark(p->blockbuf);
230- rb_gc_mark(p->predict);
231390 }
232391 }
233392
@@ -239,6 +398,9 @@
239398 if (p->decoder) {
240399 LZ4F_freeDecompressionContext(p->decoder);
241400 }
401+ if (p->blockbuf) {
402+ free(p->blockbuf);
403+ }
242404 }
243405 }
244406
@@ -256,12 +418,22 @@
256418 VALUE obj = TypedData_Make_Struct(mod, struct decoder, &decoder_type, p);
257419 p->inport = Qnil;
258420 p->readbuf = Qnil;
259- p->blockbuf = Qnil;
260- p->predict = Qnil;
261- p->status = ~(size_t)0;
421+ p->status = 0;
262422 return obj;
263423 }
264424
425+static struct decoder *
426+getdecoderp(VALUE dec)
427+{
428+ return getrefp(dec, &decoder_type);
429+}
430+
431+static struct decoder *
432+getdecoder(VALUE dec)
433+{
434+ return getref(dec, &decoder_type);
435+}
436+
265437 static inline VALUE
266438 aux_read(VALUE obj, size_t size, VALUE buf)
267439 {
@@ -272,7 +444,7 @@
272444 } else {
273445 //fprintf(stderr, "%s:%d:%s: buffer.size=%d\n", __FILE__, __LINE__, __func__, (int)RSTRING_LEN(buf));
274446 if (RSTRING_LEN(buf) > size) {
275- rb_raise(rb_eRuntimeError, "read buffer is too big (%d, but expected to %d)", (int)RSTRING_LEN(buf), (int)size);
447+ rb_raise(rb_eRuntimeError, "most read (%d, but expected to %d)", (int)RSTRING_LEN(buf), (int)size);
276448 }
277449 return buf;
278450 }
@@ -290,15 +462,14 @@
290462 static VALUE
291463 fdec_init(int argc, VALUE argv[], VALUE dec)
292464 {
293- struct decoder *p = getref(dec, &decoder_type);
294- VALUE inport, readblocksize;
465+ struct decoder *p = getdecoder(dec);
466+ VALUE inport;
467+ //VALUE readblocksize;
295468 rb_scan_args(argc, argv, "1", &inport);
296469 LZ4F_errorCode_t err = LZ4F_createDecompressionContext(&p->decoder, LZ4F_VERSION);
297470 aux_lz4f_check_error(err);
471+ rb_obj_infect(dec, inport);
298472 p->inport = inport;
299- //p->readsize = NIL_P(readblocksize) ? WORK_BUFFER_SIZE : NUM2INT(readblocksize);
300- p->readsize = 0;
301- p->blockbuf = rb_str_buf_new(AUX_LZ4F_BLOCK_SIZE_MAX);
302473 p->readbuf = rb_str_buf_new(0);
303474 char *readp;
304475 size_t readsize;
@@ -322,6 +493,10 @@
322493 s = LZ4F_getFrameInfo(p->decoder, &p->info, NULL, &zero);
323494 aux_lz4f_check_error(s);
324495
496+ size_t size = 1 << (p->info.blockSizeID * 2 + 8);
497+ p->blockbuf = ALLOC_N(char, size);
498+ p->blockend = p->blockbuf + size;
499+
325500 return dec;
326501 }
327502
@@ -349,19 +524,15 @@
349524 }
350525 }
351526
352-static void
353-fdec_read_fetch(char **blockp, size_t *blocksize, struct decoder *p)
527+static size_t
528+fdec_read_fetch(VALUE dec, struct decoder *p)
354529 {
355- RSTRING_GETMEM(p->blockbuf, *blockp, *blocksize);
356- if (*blocksize > 0) {
357- return;
358- }
359-
360- while (*blocksize <= 0 && p->status != 0) {
361- aux_read(p->inport, p->status, p->readbuf);
530+ size_t blocksize = p->blocktail - p->blockhead;
531+ while (blocksize <= 0 && p->status != 0) {
532+ VALUE v = aux_read(p->inport, p->status, p->readbuf);
362533 char *readp;
363534 size_t readsize;
364- aux_str_getmem(p->readbuf, &readp, &readsize);
535+ aux_str_getmem(v, &readp, &readsize);
365536 if (!readp) {
366537 rb_raise(eError,
367538 "read error - encounted invalid EOF - #<%s:%p>",
@@ -368,10 +539,15 @@
368539 rb_obj_classname(p->inport), (void *)p->inport);
369540 }
370541
371- *blocksize = rb_str_capacity(p->blockbuf);
372- p->status = LZ4F_decompress(p->decoder, *blockp, blocksize, readp, &readsize, NULL);
542+ rb_obj_infect(dec, v);
543+ blocksize = p->blockend - p->blockbuf;
544+ p->status = LZ4F_decompress(p->decoder, p->blockbuf, &blocksize, readp, &readsize, NULL);
373545 aux_lz4f_check_error(p->status);
546+ p->blockhead = p->blockbuf;
547+ p->blocktail = p->blockhead + blocksize;
374548 }
549+
550+ return blocksize;
375551 }
376552
377553 /*
@@ -383,11 +559,12 @@
383559 static VALUE
384560 fdec_read(int argc, VALUE argv[], VALUE dec)
385561 {
386- struct decoder *p = getref(dec, &decoder_type);
562+ struct decoder *p = getdecoder(dec);
387563 size_t size;
388564 VALUE dest;
389565 fdec_read_args(argc, argv, &size, &dest);
390566 if (size == 0) {
567+ rb_obj_infect(dest, dec);
391568 return dest;
392569 }
393570
@@ -395,21 +572,17 @@
395572 return Qnil;
396573 }
397574
398- rb_str_modify(p->blockbuf);
399-
400575 do {
401- char *blockp;
402- size_t blocksize;
403- fdec_read_fetch(&blockp, &blocksize, p);
576+ size_t blocksize = fdec_read_fetch(dec, p);
577+ rb_obj_infect(dest, dec);
404578
405579 if (size < blocksize) {
406- rb_str_buf_cat(dest, blockp, size);
407- rb_str_set_len(p->blockbuf, blocksize);
408- aux_str_drop_bytes(p->blockbuf, size);
409- size = 0;
580+ rb_str_buf_cat(dest, p->blockhead, size);
581+ p->blockhead += size;
582+ break;
410583 } else {
411- rb_str_buf_cat(dest, blockp, blocksize);
412- rb_str_set_len(p->blockbuf, 0);
584+ rb_str_buf_cat(dest, p->blockhead, blocksize);
585+ p->blocktail = p->blockhead = NULL;
413586 size -= blocksize;
414587 }
415588 } while (size > 0 && p->status != 0);
@@ -417,10 +590,58 @@
417590 return dest;
418591 }
419592
593+/*
594+ * call-seq:
595+ * getc -> String | nil
596+ *
597+ * Read one byte character.
598+ */
420599 static VALUE
600+fdec_getc(VALUE dec)
601+{
602+ struct decoder *p = getdecoder(dec);
603+
604+ for (;;) {
605+ if (p->status == 0) {
606+ return Qnil;
607+ }
608+ size_t blocksize = fdec_read_fetch(dec, p);
609+ if (blocksize != 0) {
610+ char ch = (uint8_t)*p->blockhead;
611+ p->blockhead ++;
612+ return rb_str_new(&ch, 1);
613+ }
614+ }
615+}
616+
617+/*
618+ * call-seq:
619+ * getbyte -> Integer | nil
620+ *
621+ * Read one byte code integer.
622+ */
623+static VALUE
624+fdec_getbyte(VALUE dec)
625+{
626+ struct decoder *p = getdecoder(dec);
627+
628+ for (;;) {
629+ if (p->status == 0) {
630+ return Qnil;
631+ }
632+ size_t blocksize = fdec_read_fetch(dec, p);
633+ if (blocksize != 0) {
634+ int ch = (uint8_t)*p->blockhead;
635+ p->blockhead ++;
636+ return INT2FIX(ch);
637+ }
638+ }
639+}
640+
641+static VALUE
421642 fdec_close(VALUE dec)
422643 {
423- struct decoder *p = getref(dec, &decoder_type);
644+ struct decoder *p = getdecoder(dec);
424645 p->status = 0;
425646 // TODO: destroy decoder
426647 return dec;
@@ -429,7 +650,7 @@
429650 static VALUE
430651 fdec_eof(VALUE dec)
431652 {
432- struct decoder *p = getref(dec, &decoder_type);
653+ struct decoder *p = getdecoder(dec);
433654 if (p->status == 0) {
434655 return Qtrue;
435656 } else {
@@ -437,6 +658,53 @@
437658 }
438659 }
439660
661+static VALUE
662+fdec_inport(VALUE dec)
663+{
664+ return getdecoder(dec)->inport;
665+}
666+
667+static int
668+fdec_blocksize(struct decoder *p)
669+{
670+ return aux_frame_blocksize(&p->info);
671+}
672+
673+static VALUE
674+fdec_prefs_blocksize(VALUE dec)
675+{
676+ return INT2NUM(fdec_blocksize(getdecoder(dec)));
677+}
678+
679+static VALUE
680+fdec_prefs_blocklink(VALUE dec)
681+{
682+ return aux_frame_blocklink(&getdecoder(dec)->info) ? Qtrue : Qfalse;
683+}
684+
685+static VALUE
686+fdec_prefs_checksum(VALUE dec)
687+{
688+ return aux_frame_checksum(&getdecoder(dec)->info) ? Qtrue : Qfalse;
689+}
690+
691+static VALUE
692+fdec_inspect(VALUE dec)
693+{
694+ struct decoder *p = getdecoderp(dec);
695+ if (p) {
696+ return rb_sprintf("#<%s:%p inport=#<%s:%p>, blocksize=%d, blocklink=%s, checksum=%s>",
697+ rb_obj_classname(dec), (void *)dec,
698+ rb_obj_classname(p->inport), (void *)p->inport,
699+ fdec_blocksize(p),
700+ aux_frame_blocklink(&p->info) ? "true" : "false",
701+ aux_frame_checksum(&p->info) ? "true" : "false");
702+ } else {
703+ return rb_sprintf("#<%s:%p **INVALID REFERENCE**>",
704+ rb_obj_classname(dec), (void *)dec);
705+ }
706+}
707+
440708 /*** setup for LZ4::Encoder and LZ4::Decoder ***/
441709
442710 void
@@ -450,14 +718,30 @@
450718 rb_define_method(cEncoder, "initialize", RUBY_METHOD_FUNC(fenc_init), -1);
451719 rb_define_method(cEncoder, "write", RUBY_METHOD_FUNC(fenc_write), -1);
452720 rb_define_method(cEncoder, "<<", RUBY_METHOD_FUNC(fenc_push), 1);
453- rb_define_method(cEncoder, "flush", RUBY_METHOD_FUNC(fenc_flush), -1);
721+ rb_define_method(cEncoder, "flush", RUBY_METHOD_FUNC(fenc_flush), 0);
454722 rb_define_method(cEncoder, "close", RUBY_METHOD_FUNC(fenc_close), 0);
723+ rb_define_alias(cEncoder, "finish", "close");
724+ rb_define_method(cEncoder, "outport", RUBY_METHOD_FUNC(fenc_getoutport), 0);
725+ rb_define_method(cEncoder, "outport=", RUBY_METHOD_FUNC(fenc_setoutport), 1);
726+ rb_define_method(cEncoder, "prefs_level", RUBY_METHOD_FUNC(fenc_prefs_level), 0);
727+ rb_define_method(cEncoder, "prefs_blocksize", RUBY_METHOD_FUNC(fenc_prefs_blocksize), 0);
728+ rb_define_method(cEncoder, "prefs_blocklink", RUBY_METHOD_FUNC(fenc_prefs_blocklink), 0);
729+ rb_define_method(cEncoder, "prefs_checksum", RUBY_METHOD_FUNC(fenc_prefs_checksum), 0);
730+ rb_define_method(cEncoder, "inspect", RUBY_METHOD_FUNC(fenc_inspect), 0);
455731
456732 VALUE cDecoder = rb_define_class_under(mLZ4, "Decoder", rb_cObject);
457733 rb_define_alloc_func(cDecoder, fdec_alloc);
458734 rb_define_method(cDecoder, "initialize", RUBY_METHOD_FUNC(fdec_init), -1);
459735 rb_define_method(cDecoder, "read", RUBY_METHOD_FUNC(fdec_read), -1);
736+ rb_define_method(cDecoder, "getc", RUBY_METHOD_FUNC(fdec_getc), 0);
737+ rb_define_method(cDecoder, "getbyte", RUBY_METHOD_FUNC(fdec_getbyte), 0);
460738 rb_define_method(cDecoder, "close", RUBY_METHOD_FUNC(fdec_close), 0);
739+ rb_define_alias(cDecoder, "finish", "close");
461740 rb_define_method(cDecoder, "eof", RUBY_METHOD_FUNC(fdec_eof), 0);
741+ rb_define_method(cDecoder, "inport", RUBY_METHOD_FUNC(fdec_inport), 0);
462742 rb_define_alias(cDecoder, "eof?", "eof");
743+ rb_define_method(cDecoder, "prefs_blocksize", RUBY_METHOD_FUNC(fdec_prefs_blocksize), 0);
744+ rb_define_method(cDecoder, "prefs_blocklink", RUBY_METHOD_FUNC(fdec_prefs_blocklink), 0);
745+ rb_define_method(cDecoder, "prefs_checksum", RUBY_METHOD_FUNC(fdec_prefs_checksum), 0);
746+ rb_define_method(cDecoder, "inspect", RUBY_METHOD_FUNC(fdec_inspect), 0);
463747 }
--- trunk/extlz4/ext/extconf.rb (revision 70)
+++ trunk/extlz4/ext/extconf.rb (revision 71)
@@ -7,7 +7,11 @@
77
88 $srcs = Dir.glob(File.join(File.dirname(__FILE__).gsub(/[\[\{\?\*]/, "[\\0]"), "{.,../contrib/*}/*.c")).map { |n| File.basename n }
99 $VPATH << "$(srcdir)/../contrib/lz4"
10-find_header "lz4.h", "$(srcdir)/../contrib/lz4"
11-find_header "xxhash.h", "$(srcdir)/../contrib/lz4"
10+find_header "lz4.h", "$(srcdir)/../contrib/lz4" or abort 1
11+find_header "xxhash.h", "$(srcdir)/../contrib/lz4" or abort 1
1212
13+if RbConfig::CONFIG["arch"] =~ /mingw/
14+ $LDFLAGS << " -static-libgcc"
15+end
16+
1317 create_makefile("extlz4")
--- trunk/extlz4/ext/extlz4.c (revision 70)
+++ trunk/extlz4/ext/extlz4.c (revision 71)
@@ -42,8 +42,6 @@
4242 {
4343 mLZ4 = rb_define_module("LZ4");
4444
45- rb_define_const(mLZ4, "LZ4", mLZ4);
46-
4745 /*
4846 * Document-const: LZ4::LIBVERSION
4947 *
@@ -66,6 +64,6 @@
6664
6765 eError = rb_define_class_under(mLZ4, "Error", rb_eRuntimeError);
6866
69- extlz4_init_rawapi();
67+ extlz4_init_blockapi();
7068 extlz4_init_frameapi();
7169 }
--- trunk/extlz4/ext/extlz4.h (revision 70)
+++ trunk/extlz4/ext/extlz4.h (revision 71)
@@ -8,7 +8,7 @@
88 extern VALUE mLZ4; /* module LZ4 */
99 extern VALUE eError; /* class LZ4::Error < ::RuntimeError */
1010
11-extern void extlz4_init_rawapi(void);
11+extern void extlz4_init_blockapi(void);
1212 extern void extlz4_init_frameapi(void);
1313
1414 #define AUX_FUNCALL(RECV, METHOD, ...) \
--- trunk/extlz4/Rakefile (revision 70)
+++ trunk/extlz4/Rakefile (revision 71)
@@ -2,7 +2,8 @@
22 require "rake/clean"
33
44 DOC = FileList["{README,LICENSE,CHANGELOG,Changelog,HISTORY}{,.ja}{,.txt,.rd,.rdoc,.md,.markdown}"] +
5- FileList["ext/**/{README,LICENSE,CHANGELOG,Changelog,HISTORY}{,.ja}{,.txt,.rd,.rdoc,.md,.markdown}"]
5+ FileList["{contrib,ext}/**/{README,LICENSE,CHANGELOG,Changelog,HISTORY}{,.ja}{,.txt,.rd,.rdoc,.md,.markdown}"] +
6+ FileList["ext/**/*.{c,C,cc,cxx,cpp,h,H,hh}"]
67 #EXT = FileList["ext/**/*.{h,hh,c,cc,cpp,cxx}"] +
78 # FileList["ext/externals/**/*"]
89 EXT = FileList["ext/**/*"]
@@ -9,6 +10,7 @@
910 BIN = FileList["bin/*"]
1011 LIB = FileList["lib/**/*.rb"]
1112 SPEC = FileList["spec/**/*"]
13+TEST = FileList["test/**/*"]
1214 EXAMPLE = FileList["examples/**/*"]
1315 GEMSTUB_SRC = "gemstub.rb"
1416 RAKEFILE = [File.basename(__FILE__), GEMSTUB_SRC]
@@ -25,7 +27,7 @@
2527 GEMFILE = "#{GEMSTUB.name}-#{GEMSTUB.version}.gem"
2628 GEMSPEC = "#{GEMSTUB.name}.gemspec"
2729
28-GEMSTUB.files += DOC + EXT + EXTCONF + BIN + LIB + SPEC + EXAMPLE + RAKEFILE + EXTRA
30+GEMSTUB.files += DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + RAKEFILE + EXTRA
2931 GEMSTUB.files.sort!
3032 GEMSTUB.rdoc_options ||= %w(--charset UTF-8)
3133 GEMSTUB.extra_rdoc_files += DOC + LIB + EXT.reject { |n| n.include?("/externals/") || !%w(.h .hh .c .cc .cpp .cxx).include?(File.extname(n)) }
@@ -82,7 +84,7 @@
8284 desc "generate binary gemspec"
8385 task "native-gemspec" => GEMSPEC_NATIVE
8486
85- file GEMFILE_NATIVE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + EXAMPLE + SOFILES + RAKEFILE + [GEMSPEC_NATIVE] do
87+ file GEMFILE_NATIVE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + SOFILES + RAKEFILE + [GEMSPEC_NATIVE] do
8688 sh "gem build #{GEMSPEC_NATIVE}"
8789 end
8890
@@ -123,8 +125,8 @@
123125 task :all => GEMFILE
124126
125127 desc "generate local rdoc"
126-task :rdoc => DOC + EXT + LIB do
127- sh *(%w(rdoc) + GEMSTUB.rdoc_options + DOC + EXT + LIB)
128+task :rdoc => DOC + LIB do
129+ sh *(%w(rdoc) + GEMSTUB.rdoc_options + DOC + LIB)
128130 end
129131
130132 desc "launch rspec"
@@ -138,7 +140,7 @@
138140 desc "generate gemspec"
139141 task gemspec: GEMSPEC
140142
141-file GEMFILE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + EXAMPLE + RAKEFILE + [GEMSPEC] do
143+file GEMFILE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + RAKEFILE + [GEMSPEC] do
142144 sh "gem build #{GEMSPEC}"
143145 end
144146
--- trunk/extlz4/lib/extlz4.rb (revision 70)
+++ trunk/extlz4/lib/extlz4.rb (revision 71)
@@ -2,13 +2,16 @@
22
33 require "stringio"
44
5-ver = RbConfig::CONFIG["ruby_version"]
5+ver = RUBY_VERSION.slice(/\d+\.\d+/)
66 soname = File.basename(__FILE__, ".rb") << ".so"
77 lib = File.join(File.dirname(__FILE__), ver, soname)
8-if File.file?(lib)
8+case
9+when File.file?(lib)
910 require_relative File.join(ver, soname)
11+when File.file?(File.join(File.dirname(__FILE__), ver))
12+ require_relative soname
1013 else
11- require_relative soname
14+ require soname
1215 end
1316
1417 require_relative "extlz4/version"
@@ -17,6 +20,8 @@
1720 # LZ4 data and streaming data processor.
1821 #
1922 module LZ4
23+ LZ4 = self
24+
2025 #
2126 # call-seq:
2227 # decode_file(inpath, outpath) -> nil
@@ -27,10 +32,10 @@
2732 # Return nil always.
2833 #
2934 # [inpath]
30- # Give input file path, or input io (liked) object its has ``read'' method.
35+ # Give input file path, or input IO (liked) object its has ``read'' method.
3136 #
3237 # [outpath]
33- # Give output file path, or output io (liked) object its has ``<<'' method.
38+ # Give output file path, or output IO (liked) object its has ``<<'' method.
3439 #
3540 def self.decode_file(inpath, outpath)
3641 open_file(inpath, "rb") do |infile|
@@ -48,7 +53,7 @@
4853
4954 #
5055 # call-seq:
51- # encode_file(inpath, outpath, level = 1, opt = {}) -> nil
56+ # encode_file(inpath, outpath, level = 1, opts = {}) -> nil
5257 #
5358 # Encode regular file to lz4 file.
5459 #
@@ -56,21 +61,21 @@
5661 # Return nil always.
5762 #
5863 # [inpath]
59- # Give input file path, or input io (liked) object its has ``read'' method.
64+ # Give input file path, or input IO (liked) object its has ``read'' method.
6065 #
6166 # [outpath]
62- # Give output file path, or output io (liked) object its has ``<<'' method.
67+ # Give output file path, or output IO (liked) object its has ``<<'' method.
6368 #
6469 # [level = 1 (Integer)]
6570 # See LZ4.encode method.
6671 #
67- # [opt = {} (Hash)]
72+ # [opts = {} (Hash)]
6873 # See LZ4.encode method.
6974 #
70- def self.encode_file(inpath, outpath, level = 1, **opt)
75+ def self.encode_file(inpath, outpath, *args, **opts)
7176 open_file(inpath, "rb") do |infile|
7277 open_file(outpath, "wb") do |outfile|
73- encode(outfile, level, **opt) do |lz4|
78+ encode(outfile, *args, **opts) do |lz4|
7479 inbuf = ""
7580 slicesize = 1 << 20
7681 lz4 << inbuf while infile.read(slicesize, inbuf)
@@ -111,11 +116,11 @@
111116 # encode(output_io, level = 1, opts = {}) -> stream encoder
112117 # encode(output_io, level = 1, opts = {}) { |stream_encoder| ... } -> yield_status
113118 #
114- # Encode to LZ4 stream data. This is available streaming process, but posible sequential write only.
119+ # Encode to LZ4 Frame data. This is available streaming process.
115120 #
116121 # Created data is decodable by lz4-cli.
117122 #
118- # ==== 共通引数
123+ # ==== Common parameters
119124 #
120125 # [level = 1 (Integer)]
121126 # 圧縮レベルを指定します。0 から 9 までの整数値が指定出来ます。
@@ -124,20 +129,17 @@
124129 #
125130 # 4以上の値は、高効率圧縮器の圧縮レベルとして渡されます。
126131 #
127- # [block_dependency: false (true or false)]
132+ # [blocklink: false (true or false)]
128133 # Enable or disable block dependency funcion. Default is false.
129134 #
130- # 真を与えた場合、ストリームの圧縮効率が向上しますが、特定のブロックのみを取り出すことが難しくなります。
135+ # 真を与えた場合、ストリームの圧縮効率が向上します。
131136 #
132- # [block_checksum: false (true or false)]
133- # ブロックごとのチェックサム (XXhash32) の有効・無効を切り替えます。
134- #
135- # [stream_checksum: true (true or false)]
137+ # [checksum: true (true or false)]
136138 # ストリーム全体のチェックサム (XXhash32) の有効・無効を切り替えます。
137139 #
138140 # ==== encode(source_string, level = 1, opts = {}) -> encoded_data
139141 #
140- # Basic stream encode method.
142+ # Basic encode method.
141143 #
142144 # [RETURN (String)]
143145 # Encoded data as LZ4 stream
@@ -147,19 +149,20 @@
147149 #
148150 # 文字符号情報は無視されて純粋なバイナリデータ列として処理されます。
149151 #
150- # ==== encode(output_io, level = 1, opts = {}) -> stream_encoder
152+ # ==== encode(output_io, level = 1, opts = {}) -> encoder
151153 #
152- # Available LZ4 stream encode.
154+ # Available streaming LZ4 Frame encode.
153155 #
154156 # Write to encoder for data encoding.
155157 #
156- # After finished encode process, you must call +StreamEncoder#close+.
158+ # After finished encode process, you must call Encoder#close.
157159 #
158- # Return stream encoder if given an IO object (or psudo-object).
160+ # Return stream encoder if given an IO (liked) object.
159161 #
160- # この圧縮器に『書き込む』ことでデータは圧縮されます。圧縮処理を完了するときには #close を呼び出す必要があります。
162+ # この圧縮器に『書き込む』ことでデータは圧縮されます。
163+ # 圧縮処理を完了するときには #close を呼び出す必要があります。
161164 #
162- # [RETURN (LZ4::StreamEncoder)]
165+ # [RETURN (LZ4::Encoder)]
163166 #
164167 # [output_io (IO)]
165168 # LZ4 ストリームの出力先を指定します。IO#<< と同等の機能を持つオブジェクトである必要があります。
@@ -166,7 +169,7 @@
166169 #
167170 # 一例を挙げると、IO、StringIO、Array などのインスタンスが当てはまります。
168171 #
169- # ==== encode(output_io, level = 1, opts = {}) { |stream_encoder| ... } -> yield_status
172+ # ==== encode(output_io, level = 1, opts = {}) { |encoder| ... } -> yield_status
170173 #
171174 # IO オブジェクトとともにブロックを渡した場合、ブロック引数として圧縮器が渡されます。この場合は #close を呼び出す必要がありません。
172175 #
@@ -173,16 +176,16 @@
173176 # [RETURN]
174177 # return value of given block
175178 #
176- # [YIELD (stream_encoder)]
179+ # [YIELD (encoder)]
177180 #
178181 # [YIELDRETURN]
179182 # return as method return value
180183 #
181- # ==== example: directly stream encode
184+ # ==== example: directly encode
182185 #
183186 # LZ4.encode("abcdefghijklmn") # => Encoded LZ4 stream data (string object)
184187 #
185- # ==== example: stream encode with block
188+ # ==== example: streaming encode with block
186189 #
187190 # この用例は、encode_file の実装とほぼ同じです。丸写しで利用するよりは encode_file の利用を推奨します。
188191 #
@@ -195,22 +198,23 @@
195198 # end
196199 # end
197200 #
198-
199- def self.encode(obj, level = 1, **opts)
200- if obj.kind_of?(String)
201- lz4 = LZ4::Encoder.new(out = "".force_encoding(Encoding::BINARY), level, **opts)
202- lz4 << obj
203- lz4.close
204- out
205- else
206- lz4 = LZ4::Encoder.new(obj, level, **opts)
201+ def self.encode(*args, **opts)
202+ if args.empty? || !args[0].kind_of?(String)
203+ lz4 = LZ4::Encoder.new(*args, **opts)
207204 return lz4 unless block_given?
208205 begin
209206 yield(lz4)
210- obj
207+ lz4.outport
211208 ensure
212209 lz4.close
213210 end
211+ else
212+ obj = args.shift
213+ outport = "".force_encoding(Encoding::BINARY)
214+ lz4 = LZ4::Encoder.new(outport, *args, **opts)
215+ lz4 << obj
216+ lz4.close
217+ outport
214218 end
215219 end
216220
@@ -217,10 +221,10 @@
217221 #
218222 # call-seq:
219223 # decode(encoded_data_string) -> decoded data
220- # decode(input_io) -> stream_decoder
221- # decode(input_io) { |stream_decoder| ... } -> yield_status
224+ # decode(input_io) -> decoder
225+ # decode(input_io) { |decoder| ... } -> yield_status
222226 #
223- # Decode LZ4 stream data. This is available streaming process.
227+ # Decode LZ4 Frame data. This is available streaming process.
224228 #
225229 # ==== decode(encoded_data_string)
226230 #
@@ -229,35 +233,29 @@
229233 #
230234 # ==== decode(input_io)
231235 #
232- # [RETURN (LZ4::StreamDecoder)]
236+ # [RETURN (LZ4::Decoder)]
233237 # ストリーム展開オブジェクトです。簡素な機能の読み込み専用IOオブジェクトとして扱うことが出来ます。
234238 #
235- # stream_decoder は GC によって開放処理が行われますが、利用しなくなった時点で利用者が明示的に close を呼び出すことが望まれます。
239+ # decoder は GC によって開放処理が行われますが、利用しなくなった時点で利用者が明示的に close を呼び出すことが望まれます。
236240 #
237241 # [input_io (IO)]
238242 # This is IO like object. Need read method. 'extlz4' is call as <tt>read(size, buf)</tt> style.
239243 #
240- # ==== decode(input_io) { |stream_decoder| ... }
244+ # ==== decode(input_io) { |decoder| ... }
241245 #
242246 # [RETURN]
243247 # returned value from given block
244248 #
245- # [YIELD (stream_decoder)]
249+ # [YIELD (decoder)]
246250 # ブロックなしで与えた場合の戻り値と等価です。
247251 #
248252 # ただしこちらはブロックを抜けたらすぐに開放処理が実施されます。利用者が明示的に close を呼んだり、GC されるのを待ったりせずに行われると言うことです。
249253 #
250- # ==== note
251- #
252- # Current implementation is possible 'sequential read' only.
253- #
254- # 'read behind' or 'random read' are not available.
255- #
256254 # ==== example: directly decode
257255 #
258- # LZ4.decode(lz4_stream_encoded_string) # => decoded binary string
256+ # LZ4.decode(lz4_encoded_string) # => decoded binary string
259257 #
260- # ==== example: stream decode
258+ # ==== example: streaming decode
261259 #
262260 # File.open("sample.lz4", "rb") do |fd|
263261 # LZ4.decode(fd) do |lz4dec|
@@ -267,15 +265,15 @@
267265 # end
268266 # end
269267 #
270- def self.decode(obj, *opts)
268+ def self.decode(obj, *args)
271269 if obj.kind_of?(String)
272- lz4 = Decoder.new(StringIO.new(obj), *opts)
270+ lz4 = Decoder.new(StringIO.new(obj), *args)
273271 dest = lz4.read
274272 lz4.close
275273 return (dest || "".b)
276274 end
277275
278- lz4 = Decoder.new(obj, *opts)
276+ lz4 = Decoder.new(obj, *args)
279277 return lz4 unless block_given?
280278
281279 begin
@@ -285,19 +283,19 @@
285283 end
286284 end
287285
288- def self.raw_encode(*args)
289- RawEncoder.encode(*args)
286+ def self.block_encode(*args)
287+ BlockEncoder.encode(*args)
290288 end
291289
292- def self.raw_decode(*args)
293- RawDecoder.decode(*args)
290+ def self.block_decode(*args)
291+ BlockDecoder.decode(*args)
294292 end
295293
296294 #
297- # Call LZ4::RawEncoder.new.
295+ # Call LZ4::BlockEncoder.new.
298296 #
299- def self.raw_stream_encode(*args)
300- lz4 = RawEncoder.new(*args)
297+ def self.block_stream_encode(*args)
298+ lz4 = BlockEncoder.new(*args)
301299 if block_given?
302300 yield(lz4)
303301 else
@@ -306,10 +304,10 @@
306304 end
307305
308306 #
309- # Call LZ4::RawDecoder.new.
307+ # Call LZ4::BlockDecoder.new.
310308 #
311- def self.raw_stream_decode(*args)
312- lz4 = RawDecoder.new(*args)
309+ def self.block_stream_decode(*args)
310+ lz4 = BlockDecoder.new(*args)
313311 if block_given?
314312 yield(lz4)
315313 else
@@ -321,11 +319,13 @@
321319 alias compress encode
322320 alias decompress decode
323321 alias uncompress decode
324- alias raw_compress raw_encode
325- alias raw_decompress raw_decode
326- alias raw_uncompress raw_decode
327- alias raw_stream_compress raw_stream_encode
328- alias raw_stream_decompress raw_stream_decode
329- alias raw_stream_uncompress raw_stream_decode
322+ alias block_compress block_encode
323+ alias block_decompress block_decode
324+ alias block_uncompress block_decode
325+ alias block_stream_compress block_stream_encode
326+ alias block_stream_decompress block_stream_decode
327+ alias block_stream_uncompress block_stream_decode
330328 end
331329 end
330+
331+require_relative "extlz4/compat"
--- trunk/extlz4/lib/extlz4/oldstream.rb (revision 70)
+++ trunk/extlz4/lib/extlz4/oldstream.rb (revision 71)
@@ -8,8 +8,11 @@
88 # dearblue <dearblue@users.sourceforce.jp>
99 #
1010
11-require "extlz4"
11+require_relative "../extlz4"
1212 require "stringio"
13+
14+require "rubygems"
15+gem "xxhash", "~> 0.3"
1316 require "xxhash"
1417
1518 module LZ4
@@ -178,7 +181,7 @@
178181 header << desc
179182 header << [streamsize].pack("Q<") if streamsize
180183 header << [predictid].pack("V") if predictid
181- header << [XXhash32.digest(desc) >> 8].pack("C")
184+ header << [XXhash.xxh32(desc) >> 8].pack("C")
182185 end
183186 end
184187
@@ -228,7 +231,7 @@
228231 def initialize(io, level, blocksize, block_dependency,
229232 block_checksum, stream_checksum)
230233 @block_checksum = !!block_checksum
231- @stream_checksum = XXhash32.new if stream_checksum
234+ @stream_checksum = XXhash::XXhashInternal::StreamingHash32.new(0) if stream_checksum
232235
233236 @blocksize = BLOCK_MAXIMUM_SIZES[blocksize]
234237 raise ArgumentError, "wrong blocksize (#{blocksize})" unless @blocksize
@@ -256,8 +259,8 @@
256259 desc = [sd, bd].pack("CC")
257260 header << desc
258261 # TODO: header << [stream_size].pack("Q<") if stream_size
259- # TODO: header << [XXhash32.digest(predict)].pack("V") if predict # preset dictionary
260- header << [XXhash32.digest(desc) >> 8].pack("C")
262+ # TODO: header << [XXhash.xxh32(predict)].pack("V") if predict # preset dictionary
263+ header << [XXhash.xxh32(desc) >> 8].pack("C")
261264 @io << header
262265 end
263266
@@ -312,10 +315,10 @@
312315 def get_encoder(level, block_dependency)
313316 workencbuf = "".force_encoding(Encoding::BINARY)
314317 if block_dependency
315- streamencoder = LZ4::RawStreamEncoder.new(@blocksize, level)
316- ->(src) { streamencoder.update(level, src, workencbuf) }
318+ streamencoder = LZ4::BlockEncoder.new(level)
319+ ->(src) { streamencoder.update(src, workencbuf) }
317320 else
318- ->(src) { LZ4.raw_encode(level, src, workencbuf) }
321+ ->(src) { LZ4.block_encode(level, src, workencbuf) }
319322 end
320323 end
321324
@@ -333,7 +336,7 @@
333336 end
334337
335338 if @block_checksum
336- @io << [XXhash32.digest(w)].pack("V")
339+ @io << [XXhash.xxh32(w)].pack("V")
337340 end
338341 @buf.clear
339342 end
@@ -381,9 +384,9 @@
381384 headerchecksum = io.getbyte
382385
383386 if @blockindependence
384- @decoder = LZ4.method(:raw_decode)
387+ @decoder = LZ4.method(:block_decode)
385388 else
386- @decoder = LZ4::RawStreamDecoder.new.method(:update)
389+ @decoder = LZ4::BlockDecoder.new.method(:update)
387390 end
388391 when MAGIC_NUMBER_LEGACY
389392 @version = -1
@@ -393,7 +396,7 @@
393396 @blockmaximum = 1 << 23 # 8 MiB
394397 @streamsize = nil
395398 @presetdict = nil
396- @decoder = LZ4.method(:raw_decode)
399+ @decoder = LZ4.method(:block_decode)
397400 else
398401 raise Error, "stream header error - wrong magic number"
399402 end
--- trunk/extlz4/lib/extlz4/compat.rb (nonexistent)
+++ trunk/extlz4/lib/extlz4/compat.rb (revision 71)
@@ -0,0 +1,12 @@
1+
2+module LZ4
3+ class << self
4+ alias raw_encode block_encode
5+ alias raw_decode block_decode
6+ alias raw_stream_encode block_stream_encode
7+ alias raw_stream_decode block_stream_decode
8+ end
9+
10+ RawStreamEncoder = BlockEncoder
11+ RawStreamDecoder = BlockDecoder
12+end
--- trunk/extlz4/HISTORY.ja.md (revision 70)
+++ trunk/extlz4/HISTORY.ja.md (revision 71)
@@ -1,25 +1,39 @@
11
2-# extlz4-0.2 (2015-03-26)
2+# extlz4-0.2 (2015-04-19)
33
4-## ファイル構成の変更
4+## いくつかの名称の変更
55
6-* ext/: ext/extlz4.c を複数のファイルに分割しました。
6+ * ストリームをフレーム (frame) に変更しました。
7+ * これまで extlz4 において raw\*\*\* と呼んできた名称を block\*\*\* に変更しました。
78
89 ## LZ4 ストリームの独自実装から LZ4 Frame API への移行
910
10-* lib/extlz4.rb: LZ4.encode、LZ4.decode の引数は互換性を失いました。
11-* lib/extlz4/oldstream.rb: 独自実装版は LZ4::StreamEncoder、LZ4::StreamDecoder のまま残されました。
12- これ以上保守されませんし、将来的にこのクラスは廃止されます。
13- 利用する場合は ``require "extlz4/oldstream"`` とする必要があります。
11+ * LZ4.encode、LZ4.decode の引数は互換性を失いました。
12+ * LZ4 Frame API による圧縮・伸長処理を行うためのクラスは
13+ LZ4::Encoder と LZ4::Decoder として利用できます。
14+ * 独自実装版は LZ4::StreamEncoder、LZ4::StreamDecoder のまま残されました。
15+ * ***これらのクラスは将来的に廃止される予定です。***
16+ * 利用する場合は ``require "extlz4/oldstream"`` とする必要があります。
17+ * ruby gems の xxhash-0.3 を必要とします。
18+ * 以前の LZ4.encode は LZ4.encode\_old、LZ4.decode は LZ4.decode\_old
19+ として利用できます。
1420
15-## LZ4 streaming API に対する更新
21+## 新しい LZ4 Block Streaming API への移行
1622
17-* ext/: ``LZ4_create()`` 系から ``LZ4_createStream()`` 系の API に移行しました。
18-* ext/: ``LZ4_decompress_safe_withPrefix64k()`` から ``LZ4_createStreamDecode()`` 系の API に移行しました。
19-* ext/: ``LZ4::RawStreamEncoder`` が ``LZ4::RawEncoder`` になりました。
20-* ext/: ``LZ4::RawStreamDecoder`` が ``LZ4::RawDecoder`` になりました。
23+ * ``LZ4_create()`` 系から ``LZ4_createStream()`` 系の API に移行しました。
24+ * ``LZ4_decompress_safe_withPrefix64k()`` から ``LZ4_createStreamDecode()`` 系の API に移行しました。
25+ * LZ4::RawStreamEncoder が LZ4::BlockEncoder になりました。
26+ * LZ4::RawStreamDecoder が LZ4::BlockDecoder になりました。
2127
28+## セーフレベルの確認処理を削除
2229
30+ * セーフレベルの確認処理を削除しました。
31+
32+ 今まではセーフレベルが4以上の場合に汚染状態を移す必要のある場合は、
33+ SecurityError 例外を発生させていましたが、この方針を変更して常に
34+ 汚染状態を伝搬させるだけの処理にしました。
35+
36+
2337 # extlz4-0.1.1 (2014-06-01)
2438
2539 ## 不具合の修正
@@ -34,7 +48,7 @@
3448
3549 * lib/extlz4.rb: ブロック依存ストリーム生成の場合、高効率圧縮時に圧縮レベルが常に規定値になっていましたが、これを変動するように修正しました。
3650
37-* lib/extlz4.rb (`LZ4::StreamEncoder#initialize`): `raw_encode` / `RawStreamEncoder#update` に渡す `level` の値が [nil, 0 .. 16] になるように修正しました。
51+* lib/extlz4.rb (`LZ4::StreamEncoder#initialize`): `block_encode` / `RawStreamEncoder#update` に渡す `level` の値が [nil, 0 .. 16] になるように修正しました。
3852
3953 * bin/extlz4: lz4 ストリーム検査の時、標準入力を利用した場合でも『-f』スイッチが必要となっていましたが、これを不要とするように修正しました。
4054
旧リポジトリブラウザで表示