bindata 0.9.3 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bindata might be problematic. Click here for more details.
- data/ChangeLog +18 -0
- data/NEWS +59 -0
- data/README +22 -23
- data/TODO +18 -12
- data/examples/gzip.rb +4 -4
- data/lib/bindata.rb +4 -3
- data/lib/bindata/array.rb +202 -132
- data/lib/bindata/base.rb +147 -166
- data/lib/bindata/{single.rb → base_primitive.rb} +82 -56
- data/lib/bindata/bits.rb +31 -770
- data/lib/bindata/choice.rb +157 -82
- data/lib/bindata/float.rb +25 -27
- data/lib/bindata/int.rb +144 -177
- data/lib/bindata/io.rb +59 -49
- data/lib/bindata/lazy.rb +80 -50
- data/lib/bindata/params.rb +134 -26
- data/lib/bindata/{single_value.rb → primitive.rb} +71 -64
- data/lib/bindata/{multi_value.rb → record.rb} +52 -70
- data/lib/bindata/registry.rb +49 -17
- data/lib/bindata/rest.rb +6 -10
- data/lib/bindata/sanitize.rb +55 -70
- data/lib/bindata/string.rb +60 -42
- data/lib/bindata/stringz.rb +34 -35
- data/lib/bindata/struct.rb +197 -152
- data/lib/bindata/trace.rb +35 -0
- data/spec/array_spec.rb +128 -112
- data/spec/{single_spec.rb → base_primitive_spec.rb} +102 -61
- data/spec/base_spec.rb +190 -185
- data/spec/bits_spec.rb +126 -98
- data/spec/choice_spec.rb +89 -98
- data/spec/example.rb +19 -0
- data/spec/float_spec.rb +28 -44
- data/spec/int_spec.rb +217 -127
- data/spec/io_spec.rb +41 -24
- data/spec/lazy_spec.rb +95 -49
- data/spec/primitive_spec.rb +191 -0
- data/spec/{multi_value_spec.rb → record_spec.rb} +124 -89
- data/spec/registry_spec.rb +53 -12
- data/spec/rest_spec.rb +2 -3
- data/spec/sanitize_spec.rb +47 -73
- data/spec/spec_common.rb +13 -1
- data/spec/string_spec.rb +34 -23
- data/spec/stringz_spec.rb +10 -18
- data/spec/struct_spec.rb +91 -63
- data/spec/system_spec.rb +291 -0
- metadata +12 -8
- data/spec/single_value_spec.rb +0 -131
data/spec/example.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bindata/base_primitive'
|
2
|
+
|
3
|
+
class ExampleSingle < BinData::BasePrimitive
|
4
|
+
register(self.name, self)
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def value_to_binary_string(val)
|
9
|
+
[val].pack("V")
|
10
|
+
end
|
11
|
+
|
12
|
+
def read_and_return_value(io)
|
13
|
+
io.readbytes(4).unpack("V").at(0)
|
14
|
+
end
|
15
|
+
|
16
|
+
def sensible_default
|
17
|
+
0
|
18
|
+
end
|
19
|
+
end
|
data/spec/float_spec.rb
CHANGED
@@ -7,24 +7,18 @@ describe "A FloatLe" do
|
|
7
7
|
before(:each) do
|
8
8
|
@obj = BinData::FloatLe.new
|
9
9
|
@obj.value = Math::PI
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
+
it "should be 4 bytes in size" do
|
13
|
+
@obj.num_bytes.should == 4
|
12
14
|
end
|
13
15
|
|
14
16
|
it "should write the expected value" do
|
15
|
-
@obj.
|
16
|
-
@io.rewind
|
17
|
-
|
18
|
-
@io.read.should == [Math::PI].pack('e')
|
17
|
+
written_value(@obj).should == [Math::PI].pack('e')
|
19
18
|
end
|
20
19
|
|
21
20
|
it "should read the same value as written" do
|
22
|
-
@obj.
|
23
|
-
@io.rewind
|
24
|
-
|
25
|
-
# check that we read in the same data that was written
|
26
|
-
@obj.read(@io)
|
27
|
-
@obj.value.should be_close(Math::PI, 0.000001)
|
21
|
+
value_read_from_written(@obj).should be_close(Math::PI, 0.000001)
|
28
22
|
end
|
29
23
|
end
|
30
24
|
|
@@ -32,24 +26,18 @@ describe "A FloatBe" do
|
|
32
26
|
before(:each) do
|
33
27
|
@obj = BinData::FloatBe.new
|
34
28
|
@obj.value = Math::PI
|
29
|
+
end
|
35
30
|
|
36
|
-
|
31
|
+
it "should be 4 bytes in size" do
|
32
|
+
@obj.num_bytes.should == 4
|
37
33
|
end
|
38
34
|
|
39
35
|
it "should write the expected value" do
|
40
|
-
@obj.
|
41
|
-
@io.rewind
|
42
|
-
|
43
|
-
@io.read.should == [Math::PI].pack('g')
|
36
|
+
written_value(@obj).should == [Math::PI].pack('g')
|
44
37
|
end
|
45
38
|
|
46
39
|
it "should read the same value as written" do
|
47
|
-
@obj.
|
48
|
-
@io.rewind
|
49
|
-
|
50
|
-
# check that we read in the same data that was written
|
51
|
-
@obj.read(@io)
|
52
|
-
@obj.value.should be_close(Math::PI, 0.000001)
|
40
|
+
value_read_from_written(@obj).should be_close(Math::PI, 0.000001)
|
53
41
|
end
|
54
42
|
end
|
55
43
|
|
@@ -57,24 +45,18 @@ describe "A DoubleLe" do
|
|
57
45
|
before(:each) do
|
58
46
|
@obj = BinData::DoubleLe.new
|
59
47
|
@obj.value = Math::PI
|
48
|
+
end
|
60
49
|
|
61
|
-
|
50
|
+
it "should be 8 bytes in size" do
|
51
|
+
@obj.num_bytes.should == 8
|
62
52
|
end
|
63
53
|
|
64
54
|
it "should write the expected value" do
|
65
|
-
@obj.
|
66
|
-
@io.rewind
|
67
|
-
|
68
|
-
@io.read.should == [Math::PI].pack('E')
|
55
|
+
written_value(@obj).should == [Math::PI].pack('E')
|
69
56
|
end
|
70
57
|
|
71
58
|
it "should read the same value as written" do
|
72
|
-
@obj.
|
73
|
-
@io.rewind
|
74
|
-
|
75
|
-
# check that we read in the same data that was written
|
76
|
-
@obj.read(@io)
|
77
|
-
@obj.value.should be_close(Math::PI, 0.000000000000000001)
|
59
|
+
value_read_from_written(@obj).should be_close(Math::PI, 0.0000000000000001)
|
78
60
|
end
|
79
61
|
end
|
80
62
|
|
@@ -83,23 +65,25 @@ describe "A DoubleBe" do
|
|
83
65
|
before(:each) do
|
84
66
|
@obj = BinData::DoubleBe.new
|
85
67
|
@obj.value = Math::PI
|
68
|
+
end
|
86
69
|
|
87
|
-
|
70
|
+
it "should be 8 bytes in size" do
|
71
|
+
@obj.num_bytes.should == 8
|
88
72
|
end
|
89
73
|
|
90
74
|
it "should write the expected value" do
|
91
|
-
@obj.
|
92
|
-
@io.rewind
|
93
|
-
|
94
|
-
@io.read.should == [Math::PI].pack('G')
|
75
|
+
written_value(@obj).should == [Math::PI].pack('G')
|
95
76
|
end
|
96
77
|
|
97
78
|
it "should read the same value as written" do
|
98
|
-
@obj.
|
99
|
-
@io.rewind
|
100
|
-
|
101
|
-
# check that we read in the same data that was written
|
102
|
-
@obj.read(@io)
|
103
|
-
@obj.value.should be_close(Math::PI, 0.000000000000000001)
|
79
|
+
value_read_from_written(@obj).should be_close(Math::PI, 0.0000000000000001)
|
104
80
|
end
|
105
81
|
end
|
82
|
+
|
83
|
+
def written_value(obj)
|
84
|
+
obj.to_binary_s
|
85
|
+
end
|
86
|
+
|
87
|
+
def value_read_from_written(obj)
|
88
|
+
obj.class.read(obj.to_binary_s)
|
89
|
+
end
|
data/spec/int_spec.rb
CHANGED
@@ -1,163 +1,253 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
|
4
|
-
require 'bindata
|
4
|
+
require 'bindata'
|
5
|
+
|
6
|
+
share_examples_for "All Integers" do
|
7
|
+
|
8
|
+
it "should have correct num_bytes" do
|
9
|
+
all_classes do |int_class|
|
10
|
+
int_class.new.num_bytes.should == @nbytes
|
11
|
+
end
|
12
|
+
end
|
5
13
|
|
6
|
-
describe "All signed integers" do
|
7
14
|
it "should have a sensible value of zero" do
|
8
|
-
|
9
|
-
|
10
|
-
BinData::Int16be,
|
11
|
-
BinData::Int32le,
|
12
|
-
BinData::Int32be,
|
13
|
-
BinData::Int64le,
|
14
|
-
BinData::Int64be,
|
15
|
-
BinData::Int128le,
|
16
|
-
BinData::Int128be].each do |klass|
|
17
|
-
klass.new.value.should be_zero
|
15
|
+
all_classes do |int_class|
|
16
|
+
int_class.new.value.should be_zero
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
21
|
-
it "should
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
[ 4, true, BinData::Int32be],
|
28
|
-
[ 8, false, BinData::Int64le],
|
29
|
-
[ 8, true, BinData::Int64be],
|
30
|
-
[16, false, BinData::Int128le],
|
31
|
-
[16, true, BinData::Int128be],
|
32
|
-
].each do |nbytes, big_endian, klass|
|
33
|
-
gen_int_test_data(nbytes, big_endian).each do |val, clamped_val, str|
|
34
|
-
test_read_write(klass, val, clamped_val, str)
|
35
|
-
end
|
20
|
+
it "should avoid underflow" do
|
21
|
+
all_classes do |int_class|
|
22
|
+
obj = int_class.new
|
23
|
+
obj.value = min_value - 1
|
24
|
+
|
25
|
+
obj.value.should == min_value
|
36
26
|
end
|
37
27
|
end
|
38
|
-
end
|
39
28
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
29
|
+
it "should avoid overflow" do
|
30
|
+
all_classes do |int_class|
|
31
|
+
obj = int_class.new
|
32
|
+
obj.value = max_value + 1
|
33
|
+
|
34
|
+
obj.value.should == max_value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should assign values" do
|
39
|
+
all_classes do |int_class|
|
40
|
+
obj = int_class.new
|
41
|
+
test_int = gen_test_int
|
42
|
+
obj.assign(test_int)
|
43
|
+
obj.value.should == test_int
|
52
44
|
end
|
53
45
|
end
|
54
46
|
|
55
|
-
it "should
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
47
|
+
it "should assign values from other int objects" do
|
48
|
+
all_classes do |int_class|
|
49
|
+
src = int_class.new
|
50
|
+
src.assign(gen_test_int)
|
51
|
+
|
52
|
+
obj = int_class.new
|
53
|
+
obj.assign(src)
|
54
|
+
obj.value.should == src.value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should symmetrically read and write a +ve number" do
|
59
|
+
all_classes do |int_class|
|
60
|
+
obj = int_class.new
|
61
|
+
obj.value = gen_test_int
|
62
|
+
|
63
|
+
str = obj.to_binary_s
|
64
|
+
int_class.read(str).should == obj.value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should symmetrically read and write a -ve number" do
|
69
|
+
all_classes do |int_class|
|
70
|
+
if @signed
|
71
|
+
obj = int_class.new
|
72
|
+
obj.value = -gen_test_int
|
73
|
+
|
74
|
+
str = obj.to_binary_s
|
75
|
+
int_class.read(str).should == obj.value
|
69
76
|
end
|
70
77
|
end
|
71
78
|
end
|
72
|
-
end
|
73
79
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
data = klass.new
|
78
|
-
data.value = val
|
79
|
-
data.value.should == clamped_val
|
80
|
-
|
81
|
-
# write the data
|
82
|
-
io = StringIO.new
|
83
|
-
data.write(io)
|
84
|
-
|
85
|
-
# check that we write the expected byte pattern
|
86
|
-
io.rewind
|
87
|
-
io.read.should == str
|
88
|
-
|
89
|
-
# check that we read in the same data that was written
|
90
|
-
io.rewind
|
91
|
-
data = klass.new
|
92
|
-
data.read(io)
|
93
|
-
data.value.should == clamped_val
|
94
|
-
end
|
80
|
+
it "should convert a +ve number to string" do
|
81
|
+
all_classes do |int_class|
|
82
|
+
val = gen_test_int
|
95
83
|
|
96
|
-
|
97
|
-
|
98
|
-
raise "nbytes too large" if nbytes > 16
|
99
|
-
tests = []
|
84
|
+
obj = int_class.new
|
85
|
+
obj.value = val
|
100
86
|
|
101
|
-
|
102
|
-
|
87
|
+
obj.to_binary_s.should == int_to_binary_str(val)
|
88
|
+
end
|
89
|
+
end
|
103
90
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
91
|
+
it "should convert a -ve number to string" do
|
92
|
+
all_classes do |int_class|
|
93
|
+
if @signed
|
94
|
+
val = -gen_test_int
|
108
95
|
|
109
|
-
|
110
|
-
|
96
|
+
obj = int_class.new
|
97
|
+
obj.value = val
|
111
98
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
99
|
+
obj.to_binary_s.should == int_to_binary_str(val)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def all_classes(&block)
|
105
|
+
@ints.each_pair do |int_class, nbytes|
|
106
|
+
@nbytes = nbytes
|
107
|
+
yield int_class
|
108
|
+
end
|
109
|
+
end
|
116
110
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
111
|
+
def min_value
|
112
|
+
if @signed
|
113
|
+
-max_value - 1
|
114
|
+
else
|
115
|
+
0
|
116
|
+
end
|
117
|
+
end
|
121
118
|
|
122
|
-
|
123
|
-
|
119
|
+
def max_value
|
120
|
+
if @signed
|
121
|
+
(1 << (@nbytes * 8 - 1)) - 1
|
122
|
+
else
|
123
|
+
(1 << (@nbytes * 8)) - 1
|
124
|
+
end
|
125
|
+
end
|
124
126
|
|
125
|
-
|
126
|
-
|
127
|
+
def gen_test_int
|
128
|
+
# resulting int is guaranteed to be +ve for signed or unsigned integers
|
129
|
+
(0 ... @nbytes).inject(0) { |val, i| (val << 8) | ((val + 0x11) % 0x100) }
|
130
|
+
end
|
127
131
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
+
def int_to_binary_str(val)
|
133
|
+
str = ""
|
134
|
+
v = val & ((1 << (@nbytes * 8)) - 1)
|
135
|
+
@nbytes.times do
|
136
|
+
str.concat(v & 0xff)
|
137
|
+
v >>= 8
|
138
|
+
end
|
139
|
+
(@endian == :little) ? str : str.reverse
|
140
|
+
end
|
141
|
+
end
|
132
142
|
|
133
|
-
|
134
|
-
|
143
|
+
describe "All signed big endian integers" do
|
144
|
+
it_should_behave_like "All Integers"
|
145
|
+
|
146
|
+
before(:all) do
|
147
|
+
BinData::Integer.define_class(24, :big, :signed)
|
148
|
+
BinData::Integer.define_class(48, :big, :signed)
|
149
|
+
BinData::Integer.define_class(96, :big, :signed)
|
150
|
+
@endian = :big
|
151
|
+
@signed = true
|
152
|
+
@ints = {
|
153
|
+
BinData::Int8 => 1,
|
154
|
+
BinData::Int8be => 1,
|
155
|
+
BinData::Int16be => 2,
|
156
|
+
BinData::Int24be => 3,
|
157
|
+
BinData::Int32be => 4,
|
158
|
+
BinData::Int48be => 6,
|
159
|
+
BinData::Int64be => 8,
|
160
|
+
BinData::Int96be => 12,
|
161
|
+
BinData::Int128be => 16,
|
162
|
+
}
|
163
|
+
end
|
164
|
+
end
|
135
165
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
166
|
+
describe "All unsigned big endian integers" do
|
167
|
+
it_should_behave_like "All Integers"
|
168
|
+
|
169
|
+
before(:all) do
|
170
|
+
BinData::Integer.define_class(24, :big, :unsigned)
|
171
|
+
BinData::Integer.define_class(48, :big, :unsigned)
|
172
|
+
BinData::Integer.define_class(96, :big, :unsigned)
|
173
|
+
@endian = :big
|
174
|
+
@signed = false
|
175
|
+
@ints = {
|
176
|
+
BinData::Uint8 => 1,
|
177
|
+
BinData::Uint8be => 1,
|
178
|
+
BinData::Uint16be => 2,
|
179
|
+
BinData::Uint24be => 3,
|
180
|
+
BinData::Uint32be => 4,
|
181
|
+
BinData::Uint48be => 6,
|
182
|
+
BinData::Uint64be => 8,
|
183
|
+
BinData::Uint96be => 12,
|
184
|
+
BinData::Uint128be => 16,
|
185
|
+
}
|
186
|
+
end
|
187
|
+
end
|
140
188
|
|
141
|
-
|
142
|
-
|
189
|
+
describe "All signed little endian integers" do
|
190
|
+
it_should_behave_like "All Integers"
|
191
|
+
|
192
|
+
before(:all) do
|
193
|
+
BinData::Integer.define_class(24, :little, :signed)
|
194
|
+
BinData::Integer.define_class(48, :little, :signed)
|
195
|
+
BinData::Integer.define_class(96, :little, :signed)
|
196
|
+
@endian = :little
|
197
|
+
@signed = true
|
198
|
+
@ints = {
|
199
|
+
BinData::Int8 => 1,
|
200
|
+
BinData::Int8le => 1,
|
201
|
+
BinData::Int16le => 2,
|
202
|
+
BinData::Int24le => 3,
|
203
|
+
BinData::Int32le => 4,
|
204
|
+
BinData::Int48le => 6,
|
205
|
+
BinData::Int64le => 8,
|
206
|
+
BinData::Int96le => 12,
|
207
|
+
BinData::Int128le => 16,
|
208
|
+
}
|
209
|
+
end
|
210
|
+
end
|
143
211
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
212
|
+
describe "All unsigned little endian integers" do
|
213
|
+
it_should_behave_like "All Integers"
|
214
|
+
|
215
|
+
before(:all) do
|
216
|
+
BinData::Integer.define_class(24, :little, :unsigned)
|
217
|
+
BinData::Integer.define_class(48, :little, :unsigned)
|
218
|
+
BinData::Integer.define_class(96, :little, :unsigned)
|
219
|
+
@endian = :little
|
220
|
+
@signed = false
|
221
|
+
@ints = {
|
222
|
+
BinData::Uint8 => 1,
|
223
|
+
BinData::Uint8le => 1,
|
224
|
+
BinData::Uint16le => 2,
|
225
|
+
BinData::Uint24le => 3,
|
226
|
+
BinData::Uint32le => 4,
|
227
|
+
BinData::Uint48le => 6,
|
228
|
+
BinData::Uint64le => 8,
|
229
|
+
BinData::Uint96le => 12,
|
230
|
+
BinData::Uint128le => 16,
|
231
|
+
}
|
232
|
+
end
|
233
|
+
end
|
148
234
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
235
|
+
describe "Custom defined integers" do
|
236
|
+
it "should fail unless bits are a multiple of 8" do
|
237
|
+
lambda {
|
238
|
+
BinData::Integer.define_class(7, :little, :unsigned)
|
239
|
+
}.should raise_error
|
153
240
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
tests.push [v, v, big_endian ? s : s.reverse]
|
241
|
+
lambda {
|
242
|
+
BinData::Integer.define_class(7, :big, :unsigned)
|
243
|
+
}.should raise_error
|
158
244
|
|
159
|
-
|
160
|
-
|
245
|
+
lambda {
|
246
|
+
BinData::Integer.define_class(7, :little, :signed)
|
247
|
+
}.should raise_error
|
161
248
|
|
162
|
-
|
249
|
+
lambda {
|
250
|
+
BinData::Integer.define_class(7, :big, :signed)
|
251
|
+
}.should raise_error
|
252
|
+
end
|
163
253
|
end
|