gogyou 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|