bit-struct 0.13.5 → 0.17
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/History.txt +22 -1
- data/LICENSE +56 -0
- data/{README.txt → README.md} +94 -92
- data/Rakefile +56 -30
- data/examples/field-ripper.rb +1 -1
- data/examples/ip.rb +6 -6
- data/examples/longlong.rb +2 -2
- data/examples/md.rb +1 -1
- data/examples/modular-def.rb +2 -2
- data/examples/native.rb +3 -3
- data/examples/ping.rb +1 -1
- data/examples/raw.rb +1 -1
- data/examples/switch-endian.rb +2 -2
- data/examples/vector.rb +2 -2
- data/lib/bit-struct.rb +0 -11
- data/lib/bit-struct/bit-struct.rb +61 -143
- data/lib/bit-struct/char-field.rb +3 -3
- data/lib/bit-struct/field.rb +94 -0
- data/lib/bit-struct/fields.rb +13 -13
- data/lib/bit-struct/float-field.rb +4 -4
- data/lib/bit-struct/hex-octet-field.rb +3 -3
- data/lib/bit-struct/nested-field.rb +8 -8
- data/lib/bit-struct/octet-field.rb +4 -4
- data/lib/bit-struct/signed-field.rb +23 -28
- data/lib/bit-struct/text-field.rb +2 -2
- data/lib/bit-struct/unsigned-field.rb +24 -27
- data/lib/bit-struct/vector-field.rb +7 -7
- data/lib/bit-struct/vector.rb +24 -22
- data/lib/bit-struct/yaml.rb +22 -3
- data/test/test-endian.rb +5 -5
- data/test/test-vector.rb +6 -6
- data/test/test.rb +71 -46
- metadata +43 -69
- data/.gitignore +0 -3
- data/TODO +0 -20
- data/tasks/ann.rake +0 -80
- data/tasks/bones.rake +0 -20
- data/tasks/gem.rake +0 -201
- data/tasks/git.rake +0 -40
- data/tasks/notes.rake +0 -27
- data/tasks/post_load.rake +0 -34
- data/tasks/rdoc.rake +0 -51
- data/tasks/rubyforge.rake +0 -55
- data/tasks/setup.rb +0 -292
- data/tasks/spec.rake +0 -54
- data/tasks/svn.rake +0 -47
- data/tasks/test.rake +0 -40
- data/tasks/zentest.rake +0 -36
@@ -13,13 +13,13 @@ class BitStruct
|
|
13
13
|
"Bad offset, #{offset}, for #{self.class} #{name}." +
|
14
14
|
" Must be multiple of 8."
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
unless length % 8 == 0
|
18
18
|
raise ArgumentError,
|
19
19
|
"Bad length, #{length}, for #{self.class} #{name}." +
|
20
20
|
" Must be multiple of 8."
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
offset_byte = offset / 8
|
24
24
|
length_byte = length / 8
|
25
25
|
last_byte = offset_byte + length_byte - 1
|
@@ -6,21 +6,18 @@ class BitStruct
|
|
6
6
|
def self.class_name
|
7
7
|
@class_name ||= "unsigned"
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def add_accessors_to(cl, attr = name) # :nodoc:
|
11
11
|
offset_byte = offset / 8
|
12
12
|
offset_bit = offset % 8
|
13
|
-
|
13
|
+
|
14
14
|
length_bit = offset_bit + length
|
15
15
|
length_byte = (length_bit/8.0).ceil
|
16
16
|
last_byte = offset_byte + length_byte - 1
|
17
|
-
|
17
|
+
|
18
18
|
divisor = options[:fixed] || options["fixed"]
|
19
19
|
divisor_f = divisor && divisor.to_f
|
20
|
-
|
21
|
-
# raise ArgumentError, "fixed-point divisor must be a fixnum"
|
22
|
-
# end
|
23
|
-
|
20
|
+
|
24
21
|
endian = (options[:endian] || options["endian"]).to_s
|
25
22
|
case endian
|
26
23
|
when "native"
|
@@ -33,15 +30,15 @@ class BitStruct
|
|
33
30
|
raise ArgumentError,
|
34
31
|
"Unrecognized endian option: #{endian.inspect}"
|
35
32
|
end
|
36
|
-
|
33
|
+
|
37
34
|
data_is_big_endian =
|
38
35
|
([1234].pack(ctl) == [1234].pack(length_byte <= 2 ? "n" : "N"))
|
39
|
-
|
36
|
+
|
40
37
|
if length_byte == 1
|
41
38
|
rest = 8 - length_bit
|
42
39
|
mask = ["0"*offset_bit + "1"*length + "0"*rest].pack("B8")[0].ord
|
43
40
|
mask2 = ["1"*offset_bit + "0"*length + "1"*rest].pack("B8")[0].ord
|
44
|
-
|
41
|
+
|
45
42
|
cl.class_eval do
|
46
43
|
if divisor
|
47
44
|
define_method attr do ||
|
@@ -65,11 +62,11 @@ class BitStruct
|
|
65
62
|
end
|
66
63
|
end
|
67
64
|
end
|
68
|
-
|
65
|
+
|
69
66
|
elsif offset_bit == 0 and length % 8 == 0
|
70
67
|
field_length = length
|
71
68
|
byte_range = offset_byte..last_byte
|
72
|
-
|
69
|
+
|
73
70
|
cl.class_eval do
|
74
71
|
case field_length
|
75
72
|
when 8
|
@@ -82,7 +79,7 @@ class BitStruct
|
|
82
79
|
val = (val * divisor).round
|
83
80
|
self[offset_byte] = val
|
84
81
|
end
|
85
|
-
|
82
|
+
|
86
83
|
else
|
87
84
|
define_method attr do ||
|
88
85
|
self[offset_byte]
|
@@ -92,7 +89,7 @@ class BitStruct
|
|
92
89
|
self[offset_byte] = val
|
93
90
|
end
|
94
91
|
end
|
95
|
-
|
92
|
+
|
96
93
|
when 16, 32
|
97
94
|
if divisor
|
98
95
|
define_method attr do ||
|
@@ -103,7 +100,7 @@ class BitStruct
|
|
103
100
|
val = (val * divisor).round
|
104
101
|
self[byte_range] = [val].pack(ctl)
|
105
102
|
end
|
106
|
-
|
103
|
+
|
107
104
|
else
|
108
105
|
define_method attr do ||
|
109
106
|
self[byte_range].unpack(ctl).first
|
@@ -113,7 +110,7 @@ class BitStruct
|
|
113
110
|
self[byte_range] = [val].pack(ctl)
|
114
111
|
end
|
115
112
|
end
|
116
|
-
|
113
|
+
|
117
114
|
else
|
118
115
|
reader_helper = proc do |substr|
|
119
116
|
bytes = substr.unpack("C*")
|
@@ -122,7 +119,7 @@ class BitStruct
|
|
122
119
|
(sum << 8) + byte
|
123
120
|
end
|
124
121
|
end
|
125
|
-
|
122
|
+
|
126
123
|
writer_helper = proc do |val|
|
127
124
|
bytes = []
|
128
125
|
while val > 0
|
@@ -136,21 +133,21 @@ class BitStruct
|
|
136
133
|
bytes.reverse! if data_is_big_endian
|
137
134
|
bytes.pack("C*")
|
138
135
|
end
|
139
|
-
|
136
|
+
|
140
137
|
if divisor
|
141
138
|
define_method attr do ||
|
142
139
|
reader_helper[self[byte_range]] / divisor_f
|
143
140
|
end
|
144
|
-
|
141
|
+
|
145
142
|
define_method "#{attr}=" do |val|
|
146
143
|
self[byte_range] = writer_helper[(val * divisor).round]
|
147
144
|
end
|
148
|
-
|
145
|
+
|
149
146
|
else
|
150
147
|
define_method attr do ||
|
151
148
|
reader_helper[self[byte_range]]
|
152
149
|
end
|
153
|
-
|
150
|
+
|
154
151
|
define_method "#{attr}=" do |val|
|
155
152
|
self[byte_range] = writer_helper[val]
|
156
153
|
end
|
@@ -161,10 +158,10 @@ class BitStruct
|
|
161
158
|
elsif length_byte == 2 # unaligned field that fits within two whole bytes
|
162
159
|
byte_range = offset_byte..last_byte
|
163
160
|
rest = 16 - length_bit
|
164
|
-
|
161
|
+
|
165
162
|
mask = ["0"*offset_bit + "1"*length + "0"*rest]
|
166
163
|
mask = mask.pack("B16").unpack(ctl).first
|
167
|
-
|
164
|
+
|
168
165
|
mask2 = ["1"*offset_bit + "0"*length + "1"*rest]
|
169
166
|
mask2 = mask2.pack("B16").unpack(ctl).first
|
170
167
|
|
@@ -194,14 +191,14 @@ class BitStruct
|
|
194
191
|
end
|
195
192
|
end
|
196
193
|
end
|
197
|
-
|
194
|
+
|
198
195
|
elsif length_byte == 3 # unaligned field that fits within 3 whole bytes
|
199
196
|
byte_range = offset_byte..last_byte
|
200
197
|
rest = 32 - length_bit
|
201
|
-
|
198
|
+
|
202
199
|
mask = ["0"*offset_bit + "1"*length + "0"*rest]
|
203
200
|
mask = mask.pack("B32").unpack(ctl).first
|
204
|
-
|
201
|
+
|
205
202
|
mask2 = ["1"*offset_bit + "0"*length + "1"*rest]
|
206
203
|
mask2 = mask2.pack("B32").unpack(ctl).first
|
207
204
|
|
@@ -239,7 +236,7 @@ class BitStruct
|
|
239
236
|
end
|
240
237
|
end
|
241
238
|
end
|
242
|
-
|
239
|
+
|
243
240
|
else
|
244
241
|
raise "unsupported: #{inspect}"
|
245
242
|
end
|
@@ -8,12 +8,12 @@ class BitStruct
|
|
8
8
|
def self.class_name
|
9
9
|
@class_name ||= "vector"
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
# Used in describe.
|
13
13
|
def class_name
|
14
14
|
@class_name ||= vector_class.name[/\w+$/]
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
# Returns the subclass of Vector that is used to manage the value of this
|
18
18
|
# field. If the class was specified in the BitStruct.vector declaration,
|
19
19
|
# #vector_class will return it, otherwise it will be an anonymous class
|
@@ -39,20 +39,20 @@ class BitStruct
|
|
39
39
|
"Bad offset, #{offset}, for vector field #{name}." +
|
40
40
|
" Must be multiple of 8."
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
unless length % 8 == 0
|
44
44
|
raise ArgumentError,
|
45
45
|
"Bad length, #{length}, for vector field #{name}." +
|
46
46
|
" Must be multiple of 8."
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
offset_byte = offset / 8
|
50
50
|
length_byte = length / 8
|
51
51
|
last_byte = offset_byte + length_byte - 1
|
52
52
|
byte_range = offset_byte..last_byte
|
53
53
|
|
54
54
|
vc = vector_class
|
55
|
-
|
55
|
+
|
56
56
|
cl.class_eval do
|
57
57
|
define_method attr do ||
|
58
58
|
vc.new(self[byte_range])
|
@@ -63,12 +63,12 @@ class BitStruct
|
|
63
63
|
raise ArgumentError, "Size mismatch in vector field assignment " +
|
64
64
|
"to #{attr} with value #{val.inspect}"
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
if val.class != vc
|
68
68
|
warn "Type mismatch in vector field assignment " +
|
69
69
|
"to #{attr} with value #{val.inspect}"
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
self[byte_range] = val
|
73
73
|
end
|
74
74
|
end
|
data/lib/bit-struct/vector.rb
CHANGED
@@ -22,7 +22,7 @@ class BitStruct::Vector < String
|
|
22
22
|
@struct_class = nil
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# Called as a class method with a single argument in a user-defined
|
27
27
|
# subclass to specify a particular BitStruct class to use for each entry,
|
28
28
|
# instead of generating an anonymous class. Called without arguments to
|
@@ -38,7 +38,7 @@ class BitStruct::Vector < String
|
|
38
38
|
@struct_class.default_options default_options
|
39
39
|
else
|
40
40
|
unless @struct_class
|
41
|
-
@struct_class = self == BitStruct::Vector ? BitStruct :
|
41
|
+
@struct_class = self == BitStruct::Vector ? BitStruct :
|
42
42
|
Class.new(superclass.struct_class)
|
43
43
|
@struct_class.default_options default_options
|
44
44
|
end
|
@@ -54,7 +54,7 @@ class BitStruct::Vector < String
|
|
54
54
|
def respond_to?(*m) # :nodoc:
|
55
55
|
orig_respond_to?(*m) || struct_class.respond_to?(*m)
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
# Get or set the hash of default options for the class, which apply to all
|
59
59
|
# fields in the entries. If +h+ is provided, update the default options
|
60
60
|
# with that hash. Default options are inherited.
|
@@ -70,7 +70,7 @@ class BitStruct::Vector < String
|
|
70
70
|
end
|
71
71
|
@default_options
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
def describe(*args)
|
75
75
|
fmt = args[0] || BitStruct.describe_format
|
76
76
|
if block_given?
|
@@ -81,37 +81,37 @@ class BitStruct::Vector < String
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
# Convenience method for instances. Returns the BitStruct class that
|
86
86
|
# describes each entry.
|
87
87
|
def struct_class
|
88
88
|
self.class.struct_class
|
89
89
|
end
|
90
|
-
|
91
|
-
# Convenience method for instances. Returns the string length in bytes of
|
90
|
+
|
91
|
+
# Convenience method for instances. Returns the string length in bytes of
|
92
92
|
# each entry in the vector.
|
93
93
|
def struct_class_length
|
94
94
|
self.class.struct_class.round_byte_length
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
# +arg+ can be an integer (number of entries) or a string
|
98
98
|
# (binary data, such as another Vector of the same size).
|
99
99
|
def initialize arg # :yields: instance
|
100
100
|
case arg
|
101
101
|
when Integer
|
102
102
|
super(struct_class.initial_value * arg)
|
103
|
-
|
103
|
+
|
104
104
|
else
|
105
105
|
begin
|
106
106
|
super arg
|
107
107
|
rescue NameError
|
108
108
|
raise ArgumentError, "must be string or integer: #{arg.inspect}"
|
109
109
|
end
|
110
|
-
end
|
110
|
+
end
|
111
111
|
|
112
112
|
yield self if block_given?
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
# Get the +i+-th entry. Returns a *copy* of the entry. If you want to
|
116
116
|
# use this copy to modify the entry, you must modify the copy and then
|
117
117
|
# use #[]= to replace the entry with the copy.
|
@@ -122,29 +122,29 @@ class BitStruct::Vector < String
|
|
122
122
|
unless (0...(length / entry_length)).include? i
|
123
123
|
raise ArgumentError, "index out of range: #{i}"
|
124
124
|
end
|
125
|
-
|
125
|
+
|
126
126
|
sc.new slice(entry_length * i, entry_length)
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
129
|
alias _old_replace_substr []=
|
130
130
|
|
131
131
|
# Set the +i+-th entry to +val+.
|
132
132
|
def []=(i,val)
|
133
133
|
entry_length = struct_class_length
|
134
|
-
|
134
|
+
|
135
135
|
unless (0...(length / entry_length)).include? i
|
136
136
|
raise ArgumentError, "index out of range: #{i}"
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
unless val.length == entry_length
|
140
140
|
raise ArgumentError, "wrong entry length: #{val.length} != #{entry_length}"
|
141
141
|
end
|
142
|
-
|
142
|
+
|
143
143
|
_old_replace_substr(entry_length * i, entry_length, val)
|
144
144
|
end
|
145
|
-
|
145
|
+
|
146
146
|
## TODO: [i..j] etc.
|
147
|
-
|
147
|
+
|
148
148
|
# Iterate over entries.
|
149
149
|
def each
|
150
150
|
entry_length = struct_class_length
|
@@ -152,8 +152,8 @@ class BitStruct::Vector < String
|
|
152
152
|
yield self[i]
|
153
153
|
end
|
154
154
|
end
|
155
|
-
|
156
|
-
def
|
155
|
+
|
156
|
+
def inspect_with_options(opts = BitStruct::DEFAULT_INSPECT_OPTS)
|
157
157
|
if opts[:include_class]
|
158
158
|
opts = opts.dup
|
159
159
|
opts[:include_class] = false
|
@@ -161,12 +161,14 @@ class BitStruct::Vector < String
|
|
161
161
|
else
|
162
162
|
s = ""
|
163
163
|
end
|
164
|
-
|
164
|
+
|
165
165
|
s << entries.map{|entry| entry.inspect(opts)}.join(opts[:separator])
|
166
166
|
lb, rb = opts[:brackets]
|
167
167
|
[lb, s, rb].join
|
168
168
|
end
|
169
|
-
|
169
|
+
|
170
|
+
alias inspect inspect_with_options
|
171
|
+
|
170
172
|
def inspect_detailed
|
171
173
|
inspect(BitStruct::DETAILED_INSPECT_OPTS)
|
172
174
|
end
|
data/lib/bit-struct/yaml.rb
CHANGED
@@ -7,7 +7,7 @@ class BitStruct
|
|
7
7
|
end
|
8
8
|
|
9
9
|
YAML.add_ruby_type(/^bitstruct/) do |type, val|
|
10
|
-
|
10
|
+
_subtype, subclass = YAML.read_type_class(type, Object)
|
11
11
|
subclass.new(val)
|
12
12
|
end
|
13
13
|
|
@@ -27,8 +27,27 @@ class BitStruct
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
elsif RUBY_VERSION =~ /^2\./
|
31
|
+
def encode_with coder
|
32
|
+
yaml_fields = fields.select {|field| field.inspectable?}
|
33
|
+
props = yaml_fields.map {|f| f.name.to_s}
|
34
|
+
if (rest_field = self.class.rest_field)
|
35
|
+
props << rest_field.name.to_s
|
36
|
+
end
|
37
|
+
props.each do |prop|
|
38
|
+
coder[prop] = send(prop)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def init_with coder
|
43
|
+
self << self.class.initial_value
|
44
|
+
coder.map.each do |k, v|
|
45
|
+
send("#{k}=", v)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
30
49
|
else
|
31
|
-
|
50
|
+
yaml_tag "tag:github.com:vjoel/bit-struct"
|
32
51
|
|
33
52
|
def to_yaml_properties # :nodoc:
|
34
53
|
yaml_fields = fields.select {|field| field.inspectable?}
|
@@ -55,7 +74,7 @@ class BitStruct
|
|
55
74
|
raise YAML::TypeError, "Invalid BitStruct: " + val.inspect
|
56
75
|
end
|
57
76
|
|
58
|
-
|
77
|
+
_bitstruct_name, bitstruct_type = YAML.read_type_class( tag, BitStruct )
|
59
78
|
|
60
79
|
st = bitstruct_type.new
|
61
80
|
|
data/test/test-endian.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
|
-
require '
|
1
|
+
require 'minitest/autorun'
|
2
2
|
require 'bit-struct'
|
3
3
|
|
4
|
-
class Test_Endian < Test
|
4
|
+
class Test_Endian < Minitest::Test
|
5
5
|
class Endian < BitStruct
|
6
6
|
unsigned :f_big, 32, :endian => :big
|
7
7
|
unsigned :f_little, 32, :endian => :little
|
8
8
|
unsigned :f_native, 32, :endian => :native
|
9
9
|
unsigned :f_network, 32, :endian => :network
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
attr_reader :bs
|
13
13
|
|
14
14
|
def setup
|
15
15
|
@bs = Endian.new
|
16
16
|
bs.f_big = bs.f_little = bs.f_native = bs.f_network = 0x01020304
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def test_readers
|
20
20
|
assert_equal(0x01020304, bs.f_big)
|
21
21
|
assert_equal(0x01020304, bs.f_little)
|
22
22
|
assert_equal(0x01020304, bs.f_native)
|
23
23
|
assert_equal(0x01020304, bs.f_network)
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def test_writers
|
27
27
|
bs.fields.each do |field|
|
28
28
|
byte_offset = field.offset / 8
|