bindata 0.9.1 → 0.9.2
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 +8 -0
- data/TODO +0 -6
- data/lib/bindata.rb +1 -1
- data/lib/bindata/array.rb +52 -25
- data/lib/bindata/base.rb +45 -54
- data/lib/bindata/bits.rb +126 -126
- data/lib/bindata/choice.rb +6 -41
- data/lib/bindata/float.rb +4 -4
- data/lib/bindata/int.rb +14 -14
- data/lib/bindata/multi_value.rb +34 -41
- data/lib/bindata/rest.rb +1 -1
- data/lib/bindata/sanitize.rb +88 -3
- data/lib/bindata/single.rb +7 -17
- data/lib/bindata/single_value.rb +4 -10
- data/lib/bindata/string.rb +3 -3
- data/lib/bindata/stringz.rb +1 -1
- data/lib/bindata/struct.rb +118 -139
- data/spec/array_spec.rb +16 -20
- data/spec/base_spec.rb +21 -18
- data/spec/bits_spec.rb +2 -2
- data/spec/choice_spec.rb +0 -24
- data/spec/multi_value_spec.rb +46 -5
- data/spec/sanitize_spec.rb +50 -36
- data/spec/single_spec.rb +0 -8
- data/spec/struct_spec.rb +29 -43
- metadata +2 -2
data/lib/bindata/choice.rb
CHANGED
@@ -60,7 +60,7 @@ module BinData
|
|
60
60
|
|
61
61
|
# Returns a sanitized +params+ that is of the form expected
|
62
62
|
# by #initialize.
|
63
|
-
def sanitize_parameters(
|
63
|
+
def sanitize_parameters(sanitizer, params)
|
64
64
|
params = params.dup
|
65
65
|
|
66
66
|
if params.has_key?(:choices)
|
@@ -80,12 +80,7 @@ module BinData
|
|
80
80
|
|
81
81
|
# collect sanitized choice values
|
82
82
|
type, param = choices[key]
|
83
|
-
|
84
|
-
if klass.nil?
|
85
|
-
raise TypeError, "unknown type '#{type}' for #{self}"
|
86
|
-
end
|
87
|
-
val = [klass, SanitizedParameters.new(klass, param, endian)]
|
88
|
-
new_choices[key] = val
|
83
|
+
new_choices[key] = sanitizer.sanitize(type, param)
|
89
84
|
end
|
90
85
|
params[:choices] = new_choices
|
91
86
|
when ::Array
|
@@ -94,11 +89,7 @@ module BinData
|
|
94
89
|
# allow sparse arrays
|
95
90
|
nil
|
96
91
|
else
|
97
|
-
|
98
|
-
if klass.nil?
|
99
|
-
raise TypeError, "unknown type '#{type}' for #{self}"
|
100
|
-
end
|
101
|
-
[klass, SanitizedParameters.new(klass, param, endian)]
|
92
|
+
sanitizer.sanitize(type, param)
|
102
93
|
end
|
103
94
|
end
|
104
95
|
params[:choices] = choices
|
@@ -107,28 +98,7 @@ module BinData
|
|
107
98
|
end
|
108
99
|
end
|
109
100
|
|
110
|
-
super(
|
111
|
-
end
|
112
|
-
|
113
|
-
# Returns all the possible field names a :choice may have.
|
114
|
-
def all_possible_field_names(sanitized_params)
|
115
|
-
unless SanitizedParameters === sanitized_params
|
116
|
-
raise ArgumentError, "parameters aren't sanitized"
|
117
|
-
end
|
118
|
-
|
119
|
-
choices = sanitized_params[:choices]
|
120
|
-
|
121
|
-
names = []
|
122
|
-
if ::Array === choices
|
123
|
-
choices.each do |cklass, cparams|
|
124
|
-
names.concat(cklass.all_possible_field_names(cparams))
|
125
|
-
end
|
126
|
-
elsif ::Hash === choices
|
127
|
-
choices.values.each do |cklass, cparams|
|
128
|
-
names.concat(cklass.all_possible_field_names(cparams))
|
129
|
-
end
|
130
|
-
end
|
131
|
-
names
|
101
|
+
super(sanitizer, params)
|
132
102
|
end
|
133
103
|
end
|
134
104
|
|
@@ -140,15 +110,10 @@ module BinData
|
|
140
110
|
@last_key = nil
|
141
111
|
end
|
142
112
|
|
143
|
-
def_delegators :the_choice, :clear, :clear?, :single_value
|
144
|
-
def_delegators :the_choice, :
|
113
|
+
def_delegators :the_choice, :clear, :clear?, :single_value?
|
114
|
+
def_delegators :the_choice, :done_read, :_snapshot
|
145
115
|
def_delegators :the_choice, :_do_read, :_do_write, :_do_num_bytes
|
146
116
|
|
147
|
-
# Returns the data object that stores values for +name+.
|
148
|
-
def find_obj_for_name(name)
|
149
|
-
field_names.include?(name) ? the_choice.find_obj_for_name(name) : nil
|
150
|
-
end
|
151
|
-
|
152
117
|
# Override to include selected data object.
|
153
118
|
def respond_to?(symbol, include_private = false)
|
154
119
|
super || the_choice.respond_to?(symbol, include_private)
|
data/lib/bindata/float.rb
CHANGED
@@ -63,25 +63,25 @@ module BinData
|
|
63
63
|
|
64
64
|
|
65
65
|
# Single precision floating point number in little endian format
|
66
|
-
class FloatLe < Single
|
66
|
+
class FloatLe < BinData::Single
|
67
67
|
register(self.name, self)
|
68
68
|
Float.create_float_methods(self, true, :little)
|
69
69
|
end
|
70
70
|
|
71
71
|
# Single precision floating point number in big endian format
|
72
|
-
class FloatBe < Single
|
72
|
+
class FloatBe < BinData::Single
|
73
73
|
register(self.name, self)
|
74
74
|
Float.create_float_methods(self, true, :big)
|
75
75
|
end
|
76
76
|
|
77
77
|
# Double precision floating point number in little endian format
|
78
|
-
class DoubleLe < Single
|
78
|
+
class DoubleLe < BinData::Single
|
79
79
|
register(self.name, self)
|
80
80
|
Float.create_float_methods(self, false, :little)
|
81
81
|
end
|
82
82
|
|
83
83
|
# Double precision floating point number in big endian format
|
84
|
-
class DoubleBe < Single
|
84
|
+
class DoubleBe < BinData::Single
|
85
85
|
register(self.name, self)
|
86
86
|
Float.create_float_methods(self, false, :big)
|
87
87
|
end
|
data/lib/bindata/int.rb
CHANGED
@@ -100,85 +100,85 @@ module BinData
|
|
100
100
|
|
101
101
|
|
102
102
|
# Unsigned 1 byte integer.
|
103
|
-
class Uint8 < Single
|
103
|
+
class Uint8 < BinData::Single
|
104
104
|
register(self.name, self)
|
105
105
|
Integer.create_uint_methods(self, 8, :little)
|
106
106
|
end
|
107
107
|
|
108
108
|
# Unsigned 2 byte little endian integer.
|
109
|
-
class Uint16le < Single
|
109
|
+
class Uint16le < BinData::Single
|
110
110
|
register(self.name, self)
|
111
111
|
Integer.create_uint_methods(self, 16, :little)
|
112
112
|
end
|
113
113
|
|
114
114
|
# Unsigned 2 byte big endian integer.
|
115
|
-
class Uint16be < Single
|
115
|
+
class Uint16be < BinData::Single
|
116
116
|
register(self.name, self)
|
117
117
|
Integer.create_uint_methods(self, 16, :big)
|
118
118
|
end
|
119
119
|
|
120
120
|
# Unsigned 4 byte little endian integer.
|
121
|
-
class Uint32le < Single
|
121
|
+
class Uint32le < BinData::Single
|
122
122
|
register(self.name, self)
|
123
123
|
Integer.create_uint_methods(self, 32, :little)
|
124
124
|
end
|
125
125
|
|
126
126
|
# Unsigned 4 byte big endian integer.
|
127
|
-
class Uint32be < Single
|
127
|
+
class Uint32be < BinData::Single
|
128
128
|
register(self.name, self)
|
129
129
|
Integer.create_uint_methods(self, 32, :big)
|
130
130
|
end
|
131
131
|
|
132
132
|
# Unsigned 8 byte little endian integer.
|
133
|
-
class Uint64le < Single
|
133
|
+
class Uint64le < BinData::Single
|
134
134
|
register(self.name, self)
|
135
135
|
Integer.create_uint_methods(self, 64, :little)
|
136
136
|
end
|
137
137
|
|
138
138
|
# Unsigned 8 byte big endian integer.
|
139
|
-
class Uint64be < Single
|
139
|
+
class Uint64be < BinData::Single
|
140
140
|
register(self.name, self)
|
141
141
|
Integer.create_uint_methods(self, 64, :big)
|
142
142
|
end
|
143
143
|
|
144
144
|
# Signed 1 byte integer.
|
145
|
-
class Int8 < Single
|
145
|
+
class Int8 < BinData::Single
|
146
146
|
register(self.name, self)
|
147
147
|
Integer.create_int_methods(self, 8, :little)
|
148
148
|
end
|
149
149
|
|
150
150
|
# Signed 2 byte little endian integer.
|
151
|
-
class Int16le < Single
|
151
|
+
class Int16le < BinData::Single
|
152
152
|
register(self.name, self)
|
153
153
|
Integer.create_int_methods(self, 16, :little)
|
154
154
|
end
|
155
155
|
|
156
156
|
# Signed 2 byte big endian integer.
|
157
|
-
class Int16be < Single
|
157
|
+
class Int16be < BinData::Single
|
158
158
|
register(self.name, self)
|
159
159
|
Integer.create_int_methods(self, 16, :big)
|
160
160
|
end
|
161
161
|
|
162
162
|
# Signed 4 byte little endian integer.
|
163
|
-
class Int32le < Single
|
163
|
+
class Int32le < BinData::Single
|
164
164
|
register(self.name, self)
|
165
165
|
Integer.create_int_methods(self, 32, :little)
|
166
166
|
end
|
167
167
|
|
168
168
|
# Signed 4 byte big endian integer.
|
169
|
-
class Int32be < Single
|
169
|
+
class Int32be < BinData::Single
|
170
170
|
register(self.name, self)
|
171
171
|
Integer.create_int_methods(self, 32, :big)
|
172
172
|
end
|
173
173
|
|
174
174
|
# Signed 8 byte little endian integer.
|
175
|
-
class Int64le < Single
|
175
|
+
class Int64le < BinData::Single
|
176
176
|
register(self.name, self)
|
177
177
|
Integer.create_int_methods(self, 64, :little)
|
178
178
|
end
|
179
179
|
|
180
180
|
# Signed 8 byte big endian integer.
|
181
|
-
class Int64be < Single
|
181
|
+
class Int64be < BinData::Single
|
182
182
|
register(self.name, self)
|
183
183
|
Integer.create_int_methods(self, 64, :big)
|
184
184
|
end
|
data/lib/bindata/multi_value.rb
CHANGED
@@ -16,11 +16,11 @@ module BinData
|
|
16
16
|
#
|
17
17
|
# int32le :a
|
18
18
|
# int16le :b
|
19
|
-
# tuple
|
19
|
+
# tuple :s
|
20
20
|
# end
|
21
21
|
#
|
22
22
|
# obj = SomeDataType.new
|
23
|
-
# obj.field_names =># ["b", "
|
23
|
+
# obj.field_names =># ["b", "s"]
|
24
24
|
#
|
25
25
|
#
|
26
26
|
# == Parameters
|
@@ -31,10 +31,9 @@ module BinData
|
|
31
31
|
# <tt>:fields</tt>:: An array specifying the fields for this struct.
|
32
32
|
# Each element of the array is of the form [type, name,
|
33
33
|
# params]. Type is a symbol representing a registered
|
34
|
-
# type. Name is the name of this field.
|
35
|
-
#
|
36
|
-
#
|
37
|
-
# instantiating it.
|
34
|
+
# type. Name is the name of this field. Params is an
|
35
|
+
# optional hash of parameters to pass to this field
|
36
|
+
# when instantiating it.
|
38
37
|
# <tt>:hide</tt>:: A list of the names of fields that are to be hidden
|
39
38
|
# from the outside world. Hidden fields don't appear
|
40
39
|
# in #snapshot or #field_names but are still accessible
|
@@ -42,7 +41,7 @@ module BinData
|
|
42
41
|
# <tt>:endian</tt>:: Either :little or :big. This specifies the default
|
43
42
|
# endian of any numerics in this struct, or in any
|
44
43
|
# nested data objects.
|
45
|
-
class MultiValue < Struct
|
44
|
+
class MultiValue < BinData::Struct
|
46
45
|
|
47
46
|
class << self
|
48
47
|
# Register the names of all subclasses of this class.
|
@@ -68,16 +67,14 @@ module BinData
|
|
68
67
|
def hide(*args)
|
69
68
|
# note that fields are stored in an instance variable not a class var
|
70
69
|
@hide ||= []
|
71
|
-
args.
|
72
|
-
next if name.nil?
|
73
|
-
@hide << name.to_s
|
74
|
-
end
|
70
|
+
@hide.concat(args.collect { |name| name.to_s })
|
75
71
|
@hide
|
76
72
|
end
|
77
73
|
|
78
|
-
# Returns all stored fields.
|
74
|
+
# Returns all stored fields.
|
75
|
+
# Should only be called by #sanitize_parameters
|
79
76
|
def fields
|
80
|
-
@fields
|
77
|
+
@fields ||= []
|
81
78
|
end
|
82
79
|
|
83
80
|
# Used to define fields for this structure.
|
@@ -85,37 +82,34 @@ module BinData
|
|
85
82
|
name, params = args
|
86
83
|
|
87
84
|
type = symbol
|
88
|
-
name =
|
85
|
+
name = name.to_s
|
89
86
|
params ||= {}
|
90
87
|
|
91
88
|
# note that fields are stored in an instance variable not a class var
|
92
89
|
@fields ||= []
|
93
90
|
|
94
91
|
# check that type is known
|
95
|
-
|
92
|
+
unless Sanitizer.type_exists?(type, endian)
|
96
93
|
raise TypeError, "unknown type '#{type}' for #{self}", caller
|
97
94
|
end
|
98
95
|
|
99
|
-
# check
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
if n == name
|
104
|
-
raise SyntaxError, "duplicate field '#{name}' in #{self}", caller
|
105
|
-
end
|
96
|
+
# check for duplicate names
|
97
|
+
@fields.each do |t, n, p|
|
98
|
+
if n == name
|
99
|
+
raise SyntaxError, "duplicate field '#{name}' in #{self}", caller
|
106
100
|
end
|
101
|
+
end
|
107
102
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
103
|
+
# check that name doesn't shadow an existing method
|
104
|
+
if self.instance_methods.include?(name)
|
105
|
+
raise NameError.new("", name),
|
106
|
+
"field '#{name}' shadows an existing method", caller
|
107
|
+
end
|
113
108
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
end
|
109
|
+
# check that name isn't reserved
|
110
|
+
if self::RESERVED.include?(name)
|
111
|
+
raise NameError.new("", name),
|
112
|
+
"field '#{name}' is a reserved name", caller
|
119
113
|
end
|
120
114
|
|
121
115
|
# remember this field. These fields will be recalled upon creating
|
@@ -125,19 +119,18 @@ module BinData
|
|
125
119
|
|
126
120
|
# Returns a sanitized +params+ that is of the form expected
|
127
121
|
# by #initialize.
|
128
|
-
def sanitize_parameters(
|
122
|
+
def sanitize_parameters(sanitizer, params)
|
129
123
|
params = params.dup
|
130
124
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
params[:endian] = endian
|
135
|
-
end
|
125
|
+
endian = params[:endian] || self.endian
|
126
|
+
fields = params[:fields] || self.fields
|
127
|
+
hide = params[:hide] || self.hide
|
136
128
|
|
137
|
-
params[:
|
138
|
-
params[:
|
129
|
+
params[:endian] = endian unless endian.nil?
|
130
|
+
params[:fields] = fields
|
131
|
+
params[:hide] = hide
|
139
132
|
|
140
|
-
super(
|
133
|
+
super(sanitizer, params)
|
141
134
|
end
|
142
135
|
end
|
143
136
|
end
|
data/lib/bindata/rest.rb
CHANGED
data/lib/bindata/sanitize.rb
CHANGED
@@ -1,6 +1,91 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
|
3
3
|
module BinData
|
4
|
+
class Sanitizer
|
5
|
+
class << self
|
6
|
+
# Sanitize +params+ for +obj+.
|
7
|
+
# Returns sanitized parameters.
|
8
|
+
def sanitize(obj, params)
|
9
|
+
sanitizer = self.new
|
10
|
+
klass, new_params = sanitizer.sanitize(obj.class, params)
|
11
|
+
new_params
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns true if +type+ is registered.
|
15
|
+
def type_exists?(type, endian = nil)
|
16
|
+
lookup(type, endian) != nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns the class matching a previously registered +name+.
|
20
|
+
def lookup(name, endian)
|
21
|
+
name = name.to_s
|
22
|
+
klass = Registry.instance.lookup(name)
|
23
|
+
if klass.nil? and endian != nil
|
24
|
+
# lookup failed so attempt endian lookup
|
25
|
+
if /^u?int\d{1,3}$/ =~ name
|
26
|
+
new_name = name + ((endian == :little) ? "le" : "be")
|
27
|
+
klass = Registry.instance.lookup(new_name)
|
28
|
+
elsif ["float", "double"].include?(name)
|
29
|
+
new_name = name + ((endian == :little) ? "_le" : "_be")
|
30
|
+
klass = Registry.instance.lookup(new_name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
klass
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Create a new Sanitizer.
|
38
|
+
def initialize
|
39
|
+
@seen = []
|
40
|
+
@endian = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
# Executes the given block with +endian+ set as the current endian.
|
44
|
+
def with_endian(endian, &block)
|
45
|
+
if endian != nil
|
46
|
+
saved_endian = @endian
|
47
|
+
@endian = endian
|
48
|
+
yield
|
49
|
+
@endian = saved_endian
|
50
|
+
else
|
51
|
+
yield
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Sanitizes +params+ for +type+.
|
56
|
+
# Returns [klass, sanitized_params]
|
57
|
+
def sanitize(type, params)
|
58
|
+
if Class === type
|
59
|
+
klass = type
|
60
|
+
else
|
61
|
+
klass = self.class.lookup(type, @endian)
|
62
|
+
raise TypeError, "unknown type '#{type}'" if klass.nil?
|
63
|
+
end
|
64
|
+
|
65
|
+
params ||= {}
|
66
|
+
if @seen.include?(klass)
|
67
|
+
# This klass is defined recursively. Remember the current endian
|
68
|
+
# and delay sanitizing the parameters until later.
|
69
|
+
if @endian != nil and klass.accepted_parameters.include?(:endian) and
|
70
|
+
not params.has_key?(:endian)
|
71
|
+
params = params.dup
|
72
|
+
params[:endian] = @endian
|
73
|
+
end
|
74
|
+
else
|
75
|
+
# subclasses of MultiValue may be defined recursively
|
76
|
+
# TODO: define a class field instead
|
77
|
+
possibly_recursive = (BinData.const_defined?(:MultiValue) and
|
78
|
+
klass.ancestors.include?(BinData.const_get(:MultiValue)))
|
79
|
+
@seen.push klass if possibly_recursive
|
80
|
+
|
81
|
+
new_params = klass.sanitize_parameters(self, params)
|
82
|
+
params = SanitizedParameters.new(klass, new_params)
|
83
|
+
end
|
84
|
+
|
85
|
+
[klass, params]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
4
89
|
# A BinData object accepts arbitrary parameters. This class ensures that
|
5
90
|
# the parameters have been sanitized, and categorizes them according to
|
6
91
|
# whether they are BinData::Base.accepted_parameters or are extra.
|
@@ -8,9 +93,8 @@ module BinData
|
|
8
93
|
extend Forwardable
|
9
94
|
|
10
95
|
# Sanitize the given parameters.
|
11
|
-
def initialize(klass, params
|
12
|
-
|
13
|
-
@hash = klass.sanitize_parameters(params, *args)
|
96
|
+
def initialize(klass, params)
|
97
|
+
@hash = params
|
14
98
|
@accepted_parameters = {}
|
15
99
|
@extra_parameters = {}
|
16
100
|
|
@@ -34,3 +118,4 @@ module BinData
|
|
34
118
|
def_delegators :@hash, :[], :has_key?, :include?, :keys
|
35
119
|
end
|
36
120
|
end
|
121
|
+
|