gogyou 0.1.240911.prototype → 0.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 +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
@@ -0,0 +1,397 @@
|
|
1
|
+
module Gogyou
|
2
|
+
#
|
3
|
+
# 構造体データを構造体として参照させるためのクラスです。
|
4
|
+
#
|
5
|
+
# このクラスのサブクラスをさらに派生させたクラスが、実際の役目を負います。
|
6
|
+
#
|
7
|
+
# === クラス関係図
|
8
|
+
#
|
9
|
+
# リストの入れ子関係は、クラスの親子関係を表します。
|
10
|
+
#
|
11
|
+
# * Accessor - 基本クラス
|
12
|
+
# * Accessor::BasicStruct - 構造体の基本クラス
|
13
|
+
# * Accessor::Struct - 特定の Model に対する構造体クラス
|
14
|
+
# * Accessor::TemporaryStruct - 汎用的な型情報に対する構造体クラス
|
15
|
+
# * Accessor::BasicUnion - 共用体の基本クラス
|
16
|
+
# * Accessor::Union - 特定の Model に対する共用体クラス
|
17
|
+
# * Accessor::TemporaryUnion - 汎用的な型情報に対する共用体クラス
|
18
|
+
# * Accessor::BasicArray - 配列型の基本クラス
|
19
|
+
# * Accessor::Array - 特定の Model に対する配列型クラス
|
20
|
+
# * Accessor::TemporaryArray - 汎用的な型情報に対する配列型クラス
|
21
|
+
#
|
22
|
+
class Accessor
|
23
|
+
attr_reader :buffer__GOGYOU__
|
24
|
+
attr_reader :offset__GOGYOU__
|
25
|
+
|
26
|
+
alias buffer buffer__GOGYOU__
|
27
|
+
alias offset offset__GOGYOU__
|
28
|
+
|
29
|
+
def initialize(buffer = String.alloc(self.class::BYTESIZE), offset = 0)
|
30
|
+
buffer = String.alloc(buffer.to_i) if buffer.kind_of?(Integer)
|
31
|
+
@buffer__GOGYOU__ = buffer
|
32
|
+
@offset__GOGYOU__ = offset.to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize_copy(obj)
|
36
|
+
super(obj)
|
37
|
+
unless obj.frozen?
|
38
|
+
@buffer__GOGYOU__ = obj.buffer__GOGYOU__.dup
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# バイナリデータとして取り出します。
|
44
|
+
#
|
45
|
+
def to_s
|
46
|
+
buffer__GOGYOU__.byteslice(offset__GOGYOU__, self.class::BYTESIZE)
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_buffer
|
50
|
+
buffer__GOGYOU__
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_ptr
|
54
|
+
buffer__GOGYOU__.to_ptr
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# call-seq:
|
59
|
+
# slide() -> new_accessor or nil
|
60
|
+
# slide(bytesize) -> new_accessor or nil
|
61
|
+
#
|
62
|
+
# 自身のデータ領域を指定バイト数ずらした参照体を返します。
|
63
|
+
#
|
64
|
+
def slide(bytesize = self.class::BYTESIZE)
|
65
|
+
self.class.new(buffer__GOGYOU__, offset__GOGYOU__ + bytesize)
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# call-seq:
|
70
|
+
# slide!() -> self or nil
|
71
|
+
# slide!(bytesize) -> self or nil
|
72
|
+
#
|
73
|
+
# 詳細は slide を参照して下さい。
|
74
|
+
#
|
75
|
+
def slide!(bytesize = self.class::BYTESIZE)
|
76
|
+
offset = offset__GOGYOU__ + bytesize
|
77
|
+
#return nil if offset < 0
|
78
|
+
#return nil if offset + buffer__GOGYOU__.bytesize > layout__GOGYOU__.bytesize
|
79
|
+
@offset__GOGYOU__ = offset
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
def bytesize
|
84
|
+
self.class::BYTESIZE
|
85
|
+
end
|
86
|
+
|
87
|
+
def size
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
def inspect
|
92
|
+
"#<%s buffer=%p, offset=%p>" % [self.class,
|
93
|
+
buffer__GOGYOU__,
|
94
|
+
offset__GOGYOU__]
|
95
|
+
end
|
96
|
+
|
97
|
+
def pretty_print(q)
|
98
|
+
q.group(1, "#<#{self.class}") do
|
99
|
+
q.breakable " "
|
100
|
+
q.text "buffer="
|
101
|
+
q.pp buffer__GOGYOU__
|
102
|
+
q.text ","
|
103
|
+
q.breakable " "
|
104
|
+
q.text "offset="
|
105
|
+
q.pp offset__GOGYOU__
|
106
|
+
q.text ">"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.bind(buffer, offset = 0)
|
111
|
+
new(buffer, offset)
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.model
|
115
|
+
self::MODEL
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.define(model)
|
119
|
+
klass = ::Class.new(self)
|
120
|
+
klass.class_eval do
|
121
|
+
const_set(:MODEL, model)
|
122
|
+
const_set(:BYTESIZE, model.bytesize)
|
123
|
+
const_set(:BYTEALIGN, model.bytealign)
|
124
|
+
const_set(:EXTENSIBLE, model.extensible?)
|
125
|
+
end
|
126
|
+
|
127
|
+
define_accessors(klass, model)
|
128
|
+
|
129
|
+
klass
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.define_subarray(field)
|
133
|
+
#sub-array のためのクラスを生成する (多次元配列であれば、それぞれの次元に対して作成)
|
134
|
+
#sub-array クラスの MODEL 定数は、Gogyou::Model::Array のインスタンス
|
135
|
+
fsize = field.vector.inject(&:*) * field.type.bytesize
|
136
|
+
falign = field.type.bytealign
|
137
|
+
felements = field.vector[-1]
|
138
|
+
raise "BUG: negative element bytesize - #{field.inspect}" unless felements >= 0
|
139
|
+
felements = nil if felements == 0
|
140
|
+
fvect = field.vector.slice(0 ... -1)
|
141
|
+
fvect = nil if fvect.empty?
|
142
|
+
subarray = Accessor::Array.define(Model::Array[fsize, falign, [Model::Field[nil, felements, fvect, field.type]]])
|
143
|
+
subarray.name # すでに名前が定義されてる場合はこれで固定される
|
144
|
+
Accessor.const_set("UserArray_%08X" % subarray.__id__, subarray)
|
145
|
+
subarray
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.define_accessors(accessorclass, model)
|
149
|
+
accessorclass.class_eval do
|
150
|
+
namecheck = {}
|
151
|
+
model.fields.each do |field|
|
152
|
+
name = field.name
|
153
|
+
#raise NameError, "wrong field name - #{name}" unless name =~ /\A[A-Za-z_][A-Za-z_0-9]*\Z/
|
154
|
+
name = name.intern
|
155
|
+
raise NameError, "already exist field name - #{name}" if namecheck[name]
|
156
|
+
namecheck[name] = true
|
157
|
+
|
158
|
+
if field.vector
|
159
|
+
subarray = define_subarray(field)
|
160
|
+
type = subarray
|
161
|
+
else
|
162
|
+
subarray = nil
|
163
|
+
type = field.type
|
164
|
+
end
|
165
|
+
|
166
|
+
define_method(field.name, -> {
|
167
|
+
v = type.aref(buffer__GOGYOU__, offset__GOGYOU__ + field.offset)
|
168
|
+
v.infect_from(self, buffer) unless v.frozen?
|
169
|
+
v.freeze if frozen? || buffer.frozen? || field.const?
|
170
|
+
v
|
171
|
+
})
|
172
|
+
|
173
|
+
define_method("#{field.name}=", ->(value) {
|
174
|
+
raise TypeError, "immutable object (#<%s:0x%08X>.%s)" % [self.class, __id__, field.name], caller(2) if frozen?
|
175
|
+
raise TypeError, "immutable field (#<%s:0x%08X>.%s)" % [self.class, __id__, field.name], caller(2) if field.const?
|
176
|
+
type.aset(buffer__GOGYOU__, offset__GOGYOU__ + field.offset, value)
|
177
|
+
})
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
#
|
183
|
+
# 型情報オブジェクトとしてのメソッドです。
|
184
|
+
#
|
185
|
+
def self.aref(buffer, offset)
|
186
|
+
new(buffer, offset)
|
187
|
+
end
|
188
|
+
|
189
|
+
#
|
190
|
+
# 型情報オブジェクトとしてのメソッドです。
|
191
|
+
#
|
192
|
+
def self.aset(buffer, offset, data)
|
193
|
+
raise NotImplementedError, "IMPLEMENT ME in sub class!"
|
194
|
+
end
|
195
|
+
|
196
|
+
#
|
197
|
+
# 型情報オブジェクトとしてのメソッドです。
|
198
|
+
#
|
199
|
+
def self.bytesize
|
200
|
+
self::BYTESIZE
|
201
|
+
end
|
202
|
+
|
203
|
+
#
|
204
|
+
# 型情報オブジェクトとしてのメソッドです。
|
205
|
+
#
|
206
|
+
def self.bytealign
|
207
|
+
self::BYTEALIGN
|
208
|
+
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# 型情報オブジェクトとしてのメソッドです。
|
212
|
+
#
|
213
|
+
def self.extensible?
|
214
|
+
self::EXTENSIBLE
|
215
|
+
end
|
216
|
+
|
217
|
+
class BasicStruct < Accessor
|
218
|
+
end
|
219
|
+
|
220
|
+
class BasicUnion < BasicStruct
|
221
|
+
end
|
222
|
+
|
223
|
+
class BasicArray < Accessor
|
224
|
+
end
|
225
|
+
|
226
|
+
class Struct < BasicStruct
|
227
|
+
def self.aref(buffer, offset)
|
228
|
+
new(buffer, offset)
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.aset(buffer, offset, data)
|
232
|
+
self::MODEL.aset(buffer, offset, data)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
class Union < BasicUnion
|
237
|
+
end
|
238
|
+
|
239
|
+
class Array < BasicArray
|
240
|
+
def self.elements
|
241
|
+
self::ELEMENTS
|
242
|
+
end
|
243
|
+
|
244
|
+
def self.define(model)
|
245
|
+
klass = ::Class.new(self)
|
246
|
+
klass.class_eval do
|
247
|
+
field = model.fields[0]
|
248
|
+
const_set(:MODEL, model)
|
249
|
+
const_set(:BYTESIZE, model.bytesize)
|
250
|
+
const_set(:BYTEALIGN, model.bytealign)
|
251
|
+
const_set(:EXTENSIBLE, model.bytesize == 0 || model.extensible?)
|
252
|
+
const_set(:ELEMENTS, elements = field.name)
|
253
|
+
|
254
|
+
vector = field.vector
|
255
|
+
|
256
|
+
if vector
|
257
|
+
type = define_subarray(field)
|
258
|
+
else
|
259
|
+
type = field.type
|
260
|
+
end
|
261
|
+
|
262
|
+
if type.kind_of?(::Module)
|
263
|
+
# すでに名前が定義されてる場合はこれで固定される
|
264
|
+
type.name
|
265
|
+
end
|
266
|
+
const_set(:SUBTYPE, type)
|
267
|
+
bytesize = type.bytesize
|
268
|
+
|
269
|
+
if model.bytesize == 0
|
270
|
+
check_index = ->(index) do
|
271
|
+
index = index.to_i
|
272
|
+
unless index >= 0 && index < self.size
|
273
|
+
raise IndexError, "out of element size (index #{index} for 0 ... #{self.size})", caller(2)
|
274
|
+
end
|
275
|
+
index
|
276
|
+
end
|
277
|
+
|
278
|
+
define_method(:<<, ->(value) {
|
279
|
+
raise TypeError, "immutable object (#<%s:0x%08X>)" % [self.class, __id__], caller(2) if frozen?
|
280
|
+
voff = (buffer__GOGYOU__.bytesize - offset__GOGYOU__).align_floor(type.bytesize)
|
281
|
+
expandsize = offset__GOGYOU__ + voff + type.bytesize
|
282
|
+
buffer__GOGYOU__.resize(expandsize)
|
283
|
+
type.aset(buffer__GOGYOU__, offset__GOGYOU__ + voff, value)
|
284
|
+
self
|
285
|
+
})
|
286
|
+
|
287
|
+
define_method(:size, -> {
|
288
|
+
(buffer__GOGYOU__.bytesize - offset__GOGYOU__).unit_floor(type.bytesize)
|
289
|
+
})
|
290
|
+
|
291
|
+
define_method(:bytesize, -> {
|
292
|
+
(buffer__GOGYOU__.bytesize - offset__GOGYOU__).align_floor(type.bytesize)
|
293
|
+
})
|
294
|
+
else
|
295
|
+
check_index = ->(index) do
|
296
|
+
index = index.to_i
|
297
|
+
unless index >= 0 && (elements.nil? || index < elements)
|
298
|
+
raise IndexError, "out of element size (index #{index} for 0 ... #{elements})", caller(2)
|
299
|
+
end
|
300
|
+
index
|
301
|
+
end
|
302
|
+
|
303
|
+
eval <<-EOS
|
304
|
+
def bytesize
|
305
|
+
#{elements}
|
306
|
+
end
|
307
|
+
EOS
|
308
|
+
end
|
309
|
+
|
310
|
+
define_method(:to_s, -> {
|
311
|
+
buffer__GOGYOU__.byteslice(offset__GOGYOU__, bytesize)
|
312
|
+
})
|
313
|
+
|
314
|
+
define_method(:[], ->(index) {
|
315
|
+
v = type.aref(buffer__GOGYOU__, offset__GOGYOU__ + check_index.(index) * bytesize)
|
316
|
+
v.infect_from(self, buffer) unless v.frozen?
|
317
|
+
v.freeze if frozen? || buffer.frozen? || field.const?
|
318
|
+
v
|
319
|
+
})
|
320
|
+
|
321
|
+
define_method(:[]=, ->(index, value) {
|
322
|
+
raise TypeError, "immutable object (#<%s:0x%08X>)" % [self.class, __id__, index], caller(2) if frozen? or field.const?
|
323
|
+
type.aset(buffer__GOGYOU__, offset__GOGYOU__ + check_index.(index) * bytesize, value)
|
324
|
+
})
|
325
|
+
end
|
326
|
+
klass
|
327
|
+
end
|
328
|
+
|
329
|
+
def self.aset(buffer, offset, value)
|
330
|
+
case value
|
331
|
+
when ::String
|
332
|
+
raise ArgumentError, "buffer size too small" unless value.bytesize < self::BYTESIZE
|
333
|
+
buffer.setbinary(offset, value, self::BYTESIZE, 0)
|
334
|
+
when ::Array
|
335
|
+
raise NotImplementedError
|
336
|
+
when self::SUBTYPE
|
337
|
+
raise NotImplementedError
|
338
|
+
else
|
339
|
+
raise ArgumentError
|
340
|
+
end
|
341
|
+
|
342
|
+
value
|
343
|
+
end
|
344
|
+
|
345
|
+
def bytesize
|
346
|
+
return super unless self.class.extensible?
|
347
|
+
self.class::BYTESIZE * buffer__GOGYOU__.bytesize.unit_floor(self.class::SUBTYPE)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
module TemporaryMixin
|
352
|
+
attr_reader :model__GOGYOU__
|
353
|
+
|
354
|
+
def initialize(buffer, offset, model)
|
355
|
+
super(buffer, offset)
|
356
|
+
@model__GOGYOU__ = nil
|
357
|
+
self.class.define_accessors(singleton_class, model)
|
358
|
+
end
|
359
|
+
|
360
|
+
def inspect
|
361
|
+
"#<%s buffer=%p, offset=%p, model=%p>" % [self.class,
|
362
|
+
buffer__GOGYOU__,
|
363
|
+
offset__GOGYOU__,
|
364
|
+
model__GOGYOU__]
|
365
|
+
end
|
366
|
+
|
367
|
+
def pretty_print(q)
|
368
|
+
q.group(1, "#<#{self.class}") do
|
369
|
+
q.breakable " "
|
370
|
+
q.text "buffer="
|
371
|
+
q.pp buffer__GOGYOU__
|
372
|
+
q.text ","
|
373
|
+
q.breakable " "
|
374
|
+
q.text "offset="
|
375
|
+
q.pp offset__GOGYOU__
|
376
|
+
q.text ","
|
377
|
+
q.breakable " "
|
378
|
+
q.text "model="
|
379
|
+
q.pp model__GOGYOU__ #|| self.class.model
|
380
|
+
q.text ">"
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
class TemporaryStruct < BasicStruct
|
386
|
+
include TemporaryMixin
|
387
|
+
end
|
388
|
+
|
389
|
+
class TemporaryUnion < BasicUnion
|
390
|
+
include TemporaryMixin
|
391
|
+
end
|
392
|
+
|
393
|
+
class TemporaryArray < BasicArray
|
394
|
+
include TemporaryMixin
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
data/lib/gogyou/mixin.rb
ADDED
@@ -0,0 +1,641 @@
|
|
1
|
+
#vim set fileencoding:utf-8
|
2
|
+
|
3
|
+
require_relative "typespec"
|
4
|
+
|
5
|
+
module Gogyou
|
6
|
+
module Extensions
|
7
|
+
module Object
|
8
|
+
module Mixin
|
9
|
+
def infect_from(*obj)
|
10
|
+
obj.each { |o| taint if o.tainted?; untrust if o.untrusted? }
|
11
|
+
self
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ::Object
|
17
|
+
extend Gogyou::Extensions::Object
|
18
|
+
include Gogyou::Extensions::Object::Mixin
|
19
|
+
end
|
20
|
+
|
21
|
+
UNIT_B = 1 << 0
|
22
|
+
UNIT_KiB = 1 << 10
|
23
|
+
UNIT_MiB = 1 << 20
|
24
|
+
UNIT_GiB = 1 << 30
|
25
|
+
UNIT_TiB = 1 << 40
|
26
|
+
UNIT_PiB = 1 << 50
|
27
|
+
UNIT_EiB = 1 << 60
|
28
|
+
UNIT_ZiB = 1 << 70
|
29
|
+
UNIT_YiB = 1 << 80
|
30
|
+
|
31
|
+
module Numeric
|
32
|
+
module Mixin
|
33
|
+
def B
|
34
|
+
UNIT_B * self
|
35
|
+
end
|
36
|
+
|
37
|
+
def KiB
|
38
|
+
UNIT_KiB * self
|
39
|
+
end
|
40
|
+
|
41
|
+
def MiB
|
42
|
+
UNIT_MiB * self
|
43
|
+
end
|
44
|
+
|
45
|
+
def GiB
|
46
|
+
UNIT_GiB * self
|
47
|
+
end
|
48
|
+
|
49
|
+
def TiB
|
50
|
+
UNIT_TiB * self
|
51
|
+
end
|
52
|
+
|
53
|
+
def PiB
|
54
|
+
UNIT_PiB * self
|
55
|
+
end
|
56
|
+
|
57
|
+
def EiB
|
58
|
+
UNIT_EiB * self
|
59
|
+
end
|
60
|
+
|
61
|
+
def ZiB
|
62
|
+
UNIT_ZiB * self
|
63
|
+
end
|
64
|
+
|
65
|
+
def YiB
|
66
|
+
UNIT_YiB * self
|
67
|
+
end
|
68
|
+
|
69
|
+
def unit_floor(unit)
|
70
|
+
(self / unit).to_i
|
71
|
+
end
|
72
|
+
|
73
|
+
def unit_ceil(unit)
|
74
|
+
((self + (unit - 1)) / unit).to_i
|
75
|
+
end
|
76
|
+
|
77
|
+
def align_floor(unit)
|
78
|
+
((self / unit).to_i * unit).to_i
|
79
|
+
end
|
80
|
+
|
81
|
+
def align_ceil(unit)
|
82
|
+
(((self + (unit - 1)) / unit).to_i * unit).to_i
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class ::Numeric
|
88
|
+
extend Gogyou::Extensions::Numeric
|
89
|
+
include Gogyou::Extensions::Numeric::Mixin
|
90
|
+
end
|
91
|
+
|
92
|
+
module Integer
|
93
|
+
module_function
|
94
|
+
def bitmask(shift, bits)
|
95
|
+
~(~0 << bits) << shift
|
96
|
+
end
|
97
|
+
|
98
|
+
public_class_method :bitmask
|
99
|
+
|
100
|
+
module Mixin
|
101
|
+
def getbit(shift, bits)
|
102
|
+
(self >> shift) & Integer.bitmask(0, bits)
|
103
|
+
end
|
104
|
+
|
105
|
+
def getbits(shift, bits)
|
106
|
+
getbit(shift, bits).extendsign(bits)
|
107
|
+
end
|
108
|
+
|
109
|
+
def getbitset(*bitsize)
|
110
|
+
shift = 0
|
111
|
+
list = []
|
112
|
+
bitsize.each do |bits|
|
113
|
+
if bits > 0
|
114
|
+
list << getbit(shift, bits)
|
115
|
+
shift += bits
|
116
|
+
else
|
117
|
+
list << 0
|
118
|
+
end
|
119
|
+
end
|
120
|
+
list
|
121
|
+
end
|
122
|
+
|
123
|
+
def setbit(shift, bits, num)
|
124
|
+
mask = Integer.bitmask(shift, bits)
|
125
|
+
(self & ~mask) | ((num << shift) & mask)
|
126
|
+
end
|
127
|
+
|
128
|
+
def extendsign(bits)
|
129
|
+
n = self & Integer.bitmask(0, bits)
|
130
|
+
if (n >> (bits - 1)) == 0
|
131
|
+
n
|
132
|
+
else
|
133
|
+
n | (~0 << bits)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def swapbyte(bytesize)
|
138
|
+
num = 0
|
139
|
+
mask = 0xff
|
140
|
+
bytesize.times do |i|
|
141
|
+
num <<= 8
|
142
|
+
num |= (self >> (i * 8)) & 0xff
|
143
|
+
end
|
144
|
+
num
|
145
|
+
end
|
146
|
+
|
147
|
+
def swap16
|
148
|
+
((self >> 8) & 0xff) | ((self & 0xff) << 8)
|
149
|
+
end
|
150
|
+
|
151
|
+
def swap24
|
152
|
+
((self >> 16) & 0xff) |
|
153
|
+
(self & 0xff00) |
|
154
|
+
((self & 0xff) << 16)
|
155
|
+
end
|
156
|
+
|
157
|
+
def swap32
|
158
|
+
((self >> 24) & 0xff) |
|
159
|
+
((self >> 8) & 0xff00) |
|
160
|
+
((self & 0xff00) << 8) |
|
161
|
+
((self & 0xff) << 24)
|
162
|
+
end
|
163
|
+
|
164
|
+
def swap48
|
165
|
+
((self >> 40) & 0xff) |
|
166
|
+
((self >> 24) & 0xff00) |
|
167
|
+
((self >> 8) & 0xff0000) |
|
168
|
+
((self & 0xff0000) << 8) |
|
169
|
+
((self & 0xff00) << 24) |
|
170
|
+
((self & 0xff) << 40)
|
171
|
+
end
|
172
|
+
|
173
|
+
def swap64
|
174
|
+
((self >> 56) & 0xff) |
|
175
|
+
((self >> 40) & 0xff00) |
|
176
|
+
((self >> 24) & 0xff0000) |
|
177
|
+
((self >> 8) & 0xff000000) |
|
178
|
+
((self & 0xff000000) << 8) |
|
179
|
+
((self & 0xff0000) << 24) |
|
180
|
+
((self & 0xff00) << 40) |
|
181
|
+
((self & 0xff) << 56)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class ::Integer
|
187
|
+
extend Gogyou::Extensions::Integer
|
188
|
+
include Gogyou::Extensions::Integer::Mixin
|
189
|
+
end
|
190
|
+
|
191
|
+
module String
|
192
|
+
BITS_PER_BYTE = 8
|
193
|
+
|
194
|
+
module_function
|
195
|
+
def alloc(bytesize)
|
196
|
+
?\0.force_encoding(Encoding::BINARY) * bytesize
|
197
|
+
end
|
198
|
+
|
199
|
+
public :alloc
|
200
|
+
|
201
|
+
ZERO_BUFFER = alloc(64.KiB).freeze
|
202
|
+
|
203
|
+
module Mixin
|
204
|
+
def to_ptr
|
205
|
+
[self].pack("p").load_sizet(0)
|
206
|
+
end
|
207
|
+
|
208
|
+
def binary_operation
|
209
|
+
enc = encoding
|
210
|
+
force_encoding(Encoding::BINARY) rescue (enc = nil; raise)
|
211
|
+
yield
|
212
|
+
ensure
|
213
|
+
force_encoding(enc) rescue nil if enc
|
214
|
+
end
|
215
|
+
|
216
|
+
def resize(newsize)
|
217
|
+
binary_operation do
|
218
|
+
left = newsize - bytesize
|
219
|
+
case
|
220
|
+
when left > 0
|
221
|
+
while left >= ZERO_BUFFER.bytesize
|
222
|
+
concat(ZERO_BUFFER)
|
223
|
+
left -= ZERO_BUFFER.bytesize
|
224
|
+
end
|
225
|
+
concat(ZERO_BUFFER[ZERO_BUFFER.bytesize - left, left]) # make shared string
|
226
|
+
when left < 0
|
227
|
+
left = - left
|
228
|
+
self[bytesize - left, left] = ""
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
self
|
233
|
+
end
|
234
|
+
|
235
|
+
def setbinary(index, str, bytesize = str.bytesize, offset = 0)
|
236
|
+
offset = offset.to_i
|
237
|
+
bytesize = bytesize.to_i
|
238
|
+
size1 = str.bytesize - offset
|
239
|
+
bytesize = size1 if bytesize > size1
|
240
|
+
if bytesize > 0
|
241
|
+
binary_operation do
|
242
|
+
self[index.to_i, bytesize] = str.byteslice(offset, bytesize)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
self
|
247
|
+
end
|
248
|
+
|
249
|
+
def swapbyte(index, bytesize)
|
250
|
+
i = index.to_i
|
251
|
+
j = i + bytesize.to_i - 1
|
252
|
+
while i < j
|
253
|
+
w = getbyte(i)
|
254
|
+
setbyte(i, getbyte(j))
|
255
|
+
setbyte(j, w)
|
256
|
+
i += 1
|
257
|
+
j -= 1
|
258
|
+
end
|
259
|
+
|
260
|
+
self
|
261
|
+
end
|
262
|
+
|
263
|
+
def storebe(index, num, bytesize)
|
264
|
+
raise RangeError unless index >= 0 &&
|
265
|
+
index < bytesize &&
|
266
|
+
index + bytesize <= bytesize &&
|
267
|
+
index + bytesize >= 0
|
268
|
+
while bytesize > 0
|
269
|
+
bytesize -= 1
|
270
|
+
setbyte(index, 0xff & (num >> (bytesize * BITS_PER_BYTE)))
|
271
|
+
index += 1
|
272
|
+
end
|
273
|
+
|
274
|
+
self
|
275
|
+
end
|
276
|
+
|
277
|
+
def storele(index, num, bytesize)
|
278
|
+
raise RangeError unless index >= 0 &&
|
279
|
+
index < bytesize &&
|
280
|
+
index + bytesize <= bytesize &&
|
281
|
+
index + bytesize >= 0
|
282
|
+
while bytesize > 0
|
283
|
+
bytesize -= 1
|
284
|
+
setbyte(index, 0xff & num)
|
285
|
+
num >>= BITS_PER_BYTE
|
286
|
+
index += 1
|
287
|
+
end
|
288
|
+
|
289
|
+
self
|
290
|
+
end
|
291
|
+
|
292
|
+
def loadube(index, bytesize)
|
293
|
+
n = 0
|
294
|
+
while bytesize > 0
|
295
|
+
bytesize -= 1
|
296
|
+
n <<= BITS_PER_BYTE
|
297
|
+
n |= getbyte(index)
|
298
|
+
index += 1
|
299
|
+
end
|
300
|
+
n
|
301
|
+
end
|
302
|
+
|
303
|
+
def loadibe(index, bytesize)
|
304
|
+
loadube(index, bytesize).extendsign(bytesize * BITS_PER_BYTE)
|
305
|
+
end
|
306
|
+
|
307
|
+
def loadule(index, bytesize)
|
308
|
+
n = 0
|
309
|
+
c = 0
|
310
|
+
while bytesize > 0
|
311
|
+
bytesize -= 1
|
312
|
+
n |= getbyte(index) << (BITS_PER_BYTE * c)
|
313
|
+
index += 1
|
314
|
+
c += 1
|
315
|
+
end
|
316
|
+
n
|
317
|
+
end
|
318
|
+
|
319
|
+
def loadile(index, bytesize)
|
320
|
+
loadule(index, bytesize).extendsign(bytesize * BITS_PER_BYTE)
|
321
|
+
end
|
322
|
+
|
323
|
+
def loadu8(index)
|
324
|
+
getbyte(index.to_i)
|
325
|
+
end
|
326
|
+
|
327
|
+
def loadi8(index)
|
328
|
+
loadu8(index).extendsign(8)
|
329
|
+
end
|
330
|
+
|
331
|
+
def loadu16be(index)
|
332
|
+
(loadu8(index) << 8) | loadu8(index + 1)
|
333
|
+
end
|
334
|
+
|
335
|
+
def loadi16be(index)
|
336
|
+
loadu16be(index).extendsign(16)
|
337
|
+
end
|
338
|
+
|
339
|
+
def loadu16le(index)
|
340
|
+
loadu8(index) | (loadu8(index + 1) << 8)
|
341
|
+
end
|
342
|
+
|
343
|
+
def loadi16le(index)
|
344
|
+
loadu16le(index).extendsign(16)
|
345
|
+
end
|
346
|
+
|
347
|
+
def loadu24be(index)
|
348
|
+
(loadu8(index) << 16) | (loadu8(index + 1) << 8) | loadu8(index + 2)
|
349
|
+
end
|
350
|
+
|
351
|
+
def loadi24be(index)
|
352
|
+
loadu24be(index).extendsign(24)
|
353
|
+
end
|
354
|
+
|
355
|
+
def loadu24le(index)
|
356
|
+
loadu8(index) | (loadu8(index + 1) << 8) | (loadu8(index + 2) << 16)
|
357
|
+
end
|
358
|
+
|
359
|
+
def loadi24le(index)
|
360
|
+
loadu24le(index).extendsign(24)
|
361
|
+
end
|
362
|
+
|
363
|
+
def loadu32be(index)
|
364
|
+
(loadu8(index) << 24) | (loadu8(index + 1) << 16) | (loadu8(index + 2) << 8) | loadu8(index + 3)
|
365
|
+
end
|
366
|
+
|
367
|
+
def loadi32be(index)
|
368
|
+
loadu32be(index).extendsign(32)
|
369
|
+
end
|
370
|
+
|
371
|
+
def loadu32le(index)
|
372
|
+
loadu8(index) | (loadu8(index + 1) << 8) | (loadu8(index + 2) << 16) | (loadu8(index + 3) << 24)
|
373
|
+
end
|
374
|
+
|
375
|
+
def loadi32le(index)
|
376
|
+
loadu32le(index).extendsign(32)
|
377
|
+
end
|
378
|
+
|
379
|
+
def loadu48be(index)
|
380
|
+
(loadu24be(index) << 24) | loadu24be(index + 3)
|
381
|
+
end
|
382
|
+
|
383
|
+
def loadi48be(index)
|
384
|
+
loadu48be(index).extendsign(48)
|
385
|
+
end
|
386
|
+
|
387
|
+
def loadu48le(index)
|
388
|
+
loadu24le(index) | (loadu24le(index + 3) << 24)
|
389
|
+
end
|
390
|
+
|
391
|
+
def loadi48le(index)
|
392
|
+
loadu48le(index).extendsign(48)
|
393
|
+
end
|
394
|
+
|
395
|
+
def loadu64be(index)
|
396
|
+
(loadu32be(index) << 32) | loadu32be(index + 4)
|
397
|
+
end
|
398
|
+
|
399
|
+
def loadi64be(index)
|
400
|
+
loadu64be(index).extendsign(64)
|
401
|
+
end
|
402
|
+
|
403
|
+
def loadu64le(index)
|
404
|
+
loadu32le(index) | (loadu32le(index + 4) << 32)
|
405
|
+
end
|
406
|
+
|
407
|
+
def loadi64le(index)
|
408
|
+
loadu64le(index).extendsign(64)
|
409
|
+
end
|
410
|
+
|
411
|
+
def loadf32be(index)
|
412
|
+
unpack("@#{index.to_i}g")[0]
|
413
|
+
end
|
414
|
+
|
415
|
+
def loadf32le(index)
|
416
|
+
unpack("@#{index.to_i}e")[0]
|
417
|
+
end
|
418
|
+
|
419
|
+
def loadf64be(index)
|
420
|
+
unpack("@#{index.to_i}G")[0]
|
421
|
+
end
|
422
|
+
|
423
|
+
def loadf64le(index)
|
424
|
+
unpack("@#{index.to_i}E")[0]
|
425
|
+
end
|
426
|
+
|
427
|
+
def store8(index, num)
|
428
|
+
setbyte(index.to_i, num.to_i & 0xff)
|
429
|
+
end
|
430
|
+
|
431
|
+
def store16be(index, num)
|
432
|
+
store8(index, num >> 8)
|
433
|
+
store8(index + 1, num)
|
434
|
+
end
|
435
|
+
|
436
|
+
def store16le(index, num)
|
437
|
+
store8(index, num)
|
438
|
+
store8(index + 1, num >> 8)
|
439
|
+
end
|
440
|
+
|
441
|
+
def store24be(index, num)
|
442
|
+
store8(index, num >> 16)
|
443
|
+
store8(index + 1, num >> 8)
|
444
|
+
store8(index + 2, num)
|
445
|
+
end
|
446
|
+
|
447
|
+
def store24le(index, num)
|
448
|
+
store8(index, num)
|
449
|
+
store8(index + 1, num >> 8)
|
450
|
+
store8(index + 2, num >> 16)
|
451
|
+
end
|
452
|
+
|
453
|
+
def store32be(index, num)
|
454
|
+
store8(index, num >> 24)
|
455
|
+
store8(index + 1, num >> 16)
|
456
|
+
store8(index + 2, num >> 8)
|
457
|
+
store8(index + 3, num)
|
458
|
+
end
|
459
|
+
|
460
|
+
def store32le(index, num)
|
461
|
+
store8(index, num)
|
462
|
+
store8(index + 1, num >> 8)
|
463
|
+
store8(index + 2, num >> 16)
|
464
|
+
store8(index + 3, num >> 24)
|
465
|
+
end
|
466
|
+
|
467
|
+
def store48be(index, num)
|
468
|
+
store24be(index, num >> 24)
|
469
|
+
store24be(index + 3, num)
|
470
|
+
end
|
471
|
+
|
472
|
+
def store48le(index, num)
|
473
|
+
store24le(index, num)
|
474
|
+
store24le(index + 3, num >> 24)
|
475
|
+
end
|
476
|
+
|
477
|
+
def store64be(index, num)
|
478
|
+
store32be(index, num >> 32)
|
479
|
+
store32be(index + 4, num)
|
480
|
+
end
|
481
|
+
|
482
|
+
def store64le(index, num)
|
483
|
+
store32le(index, num)
|
484
|
+
store32le(index + 4, num >> 32)
|
485
|
+
end
|
486
|
+
|
487
|
+
def storef32be(index, num)
|
488
|
+
setbinary(index, [num].pack("g"))
|
489
|
+
end
|
490
|
+
|
491
|
+
def storef32le(index, num)
|
492
|
+
setbinary(index, [num].pack("e"))
|
493
|
+
end
|
494
|
+
|
495
|
+
def storef64be(index, num)
|
496
|
+
setbinary(index, [num].pack("G"))
|
497
|
+
end
|
498
|
+
|
499
|
+
def storef64le(index, num)
|
500
|
+
setbinary(index, [num].pack("E"))
|
501
|
+
end
|
502
|
+
|
503
|
+
#---
|
504
|
+
## native byte order operations
|
505
|
+
#+++
|
506
|
+
|
507
|
+
def loadf32(index)
|
508
|
+
unpack("@#{index.to_i}f")[0]
|
509
|
+
end
|
510
|
+
|
511
|
+
def loadf64(index)
|
512
|
+
unpack("@#{index.to_i}d")[0]
|
513
|
+
end
|
514
|
+
|
515
|
+
def storef32(index, num)
|
516
|
+
setbinary(index, [num].pack("f"))
|
517
|
+
end
|
518
|
+
|
519
|
+
def storef64(index, num)
|
520
|
+
setbinary(index, [num].pack("d"))
|
521
|
+
end
|
522
|
+
|
523
|
+
case "\0\1\2\3".unpack("I")[0]
|
524
|
+
when 0x00010203 # big endian (network byte order)
|
525
|
+
alias store storebe
|
526
|
+
alias store16 store16be
|
527
|
+
alias store24 store24be
|
528
|
+
alias store32 store32be
|
529
|
+
alias store48 store48be
|
530
|
+
alias store64 store64be
|
531
|
+
alias loadi loadibe
|
532
|
+
alias loadi16 loadi16be
|
533
|
+
alias loadi24 loadi24be
|
534
|
+
alias loadi32 loadi32be
|
535
|
+
alias loadi48 loadi48be
|
536
|
+
alias loadi64 loadi64be
|
537
|
+
alias loadu loadube
|
538
|
+
alias loadu16 loadu16be
|
539
|
+
alias loadu24 loadu24be
|
540
|
+
alias loadu32 loadu32be
|
541
|
+
alias loadu48 loadu48be
|
542
|
+
alias loadu64 loadu64be
|
543
|
+
|
544
|
+
alias storeswap storele
|
545
|
+
alias store16swap store16le
|
546
|
+
alias store24swap store24le
|
547
|
+
alias store32swap store32le
|
548
|
+
alias store48swap store48le
|
549
|
+
alias store64swap store64le
|
550
|
+
alias loadiswap loadile
|
551
|
+
alias loadi16swap loadi16le
|
552
|
+
alias loadi24swap loadi24le
|
553
|
+
alias loadi32swap loadi32le
|
554
|
+
alias loadi48swap loadi48le
|
555
|
+
alias loadi64swap loadi64le
|
556
|
+
alias loaduswap loadule
|
557
|
+
alias loadu16swap loadu16le
|
558
|
+
alias loadu24swap loadu24le
|
559
|
+
alias loadu32swap loadu32le
|
560
|
+
alias loadu48swap loadu48le
|
561
|
+
alias loadu64swap loadu64le
|
562
|
+
alias loadf32swap loadf32le
|
563
|
+
alias loadf64swap loadf64le
|
564
|
+
when 0x03020100 # little endian (vax byte order)
|
565
|
+
alias store storele
|
566
|
+
alias store16 store16le
|
567
|
+
alias store24 store24le
|
568
|
+
alias store32 store32le
|
569
|
+
alias store48 store48le
|
570
|
+
alias store64 store64le
|
571
|
+
alias loadi loadile
|
572
|
+
alias loadi16 loadi16le
|
573
|
+
alias loadi24 loadi24le
|
574
|
+
alias loadi32 loadi32le
|
575
|
+
alias loadi48 loadi48le
|
576
|
+
alias loadi64 loadi64le
|
577
|
+
alias loadu loadule
|
578
|
+
alias loadu16 loadu16le
|
579
|
+
alias loadu24 loadu24le
|
580
|
+
alias loadu32 loadu32le
|
581
|
+
alias loadu48 loadu48le
|
582
|
+
alias loadu64 loadu64le
|
583
|
+
|
584
|
+
alias storeswap storebe
|
585
|
+
alias store16swap store16be
|
586
|
+
alias store24swap store24be
|
587
|
+
alias store32swap store32be
|
588
|
+
alias store48swap store48be
|
589
|
+
alias store64swap store64be
|
590
|
+
alias loadiswap loadibe
|
591
|
+
alias loadi16swap loadi16be
|
592
|
+
alias loadi24swap loadi24be
|
593
|
+
alias loadi32swap loadi32be
|
594
|
+
alias loadi48swap loadi48be
|
595
|
+
alias loadi64swap loadi64be
|
596
|
+
alias loaduswap loadube
|
597
|
+
alias loadu16swap loadu16be
|
598
|
+
alias loadu24swap loadu24be
|
599
|
+
alias loadu32swap loadu32be
|
600
|
+
alias loadu48swap loadu48be
|
601
|
+
alias loadu64swap loadu64be
|
602
|
+
alias loadf32swap loadf32be
|
603
|
+
alias loadf64swap loadf64be
|
604
|
+
else
|
605
|
+
raise NotImplementedError
|
606
|
+
end
|
607
|
+
|
608
|
+
case TypeSpec::SIZEOF_SIZE_T
|
609
|
+
when 4
|
610
|
+
alias store_sizet store32
|
611
|
+
alias load_sizet loadu32
|
612
|
+
alias load_ssizet loadi32
|
613
|
+
when 8
|
614
|
+
alias store_sizet store64
|
615
|
+
alias load_sizet loadu64
|
616
|
+
alias load_ssizet loadi64
|
617
|
+
else
|
618
|
+
raise NotImplementedError
|
619
|
+
end
|
620
|
+
|
621
|
+
case TypeSpec::SIZEOF_LONG
|
622
|
+
when 4
|
623
|
+
alias store_long store32
|
624
|
+
alias load_long loadi32
|
625
|
+
alias load_ulong loadu32
|
626
|
+
when 8
|
627
|
+
alias store_long store64
|
628
|
+
alias load_long loadi64
|
629
|
+
alias load_ulong loadu64
|
630
|
+
else
|
631
|
+
raise NotImplementedError
|
632
|
+
end
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
class ::String
|
637
|
+
extend Gogyou::Extensions::String
|
638
|
+
include Gogyou::Extensions::String::Mixin
|
639
|
+
end
|
640
|
+
end
|
641
|
+
end
|