gogyou 0.1.240911.prototype → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/{LICENSE.txt → LICENSE.markdown} +35 -39
- data/README.markdown +429 -0
- data/Rakefile +106 -0
- data/gemstub.rb +40 -0
- data/lib/gogyou.rb +264 -593
- data/lib/gogyou/accessor.rb +397 -0
- data/lib/gogyou/mixin.rb +641 -0
- data/lib/gogyou/model.rb +504 -0
- data/lib/gogyou/primitives.rb +317 -0
- data/lib/gogyou/typespec.rb +15 -0
- data/mkprims.rb +172 -0
- data/spec/gogyou_spec.rb +160 -0
- metadata +65 -34
- data/README.txt +0 -3
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: be64eff572c8de86fa028cf2b0a3f43ced61f7fc
|
4
|
+
data.tar.gz: 60ba38f8395e03b59c06053f915e255e151009ac
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1b23fd8023dc3210c51228f0849a92aa541d4621a11e5ee4d57086e30458ede76d4b733cbbed1183667f5a2874964632c902e12017a8121aa17a91370124e4e8
|
7
|
+
data.tar.gz: 08f775733ffe50d57ebbac3dc48c6bc2420dd112e8e6e5c8eb3bb3ae7dbaa7d91bb6fe607c2c1f38abbad56962bc9883f717fe132c1fafed942324a1220dd844
|
@@ -1,39 +1,35 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
In Japanese.
|
37
|
-
|
38
|
-
日本語訳については次のページが参考になるでしょう:
|
39
|
-
http://www.freebsd.org/ja/copyright/freebsd-license.html
|
1
|
+
# Gogyou License (2-clause BSD License)
|
2
|
+
|
3
|
+
----
|
4
|
+
|
5
|
+
Copyright (c) 2012, dearblue
|
6
|
+
All rights reserved.
|
7
|
+
|
8
|
+
Redistribution and use in source and binary forms, with or without
|
9
|
+
modification, are permitted provided that the following conditions are met:
|
10
|
+
|
11
|
+
1. Redistributions of source code must retain the above copyright notice,
|
12
|
+
this list of conditions and the following disclaimer.
|
13
|
+
|
14
|
+
2. Redistributions in binary form must reproduce the above copyright
|
15
|
+
notice, this list of conditions and the following disclaimer in the
|
16
|
+
documentation and/or other materials provided with the distribution.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
21
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
22
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
23
|
+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
24
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
25
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
26
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
27
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
28
|
+
POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
|
30
|
+
----
|
31
|
+
|
32
|
+
In Japanese.
|
33
|
+
|
34
|
+
日本語訳については次のページが参考になるでしょう:
|
35
|
+
http://www.freebsd.org/ja/copyright/freebsd-license.html
|
data/README.markdown
ADDED
@@ -0,0 +1,429 @@
|
|
1
|
+
# gogyou (ゴギョウ)
|
2
|
+
|
3
|
+
The gogyou is a library that provides auxiliary features of binary data operation for ruby.
|
4
|
+
|
5
|
+
The C-liked struct, union and multidimensional array definition are posible in ruby syntax.
|
6
|
+
|
7
|
+
"gogyou" is means "Gnaphalium affine" in japanese.
|
8
|
+
|
9
|
+
----
|
10
|
+
|
11
|
+
(in Japanese)
|
12
|
+
|
13
|
+
gogyou は、バイナリデータ操作の補助機能を提供する、ruby 拡張ライブラリです。
|
14
|
+
|
15
|
+
ruby 構文による、C 言語の構造体・共用体・多次元配列 (もどき) の定義が可能です。
|
16
|
+
|
17
|
+
名称は春の七種の一つである『ゴギョウ』から取りました。
|
18
|
+
|
19
|
+
----
|
20
|
+
|
21
|
+
* Product Name (名称): gogyou (ゴギョウ / 御形 / Gnaphalium affine)
|
22
|
+
* Author (制作者): dearblue <<dearblue@users.sourceforge.jp>>
|
23
|
+
* Distribute License (頒布ライセンス): 2-clause BSD License (二条項 BSD ライセンス)
|
24
|
+
* Software Quarity (ソフトウェア品質): alpha
|
25
|
+
* User (想定利用者): Rubyist
|
26
|
+
* Release Number (リリースナンバー): 0.2
|
27
|
+
* Memory Usage (使用メモリ量): 2 MB +
|
28
|
+
* Installed Size (インストール容量): under 1 MB
|
29
|
+
* Project Page: <http://sourceforge.jp/projects/rutsubo/>
|
30
|
+
* Support Ruby: ruby-2.0+ <http://www.ruby-lang.org/>
|
31
|
+
|
32
|
+
## Example
|
33
|
+
|
34
|
+
ruby/ruby.h の struct RBasic と struct RObject を gogyou を用いて次のように記述出来ます:
|
35
|
+
|
36
|
+
```ruby:ruby
|
37
|
+
require "gogyou"
|
38
|
+
|
39
|
+
module MyRuby
|
40
|
+
extend Gogyou
|
41
|
+
|
42
|
+
ROBJECT_EMBED_LEN_MAX = 3
|
43
|
+
|
44
|
+
typedef :uintptr_t, :VALUE
|
45
|
+
|
46
|
+
RBasic = struct {
|
47
|
+
VALUE :flags
|
48
|
+
union {
|
49
|
+
const VALUE :klass
|
50
|
+
struct -> {
|
51
|
+
VALUE :klass
|
52
|
+
}, :force_modify
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
RObject = struct {
|
57
|
+
RBasic :basic
|
58
|
+
union -> {
|
59
|
+
struct -> {
|
60
|
+
long :numiv
|
61
|
+
uintptr_t :ivptr
|
62
|
+
uintptr_t :iv_index_tbl
|
63
|
+
}, :heap
|
64
|
+
VALUE :ary, ROBJECT_EMBED_LEN_MAX
|
65
|
+
}, :as
|
66
|
+
}
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
`extend Gogyou` して呼ばれた `struct` は、構築した構造体の無名クラスを返します。
|
71
|
+
|
72
|
+
この無名クラスを定数に代入すれば、ruby の一般的なクラスと同様に扱うことが出来ます。
|
73
|
+
|
74
|
+
`RObject` のインスタンスは次のように (C 言語のそれや、ruby の他のオブジェクトと相違無く) 扱うことが出来ます。
|
75
|
+
|
76
|
+
```ruby:ruby
|
77
|
+
obj = MyRuby::RObject.new
|
78
|
+
# or obj = MyRuby::RObject.new(File.read("sample.bin", MyRuby::RObject.size, mode: "rb"))
|
79
|
+
obj.basic.flags = 0x12345678
|
80
|
+
(obj.basic.klass = 0xaaaaaaaa) rescue $! # => exception! klass field is immutable type
|
81
|
+
obj.basic.force_modify.klass = 0xaaaaaaaa
|
82
|
+
obj.as.heap.numiv = 0x55555555
|
83
|
+
p obj.as.ary[0] # => 0x55555555
|
84
|
+
tmp = obj.as.heap
|
85
|
+
tmp.ivptr = 0x44444444
|
86
|
+
p obj.as.ary[1] # => 0x44444444
|
87
|
+
|
88
|
+
# 以下の結果は 64ビット環境によるものです
|
89
|
+
p obj.bytesize # => 40
|
90
|
+
p obj.to_buffer # => "xV4\x12\0\0\0\0\xaa\xaa\xaa\xaa\0\0\0\0UUUU\0\0\0\0DDDD\0\0\0\0\0\0\0\0\0\0\0\0"
|
91
|
+
```
|
92
|
+
|
93
|
+
|
94
|
+
## About features (機能について)
|
95
|
+
|
96
|
+
* Support A C-liked struct and union (with nested containers)
|
97
|
+
|
98
|
+
C に似た構造体・共用体に対応 (入れ子構造も可能)
|
99
|
+
|
100
|
+
struct {
|
101
|
+
struct {
|
102
|
+
....
|
103
|
+
union {
|
104
|
+
....
|
105
|
+
struct {
|
106
|
+
....
|
107
|
+
}
|
108
|
+
}
|
109
|
+
....
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
* Support multidimensional arrays
|
114
|
+
|
115
|
+
多次元配列に対応
|
116
|
+
|
117
|
+
struct {
|
118
|
+
char :name, 64, 4 # => char name[64][4];
|
119
|
+
}
|
120
|
+
|
121
|
+
* Alias types by `typedef` (with array)
|
122
|
+
|
123
|
+
`typedef` による型の別名定義 (配列も可能)
|
124
|
+
|
125
|
+
typedef :float, :vector3f, 3 # => C: typedef float vector3f[3];
|
126
|
+
|
127
|
+
X = struct { # struct X {
|
128
|
+
vector3f :a # vector3f a;
|
129
|
+
vector3f :b, 4 # vector3f b[4];
|
130
|
+
} # };
|
131
|
+
|
132
|
+
* Appended bit operation for Integer
|
133
|
+
|
134
|
+
Integer に対する追加のビット操作
|
135
|
+
|
136
|
+
* Appended binary operation for String
|
137
|
+
|
138
|
+
String に対する追加のバイナリ操作
|
139
|
+
|
140
|
+
|
141
|
+
## How to usage (使い方)
|
142
|
+
|
143
|
+
最初に gogyou を読み込みます。
|
144
|
+
|
145
|
+
```ruby:ruby
|
146
|
+
require "gogyou"
|
147
|
+
```
|
148
|
+
|
149
|
+
次に、クラスやモジュールの中で `extend Gogyou` します。
|
150
|
+
|
151
|
+
```ruby:ruby
|
152
|
+
module MyModule
|
153
|
+
extend Gogyou
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
### Define struct (構造体の定義)
|
158
|
+
|
159
|
+
構造体(もどき)を構築するには、`struct` をブロック付きで呼び出します。
|
160
|
+
|
161
|
+
***このブロックは struct 内部で生成されるオブジェクトが `instance_exec` するときにそのまま渡されます。self が切り替わることに注意して下さい。***
|
162
|
+
|
163
|
+
フィールド名はシンボル (または文字列) で与えます。
|
164
|
+
|
165
|
+
```ruby:ruby
|
166
|
+
module MyModule
|
167
|
+
TypeA = struct {
|
168
|
+
int :a
|
169
|
+
}
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
これで int 型一つのフィールドからなる構造体(もどき)のクラスが TypeA として定義されました。
|
174
|
+
|
175
|
+
`struct` は定義した無名クラスを返すため、利用者側で定数に代入することで構造体名が定義されるわけです。
|
176
|
+
|
177
|
+
|
178
|
+
### Define array in struct (配列の定義)
|
179
|
+
|
180
|
+
配列として定義する場合は、フィールド名に続く引数として整数値を与えます。
|
181
|
+
|
182
|
+
```ruby:ruby
|
183
|
+
module MyModule
|
184
|
+
TypeA1 = struct {
|
185
|
+
int :b, 4 # => C: int b[4];
|
186
|
+
}
|
187
|
+
end
|
188
|
+
```
|
189
|
+
|
190
|
+
多次元配列の場合は、連続して整数値を与えます。
|
191
|
+
|
192
|
+
```ruby:ruby
|
193
|
+
module MyModule
|
194
|
+
TypeA2 = struct {
|
195
|
+
int :c, 8, 4, 2 # => C: int c[8][4][2];
|
196
|
+
}
|
197
|
+
end
|
198
|
+
```
|
199
|
+
|
200
|
+
配列の場合でも、複数のフィールドを連続してまとめることが出来ます。
|
201
|
+
|
202
|
+
```ruby:ruby
|
203
|
+
module MyModule
|
204
|
+
TypeA3 = struct {
|
205
|
+
int :a, :b, 4, :c, 8, 4, 2 # => C: int a, b[4], c[8][4][2];
|
206
|
+
}
|
207
|
+
end
|
208
|
+
```
|
209
|
+
|
210
|
+
|
211
|
+
### Define nested struct (入れ子になった構造体の定義)
|
212
|
+
|
213
|
+
入れ子構造体を定義するには、struct の内部で struct を使えばいいだけです。
|
214
|
+
|
215
|
+
struct の最初の引数にブロックを与えること以外は、先に述べた通常のフィールド定義と同じです。
|
216
|
+
|
217
|
+
コメントは C 言語で記述した場合の対比としてあります。
|
218
|
+
|
219
|
+
```ruby:ruby
|
220
|
+
module MyModule
|
221
|
+
TypeB = struct { # struct TypeB {
|
222
|
+
struct -> { # struct {
|
223
|
+
int :a, :b # int a, b;
|
224
|
+
}, :n, 2, 4, 8, :m # } n[2][4][8], m;
|
225
|
+
} # };
|
226
|
+
end
|
227
|
+
```
|
228
|
+
|
229
|
+
最初の引数にブロックではなく、型情報を持つオブジェクトを与えることも出来ます。
|
230
|
+
|
231
|
+
```ruby:ruby
|
232
|
+
module MyModule
|
233
|
+
TypeC = struct { # struct TypeC {
|
234
|
+
struct TypeA, :n, 2, 4, 8, :m # struct TypeA n[2][4][8], m;
|
235
|
+
} # };
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
無名構造体の場合、引数は渡さずにブロックを渡すだけです。
|
240
|
+
|
241
|
+
```ruby:ruby
|
242
|
+
module MyModule
|
243
|
+
TypeD = struct { # struct TypeD {
|
244
|
+
struct { # struct {
|
245
|
+
int :a, :b # int a, b;
|
246
|
+
} # };
|
247
|
+
} # };
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
struct 内の struct の呼び出し方法を示します。union も同様に利用できます。
|
252
|
+
|
253
|
+
* `struct { ... } -> nil`
|
254
|
+
* `struct proc_object, field_name, *array_elements`
|
255
|
+
* `struct user_type_info, field_name, *array_elements`
|
256
|
+
|
257
|
+
* `union { ... } -> nil`
|
258
|
+
* `union proc_object, field_name, *array_elements`
|
259
|
+
* `union user_type_info, field_name, *array_elements`
|
260
|
+
|
261
|
+
引数なしのブロック付きで呼ぶと、無名構造体 (union であれば無名共用体) を定義します。
|
262
|
+
|
263
|
+
`proc_object` を与えて呼ぶことで、続く `field_name` によってその内部を参照することが出来ます。
|
264
|
+
|
265
|
+
`array_elements` は任意個の整数値で、直前のフィールド名を配列として定義します。
|
266
|
+
|
267
|
+
`field_name` と `array_elements` を組にして複数個並べることが出来ます。
|
268
|
+
|
269
|
+
`user_type_info` は、任意のオブジェクト (クラスやオブジェクトを含む) を型として用いる場合に利用できます。
|
270
|
+
詳細は『About user typed info』を見て下さい。
|
271
|
+
|
272
|
+
|
273
|
+
## About user typed info (利用者定義の型情報について)
|
274
|
+
|
275
|
+
構造体・共用体の内部フィールドには、利用者が定義した型情報を用いることが出来ます。
|
276
|
+
|
277
|
+
この型情報は次のメソッドを持ったあらゆるオブジェクト (クラスでもモジュールでも、インスタンスでも構いません) のことです。
|
278
|
+
|
279
|
+
* `.bytesize`
|
280
|
+
* `.bytealign`
|
281
|
+
* `.extensible?`
|
282
|
+
* `.aref(buffer, offset)`
|
283
|
+
* `.aset(buffer, offset, data)`
|
284
|
+
|
285
|
+
例として、MD5 を定義する場合の型情報は次のようになります。
|
286
|
+
|
287
|
+
```ruby:ruby
|
288
|
+
class MD5
|
289
|
+
def self.bytesize
|
290
|
+
16
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.bytealign
|
294
|
+
1
|
295
|
+
end
|
296
|
+
|
297
|
+
def self.extensible?
|
298
|
+
false
|
299
|
+
end
|
300
|
+
|
301
|
+
def self.aref(buffer, offset)
|
302
|
+
... snip ...
|
303
|
+
end
|
304
|
+
|
305
|
+
def self.aset(buffer, offset, data)
|
306
|
+
... snip ...
|
307
|
+
end
|
308
|
+
end
|
309
|
+
```
|
310
|
+
|
311
|
+
順を追って説明していきます。
|
312
|
+
|
313
|
+
### `.bytesize`
|
314
|
+
|
315
|
+
このメソッドはその型が必要とする領域のバイト数を正の整数値で返します。
|
316
|
+
|
317
|
+
型が拡張構造になっている場合は、最小値となる値を返します。
|
318
|
+
|
319
|
+
MD5 を定義する場合、16バイトなので `16` を返します。
|
320
|
+
|
321
|
+
### `.bytealign`
|
322
|
+
|
323
|
+
このメソッドはその型のアライメントサイズを正の整数値で返します。
|
324
|
+
|
325
|
+
MD5 を定義する場合、内部表現は1バイトの塊なので `1` を返します (MD5 の実装によっては `4` だったり `8` だったり、はたまた `16` になるかもしれません)。
|
326
|
+
|
327
|
+
### `.extensible?`
|
328
|
+
|
329
|
+
このメソッドはその型が常に固定長か、任意に拡張する構造になっているかどうかを返します。
|
330
|
+
|
331
|
+
`true` であれば拡張構造であることを意味し、`false` であれば固定長であることを意味します。
|
332
|
+
|
333
|
+
MD5 は固定長なので、`false` を返します。
|
334
|
+
|
335
|
+
### `.aref(buffer, offset)`
|
336
|
+
|
337
|
+
このメソッドは構造体のフィールドを参照した場合に呼ばれます。
|
338
|
+
|
339
|
+
`buffer` は上位構造のバイナリデータとしての String インスタンスです。
|
340
|
+
|
341
|
+
`offset` は上位構造から見た、フィールドの絶対位置をバイト値で表した整数値です。
|
342
|
+
|
343
|
+
戻り値はその構造体のフィールドに対するインスタンスを返します。
|
344
|
+
|
345
|
+
MD5 の場合、`buffer` からデータを切り出して MD5 のインスタンスを返すべきです。
|
346
|
+
|
347
|
+
```ruby:ruby
|
348
|
+
class MD5
|
349
|
+
def self.aref(buffer, offset)
|
350
|
+
new(buffer.byteslice(offset, 16))
|
351
|
+
end
|
352
|
+
end
|
353
|
+
```
|
354
|
+
|
355
|
+
もしもインスタンスの変更を反映させる `MD5#[]=` のようなメソッドが必要であるならば、上述したメソッドではうまく行きません。
|
356
|
+
理由は `buffer.byteslice` によって `buffer` オブジェクトが切り離されてしまっているからです。
|
357
|
+
|
358
|
+
クラスを MD5 のデータが保持されるだけの構造から、`buffer` と `offset` を保持する構造に変更する必要があります。
|
359
|
+
その上でメソッドの定義を変更します。
|
360
|
+
|
361
|
+
```ruby:ruby
|
362
|
+
class MD5
|
363
|
+
def self.aref(buffer, offset)
|
364
|
+
new(buffer, offset)
|
365
|
+
end
|
366
|
+
|
367
|
+
def [](index)
|
368
|
+
raise IndexError unless index >= 0 && index < 16
|
369
|
+
@buffer.getbyte(@offset + index)
|
370
|
+
end
|
371
|
+
|
372
|
+
def []=(index, num)
|
373
|
+
raise IndexError unless index >= 0 && index < 16
|
374
|
+
@buffer.setbyte(@offset + index, num)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
```
|
378
|
+
|
379
|
+
### `.aset(buffer, offset, data)`
|
380
|
+
|
381
|
+
このメソッドは構造体のフィールドへデータを代入した時に呼ばれます。
|
382
|
+
|
383
|
+
例えば、`structobj.field = data` のような場合です。
|
384
|
+
|
385
|
+
`buffer` は上位構造のバイナリデータとしての String インスタンスです。
|
386
|
+
|
387
|
+
`offset` は上位構造から見た、フィールドの絶対位置をバイト値で表した整数値です。
|
388
|
+
|
389
|
+
`data` は代入する値です。
|
390
|
+
|
391
|
+
戻り値は無視されます。
|
392
|
+
|
393
|
+
`data` に対してどのような値 (オブジェクト) を受け入れるのかを決定するのは、型情報を定義する側の問題となります。
|
394
|
+
|
395
|
+
MD5 の場合、最低でも MD5 インスタンスを受け入れるようにするべきです。
|
396
|
+
|
397
|
+
今回は MD5 インスタンスだけではなく 16バイトの文字列、そして `nil` を受け取れるようにしてみます。
|
398
|
+
|
399
|
+
```ruby:ruby
|
400
|
+
class MD5
|
401
|
+
def self.aset(buffer, offset, data)
|
402
|
+
case data
|
403
|
+
when MD5
|
404
|
+
buffer.setbinary(offset, data.to_binary)
|
405
|
+
when String
|
406
|
+
buffer.setbinary(offset, data.byteslice(0, 16))
|
407
|
+
when nil
|
408
|
+
buffer[offset, 16] = ?0 * 16
|
409
|
+
else
|
410
|
+
raise ArgumentError, "data is not a MD5, String or nil"
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
```
|
415
|
+
|
416
|
+
|
417
|
+
## Demerit (短所)
|
418
|
+
|
419
|
+
* Can't be handled pointer
|
420
|
+
|
421
|
+
ポインタが扱えない
|
422
|
+
|
423
|
+
* The cost is high for reference/asignment from/to fields
|
424
|
+
|
425
|
+
フィールドに対する参照・代入のコストが高い
|
426
|
+
|
427
|
+
* Can't be definition for packed struct
|
428
|
+
|
429
|
+
パックされた構造体の定義が出来ない (常にフィールドは型によるバイト境界に強制配置される)
|