bit-struct 0.13.1
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.
- data/.gitignore +2 -0
- data/History.txt +102 -0
- data/README.txt +189 -0
- data/Rakefile +34 -0
- data/TODO +23 -0
- data/TODO-ALSO +71 -0
- data/examples/ara-player-data.rb +82 -0
- data/examples/bignum.rb +18 -0
- data/examples/bits.rb +19 -0
- data/examples/byte-bdy.rb +30 -0
- data/examples/field-ripper.rb +22 -0
- data/examples/fixed-point.rb +17 -0
- data/examples/ip.rb +81 -0
- data/examples/longlong.rb +30 -0
- data/examples/md.rb +23 -0
- data/examples/modular-def.rb +38 -0
- data/examples/native.rb +31 -0
- data/examples/nested.rb +33 -0
- data/examples/pad.rb +14 -0
- data/examples/ping-recv.rb +25 -0
- data/examples/ping.rb +73 -0
- data/examples/player-data.rb +75 -0
- data/examples/raw.rb +62 -0
- data/examples/rest.rb +30 -0
- data/examples/switch-endian.rb +49 -0
- data/examples/vector.rb +98 -0
- data/lib/bit-struct.rb +6 -0
- data/lib/bit-struct/bit-struct.rb +549 -0
- data/lib/bit-struct/char-field.rb +48 -0
- data/lib/bit-struct/fields.rb +273 -0
- data/lib/bit-struct/float-field.rb +61 -0
- data/lib/bit-struct/hex-octet-field.rb +20 -0
- data/lib/bit-struct/nested-field.rb +76 -0
- data/lib/bit-struct/octet-field.rb +45 -0
- data/lib/bit-struct/pad-field.rb +15 -0
- data/lib/bit-struct/signed-field.rb +258 -0
- data/lib/bit-struct/text-field.rb +44 -0
- data/lib/bit-struct/unsigned-field.rb +248 -0
- data/lib/bit-struct/vector-field.rb +77 -0
- data/lib/bit-struct/vector.rb +173 -0
- data/lib/bit-struct/yaml.rb +69 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- data/test/test-endian.rb +39 -0
- data/test/test-vector.rb +38 -0
- data/test/test.rb +433 -0
- metadata +126 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'bit-struct/char-field'
|
2
|
+
|
3
|
+
class BitStruct
|
4
|
+
# Class for char fields that can be accessed with values like
|
5
|
+
# "xxx.xxx.xxx.xxx", where each xxx is up to 3 decimal digits representing a
|
6
|
+
# single octet. The original string-based accessors are still available with
|
7
|
+
# the <tt>_chars</tt> suffix.
|
8
|
+
#
|
9
|
+
# Declared with BitStruct.octets.
|
10
|
+
class OctetField < BitStruct::CharField
|
11
|
+
# Used in describe.
|
12
|
+
def self.class_name
|
13
|
+
@class_name ||= "octets"
|
14
|
+
end
|
15
|
+
|
16
|
+
SEPARATOR = "."
|
17
|
+
FORMAT = "%d"
|
18
|
+
BASE = 10
|
19
|
+
|
20
|
+
def add_accessors_to(cl, attr = name) # :nodoc:
|
21
|
+
attr_chars = "#{attr}_chars"
|
22
|
+
super(cl, attr_chars)
|
23
|
+
sep = self.class::SEPARATOR
|
24
|
+
base = self.class::BASE
|
25
|
+
fmt = self.class::FORMAT
|
26
|
+
|
27
|
+
cl.class_eval do
|
28
|
+
define_method attr do ||
|
29
|
+
ary = []
|
30
|
+
send(attr_chars).each_byte do |c|
|
31
|
+
ary << fmt % c
|
32
|
+
end
|
33
|
+
ary.join(sep)
|
34
|
+
end
|
35
|
+
|
36
|
+
old_writer = "#{attr_chars}="
|
37
|
+
|
38
|
+
define_method "#{attr}=" do |val|
|
39
|
+
data = val.split(sep).map{|s|s.to_i(base)}.pack("c*")
|
40
|
+
send(old_writer, data)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class BitStruct
|
2
|
+
# Class for fixed length padding.
|
3
|
+
class PadField < Field
|
4
|
+
# Used in describe.
|
5
|
+
def self.class_name
|
6
|
+
@class_name ||= "padding"
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_accessors_to(cl, attr = name) # :nodoc:
|
10
|
+
# No accessors for padding.
|
11
|
+
end
|
12
|
+
|
13
|
+
def inspectable?; false; end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,258 @@
|
|
1
|
+
class BitStruct
|
2
|
+
# Class for signed integers in network order, 1-16 bits, or 8n bits.
|
3
|
+
# Declared with BitStruct.signed.
|
4
|
+
class SignedField < Field
|
5
|
+
# Used in describe.
|
6
|
+
def self.class_name
|
7
|
+
@class_name ||= "signed"
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_accessors_to(cl, attr = name) # :nodoc:
|
11
|
+
offset_byte = offset / 8
|
12
|
+
offset_bit = offset % 8
|
13
|
+
|
14
|
+
length_bit = offset_bit + length
|
15
|
+
length_byte = (length_bit/8.0).ceil
|
16
|
+
last_byte = offset_byte + length_byte - 1
|
17
|
+
max = 2**length-1
|
18
|
+
mid = 2**(length-1)
|
19
|
+
max_unsigned = 2**length
|
20
|
+
to_signed = proc {|n| (n>=mid) ? n - max_unsigned : n}
|
21
|
+
# to_signed = proc {|n| (n>=mid) ? -((n ^ max) + 1) : n}
|
22
|
+
|
23
|
+
divisor = options[:fixed] || options["fixed"]
|
24
|
+
divisor_f = divisor && divisor.to_f
|
25
|
+
# if divisor and not divisor.is_a? Fixnum
|
26
|
+
# raise ArgumentError, "fixed-point divisor must be a fixnum"
|
27
|
+
# end
|
28
|
+
|
29
|
+
endian = (options[:endian] || options["endian"]).to_s
|
30
|
+
case endian
|
31
|
+
when "native"
|
32
|
+
ctl = length_byte <= 2 ? "s" : "l"
|
33
|
+
if length == 16 or length == 32
|
34
|
+
to_signed = proc {|n| n}
|
35
|
+
# with pack support, to_signed can be replaced with no-op
|
36
|
+
end
|
37
|
+
when "little"
|
38
|
+
ctl = length_byte <= 2 ? "v" : "V"
|
39
|
+
when "network", "big", ""
|
40
|
+
ctl = length_byte <= 2 ? "n" : "N"
|
41
|
+
else
|
42
|
+
raise ArgumentError,
|
43
|
+
"Unrecognized endian option: #{endian.inspect}"
|
44
|
+
end
|
45
|
+
|
46
|
+
data_is_big_endian =
|
47
|
+
([1234].pack(ctl) == [1234].pack(length_byte <= 2 ? "n" : "N"))
|
48
|
+
|
49
|
+
if length_byte == 1
|
50
|
+
rest = 8 - length_bit
|
51
|
+
mask = ["0"*offset_bit + "1"*length + "0"*rest].pack("B8")[0]
|
52
|
+
mask2 = ["1"*offset_bit + "0"*length + "1"*rest].pack("B8")[0]
|
53
|
+
|
54
|
+
cl.class_eval do
|
55
|
+
if divisor
|
56
|
+
define_method attr do ||
|
57
|
+
to_signed[(self[offset_byte] & mask) >> rest] / divisor_f
|
58
|
+
end
|
59
|
+
|
60
|
+
define_method "#{attr}=" do |val|
|
61
|
+
val = (val * divisor).round
|
62
|
+
self[offset_byte] =
|
63
|
+
(self[offset_byte] & mask2) | ((val<<rest) & mask)
|
64
|
+
end
|
65
|
+
|
66
|
+
else
|
67
|
+
define_method attr do ||
|
68
|
+
to_signed[(self[offset_byte] & mask) >> rest]
|
69
|
+
end
|
70
|
+
|
71
|
+
define_method "#{attr}=" do |val|
|
72
|
+
self[offset_byte] =
|
73
|
+
(self[offset_byte] & mask2) | ((val<<rest) & mask)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
elsif offset_bit == 0 and length % 8 == 0
|
79
|
+
field_length = length
|
80
|
+
byte_range = offset_byte..last_byte
|
81
|
+
|
82
|
+
cl.class_eval do
|
83
|
+
case field_length
|
84
|
+
when 8
|
85
|
+
if divisor
|
86
|
+
define_method attr do ||
|
87
|
+
to_signed[self[offset_byte]] / divisor_f
|
88
|
+
end
|
89
|
+
|
90
|
+
define_method "#{attr}=" do |val|
|
91
|
+
val = (val * divisor).round
|
92
|
+
self[offset_byte] = val
|
93
|
+
end
|
94
|
+
|
95
|
+
else
|
96
|
+
define_method attr do ||
|
97
|
+
to_signed[self[offset_byte]]
|
98
|
+
end
|
99
|
+
|
100
|
+
define_method "#{attr}=" do |val|
|
101
|
+
self[offset_byte] = val
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
when 16, 32
|
106
|
+
if divisor
|
107
|
+
define_method attr do ||
|
108
|
+
to_signed[self[byte_range].unpack(ctl).first] / divisor_f
|
109
|
+
end
|
110
|
+
|
111
|
+
define_method "#{attr}=" do |val|
|
112
|
+
val = (val * divisor).round
|
113
|
+
self[byte_range] = [val].pack(ctl)
|
114
|
+
end
|
115
|
+
|
116
|
+
else
|
117
|
+
define_method attr do ||
|
118
|
+
to_signed[self[byte_range].unpack(ctl).first]
|
119
|
+
end
|
120
|
+
|
121
|
+
define_method "#{attr}=" do |val|
|
122
|
+
self[byte_range] = [val].pack(ctl)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
else
|
127
|
+
reader_helper = proc do |substr|
|
128
|
+
bytes = substr.unpack("C*")
|
129
|
+
bytes.reverse! unless data_is_big_endian
|
130
|
+
bytes.inject do |sum, byte|
|
131
|
+
(sum << 8) + byte
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
writer_helper = proc do |val|
|
136
|
+
bytes = []
|
137
|
+
val += max_unsigned if val < 0
|
138
|
+
while val > 0
|
139
|
+
bytes.push val % 256
|
140
|
+
val = val >> 8
|
141
|
+
end
|
142
|
+
if bytes.length < length_byte
|
143
|
+
bytes.concat [0] * (length_byte - bytes.length)
|
144
|
+
end
|
145
|
+
|
146
|
+
bytes.reverse! if data_is_big_endian
|
147
|
+
bytes.pack("C*")
|
148
|
+
end
|
149
|
+
|
150
|
+
if divisor
|
151
|
+
define_method attr do ||
|
152
|
+
to_signed[reader_helper[self[byte_range]] / divisor_f]
|
153
|
+
end
|
154
|
+
|
155
|
+
define_method "#{attr}=" do |val|
|
156
|
+
self[byte_range] = writer_helper[(val * divisor).round]
|
157
|
+
end
|
158
|
+
|
159
|
+
else
|
160
|
+
define_method attr do ||
|
161
|
+
to_signed[reader_helper[self[byte_range]]]
|
162
|
+
end
|
163
|
+
|
164
|
+
define_method "#{attr}=" do |val|
|
165
|
+
self[byte_range] = writer_helper[val]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
elsif length_byte == 2 # unaligned field that fits within two whole bytes
|
172
|
+
byte_range = offset_byte..last_byte
|
173
|
+
rest = 16 - length_bit
|
174
|
+
|
175
|
+
mask = ["0"*offset_bit + "1"*length + "0"*rest]
|
176
|
+
mask = mask.pack("B16").unpack(ctl).first
|
177
|
+
|
178
|
+
mask2 = ["1"*offset_bit + "0"*length + "1"*rest]
|
179
|
+
mask2 = mask2.pack("B16").unpack(ctl).first
|
180
|
+
|
181
|
+
cl.class_eval do
|
182
|
+
if divisor
|
183
|
+
define_method attr do ||
|
184
|
+
to_signed[(self[byte_range].unpack(ctl).first & mask) >> rest] /
|
185
|
+
divisor_f
|
186
|
+
end
|
187
|
+
|
188
|
+
define_method "#{attr}=" do |val|
|
189
|
+
val = (val * divisor).round
|
190
|
+
x = (self[byte_range].unpack(ctl).first & mask2) |
|
191
|
+
((val<<rest) & mask)
|
192
|
+
self[byte_range] = [x].pack(ctl)
|
193
|
+
end
|
194
|
+
|
195
|
+
else
|
196
|
+
define_method attr do ||
|
197
|
+
to_signed[(self[byte_range].unpack(ctl).first & mask) >> rest]
|
198
|
+
end
|
199
|
+
|
200
|
+
define_method "#{attr}=" do |val|
|
201
|
+
x = (self[byte_range].unpack(ctl).first & mask2) |
|
202
|
+
((val<<rest) & mask)
|
203
|
+
self[byte_range] = [x].pack(ctl)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
elsif length_byte == 3 # unaligned field that fits within 3 whole bytes
|
209
|
+
byte_range = offset_byte..last_byte
|
210
|
+
rest = 32 - length_bit
|
211
|
+
|
212
|
+
mask = ["0"*offset_bit + "1"*length + "0"*rest]
|
213
|
+
mask = mask.pack("B32").unpack(ctl).first
|
214
|
+
|
215
|
+
mask2 = ["1"*offset_bit + "0"*length + "1"*rest]
|
216
|
+
mask2 = mask2.pack("B32").unpack(ctl).first
|
217
|
+
|
218
|
+
cl.class_eval do
|
219
|
+
if divisor
|
220
|
+
define_method attr do ||
|
221
|
+
bytes = self[byte_range]
|
222
|
+
bytes << 0
|
223
|
+
to_signed[((bytes.unpack(ctl).first & mask) >> rest)] /
|
224
|
+
divisor_f
|
225
|
+
end
|
226
|
+
|
227
|
+
define_method "#{attr}=" do |val|
|
228
|
+
val = (val * divisor).round
|
229
|
+
bytes = self[byte_range]
|
230
|
+
bytes << 0
|
231
|
+
x = (bytes.unpack(ctl).first & mask2) |
|
232
|
+
((val<<rest) & mask)
|
233
|
+
self[byte_range] = [x].pack(ctl)[0..2]
|
234
|
+
end
|
235
|
+
|
236
|
+
else
|
237
|
+
define_method attr do ||
|
238
|
+
bytes = self[byte_range]
|
239
|
+
bytes << 0
|
240
|
+
to_signed[(bytes.unpack(ctl).first & mask) >> rest]
|
241
|
+
end
|
242
|
+
|
243
|
+
define_method "#{attr}=" do |val|
|
244
|
+
bytes = self[byte_range]
|
245
|
+
bytes << 0
|
246
|
+
x = (bytes.unpack(ctl).first & mask2) |
|
247
|
+
((val<<rest) & mask)
|
248
|
+
self[byte_range] = [x].pack(ctl)[0..2]
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
else
|
254
|
+
raise "unsupported: #{inspect}"
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class BitStruct
|
2
|
+
# Class for null-terminated printable text strings.
|
3
|
+
# Declared with BitStruct.text.
|
4
|
+
class TextField < Field
|
5
|
+
# Used in describe.
|
6
|
+
def self.class_name
|
7
|
+
@class_name ||= "text"
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_accessors_to(cl, attr = name) # :nodoc:
|
11
|
+
unless offset % 8 == 0
|
12
|
+
raise ArgumentError,
|
13
|
+
"Bad offset, #{offset}, for #{self.class} #{name}." +
|
14
|
+
" Must be multiple of 8."
|
15
|
+
end
|
16
|
+
|
17
|
+
unless length % 8 == 0
|
18
|
+
raise ArgumentError,
|
19
|
+
"Bad length, #{length}, for #{self.class} #{name}." +
|
20
|
+
" Must be multiple of 8."
|
21
|
+
end
|
22
|
+
|
23
|
+
offset_byte = offset / 8
|
24
|
+
length_byte = length / 8
|
25
|
+
last_byte = offset_byte + length_byte - 1
|
26
|
+
byte_range = offset_byte..last_byte
|
27
|
+
val_byte_range = 0..length_byte-1
|
28
|
+
|
29
|
+
cl.class_eval do
|
30
|
+
define_method attr do ||
|
31
|
+
self[byte_range].sub(/\0*$/, "").to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
define_method "#{attr}=" do |val|
|
35
|
+
val = val.to_s
|
36
|
+
if val.length < length_byte
|
37
|
+
val += "\0" * (length_byte - val.length)
|
38
|
+
end
|
39
|
+
self[byte_range] = val[val_byte_range]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
class BitStruct
|
2
|
+
# Class for unsigned integers in network order, 1-16 bits, or 8n bits.
|
3
|
+
# Declared with BitStruct.unsigned.
|
4
|
+
class UnsignedField < Field
|
5
|
+
# Used in describe.
|
6
|
+
def self.class_name
|
7
|
+
@class_name ||= "unsigned"
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_accessors_to(cl, attr = name) # :nodoc:
|
11
|
+
offset_byte = offset / 8
|
12
|
+
offset_bit = offset % 8
|
13
|
+
|
14
|
+
length_bit = offset_bit + length
|
15
|
+
length_byte = (length_bit/8.0).ceil
|
16
|
+
last_byte = offset_byte + length_byte - 1
|
17
|
+
|
18
|
+
divisor = options[:fixed] || options["fixed"]
|
19
|
+
divisor_f = divisor && divisor.to_f
|
20
|
+
# if divisor and not divisor.is_a? Fixnum
|
21
|
+
# raise ArgumentError, "fixed-point divisor must be a fixnum"
|
22
|
+
# end
|
23
|
+
|
24
|
+
endian = (options[:endian] || options["endian"]).to_s
|
25
|
+
case endian
|
26
|
+
when "native"
|
27
|
+
ctl = length_byte <= 2 ? "S" : "L"
|
28
|
+
when "little"
|
29
|
+
ctl = length_byte <= 2 ? "v" : "V"
|
30
|
+
when "network", "big", ""
|
31
|
+
ctl = length_byte <= 2 ? "n" : "N"
|
32
|
+
else
|
33
|
+
raise ArgumentError,
|
34
|
+
"Unrecognized endian option: #{endian.inspect}"
|
35
|
+
end
|
36
|
+
|
37
|
+
data_is_big_endian =
|
38
|
+
([1234].pack(ctl) == [1234].pack(length_byte <= 2 ? "n" : "N"))
|
39
|
+
|
40
|
+
if length_byte == 1
|
41
|
+
rest = 8 - length_bit
|
42
|
+
mask = ["0"*offset_bit + "1"*length + "0"*rest].pack("B8")[0]
|
43
|
+
mask2 = ["1"*offset_bit + "0"*length + "1"*rest].pack("B8")[0]
|
44
|
+
|
45
|
+
cl.class_eval do
|
46
|
+
if divisor
|
47
|
+
define_method attr do ||
|
48
|
+
((self[offset_byte] & mask) >> rest) / divisor_f
|
49
|
+
end
|
50
|
+
|
51
|
+
define_method "#{attr}=" do |val|
|
52
|
+
val = (val * divisor).round
|
53
|
+
self[offset_byte] =
|
54
|
+
(self[offset_byte] & mask2) | ((val<<rest) & mask)
|
55
|
+
end
|
56
|
+
|
57
|
+
else
|
58
|
+
define_method attr do ||
|
59
|
+
(self[offset_byte] & mask) >> rest
|
60
|
+
end
|
61
|
+
|
62
|
+
define_method "#{attr}=" do |val|
|
63
|
+
self[offset_byte] =
|
64
|
+
(self[offset_byte] & mask2) | ((val<<rest) & mask)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
elsif offset_bit == 0 and length % 8 == 0
|
70
|
+
field_length = length
|
71
|
+
byte_range = offset_byte..last_byte
|
72
|
+
|
73
|
+
cl.class_eval do
|
74
|
+
case field_length
|
75
|
+
when 8
|
76
|
+
if divisor
|
77
|
+
define_method attr do ||
|
78
|
+
self[offset_byte] / divisor_f
|
79
|
+
end
|
80
|
+
|
81
|
+
define_method "#{attr}=" do |val|
|
82
|
+
val = (val * divisor).round
|
83
|
+
self[offset_byte] = val
|
84
|
+
end
|
85
|
+
|
86
|
+
else
|
87
|
+
define_method attr do ||
|
88
|
+
self[offset_byte]
|
89
|
+
end
|
90
|
+
|
91
|
+
define_method "#{attr}=" do |val|
|
92
|
+
self[offset_byte] = val
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
when 16, 32
|
97
|
+
if divisor
|
98
|
+
define_method attr do ||
|
99
|
+
self[byte_range].unpack(ctl).first / divisor_f
|
100
|
+
end
|
101
|
+
|
102
|
+
define_method "#{attr}=" do |val|
|
103
|
+
val = (val * divisor).round
|
104
|
+
self[byte_range] = [val].pack(ctl)
|
105
|
+
end
|
106
|
+
|
107
|
+
else
|
108
|
+
define_method attr do ||
|
109
|
+
self[byte_range].unpack(ctl).first
|
110
|
+
end
|
111
|
+
|
112
|
+
define_method "#{attr}=" do |val|
|
113
|
+
self[byte_range] = [val].pack(ctl)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
else
|
118
|
+
reader_helper = proc do |substr|
|
119
|
+
bytes = substr.unpack("C*")
|
120
|
+
bytes.reverse! unless data_is_big_endian
|
121
|
+
bytes.inject do |sum, byte|
|
122
|
+
(sum << 8) + byte
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
writer_helper = proc do |val|
|
127
|
+
bytes = []
|
128
|
+
while val > 0
|
129
|
+
bytes.push val % 256
|
130
|
+
val = val >> 8
|
131
|
+
end
|
132
|
+
if bytes.length < length_byte
|
133
|
+
bytes.concat [0] * (length_byte - bytes.length)
|
134
|
+
end
|
135
|
+
|
136
|
+
bytes.reverse! if data_is_big_endian
|
137
|
+
bytes.pack("C*")
|
138
|
+
end
|
139
|
+
|
140
|
+
if divisor
|
141
|
+
define_method attr do ||
|
142
|
+
reader_helper[self[byte_range]] / divisor_f
|
143
|
+
end
|
144
|
+
|
145
|
+
define_method "#{attr}=" do |val|
|
146
|
+
self[byte_range] = writer_helper[(val * divisor).round]
|
147
|
+
end
|
148
|
+
|
149
|
+
else
|
150
|
+
define_method attr do ||
|
151
|
+
reader_helper[self[byte_range]]
|
152
|
+
end
|
153
|
+
|
154
|
+
define_method "#{attr}=" do |val|
|
155
|
+
self[byte_range] = writer_helper[val]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
elsif length_byte == 2 # unaligned field that fits within two whole bytes
|
162
|
+
byte_range = offset_byte..last_byte
|
163
|
+
rest = 16 - length_bit
|
164
|
+
|
165
|
+
mask = ["0"*offset_bit + "1"*length + "0"*rest]
|
166
|
+
mask = mask.pack("B16").unpack(ctl).first
|
167
|
+
|
168
|
+
mask2 = ["1"*offset_bit + "0"*length + "1"*rest]
|
169
|
+
mask2 = mask2.pack("B16").unpack(ctl).first
|
170
|
+
|
171
|
+
cl.class_eval do
|
172
|
+
if divisor
|
173
|
+
define_method attr do ||
|
174
|
+
((self[byte_range].unpack(ctl).first & mask) >> rest) /
|
175
|
+
divisor_f
|
176
|
+
end
|
177
|
+
|
178
|
+
define_method "#{attr}=" do |val|
|
179
|
+
val = (val * divisor).round
|
180
|
+
x = (self[byte_range].unpack(ctl).first & mask2) |
|
181
|
+
((val<<rest) & mask)
|
182
|
+
self[byte_range] = [x].pack(ctl)
|
183
|
+
end
|
184
|
+
|
185
|
+
else
|
186
|
+
define_method attr do ||
|
187
|
+
(self[byte_range].unpack(ctl).first & mask) >> rest
|
188
|
+
end
|
189
|
+
|
190
|
+
define_method "#{attr}=" do |val|
|
191
|
+
x = (self[byte_range].unpack(ctl).first & mask2) |
|
192
|
+
((val<<rest) & mask)
|
193
|
+
self[byte_range] = [x].pack(ctl)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
elsif length_byte == 3 # unaligned field that fits within 3 whole bytes
|
199
|
+
byte_range = offset_byte..last_byte
|
200
|
+
rest = 32 - length_bit
|
201
|
+
|
202
|
+
mask = ["0"*offset_bit + "1"*length + "0"*rest]
|
203
|
+
mask = mask.pack("B32").unpack(ctl).first
|
204
|
+
|
205
|
+
mask2 = ["1"*offset_bit + "0"*length + "1"*rest]
|
206
|
+
mask2 = mask2.pack("B32").unpack(ctl).first
|
207
|
+
|
208
|
+
cl.class_eval do
|
209
|
+
if divisor
|
210
|
+
define_method attr do ||
|
211
|
+
bytes = self[byte_range]
|
212
|
+
bytes << 0
|
213
|
+
((bytes.unpack(ctl).first & mask) >> rest) /
|
214
|
+
divisor_f
|
215
|
+
end
|
216
|
+
|
217
|
+
define_method "#{attr}=" do |val|
|
218
|
+
val = (val * divisor).round
|
219
|
+
bytes = self[byte_range]
|
220
|
+
bytes << 0
|
221
|
+
x = (bytes.unpack(ctl).first & mask2) |
|
222
|
+
((val<<rest) & mask)
|
223
|
+
self[byte_range] = [x].pack(ctl)[0..2]
|
224
|
+
end
|
225
|
+
|
226
|
+
else
|
227
|
+
define_method attr do ||
|
228
|
+
bytes = self[byte_range]
|
229
|
+
bytes << 0
|
230
|
+
(bytes.unpack(ctl).first & mask) >> rest
|
231
|
+
end
|
232
|
+
|
233
|
+
define_method "#{attr}=" do |val|
|
234
|
+
bytes = self[byte_range]
|
235
|
+
bytes << 0
|
236
|
+
x = (bytes.unpack(ctl).first & mask2) |
|
237
|
+
((val<<rest) & mask)
|
238
|
+
self[byte_range] = [x].pack(ctl)[0..2]
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
else
|
244
|
+
raise "unsupported: #{inspect}"
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|