gogyou 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.markdown +124 -26
- data/lib/gogyou.rb +84 -1
- data/lib/gogyou/accessor.rb +2 -2
- data/lib/gogyou/mixin.rb +1 -1
- data/lib/gogyou/model.rb +65 -40
- data/spec/gogyou_spec.rb +153 -13
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff192352d61629b6bcec6f1f4a3ce798c2cab5ff
|
4
|
+
data.tar.gz: 244710ba81429d85608ed708424971d5c1bcd843
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b575790ca4b409310f7418dcc4e12220a9dfaeb511f4449756ad9997e83abf1c77953efa2d3dcc33c28e8b5fe92e0f71b66bb65ba296603054ab2639b85904eb
|
7
|
+
data.tar.gz: 3cc09af86d7884cca95aa399c912d19963608399273d45dd96cfbedc239c136f718e87ce2d2a8c6918d5757a0e2ddded0d93ff94afe45840f894de9ded4f003c
|
data/README.markdown
CHANGED
@@ -77,7 +77,7 @@ end
|
|
77
77
|
obj = MyRuby::RObject.new
|
78
78
|
# or obj = MyRuby::RObject.new(File.read("sample.bin", MyRuby::RObject.size, mode: "rb"))
|
79
79
|
obj.basic.flags = 0x12345678
|
80
|
-
(obj.basic.klass = 0xaaaaaaaa) rescue $! # => exception! klass field is immutable type
|
80
|
+
(obj.basic.klass = 0xaaaaaaaa) rescue p $! # => exception! klass field is immutable type
|
81
81
|
obj.basic.force_modify.klass = 0xaaaaaaaa
|
82
82
|
obj.as.heap.numiv = 0x55555555
|
83
83
|
p obj.as.ary[0] # => 0x55555555
|
@@ -97,37 +97,73 @@ p obj.to_buffer # => "xV4\x12\0\0\0\0\xaa\xaa\xaa\xaa\0\0\0\0UUUU\0\0\0\0DDDD\0
|
|
97
97
|
|
98
98
|
C に似た構造体・共用体に対応 (入れ子構造も可能)
|
99
99
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
}
|
100
|
+
``` ruby:ruby
|
101
|
+
X = Gogyou.struct {
|
102
|
+
int :a
|
103
|
+
float :b
|
104
|
+
double :c
|
105
|
+
union {
|
106
|
+
struct -> {
|
107
|
+
float :x, y, z
|
108
|
+
}, :d
|
109
|
+
const struct -> {
|
110
|
+
int :x, :y, :z
|
111
|
+
}, :e
|
112
|
+
}
|
113
|
+
}
|
114
|
+
```
|
112
115
|
|
113
116
|
* Support multidimensional arrays
|
114
117
|
|
115
118
|
多次元配列に対応
|
116
119
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
+
``` ruby:ruby
|
121
|
+
Gogyou.struct {
|
122
|
+
char :name, 64, 4 # => char name[64][4];
|
123
|
+
}
|
124
|
+
```
|
120
125
|
|
121
126
|
* Alias types by `typedef` (with array)
|
122
127
|
|
123
128
|
`typedef` による型の別名定義 (配列も可能)
|
124
129
|
|
125
|
-
|
130
|
+
``` ruby:ruby
|
131
|
+
module MyModule
|
132
|
+
extend Gogyou
|
133
|
+
|
134
|
+
typedef :float, :vector3f, 3 # => C: typedef float vector3f[3];
|
135
|
+
|
136
|
+
X = struct { # struct X {
|
137
|
+
vector3f :a # vector3f a;
|
138
|
+
vector3f :b, 4 # vector3f b[4];
|
139
|
+
} # };
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
* Support packed struct liked GCC ``__attribute__((packed))``
|
144
|
+
|
145
|
+
GCC の ``__attribute__((packed))`` に似た、パックされた構造体に対応
|
146
|
+
|
147
|
+
C 言語での記述
|
148
|
+
|
149
|
+
``` c:c
|
150
|
+
struct X
|
151
|
+
{
|
152
|
+
char a;
|
153
|
+
int b;
|
154
|
+
} __attribute__((packed));
|
155
|
+
```
|
156
|
+
|
157
|
+
ruby による記述
|
126
158
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
159
|
+
``` ruby:ruby
|
160
|
+
X = Gogyou.struct {
|
161
|
+
packed {
|
162
|
+
char :a
|
163
|
+
int :b
|
164
|
+
}
|
165
|
+
}
|
166
|
+
```
|
131
167
|
|
132
168
|
* Appended bit operation for Integer
|
133
169
|
|
@@ -284,7 +320,7 @@ struct 内の struct の呼び出し方法を示します。union も同様に
|
|
284
320
|
|
285
321
|
例として、MD5 を定義する場合の型情報は次のようになります。
|
286
322
|
|
287
|
-
```ruby:ruby
|
323
|
+
``` ruby:ruby
|
288
324
|
class MD5
|
289
325
|
def self.bytesize
|
290
326
|
16
|
@@ -308,6 +344,18 @@ class MD5
|
|
308
344
|
end
|
309
345
|
```
|
310
346
|
|
347
|
+
これらのメソッドを一つ一つ定義する代わりに、任意のクラス・モジュールの中で ``Gogyou.define_typeinfo`` を用いることでまとめて定義することも出来ます。
|
348
|
+
|
349
|
+
``` ruby:ruby
|
350
|
+
class MD5
|
351
|
+
Gogyou.define_typeinfo(16, # bytesize
|
352
|
+
1, # bytealign
|
353
|
+
false, # extensible?
|
354
|
+
->(buffer, offset) { ... snip ... }, # aref
|
355
|
+
->(buffer, offset, data) { ... snip ... }) # aset
|
356
|
+
end
|
357
|
+
```
|
358
|
+
|
311
359
|
順を追って説明していきます。
|
312
360
|
|
313
361
|
### `.bytesize`
|
@@ -413,6 +461,60 @@ class MD5
|
|
413
461
|
end
|
414
462
|
```
|
415
463
|
|
464
|
+
## Define packed struct
|
465
|
+
|
466
|
+
GCC の ``__attribute__((packed))`` に似たパックされた構造体のフィールドを定義するには、そのフィールドを ``packed`` メソッドのブロックとして囲うことで行います。
|
467
|
+
|
468
|
+
構造体自体をパックするには、その構造体のフィールド全体を ``packed`` することで行います。
|
469
|
+
|
470
|
+
また、``packed`` の中に ``struct`` や ``union`` を含めることも出来、その入れ子内部で ``packed`` を行うことも出来ます。
|
471
|
+
|
472
|
+
ただし ``packed`` を直接入れ子にして呼び出すことは出来ません。
|
473
|
+
|
474
|
+
構造体全体を ``packed`` する場合:
|
475
|
+
|
476
|
+
``` ruby:ruby
|
477
|
+
X = Gogyou.struct {
|
478
|
+
packed {
|
479
|
+
char :a
|
480
|
+
int :b
|
481
|
+
int :c
|
482
|
+
}
|
483
|
+
}
|
484
|
+
|
485
|
+
p X.bytesize # => 9
|
486
|
+
```
|
487
|
+
|
488
|
+
``packed`` された入れ子構造体の内部でさらに ``packed`` する場合:
|
489
|
+
|
490
|
+
``` ruby:ruby
|
491
|
+
Y = Gogyou.struct {
|
492
|
+
char :a
|
493
|
+
packed {
|
494
|
+
struct {
|
495
|
+
int :b
|
496
|
+
}
|
497
|
+
}
|
498
|
+
char :c, 3
|
499
|
+
int :d
|
500
|
+
}
|
501
|
+
|
502
|
+
p Y.bytesize # => 12
|
503
|
+
```
|
504
|
+
|
505
|
+
直接入れ子にして ``packed`` して例外が発生する場合:
|
506
|
+
|
507
|
+
``` ruby:ruby
|
508
|
+
Z = Gogyou.struct {
|
509
|
+
packed {
|
510
|
+
packed { ## => EXCEPTION!
|
511
|
+
char :a
|
512
|
+
int :b
|
513
|
+
}
|
514
|
+
}
|
515
|
+
}
|
516
|
+
```
|
517
|
+
|
416
518
|
|
417
519
|
## Demerit (短所)
|
418
520
|
|
@@ -423,7 +525,3 @@ end
|
|
423
525
|
* The cost is high for reference/asignment from/to fields
|
424
526
|
|
425
527
|
フィールドに対する参照・代入のコストが高い
|
426
|
-
|
427
|
-
* Can't be definition for packed struct
|
428
|
-
|
429
|
-
パックされた構造体の定義が出来ない (常にフィールドは型によるバイト境界に強制配置される)
|
data/lib/gogyou.rb
CHANGED
@@ -141,7 +141,7 @@
|
|
141
141
|
#
|
142
142
|
module Gogyou
|
143
143
|
Gogyou = self
|
144
|
-
VERSION = Gem::Version.new("0.2.
|
144
|
+
VERSION = Gem::Version.new("0.2.2")
|
145
145
|
|
146
146
|
require_relative "gogyou/typespec"
|
147
147
|
require_relative "gogyou/mixin"
|
@@ -196,6 +196,89 @@ module Gogyou
|
|
196
196
|
end
|
197
197
|
end
|
198
198
|
|
199
|
+
#
|
200
|
+
# call-seq:
|
201
|
+
# define_typeinfo(type, bytesize, bytealign, extensible, aref, aset) -> type
|
202
|
+
#
|
203
|
+
# ``type`` に対して、型情報子とするための特異メソッドである ``#bytesize`` ``#bytealign`` ``#extensible?`` ``#aref`` ``#aset`` を定義します。
|
204
|
+
#
|
205
|
+
# ``bytesize`` と ``bytealign`` には整数値、文字列、nil を与えます。
|
206
|
+
#
|
207
|
+
# ``extensible`` には真偽値、文字列、nil を与えます。
|
208
|
+
#
|
209
|
+
# ``aref`` には、引数として ``(buffer, offset)`` を受け取る Proc オブジェクト、文字列、nil を与えます。
|
210
|
+
#
|
211
|
+
# ``aset`` には、引数として ``(buffer, offset, value)`` を受け取る Proc オブジェクト、文字列、nil を与えます。
|
212
|
+
#
|
213
|
+
# これらの引数に文字列を与えた場合、メソッド定義コードとして直接埋め込まれます。
|
214
|
+
#
|
215
|
+
# ``bytesize`` と ``bytealign``、``extensible`` の引数はありません。
|
216
|
+
#
|
217
|
+
# ``aref`` の文字列内部で利用できる引数は ``buffer`` ``offset`` です。
|
218
|
+
#
|
219
|
+
# ``aset`` の文字列内部で利用できる引数は ``buffer`` ``offset`` ``value`` です。
|
220
|
+
#
|
221
|
+
# また nil を与えた場合は、対応するメソッドの定義を省略します。
|
222
|
+
#
|
223
|
+
# 常に ``type`` を返します。
|
224
|
+
#
|
225
|
+
def self.define_typeinfo(type, bytesize, bytealign, extensible, aref, aset)
|
226
|
+
type.instance_eval do
|
227
|
+
unless bytesize.nil?
|
228
|
+
bytesize = bytesize.to_i unless bytesize.kind_of?(String)
|
229
|
+
eval <<-EOM
|
230
|
+
def bytesize
|
231
|
+
#{bytesize}
|
232
|
+
end
|
233
|
+
EOM
|
234
|
+
end
|
235
|
+
|
236
|
+
unless bytealign.nil?
|
237
|
+
bytealign = bytealign.to_i unless bytealign.kind_of?(String)
|
238
|
+
eval <<-EOM
|
239
|
+
def bytealign
|
240
|
+
#{bytealign}
|
241
|
+
end
|
242
|
+
EOM
|
243
|
+
end
|
244
|
+
|
245
|
+
unless extensible.nil?
|
246
|
+
extensible = (!!extensible).inspect unless extensible.kind_of?(String)
|
247
|
+
eval <<-EOM
|
248
|
+
def extensible?
|
249
|
+
#{extensible}
|
250
|
+
end
|
251
|
+
EOM
|
252
|
+
end
|
253
|
+
|
254
|
+
unless aref.nil?
|
255
|
+
if aref.kind_of?(String)
|
256
|
+
eval <<-EOM
|
257
|
+
def aref(buffer, offset)
|
258
|
+
#{aref}
|
259
|
+
end
|
260
|
+
EOM
|
261
|
+
else
|
262
|
+
define_singleton_method(:aref, aref)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
unless aset.nil?
|
267
|
+
if aset.kind_of?(String)
|
268
|
+
eval <<-EOM
|
269
|
+
def aset(buffer, offset, value)
|
270
|
+
#{aset}
|
271
|
+
end
|
272
|
+
EOM
|
273
|
+
else
|
274
|
+
define_singleton_method(:aset, aset)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
type
|
280
|
+
end
|
281
|
+
|
199
282
|
#
|
200
283
|
# 構造体 (もどき) を定義します。
|
201
284
|
#
|
data/lib/gogyou/accessor.rb
CHANGED
@@ -90,7 +90,7 @@ module Gogyou
|
|
90
90
|
|
91
91
|
def inspect
|
92
92
|
"#<%s buffer=%p, offset=%p>" % [self.class,
|
93
|
-
buffer__GOGYOU__,
|
93
|
+
buffer__GOGYOU__.inspect,
|
94
94
|
offset__GOGYOU__]
|
95
95
|
end
|
96
96
|
|
@@ -337,7 +337,7 @@ module Gogyou
|
|
337
337
|
case value
|
338
338
|
when ::String
|
339
339
|
raise ArgumentError, "buffer size too small" unless value.bytesize < self::BYTESIZE
|
340
|
-
buffer.setbinary(offset, value, self::BYTESIZE
|
340
|
+
buffer.setbinary(offset, value, 0, self::BYTESIZE)
|
341
341
|
when ::Array
|
342
342
|
raise NotImplementedError
|
343
343
|
when self::SUBTYPE
|
data/lib/gogyou/mixin.rb
CHANGED
@@ -231,7 +231,7 @@ module Gogyou
|
|
231
231
|
self
|
232
232
|
end
|
233
233
|
|
234
|
-
def setbinary(index, str,
|
234
|
+
def setbinary(index, str, offset = 0, bytesize = str.bytesize)
|
235
235
|
offset = offset.to_i
|
236
236
|
bytesize = bytesize.to_i
|
237
237
|
size1 = str.bytesize - offset
|
data/lib/gogyou/model.rb
CHANGED
@@ -66,13 +66,14 @@ module Gogyou
|
|
66
66
|
:name, # field name
|
67
67
|
:vector, # 要素数。任意数配列の場合は 0。配列でないならば nil。
|
68
68
|
:type, # type specification (or model object) of this field
|
69
|
-
:flags) #
|
69
|
+
:flags) # LSB-0+8: packed size exponent (not aligned) / LSB-16: const
|
70
70
|
BasicStruct = superclass
|
71
71
|
|
72
|
-
|
73
|
-
|
72
|
+
CONST_BITMASK = 1 << 16
|
73
|
+
PACKSIZE_BITMASK = 0xff
|
74
|
+
PACKSIZE_NOTDEFINE = 20 # = (1 << 20) = 1 MiB # 事実上の無限
|
74
75
|
|
75
|
-
def initialize(offset, name, vector, type, flags = 0)
|
76
|
+
def initialize(offset, name, vector, type, flags = 0 | PACKSIZE_NOTDEFINE)
|
76
77
|
super(offset, name, vector, type, flags)
|
77
78
|
end
|
78
79
|
|
@@ -85,25 +86,30 @@ module Gogyou
|
|
85
86
|
end
|
86
87
|
|
87
88
|
def const?
|
88
|
-
((flags &
|
89
|
+
((flags & CONST_BITMASK) == CONST_BITMASK) ? true : false
|
89
90
|
end
|
90
91
|
|
91
92
|
def packed?
|
92
|
-
((flags &
|
93
|
+
((flags & PACKSIZE_BITMASK) == PACKSIZE_NOTDEFINE) ? false : true
|
93
94
|
end
|
94
95
|
|
95
|
-
def
|
96
|
-
self.flags |=
|
96
|
+
def set_const
|
97
|
+
self.flags |= CONST_BITMASK
|
97
98
|
self
|
98
99
|
end
|
99
100
|
|
100
|
-
def
|
101
|
-
|
101
|
+
def set_packsize(pack_exponent)
|
102
|
+
pack_exponent = PACKSIZE_NOTDEFINE if pack_exponent > PACKSIZE_NOTDEFINE
|
103
|
+
self.flags = flags.setbit(0, 8, pack_exponent)
|
102
104
|
self
|
103
105
|
end
|
104
106
|
|
107
|
+
def packsize
|
108
|
+
1 << flags.getbit(0, 8)
|
109
|
+
end
|
110
|
+
|
105
111
|
def strflags
|
106
|
-
set = [const? ? "const" : nil, packed? ? "packed" : nil]
|
112
|
+
set = [const? ? "const" : nil, packed? ? "packed(#{packsize})" : nil]
|
107
113
|
set.compact!
|
108
114
|
return nil if set.empty?
|
109
115
|
set.join(",")
|
@@ -145,12 +151,12 @@ module Gogyou
|
|
145
151
|
end
|
146
152
|
end
|
147
153
|
|
148
|
-
def self.struct(typemap, &block)
|
149
|
-
define_container(typemap, Model::Struct, &block)
|
154
|
+
def self.struct(typemap, packexp = Field::PACKSIZE_NOTDEFINE, &block)
|
155
|
+
define_container(typemap, packexp, Model::Struct, &block)
|
150
156
|
end
|
151
157
|
|
152
|
-
def self.union(typemap, &block)
|
153
|
-
define_container(typemap, Model::Union, &block)
|
158
|
+
def self.union(typemap, packexp = Field::PACKSIZE_NOTDEFINE, &block)
|
159
|
+
define_container(typemap, packexp, Model::Union, &block)
|
154
160
|
end
|
155
161
|
|
156
162
|
def self.typedef(typemap, type, aliasname, *elements)
|
@@ -178,9 +184,9 @@ module Gogyou
|
|
178
184
|
nil
|
179
185
|
end
|
180
186
|
|
181
|
-
def self.define_container(typemap, model_type, &block)
|
187
|
+
def self.define_container(typemap, packexp, model_type, &block)
|
182
188
|
creator = model_type::Creator.new(typemap, 0, [])
|
183
|
-
proxy = model_type::Creator::Proxy.new(creator)
|
189
|
+
proxy = model_type::Creator::Proxy.new(creator, packexp)
|
184
190
|
proxy.instance_exec(&block)
|
185
191
|
model = creator.to_model
|
186
192
|
model
|
@@ -205,7 +211,7 @@ module Gogyou
|
|
205
211
|
|
206
212
|
class BasicCreator
|
207
213
|
def maxalign(fields = self.fields)
|
208
|
-
fields.map { |f| f.type.bytealign }.max
|
214
|
+
fields.map { |f| f.packed? ? f.packsize : f.type.bytealign }.max
|
209
215
|
end
|
210
216
|
|
211
217
|
def maxsize(fields = self.fields)
|
@@ -223,7 +229,7 @@ module Gogyou
|
|
223
229
|
else
|
224
230
|
raise "BUG? : field.type is not a Model (%p)" % f.type unless f.type.kind_of?(Model)
|
225
231
|
fs = flatten_field(f.type.fields)
|
226
|
-
fs.each { |ff| ff.offset += f.offset; ff.
|
232
|
+
fs.each { |ff| ff.offset += f.offset; ff.set_const if f.const? }
|
227
233
|
fields2.concat fs
|
228
234
|
end
|
229
235
|
end
|
@@ -233,23 +239,42 @@ module Gogyou
|
|
233
239
|
# :nodoc: all
|
234
240
|
class Proxy < Object
|
235
241
|
#class Proxy < BasicObject
|
236
|
-
def initialize(creator)
|
242
|
+
def initialize(creator, packexp = Field::PACKSIZE_NOTDEFINE)
|
237
243
|
#singleton_class = (class << proxy; self; end)
|
238
244
|
singleton_class.class_eval do
|
239
245
|
latest_fields = nil
|
240
246
|
#define_method(:method_missing, ->(type, *args) { latest_fields = creator.addfield(type, args); nil })
|
241
247
|
creator.typemap.each_key do |t|
|
242
|
-
define_method(t, ->(*args) { latest_fields = creator.addfield(t, args); nil })
|
248
|
+
define_method(t, ->(*args) { latest_fields = creator.addfield(t, packexp, args); nil })
|
243
249
|
end
|
244
|
-
define_method(:struct, ->(*args, &block) { latest_fields = creator.struct(args, &block); nil })
|
245
|
-
define_method(:union, ->(*args, &block) { latest_fields = creator.union(args, &block); nil })
|
250
|
+
define_method(:struct, ->(*args, &block) { latest_fields = creator.struct(args, packexp, &block); nil })
|
251
|
+
define_method(:union, ->(*args, &block) { latest_fields = creator.union(args, packexp, &block); nil })
|
246
252
|
define_method(:const, ->(dummy_fields) { creator.const(latest_fields); latest_fields = nil; nil })
|
247
253
|
define_method(:typedef, ->(*args, &block) { creator.typedef(args, &block) })
|
254
|
+
packexp0 = nil
|
255
|
+
define_method(:packed, ->(bytealign = 1, &block) {
|
256
|
+
raise "wrong nested ``packed''" if packexp0
|
257
|
+
exp = Math.log(bytealign, 2)
|
258
|
+
# exp が Nan Infinity -Infinity の場合は例外が発生するので、それに対する処置も行う
|
259
|
+
unless ((exp = exp.to_i) rescue nil) && (1 << exp) == bytealign
|
260
|
+
raise ArgumentError, "shall be given power of two (but #{bytealign})"
|
261
|
+
end
|
262
|
+
|
263
|
+
begin
|
264
|
+
packexp0 = packexp
|
265
|
+
packexp = exp
|
266
|
+
self.instance_exec(&block)
|
267
|
+
ensure
|
268
|
+
(packexp, packexp0) = packexp0, nil
|
269
|
+
end
|
270
|
+
|
271
|
+
nil
|
272
|
+
})
|
248
273
|
if creator.respond_to?(:bytealign)
|
249
|
-
define_method(:bytealign, ->(bytesize, &block) { creator.bytealign(bytesize, &block) })
|
274
|
+
define_method(:bytealign, ->(bytesize, &block) { creator.bytealign(bytesize, &block); nil })
|
250
275
|
end
|
251
276
|
if creator.respond_to?(:padding)
|
252
|
-
define_method(:padding, ->(bytesize, &block) { creator.padding(bytesize, &block) })
|
277
|
+
define_method(:padding, ->(bytesize, &block) { creator.padding(bytesize, &block); nil })
|
253
278
|
end
|
254
279
|
end
|
255
280
|
end
|
@@ -287,8 +312,8 @@ module Gogyou
|
|
287
312
|
# }
|
288
313
|
# }
|
289
314
|
#
|
290
|
-
def struct(args, &block)
|
291
|
-
define_container(args, block, Model.method(:struct))
|
315
|
+
def struct(args, packexp, &block)
|
316
|
+
define_container(args, packexp, block, Model.method(:struct))
|
292
317
|
end
|
293
318
|
|
294
319
|
#
|
@@ -306,24 +331,24 @@ module Gogyou
|
|
306
331
|
# この記述ができる唯一の理由は、人間が見てわかりやすくすることを意図しています
|
307
332
|
# (ただし、ミスリードを誘う手口にも利用されてしまうのが最大の欠点です)。
|
308
333
|
#
|
309
|
-
def union(args, &block)
|
310
|
-
define_container(args, block, Model.method(:union))
|
334
|
+
def union(args, packexp, &block)
|
335
|
+
define_container(args, packexp, block, Model.method(:union))
|
311
336
|
end
|
312
337
|
|
313
|
-
def define_container(args, anonymblock, container)
|
338
|
+
def define_container(args, packexp, anonymblock, container)
|
314
339
|
if anonymblock
|
315
340
|
raise ArgumentError, "given block and arguments" unless args.empty?
|
316
|
-
model = container.(typemap.dup, &anonymblock)
|
341
|
+
model = container.(typemap.dup, packexp, &anonymblock)
|
317
342
|
raise "BUG - object is not a Model (#{model.class})" unless model.kind_of?(Model)
|
318
343
|
#p model: model, superclass: model.superclass
|
319
344
|
self.offset = offset.align_ceil(model.bytealign) unless kind_of?(Model::Union::Creator)
|
320
|
-
fields << f = Field[offset, nil, nil, model,
|
345
|
+
fields << f = Field[offset, nil, nil, model, packexp]
|
321
346
|
self.offset += model.bytesize unless kind_of?(Model::Union::Creator)
|
322
347
|
[f]
|
323
348
|
else
|
324
349
|
type = args.shift
|
325
|
-
type = container.(typemap.dup, &type) if type.kind_of?(::Proc)
|
326
|
-
addfield!(type, args)
|
350
|
+
type = container.(typemap.dup, packexp, &type) if type.kind_of?(::Proc)
|
351
|
+
addfield!(type, packexp, args)
|
327
352
|
end
|
328
353
|
end
|
329
354
|
|
@@ -332,7 +357,7 @@ module Gogyou
|
|
332
357
|
end
|
333
358
|
|
334
359
|
def const(fields)
|
335
|
-
fields.each { |f| f.
|
360
|
+
fields.each { |f| f.set_const }
|
336
361
|
end
|
337
362
|
|
338
363
|
#
|
@@ -371,16 +396,16 @@ module Gogyou
|
|
371
396
|
nil
|
372
397
|
end
|
373
398
|
|
374
|
-
def addfield(type, args)
|
399
|
+
def addfield(type, packexp, args)
|
375
400
|
typeobj = typemap[type.intern]
|
376
401
|
unless typeobj
|
377
402
|
raise NoMethodError, "typename or method is missing (#{type})"
|
378
403
|
end
|
379
404
|
|
380
|
-
addfield!(typeobj, args)
|
405
|
+
addfield!(typeobj, packexp, args)
|
381
406
|
end
|
382
407
|
|
383
|
-
def addfield!(typeobj, args)
|
408
|
+
def addfield!(typeobj, packexp, args)
|
384
409
|
#p typeobj
|
385
410
|
# check extensible field >>> creator.fields[-1].vector[-1]
|
386
411
|
if (x = fields[-1]) && (x = x.vector) && x[-1] == 0
|
@@ -388,13 +413,13 @@ module Gogyou
|
|
388
413
|
end
|
389
414
|
|
390
415
|
typesize = typeobj.bytesize
|
391
|
-
typealign = typeobj.bytealign
|
416
|
+
typealign = [typeobj.bytealign, 1 << packexp].min
|
392
417
|
|
393
418
|
tmpfields = []
|
394
419
|
|
395
420
|
parse!(args) do |name, vect|
|
396
421
|
self.offset = offset.align_ceil(typealign) unless kind_of?(Model::Union::Creator)
|
397
|
-
fields << f = Field[offset, name, vect, typeobj, 0]
|
422
|
+
fields << f = Field[offset, name, vect, typeobj, 0 | packexp]
|
398
423
|
tmpfields << f
|
399
424
|
unless kind_of?(Model::Union::Creator)
|
400
425
|
elements = vect ? vect.inject(1, &:*) : 1
|
data/spec/gogyou_spec.rb
CHANGED
@@ -35,8 +35,8 @@ describe Gogyou::Model do
|
|
35
35
|
|
36
36
|
reference = Gogyou::Model::Union[
|
37
37
|
4, 4,
|
38
|
-
Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::INT32_T
|
39
|
-
Gogyou::Model::Field[0, :b, nil, Gogyou::Primitives::UINT32_T
|
38
|
+
Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::INT32_T],
|
39
|
+
Gogyou::Model::Field[0, :b, nil, Gogyou::Primitives::UINT32_T]
|
40
40
|
]
|
41
41
|
|
42
42
|
expect(x::MODEL).to eq reference
|
@@ -57,11 +57,11 @@ describe Gogyou::Model do
|
|
57
57
|
|
58
58
|
ref = Gogyou::Model::Struct[
|
59
59
|
32, 8,
|
60
|
-
Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::CHAR
|
61
|
-
Gogyou::Model::Field[8, :b, nil, Gogyou::Primitives::INT
|
62
|
-
Gogyou::Model::Field[8, :c, nil, Gogyou::Primitives::INT64_T
|
63
|
-
Gogyou::Model::Field[16, :d, nil, Gogyou::Primitives::INT32_T
|
64
|
-
Gogyou::Model::Field[24, :e, nil, Gogyou::Primitives::CHAR
|
60
|
+
Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::CHAR],
|
61
|
+
Gogyou::Model::Field[8, :b, nil, Gogyou::Primitives::INT],
|
62
|
+
Gogyou::Model::Field[8, :c, nil, Gogyou::Primitives::INT64_T],
|
63
|
+
Gogyou::Model::Field[16, :d, nil, Gogyou::Primitives::INT32_T],
|
64
|
+
Gogyou::Model::Field[24, :e, nil, Gogyou::Primitives::CHAR]
|
65
65
|
]
|
66
66
|
|
67
67
|
expect(x::MODEL).to eq ref
|
@@ -81,12 +81,12 @@ describe Gogyou::Model do
|
|
81
81
|
|
82
82
|
ref = Gogyou::Model::Struct[
|
83
83
|
72, 8,
|
84
|
-
Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::CHAR
|
85
|
-
Gogyou::Model::Field[8, :b, nil, Gogyou::Primitives::INT
|
84
|
+
Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::CHAR],
|
85
|
+
Gogyou::Model::Field[8, :b, nil, Gogyou::Primitives::INT],
|
86
86
|
Gogyou::Model::Field[8, :e, [4], Gogyou::Model::Struct[
|
87
87
|
16, 8,
|
88
|
-
Gogyou::Model::Field[0, :c, nil, Gogyou::Primitives::INT64_T
|
89
|
-
Gogyou::Model::Field[8, :d, nil, Gogyou::Primitives::INT32_T
|
88
|
+
Gogyou::Model::Field[0, :c, nil, Gogyou::Primitives::INT64_T],
|
89
|
+
Gogyou::Model::Field[8, :d, nil, Gogyou::Primitives::INT32_T]]]]
|
90
90
|
expect(x::MODEL).to eq ref
|
91
91
|
end
|
92
92
|
|
@@ -108,8 +108,8 @@ describe Gogyou::Model do
|
|
108
108
|
|
109
109
|
ref = Gogyou::Model::Union[
|
110
110
|
24, 8,
|
111
|
-
Gogyou::Model::Field[0, :a, nil, x
|
112
|
-
Gogyou::Model::Field[0, :b, nil, x
|
111
|
+
Gogyou::Model::Field[0, :a, nil, x],
|
112
|
+
Gogyou::Model::Field[0, :b, nil, x]]
|
113
113
|
expect(y::MODEL).to eq ref
|
114
114
|
end
|
115
115
|
end
|
@@ -163,4 +163,144 @@ describe Gogyou::Accessor do
|
|
163
163
|
obj = type.new
|
164
164
|
expect(obj.bytesize).to eq 20
|
165
165
|
end
|
166
|
+
|
167
|
+
it "packed struct" do
|
168
|
+
type1 = Gogyou.struct {
|
169
|
+
packed(1) {
|
170
|
+
char :a
|
171
|
+
int32_t :b
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
expect(type1.bytesize).to eq 5
|
176
|
+
expect(type1.bytealign).to eq 1
|
177
|
+
expect(type1.extensible?).to eq false
|
178
|
+
expect(type1.new.bytesize).to eq 5
|
179
|
+
|
180
|
+
type2 = Gogyou.struct {
|
181
|
+
packed(2) {
|
182
|
+
char :a
|
183
|
+
int32_t :b
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
expect(type2.bytesize).to eq 6
|
188
|
+
expect(type2.bytealign).to eq 2
|
189
|
+
expect(type2.extensible?).to eq false
|
190
|
+
expect(type2.new.bytesize).to eq 6
|
191
|
+
end
|
192
|
+
|
193
|
+
it "packed and nested struct" do
|
194
|
+
type1 = Gogyou.struct {
|
195
|
+
struct {
|
196
|
+
packed(1) {
|
197
|
+
char :a
|
198
|
+
int32_t :b
|
199
|
+
}
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
expect(type1.bytesize).to eq 5
|
204
|
+
expect(type1.bytealign).to eq 1
|
205
|
+
expect(type1.extensible?).to eq false
|
206
|
+
expect(type1.new.bytesize).to eq 5
|
207
|
+
|
208
|
+
type2 = Gogyou.struct {
|
209
|
+
packed(1) {
|
210
|
+
struct {
|
211
|
+
char :a
|
212
|
+
int32_t :b
|
213
|
+
}
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
expect(type2.bytesize).to eq 5
|
218
|
+
expect(type2.bytealign).to eq 1
|
219
|
+
expect(type2.extensible?).to eq false
|
220
|
+
expect(type2.new.bytesize).to eq 5
|
221
|
+
|
222
|
+
type3 = Gogyou.struct {
|
223
|
+
packed(1) {
|
224
|
+
struct -> {
|
225
|
+
char :a
|
226
|
+
int32_t :b
|
227
|
+
}, :x
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
expect(type3.bytesize).to eq 5
|
232
|
+
expect(type3.bytealign).to eq 1
|
233
|
+
expect(type3.extensible?).to eq false
|
234
|
+
expect(type3.new.bytesize).to eq 5
|
235
|
+
end
|
236
|
+
|
237
|
+
it "packed and nested struct" do
|
238
|
+
type1 = Gogyou.struct {
|
239
|
+
packed(2) {
|
240
|
+
struct {
|
241
|
+
packed(1) {
|
242
|
+
char :a
|
243
|
+
int32_t :b
|
244
|
+
}
|
245
|
+
}
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
expect(type1.bytesize).to eq 6
|
250
|
+
expect(type1.bytealign).to eq 2
|
251
|
+
expect(type1.extensible?).to eq false
|
252
|
+
expect(type1.new.bytesize).to eq 6
|
253
|
+
|
254
|
+
expect {
|
255
|
+
Gogyou.struct {
|
256
|
+
packed(1) {
|
257
|
+
packed(2) {
|
258
|
+
struct {
|
259
|
+
char :a
|
260
|
+
int32_t :b
|
261
|
+
}
|
262
|
+
}
|
263
|
+
}
|
264
|
+
}
|
265
|
+
}.to raise_error RuntimeError
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe "user typeinfo" do
|
270
|
+
it "definition and use" do
|
271
|
+
x1 = Object.new
|
272
|
+
Gogyou.define_typeinfo(x1, 8.0, Rational(5, 2), false,
|
273
|
+
->(buffer, offset) { buffer.byteslice(offset, 8) },
|
274
|
+
->(buffer, offset, value) { buffer.setbinary(offset, value, 0, 16) })
|
275
|
+
expect(x1.bytesize).to eq 8
|
276
|
+
expect(x1.bytealign).to eq 2
|
277
|
+
expect(x1.extensible?).to eq false
|
278
|
+
|
279
|
+
x2 = Object.new
|
280
|
+
Gogyou.define_typeinfo(x2, "16", "4", "false",
|
281
|
+
"buffer.byteslice(offset, 16)",
|
282
|
+
"buffer.setbinary(offset, value.downcase, 0, 16)")
|
283
|
+
expect(x2.bytesize).to eq 16
|
284
|
+
expect(x2.bytealign).to eq 4
|
285
|
+
expect(x2.extensible?).to eq false
|
286
|
+
|
287
|
+
type = Gogyou.struct {
|
288
|
+
struct x1, :a
|
289
|
+
struct x2, :b
|
290
|
+
}
|
291
|
+
|
292
|
+
expect(type.bytesize).to eq 24
|
293
|
+
expect(type.bytealign).to eq 4
|
294
|
+
expect(type.extensible?).to eq false
|
295
|
+
|
296
|
+
v = type.bind("abcdefghijklmnopqrstuvwx")
|
297
|
+
expect(v.bytesize).to eq 24
|
298
|
+
expect(v.size).to eq 2
|
299
|
+
expect(v.a).to eq "abcdefgh"
|
300
|
+
v.a = "ABCDEFGH"
|
301
|
+
expect(v.buffer).to eq "ABCDEFGHijklmnopqrstuvwx"
|
302
|
+
expect(v.b).to eq "ijklmnopqrstuvwx"
|
303
|
+
v.b = "0ijklmnopqrstuv9wx"
|
304
|
+
expect(v.buffer).to eq "ABCDEFGH0ijklmnopqrstuv9"
|
305
|
+
end
|
166
306
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gogyou
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dearblue
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -57,8 +57,8 @@ extra_rdoc_files:
|
|
57
57
|
- lib/gogyou/accessor.rb
|
58
58
|
- lib/gogyou/mixin.rb
|
59
59
|
- lib/gogyou/model.rb
|
60
|
-
- lib/gogyou/primitives.rb
|
61
60
|
- lib/gogyou/typespec.rb
|
61
|
+
- lib/gogyou/primitives.rb
|
62
62
|
files:
|
63
63
|
- LICENSE.markdown
|
64
64
|
- README.markdown
|