bindata 1.8.3 → 2.0.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.
- checksums.yaml +7 -0
- data/.travis.yml +1 -1
- data/ChangeLog.rdoc +5 -14
- data/INSTALL +10 -9
- data/NEWS.rdoc +19 -0
- data/README.md +2 -6
- data/Rakefile +0 -2
- data/bindata.gemspec +0 -3
- data/examples/gzip.rb +70 -106
- data/examples/tcp_ip.rb +8 -10
- data/lib/bindata.rb +4 -0
- data/lib/bindata/base.rb +5 -10
- data/lib/bindata/bits.rb +15 -84
- data/lib/bindata/buffer.rb +1 -1
- data/lib/bindata/choice.rb +24 -8
- data/lib/bindata/deprecated.rb +3 -26
- data/lib/bindata/int.rb +10 -2
- data/lib/bindata/io.rb +5 -17
- data/lib/bindata/lazy.rb +1 -1
- data/lib/bindata/params.rb +1 -1
- data/lib/bindata/record.rb +19 -1
- data/lib/bindata/sanitize.rb +0 -20
- data/lib/bindata/string.rb +4 -5
- data/lib/bindata/struct.rb +23 -124
- data/lib/bindata/version.rb +1 -1
- data/test/alignment_test.rb +1 -1
- data/test/array_test.rb +3 -3
- data/test/bits_test.rb +34 -38
- data/test/common.rb +1 -5
- data/test/io_test.rb +0 -15
- data/test/lazy_test.rb +3 -11
- data/test/record_test.rb +21 -27
- data/test/string_test.rb +23 -25
- data/test/struct_test.rb +21 -52
- data/test/system_test.rb +9 -9
- metadata +48 -119
- data/doc/manual.haml +0 -407
- data/doc/manual.md +0 -1682
- data/setup.rb +0 -1585
- data/tasks/manual.rake +0 -36
data/lib/bindata/string.rb
CHANGED
@@ -91,14 +91,13 @@ module BinData
|
|
91
91
|
|
92
92
|
def snapshot
|
93
93
|
# override to trim padding
|
94
|
-
|
95
|
-
|
94
|
+
result = super
|
95
|
+
result = clamp_to_length(result)
|
96
96
|
|
97
97
|
if get_parameter(:trim_padding)
|
98
|
-
trim_padding(
|
99
|
-
else
|
100
|
-
snap
|
98
|
+
result = trim_padding(result)
|
101
99
|
end
|
100
|
+
result
|
102
101
|
end
|
103
102
|
|
104
103
|
#---------------
|
data/lib/bindata/struct.rb
CHANGED
@@ -3,7 +3,7 @@ require 'bindata/base'
|
|
3
3
|
module BinData
|
4
4
|
|
5
5
|
class Base
|
6
|
-
optional_parameter :onlyif
|
6
|
+
optional_parameter :onlyif # Used by Struct
|
7
7
|
end
|
8
8
|
|
9
9
|
# A Struct is an ordered collection of named data objects.
|
@@ -20,7 +20,7 @@ module BinData
|
|
20
20
|
# :fields => [ [:int32le, :a],
|
21
21
|
# [:int16le, :b],
|
22
22
|
# [:tuple, :s] ])
|
23
|
-
# obj.field_names =># [
|
23
|
+
# obj.field_names =># [:b, :s]
|
24
24
|
#
|
25
25
|
#
|
26
26
|
# == Parameters
|
@@ -47,11 +47,9 @@ module BinData
|
|
47
47
|
#
|
48
48
|
# Fields may have have extra parameters as listed below:
|
49
49
|
#
|
50
|
-
# [<tt>:onlyif</tt>]
|
51
|
-
#
|
52
|
-
#
|
53
|
-
# [<tt>:byte_align</tt>] This field's rel_offset must be a multiple of
|
54
|
-
# <tt>:byte_align</tt>.
|
50
|
+
# [<tt>:onlyif</tt>] Used to indicate a data object is optional.
|
51
|
+
# if +false+, this object will not be included in any
|
52
|
+
# calls to #read, #write, #num_bytes or #snapshot.
|
55
53
|
class Struct < BinData::Base
|
56
54
|
|
57
55
|
mandatory_parameter :fields
|
@@ -139,9 +137,7 @@ module BinData
|
|
139
137
|
end
|
140
138
|
|
141
139
|
def initialize_shared_instance
|
142
|
-
|
143
|
-
@field_names = fields.field_names.freeze
|
144
|
-
extend ByteAlignPlugin if fields.any_field_has_parameter?(:byte_align)
|
140
|
+
@field_names = get_parameter(:fields).field_names.freeze
|
145
141
|
super
|
146
142
|
end
|
147
143
|
|
@@ -166,7 +162,7 @@ module BinData
|
|
166
162
|
snapshot = Snapshot.new
|
167
163
|
field_names.each do |name|
|
168
164
|
obj = find_obj_for_name(name)
|
169
|
-
snapshot[name] = obj.snapshot if include_obj
|
165
|
+
snapshot[name] = obj.snapshot if include_obj(obj)
|
170
166
|
end
|
171
167
|
snapshot
|
172
168
|
end
|
@@ -180,13 +176,13 @@ module BinData
|
|
180
176
|
else
|
181
177
|
hidden = get_parameter(:hide) || []
|
182
178
|
@field_names.compact - hidden
|
183
|
-
end
|
179
|
+
end
|
184
180
|
end
|
185
181
|
|
186
182
|
def respond_to?(symbol, include_private = false) #:nodoc:
|
187
183
|
@field_names.include?(base_field_name(symbol)) || super
|
188
184
|
end
|
189
|
-
|
185
|
+
|
190
186
|
def method_missing(symbol, *args, &block) #:nodoc:
|
191
187
|
obj = find_obj_for_name(symbol)
|
192
188
|
if obj
|
@@ -209,12 +205,12 @@ module BinData
|
|
209
205
|
|
210
206
|
def do_read(io) #:nodoc:
|
211
207
|
instantiate_all_objs
|
212
|
-
@field_objs.each { |f| f.do_read(io) if include_obj
|
208
|
+
@field_objs.each { |f| f.do_read(io) if include_obj(f) }
|
213
209
|
end
|
214
210
|
|
215
211
|
def do_write(io) #:nodoc
|
216
212
|
instantiate_all_objs
|
217
|
-
@field_objs.each { |f| f.do_write(io) if include_obj
|
213
|
+
@field_objs.each { |f| f.do_write(io) if include_obj(f) }
|
218
214
|
end
|
219
215
|
|
220
216
|
def do_num_bytes #:nodoc:
|
@@ -246,15 +242,16 @@ module BinData
|
|
246
242
|
#---------------
|
247
243
|
private
|
248
244
|
|
245
|
+
def base_field_name(name)
|
246
|
+
name.to_s.chomp("=").to_sym
|
247
|
+
end
|
248
|
+
|
249
249
|
def invoke_field(obj, symbol, args)
|
250
250
|
name = symbol.to_s
|
251
251
|
is_writer = (name[-1, 1] == "=")
|
252
|
-
is_query = (name[-1, 1] == "?")
|
253
252
|
|
254
253
|
if is_writer
|
255
254
|
obj.assign(*args)
|
256
|
-
elsif is_query
|
257
|
-
include_obj?(obj)
|
258
255
|
else
|
259
256
|
obj
|
260
257
|
end
|
@@ -274,10 +271,6 @@ module BinData
|
|
274
271
|
end
|
275
272
|
end
|
276
273
|
|
277
|
-
def base_field_name(name)
|
278
|
-
name.to_s.sub(/(=|\?)\z/, "").to_sym
|
279
|
-
end
|
280
|
-
|
281
274
|
def instantiate_all_objs
|
282
275
|
@field_names.each_index { |i| instantiate_obj_at(i) }
|
283
276
|
end
|
@@ -317,65 +310,26 @@ module BinData
|
|
317
310
|
end
|
318
311
|
|
319
312
|
def sum_num_bytes_below_index(index)
|
320
|
-
|
313
|
+
sum = 0
|
314
|
+
(0...index).each do |i|
|
321
315
|
obj = @field_objs[i]
|
322
|
-
if include_obj
|
316
|
+
if include_obj(obj)
|
323
317
|
nbytes = obj.do_num_bytes
|
324
|
-
(nbytes.is_a?(Integer) ? sum.ceil : sum) + nbytes
|
325
|
-
else
|
326
|
-
sum
|
318
|
+
sum = (nbytes.is_a?(Integer) ? sum.ceil : sum) + nbytes
|
327
319
|
end
|
328
320
|
end
|
329
|
-
end
|
330
321
|
|
331
|
-
|
332
|
-
not obj.has_parameter?(:onlyif) or obj.eval_parameter(:onlyif)
|
322
|
+
sum
|
333
323
|
end
|
334
324
|
|
335
|
-
|
336
|
-
|
337
|
-
def keys
|
338
|
-
@order ||= []
|
339
|
-
k = super
|
340
|
-
@order & k
|
341
|
-
end
|
342
|
-
|
343
|
-
def []=(key, value)
|
344
|
-
@order ||= []
|
345
|
-
@order << key
|
346
|
-
super(key, value)
|
347
|
-
end
|
348
|
-
|
349
|
-
def each
|
350
|
-
keys.each do |k|
|
351
|
-
yield [k, self[k]]
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
|
-
def each_pair
|
356
|
-
each do |el|
|
357
|
-
yield *el
|
358
|
-
end
|
359
|
-
end
|
360
|
-
end
|
325
|
+
def include_obj(obj)
|
326
|
+
not obj.has_parameter?(:onlyif) or obj.eval_parameter(:onlyif)
|
361
327
|
end
|
362
328
|
|
363
329
|
# A hash that can be accessed via attributes.
|
364
330
|
class Snapshot < ::Hash #:nodoc:
|
365
|
-
include OrderedHash if RUBY_VERSION <= "1.9"
|
366
|
-
|
367
|
-
def has_key?(key)
|
368
|
-
super(key.to_s)
|
369
|
-
end
|
370
|
-
|
371
|
-
def [](key)
|
372
|
-
super(key.to_s)
|
373
|
-
end
|
374
|
-
|
375
331
|
def []=(key, value)
|
376
|
-
|
377
|
-
super(key.to_s, value)
|
378
|
-
end
|
332
|
+
super(key, value) unless value.nil?
|
379
333
|
end
|
380
334
|
|
381
335
|
def respond_to?(symbol, include_private = false)
|
@@ -387,59 +341,4 @@ module BinData
|
|
387
341
|
end
|
388
342
|
end
|
389
343
|
end
|
390
|
-
|
391
|
-
# Align fields to a multiple of :byte_align
|
392
|
-
module ByteAlignPlugin
|
393
|
-
def do_read(io)
|
394
|
-
initial_offset = io.offset
|
395
|
-
instantiate_all_objs
|
396
|
-
@field_objs.each do |f|
|
397
|
-
if include_obj?(f)
|
398
|
-
if align_obj?(f)
|
399
|
-
io.seekbytes(bytes_to_align(f, io.offset - initial_offset))
|
400
|
-
end
|
401
|
-
f.do_read(io)
|
402
|
-
end
|
403
|
-
end
|
404
|
-
end
|
405
|
-
|
406
|
-
def do_write(io)
|
407
|
-
initial_offset = io.offset
|
408
|
-
instantiate_all_objs
|
409
|
-
@field_objs.each do |f|
|
410
|
-
if include_obj?(f)
|
411
|
-
if align_obj?(f)
|
412
|
-
io.writebytes("\x00" * bytes_to_align(f, io.offset - initial_offset))
|
413
|
-
end
|
414
|
-
f.do_write(io)
|
415
|
-
end
|
416
|
-
end
|
417
|
-
end
|
418
|
-
|
419
|
-
def sum_num_bytes_below_index(index)
|
420
|
-
sum = 0
|
421
|
-
(0...@field_objs.length).each do |i|
|
422
|
-
obj = @field_objs[i]
|
423
|
-
if include_obj?(obj)
|
424
|
-
sum = sum.ceil + bytes_to_align(obj, sum.ceil) if align_obj?(obj)
|
425
|
-
|
426
|
-
break if i >= index
|
427
|
-
|
428
|
-
nbytes = obj.do_num_bytes
|
429
|
-
sum = (nbytes.is_a?(Integer) ? sum.ceil : sum) + nbytes
|
430
|
-
end
|
431
|
-
end
|
432
|
-
|
433
|
-
sum
|
434
|
-
end
|
435
|
-
|
436
|
-
def bytes_to_align(obj, rel_offset)
|
437
|
-
align = obj.eval_parameter(:byte_align)
|
438
|
-
(align - (rel_offset % align)) % align
|
439
|
-
end
|
440
|
-
|
441
|
-
def align_obj?(obj)
|
442
|
-
obj.has_parameter?(:byte_align)
|
443
|
-
end
|
444
|
-
end
|
445
344
|
end
|
data/lib/bindata/version.rb
CHANGED
data/test/alignment_test.rb
CHANGED
@@ -52,7 +52,7 @@ describe BinData::BitAligned do
|
|
52
52
|
|
53
53
|
it "reads as expected" do
|
54
54
|
obj.read("\x56\x36\x42")
|
55
|
-
obj.snapshot.must_equal({
|
55
|
+
obj.snapshot.must_equal({:preamble => 5, :str => "cd", :afterward => 2})
|
56
56
|
end
|
57
57
|
|
58
58
|
it "writes as expected" do
|
data/test/array_test.rb
CHANGED
@@ -168,7 +168,7 @@ describe BinData::Array, "with several elements" do
|
|
168
168
|
end
|
169
169
|
|
170
170
|
it "has correct offset" do
|
171
|
-
obj[2].
|
171
|
+
obj[2].offset.must_equal ExampleSingle.new.num_bytes * 2
|
172
172
|
end
|
173
173
|
|
174
174
|
it "has correct num_bytes" do
|
@@ -364,8 +364,8 @@ describe BinData::Array, "of bits" do
|
|
364
364
|
end
|
365
365
|
|
366
366
|
it "has correct offset" do
|
367
|
-
obj[7].
|
368
|
-
obj[8].
|
367
|
+
obj[7].offset.must_equal 0
|
368
|
+
obj[8].offset.must_equal 1
|
369
369
|
end
|
370
370
|
end
|
371
371
|
|
data/test/bits_test.rb
CHANGED
@@ -5,58 +5,66 @@ require File.expand_path(File.join(File.dirname(__FILE__), "common"))
|
|
5
5
|
module AllBitfields
|
6
6
|
|
7
7
|
def test_has_a_sensible_value_of_zero
|
8
|
-
|
9
|
-
|
8
|
+
all_classes do |bit_class|
|
9
|
+
bit_class.new.must_equal 0
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_avoids_underflow
|
14
|
-
|
14
|
+
all_classes do |bit_class|
|
15
|
+
obj = bit_class.new
|
16
|
+
|
15
17
|
obj.assign(min_value - 1)
|
16
18
|
obj.must_equal min_value
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
22
|
def test_avoids_overflow
|
21
|
-
|
23
|
+
all_classes do |bit_class|
|
24
|
+
obj = bit_class.new
|
25
|
+
|
22
26
|
obj.assign(max_value + 1)
|
23
27
|
obj.must_equal max_value
|
24
28
|
end
|
25
29
|
end
|
26
30
|
|
27
31
|
def test_assign_values
|
28
|
-
|
32
|
+
all_classes do |bit_class|
|
29
33
|
some_values_within_range.each do |val|
|
34
|
+
obj = bit_class.new
|
30
35
|
obj.assign(val)
|
36
|
+
|
31
37
|
obj.must_equal val
|
32
38
|
end
|
33
39
|
end
|
34
40
|
end
|
35
41
|
|
36
42
|
def test_assign_values_from_other_bit_objects
|
37
|
-
|
43
|
+
all_classes do |bit_class|
|
38
44
|
some_values_within_range.each do |val|
|
39
|
-
obj.
|
45
|
+
obj = bit_class.new
|
46
|
+
obj.assign(bit_class.new(val))
|
47
|
+
|
40
48
|
obj.must_equal val
|
41
49
|
end
|
42
50
|
end
|
43
51
|
end
|
44
52
|
|
45
53
|
def test_symmetrically_read_and_write
|
46
|
-
|
54
|
+
all_classes do |bit_class|
|
47
55
|
some_values_within_range.each do |val|
|
56
|
+
obj = bit_class.new
|
48
57
|
obj.assign(val)
|
49
|
-
|
50
|
-
|
51
|
-
other.must_equal obj
|
58
|
+
|
59
|
+
obj.value_read_from_written.must_equal obj
|
52
60
|
end
|
53
61
|
end
|
54
62
|
end
|
55
63
|
|
56
|
-
def
|
57
|
-
@bits.
|
64
|
+
def all_classes(&block)
|
65
|
+
@bits.each_pair do |bit_class, nbits|
|
58
66
|
@nbits = nbits
|
59
|
-
yield
|
67
|
+
yield bit_class
|
60
68
|
end
|
61
69
|
end
|
62
70
|
|
@@ -90,7 +98,7 @@ module AllBitfields
|
|
90
98
|
end
|
91
99
|
|
92
100
|
def generate_bit_classes_to_test(endian, signed)
|
93
|
-
bits =
|
101
|
+
bits = {}
|
94
102
|
if signed
|
95
103
|
base = "Sbit"
|
96
104
|
start = 2
|
@@ -99,20 +107,12 @@ def generate_bit_classes_to_test(endian, signed)
|
|
99
107
|
start = 1
|
100
108
|
end
|
101
109
|
|
102
|
-
(start ..
|
110
|
+
(start .. 50).each do |nbits|
|
103
111
|
name = "#{base}#{nbits}"
|
104
112
|
name << "le" if endian == :little
|
105
|
-
|
106
|
-
bits
|
107
|
-
end
|
108
|
-
|
109
|
-
(start .. 64).each do |nbits|
|
110
|
-
name = "#{base}"
|
111
|
-
name << "Le" if endian == :little
|
112
|
-
obj = BinData.const_get(name).new(:nbits => nbits)
|
113
|
-
bits << [obj, nbits]
|
113
|
+
bit_class = BinData.const_get(name)
|
114
|
+
bits[bit_class] = nbits
|
114
115
|
end
|
115
|
-
|
116
116
|
bits
|
117
117
|
end
|
118
118
|
|
@@ -125,12 +125,11 @@ describe "Unsigned big endian bitfields" do
|
|
125
125
|
end
|
126
126
|
|
127
127
|
it "read big endian values" do
|
128
|
-
|
128
|
+
@bits.each_pair do |bit_class, nbits|
|
129
129
|
nbytes = (nbits + 7) / 8
|
130
130
|
str = [0b1000_0000].pack("C") + "\000" * (nbytes - 1)
|
131
131
|
|
132
|
-
|
133
|
-
obj.must_equal 1 << (nbits - 1)
|
132
|
+
bit_class.read(str).must_equal 1 << (nbits - 1)
|
134
133
|
end
|
135
134
|
end
|
136
135
|
end
|
@@ -144,12 +143,11 @@ describe "Signed big endian bitfields" do
|
|
144
143
|
end
|
145
144
|
|
146
145
|
it "read big endian values" do
|
147
|
-
|
146
|
+
@bits.each_pair do |bit_class, nbits|
|
148
147
|
nbytes = (nbits + 7) / 8
|
149
148
|
str = [0b0100_0000].pack("C") + "\000" * (nbytes - 1)
|
150
149
|
|
151
|
-
|
152
|
-
obj.must_equal 1 << (nbits - 2)
|
150
|
+
bit_class.read(str).must_equal 1 << (nbits - 2)
|
153
151
|
end
|
154
152
|
end
|
155
153
|
end
|
@@ -163,12 +161,11 @@ describe "Unsigned little endian bitfields" do
|
|
163
161
|
end
|
164
162
|
|
165
163
|
it "read little endian values" do
|
166
|
-
|
164
|
+
@bits.each_pair do |bit_class, nbits|
|
167
165
|
nbytes = (nbits + 7) / 8
|
168
166
|
str = [0b0000_0001].pack("C") + "\000" * (nbytes - 1)
|
169
167
|
|
170
|
-
|
171
|
-
obj.must_equal 1
|
168
|
+
bit_class.read(str).must_equal 1
|
172
169
|
end
|
173
170
|
end
|
174
171
|
end
|
@@ -182,12 +179,11 @@ describe "Signed little endian bitfields" do
|
|
182
179
|
end
|
183
180
|
|
184
181
|
it "read little endian values" do
|
185
|
-
|
182
|
+
@bits.each_pair do |bit_class, nbits|
|
186
183
|
nbytes = (nbits + 7) / 8
|
187
184
|
str = [0b0000_0001].pack("C") + "\000" * (nbytes - 1)
|
188
185
|
|
189
|
-
|
190
|
-
obj.must_equal 1
|
186
|
+
bit_class.read(str).must_equal 1
|
191
187
|
end
|
192
188
|
end
|
193
189
|
end
|