bindata 1.5.1 → 1.6.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.rdoc +7 -0
- data/NEWS.rdoc +11 -0
- data/Rakefile +6 -1
- data/bindata.gemspec +2 -1
- data/doc/manual.md +17 -9
- data/examples/gzip.rb +2 -2
- data/examples/list.rb +2 -2
- data/lib/bindata/alignment.rb +4 -9
- data/lib/bindata/array.rb +57 -51
- data/lib/bindata/base.rb +13 -110
- data/lib/bindata/base_primitive.rb +130 -75
- data/lib/bindata/bits.rb +5 -7
- data/lib/bindata/choice.rb +24 -32
- data/lib/bindata/dsl.rb +1 -6
- data/lib/bindata/framework.rb +81 -0
- data/lib/bindata/int.rb +5 -7
- data/lib/bindata/name.rb +28 -0
- data/lib/bindata/offset.rb +42 -53
- data/lib/bindata/params.rb +33 -38
- data/lib/bindata/struct.rb +2 -6
- data/lib/bindata/trace.rb +16 -16
- data/lib/bindata/version.rb +1 -1
- data/lib/bindata/virtual.rb +3 -3
- data/{spec/alignment_spec.rb → test/alignment_test.rb} +17 -16
- data/test/array_test.rb +371 -0
- data/test/base_primitive_test.rb +312 -0
- data/test/base_test.rb +183 -0
- data/{spec/bits_spec.rb → test/bits_test.rb} +59 -59
- data/test/choice_test.rb +260 -0
- data/{spec/spec_common.rb → test/common.rb} +33 -18
- data/test/count_bytes_remaining_test.rb +41 -0
- data/{spec/deprecated_spec.rb → test/deprecated_test.rb} +5 -7
- data/test/float_test.rb +72 -0
- data/{spec/int_spec.rb → test/int_test.rb} +34 -43
- data/{spec/io_spec.rb → test/io_test.rb} +70 -71
- data/{spec/lazy_spec.rb → test/lazy_test.rb} +38 -39
- data/test/offset_test.rb +93 -0
- data/test/params_test.rb +144 -0
- data/{spec/primitive_spec.rb → test/primitive_test.rb} +42 -54
- data/{spec/record_spec.rb → test/record_test.rb} +133 -154
- data/test/registry_test.rb +104 -0
- data/test/rest_test.rb +29 -0
- data/test/skip_test.rb +28 -0
- data/{spec/string_spec.rb → test/string_test.rb} +96 -97
- data/test/stringz_test.rb +127 -0
- data/{spec/struct_spec.rb → test/struct_test.rb} +119 -120
- data/{spec/system_spec.rb → test/system_test.rb} +66 -106
- metadata +39 -38
- data/lib/a.rb +0 -24
- data/spec/array_spec.rb +0 -331
- data/spec/base_primitive_spec.rb +0 -238
- data/spec/base_spec.rb +0 -376
- data/spec/choice_spec.rb +0 -263
- data/spec/count_bytes_remaining_spec.rb +0 -38
- data/spec/example.rb +0 -21
- data/spec/float_spec.rb +0 -37
- data/spec/registry_spec.rb +0 -108
- data/spec/rest_spec.rb +0 -26
- data/spec/skip_spec.rb +0 -27
- data/spec/stringz_spec.rb +0 -118
- data/tasks/rspec.rake +0 -17
data/lib/bindata/int.rb
CHANGED
@@ -157,10 +157,8 @@ module BinData
|
|
157
157
|
end
|
158
158
|
|
159
159
|
# Create classes on demand
|
160
|
-
|
161
|
-
|
162
|
-
def const_missing_with_int(name)
|
163
|
-
name = name.to_s
|
160
|
+
module IntFactory
|
161
|
+
def const_missing(name)
|
164
162
|
mappings = {
|
165
163
|
/^Uint(\d+)be$/ => [:big, :unsigned],
|
166
164
|
/^Uint(\d+)le$/ => [:little, :unsigned],
|
@@ -169,7 +167,7 @@ module BinData
|
|
169
167
|
}
|
170
168
|
|
171
169
|
mappings.each_pair do |regex, args|
|
172
|
-
if regex =~ name
|
170
|
+
if regex =~ name.to_s
|
173
171
|
nbits = $1.to_i
|
174
172
|
if (nbits % 8).zero?
|
175
173
|
return Int.define_class(nbits, *args)
|
@@ -177,8 +175,8 @@ module BinData
|
|
177
175
|
end
|
178
176
|
end
|
179
177
|
|
180
|
-
|
178
|
+
super
|
181
179
|
end
|
182
|
-
alias_method :const_missing, :const_missing_with_int
|
183
180
|
end
|
181
|
+
BinData.extend IntFactory
|
184
182
|
end
|
data/lib/bindata/name.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module BinData
|
2
|
+
# == Parameters
|
3
|
+
#
|
4
|
+
# Parameters may be provided at initialisation to control the behaviour of
|
5
|
+
# an object. These parameters are:
|
6
|
+
#
|
7
|
+
# <tt>:name</tt>:: The name that this object can be referred to may be
|
8
|
+
# set explicitly. This is only useful when dynamically
|
9
|
+
# generating types.
|
10
|
+
# <code><pre>
|
11
|
+
# BinData::Struct.new(:name => :my_struct, :fields => ...)
|
12
|
+
# array = BinData::Array.new(:type => :my_struct)
|
13
|
+
# </pre></code>
|
14
|
+
module RegisterNamePlugin
|
15
|
+
|
16
|
+
def self.included(base) #:nodoc:
|
17
|
+
# The registered name may be provided explicitly.
|
18
|
+
base.optional_parameter :name
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize_shared_instance
|
22
|
+
if has_parameter?(:name)
|
23
|
+
RegisteredClasses.register(get_parameter(:name), self)
|
24
|
+
end
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/bindata/offset.rb
CHANGED
@@ -15,77 +15,66 @@ module BinData
|
|
15
15
|
# position before reading. This is like
|
16
16
|
# <tt>:check_offset</tt>, except that it will
|
17
17
|
# adjust the IO offset instead of raising an error.
|
18
|
-
module
|
18
|
+
module CheckOrAdjustOffsetPlugin
|
19
19
|
|
20
20
|
def self.included(base) #:nodoc:
|
21
21
|
base.optional_parameters :check_offset, :adjust_offset
|
22
22
|
base.mutually_exclusive_parameters :check_offset, :adjust_offset
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def do_read_with_check_offset(io) #:nodoc:
|
30
|
-
check_offset(io)
|
31
|
-
do_read_without_check_offset(io)
|
25
|
+
def initialize_shared_instance
|
26
|
+
extend CheckOffsetMixin if has_parameter?(:check_offset)
|
27
|
+
extend AdjustOffsetMixin if has_parameter?(:adjust_offset)
|
28
|
+
super
|
32
29
|
end
|
33
30
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
module CheckOffsetMixin
|
32
|
+
def do_read(io) #:nodoc:
|
33
|
+
check_offset(io)
|
34
|
+
super(io)
|
35
|
+
end
|
38
36
|
|
39
|
-
|
40
|
-
|
37
|
+
#---------------
|
38
|
+
private
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
53
|
-
if has_parameter?(:adjust_offset)
|
54
|
-
class << self
|
55
|
-
alias_method :do_read_without_adjust_offset, :do_read
|
56
|
-
alias_method :do_read, :do_read_with_adjust_offset
|
40
|
+
def check_offset(io)
|
41
|
+
actual_offset = io.offset
|
42
|
+
expected = eval_parameter(:check_offset, :offset => actual_offset)
|
43
|
+
|
44
|
+
if not expected
|
45
|
+
raise ValidityError, "offset not as expected for #{debug_name}"
|
46
|
+
elsif actual_offset != expected and expected != true
|
47
|
+
raise ValidityError,
|
48
|
+
"offset is '#{actual_offset}' but " +
|
49
|
+
"expected '#{expected}' for #{debug_name}"
|
57
50
|
end
|
58
51
|
end
|
59
52
|
end
|
60
53
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
if not expected
|
66
|
-
raise ValidityError, "offset not as expected for #{debug_name}"
|
67
|
-
elsif actual_offset != expected and expected != true
|
68
|
-
raise ValidityError,
|
69
|
-
"offset is '#{actual_offset}' but " +
|
70
|
-
"expected '#{expected}' for #{debug_name}"
|
54
|
+
module AdjustOffsetMixin
|
55
|
+
def do_read(io) #:nodoc:
|
56
|
+
adjust_offset(io)
|
57
|
+
super(io)
|
71
58
|
end
|
72
|
-
end
|
73
59
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
60
|
+
#---------------
|
61
|
+
private
|
62
|
+
|
63
|
+
def adjust_offset(io)
|
64
|
+
actual_offset = io.offset
|
65
|
+
expected = eval_parameter(:adjust_offset)
|
66
|
+
if actual_offset != expected
|
67
|
+
begin
|
68
|
+
seek = expected - actual_offset
|
69
|
+
io.seekbytes(seek)
|
70
|
+
warn "adjusting stream position by #{seek} bytes" if $VERBOSE
|
71
|
+
rescue
|
72
|
+
raise ValidityError,
|
73
|
+
"offset is '#{actual_offset}' but couldn't seek to " +
|
74
|
+
"expected '#{expected}' for #{debug_name}"
|
75
|
+
end
|
86
76
|
end
|
87
77
|
end
|
88
78
|
end
|
89
79
|
end
|
90
80
|
end
|
91
|
-
|
data/lib/bindata/params.rb
CHANGED
@@ -1,53 +1,45 @@
|
|
1
1
|
require 'bindata/lazy'
|
2
2
|
|
3
3
|
module BinData
|
4
|
-
module
|
5
|
-
|
6
|
-
|
4
|
+
module AcceptedParametersPlugin
|
5
|
+
# Mandatory parameters must be present when instantiating a data object.
|
6
|
+
def mandatory_parameters(*args)
|
7
|
+
accepted_parameters.mandatory(*args)
|
7
8
|
end
|
8
9
|
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
accepted_parameters.mandatory(*args)
|
14
|
-
end
|
15
|
-
|
16
|
-
# Optional parameters may be present when instantiating a data object.
|
17
|
-
def optional_parameters(*args)
|
18
|
-
accepted_parameters.optional(*args)
|
19
|
-
end
|
10
|
+
# Optional parameters may be present when instantiating a data object.
|
11
|
+
def optional_parameters(*args)
|
12
|
+
accepted_parameters.optional(*args)
|
13
|
+
end
|
20
14
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
15
|
+
# Default parameters can be overridden when instantiating a data object.
|
16
|
+
def default_parameters(*args)
|
17
|
+
accepted_parameters.default(*args)
|
18
|
+
end
|
25
19
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
20
|
+
# Mutually exclusive parameters may not all be present when
|
21
|
+
# instantiating a data object.
|
22
|
+
def mutually_exclusive_parameters(*args)
|
23
|
+
accepted_parameters.mutually_exclusive(*args)
|
24
|
+
end
|
31
25
|
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
alias_method :mandatory_parameter, :mandatory_parameters
|
27
|
+
alias_method :optional_parameter, :optional_parameters
|
28
|
+
alias_method :default_parameter, :default_parameters
|
35
29
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
42
|
-
@accepted_parameters
|
30
|
+
def accepted_parameters #:nodoc:
|
31
|
+
unless defined? @accepted_parameters
|
32
|
+
ancestor_params = superclass.respond_to?(:accepted_parameters) ?
|
33
|
+
superclass.accepted_parameters : nil
|
34
|
+
@accepted_parameters = AcceptedParameters.new(ancestor_params)
|
43
35
|
end
|
36
|
+
@accepted_parameters
|
44
37
|
end
|
45
38
|
|
46
39
|
# BinData objects accept parameters when initializing. AcceptedParameters
|
47
40
|
# allow a BinData class to declaratively identify accepted parameters as
|
48
41
|
# mandatory, optional, default or mutually exclusive.
|
49
42
|
class AcceptedParameters
|
50
|
-
|
51
43
|
def initialize(ancestor_parameters = nil)
|
52
44
|
if ancestor_parameters
|
53
45
|
@mandatory = ancestor_parameters.mandatory.dup
|
@@ -89,10 +81,13 @@ module BinData
|
|
89
81
|
end
|
90
82
|
|
91
83
|
def mutually_exclusive(*args)
|
92
|
-
arg1
|
93
|
-
|
94
|
-
|
95
|
-
|
84
|
+
arg1 = args.shift
|
85
|
+
while not args.empty?
|
86
|
+
args.each do |arg2|
|
87
|
+
@mutually_exclusive.push([arg1.to_sym, arg2.to_sym])
|
88
|
+
@mutually_exclusive.uniq!
|
89
|
+
end
|
90
|
+
arg1 = args.shift
|
96
91
|
end
|
97
92
|
@mutually_exclusive
|
98
93
|
end
|
data/lib/bindata/struct.rb
CHANGED
@@ -113,12 +113,7 @@ module BinData
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def hidden_field_names(hidden)
|
116
|
-
(hidden || []).collect
|
117
|
-
unless Symbol === h
|
118
|
-
warn "Hidden field '#{h}' should be provided as a symbol. Using strings is deprecated"
|
119
|
-
end
|
120
|
-
h.to_sym
|
121
|
-
end
|
116
|
+
(hidden || []).collect { |h| h.to_sym }
|
122
117
|
end
|
123
118
|
|
124
119
|
def ensure_field_names_are_valid(field_names)
|
@@ -143,6 +138,7 @@ module BinData
|
|
143
138
|
|
144
139
|
def initialize_shared_instance
|
145
140
|
@field_names = get_parameter(:fields).field_names.freeze
|
141
|
+
super
|
146
142
|
end
|
147
143
|
|
148
144
|
def initialize_instance
|
data/lib/bindata/trace.rb
CHANGED
@@ -25,14 +25,12 @@ module BinData
|
|
25
25
|
# This is useful for debugging a BinData declaration.
|
26
26
|
def trace_reading(io = STDERR, &block)
|
27
27
|
@tracer = Tracer.new(io)
|
28
|
-
BasePrimitive.turn_on_tracing
|
29
|
-
Choice.turn_on_tracing
|
28
|
+
[BasePrimitive, Choice].each { |traced| traced.turn_on_tracing }
|
30
29
|
if block_given?
|
31
30
|
begin
|
32
31
|
block.call
|
33
32
|
ensure
|
34
|
-
BasePrimitive.turn_off_tracing
|
35
|
-
Choice.turn_off_tracing
|
33
|
+
[BasePrimitive, Choice].each { |traced| traced.turn_off_tracing }
|
36
34
|
@tracer = nil
|
37
35
|
end
|
38
36
|
end
|
@@ -47,18 +45,19 @@ module BinData
|
|
47
45
|
class BasePrimitive < BinData::Base
|
48
46
|
class << self
|
49
47
|
def turn_on_tracing
|
50
|
-
alias_method :
|
48
|
+
alias_method :do_read_without_hook, :do_read
|
49
|
+
alias_method :do_read, :do_read_with_hook
|
51
50
|
end
|
52
51
|
|
53
52
|
def turn_off_tracing
|
54
|
-
alias_method :
|
53
|
+
alias_method :do_read, :do_read_without_hook
|
55
54
|
end
|
56
55
|
end
|
57
56
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
57
|
+
def do_read_with_hook(io)
|
58
|
+
do_read_without_hook(io)
|
59
|
+
trace_value
|
60
|
+
end
|
62
61
|
|
63
62
|
def trace_value
|
64
63
|
BinData::trace_message do |tracer|
|
@@ -71,18 +70,19 @@ module BinData
|
|
71
70
|
class Choice < BinData::Base
|
72
71
|
class << self
|
73
72
|
def turn_on_tracing
|
74
|
-
alias_method :
|
73
|
+
alias_method :do_read_without_hook, :do_read
|
74
|
+
alias_method :do_read, :do_read_with_hook
|
75
75
|
end
|
76
76
|
|
77
77
|
def turn_off_tracing
|
78
|
-
alias_method :
|
78
|
+
alias_method :do_read, :do_read_without_hook
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
82
|
+
def do_read_with_hook(io)
|
83
|
+
trace_selection
|
84
|
+
do_read_without_hook(io)
|
85
|
+
end
|
86
86
|
|
87
87
|
def trace_selection
|
88
88
|
BinData::trace_message do |tracer|
|
data/lib/bindata/version.rb
CHANGED
data/lib/bindata/virtual.rb
CHANGED
@@ -15,7 +15,7 @@ module BinData
|
|
15
15
|
#
|
16
16
|
# obj = A.read("abcdeabcde")
|
17
17
|
# obj.a #=> "abcde"
|
18
|
-
# obj.
|
18
|
+
# obj.c.offset #=> 10
|
19
19
|
#
|
20
20
|
class Virtual < BinData::BasePrimitive
|
21
21
|
|
@@ -23,8 +23,8 @@ module BinData
|
|
23
23
|
|
24
24
|
class << self
|
25
25
|
def sanitize_parameters!(params) #:nodoc:
|
26
|
-
if params.has_parameter?(:
|
27
|
-
fail ":
|
26
|
+
if params.has_parameter?(:asserted_value)
|
27
|
+
fail ":asserted_value can not be used on virtual field"
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require File.expand_path(File.join(File.dirname(__FILE__), "
|
4
|
-
require 'bindata'
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "common"))
|
5
4
|
|
6
5
|
describe BinData::ResumeByteAlignment do
|
7
6
|
class ResumeAlignmentRecord < BinData::Record
|
@@ -10,29 +9,29 @@ describe BinData::ResumeByteAlignment do
|
|
10
9
|
bit4 :b
|
11
10
|
end
|
12
11
|
|
13
|
-
|
12
|
+
let(:obj) { ResumeAlignmentRecord.new }
|
14
13
|
|
15
14
|
it "resets read alignment" do
|
16
|
-
|
15
|
+
obj.read "\x12\x34"
|
17
16
|
|
18
|
-
|
19
|
-
|
17
|
+
obj.a.must_equal 1
|
18
|
+
obj.b.must_equal 3
|
20
19
|
end
|
21
20
|
|
22
21
|
it "resets write alignment" do
|
23
|
-
|
22
|
+
obj.assign(:a => 2, :b => 7)
|
24
23
|
|
25
|
-
|
24
|
+
obj.to_binary_s.must_equal "\x20\x70"
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
29
28
|
describe BinData::BitAligned do
|
30
29
|
it "does not apply to BinData::Primitives" do
|
31
|
-
|
30
|
+
lambda {
|
32
31
|
class BitAlignedPrimitive < BinData::Primitive
|
33
32
|
bit_aligned
|
34
33
|
end
|
35
|
-
}.
|
34
|
+
}.must_raise RuntimeError
|
36
35
|
end
|
37
36
|
|
38
37
|
class BitString < BinData::String
|
@@ -45,17 +44,19 @@ describe BinData::BitAligned do
|
|
45
44
|
bit4 :afterward
|
46
45
|
end
|
47
46
|
|
48
|
-
|
47
|
+
let(:obj) { BitAlignedRecord.new }
|
49
48
|
|
50
|
-
|
49
|
+
it "#num_bytes as expected" do
|
50
|
+
obj.num_bytes.must_equal 3
|
51
|
+
end
|
51
52
|
|
52
53
|
it "reads as expected" do
|
53
|
-
|
54
|
-
|
54
|
+
obj.read("\x56\x36\x42")
|
55
|
+
obj.snapshot.must_equal({"preamble" => 5, "str" => "cd", "afterward" => 2})
|
55
56
|
end
|
56
57
|
|
57
58
|
it "writes as expected" do
|
58
|
-
|
59
|
-
|
59
|
+
obj.assign(:preamble => 5, :str => "ab", :afterward => 1)
|
60
|
+
obj.to_binary_s.must_equal "\x56\x16\x21"
|
60
61
|
end
|
61
62
|
end
|