bindata 0.9.2 → 0.9.3

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.

@@ -47,11 +47,11 @@ module BinData
47
47
  # the value just read in.
48
48
  class Single < BinData::Base
49
49
  # These are the parameters used by this class.
50
- optional_parameters :initial_value, :value, :check_value
51
- mutually_exclusive_parameters :initial_value, :value
50
+ bindata_optional_parameters :initial_value, :value, :check_value
51
+ bindata_mutually_exclusive_parameters :initial_value, :value
52
52
 
53
- def initialize(params = {}, env = nil)
54
- super(params, env)
53
+ def initialize(params = {}, parent = nil)
54
+ super(params, parent)
55
55
  clear
56
56
  end
57
57
 
@@ -67,6 +67,11 @@ module BinData
67
67
  register(subclass.name, subclass)
68
68
  end
69
69
 
70
+ # Can this data object self reference itself?
71
+ def recursive?
72
+ true
73
+ end
74
+
70
75
  # Returns or sets the endianess of numerics used in this stucture.
71
76
  # Endianess is applied to the fields of this structure.
72
77
  # Valid values are :little and :big.
@@ -123,28 +128,25 @@ module BinData
123
128
  @fields.push([type, name, params])
124
129
  end
125
130
 
126
- # Returns a sanitized +params+ that is of the form expected
127
- # by #initialize.
128
- def sanitize_parameters(sanitizer, params)
129
- params = params.dup
130
-
131
- hash = {}
132
- hash[:fields] = self.fields
133
- hash[:endian] = self.endian unless self.endian.nil?
131
+ # Ensures that +params+ is of the form expected by #initialize.
132
+ def sanitize_parameters!(sanitizer, params)
133
+ struct_params = {}
134
+ struct_params[:fields] = self.fields
135
+ struct_params[:endian] = self.endian unless self.endian.nil?
134
136
 
135
- params[:struct_params] = hash
137
+ params[:struct_params] = struct_params
136
138
 
137
139
  super(sanitizer, params)
138
140
  end
139
141
  end
140
142
 
141
143
  # These are the parameters used by this class.
142
- mandatory_parameter :struct_params
144
+ bindata_mandatory_parameter :struct_params
143
145
 
144
- def initialize(params = {}, env = nil)
145
- super(params, env)
146
+ def initialize(params = {}, parent = nil)
147
+ super(params, parent)
146
148
 
147
- @struct = BinData::Struct.new(param(:struct_params), create_env)
149
+ @struct = BinData::Struct.new(no_eval_param(:struct_params), self)
148
150
  end
149
151
 
150
152
  # Forward method calls to the internal struct.
@@ -51,18 +51,15 @@ module BinData
51
51
  register(self.name, self)
52
52
 
53
53
  # These are the parameters used by this class.
54
- optional_parameters :read_length, :length, :trim_value
55
- default_parameters :pad_char => "\0"
56
- mutually_exclusive_parameters :read_length, :length
57
- mutually_exclusive_parameters :length, :value
54
+ bindata_optional_parameters :read_length, :length, :trim_value
55
+ bindata_default_parameters :pad_char => "\0"
56
+ bindata_mutually_exclusive_parameters :read_length, :length
57
+ bindata_mutually_exclusive_parameters :length, :value
58
58
 
59
59
  class << self
60
60
 
61
- # Returns a sanitized +params+ that is of the form expected
62
- # by #initialize.
63
- def sanitize_parameters(sanitizer, params, *args)
64
- params = params.dup
65
-
61
+ # Ensures that +params+ is of the form expected by #initialize.
62
+ def sanitize_parameters!(sanitizer, params)
66
63
  # warn about deprecated param - remove before releasing 1.0
67
64
  if params[:initial_length]
68
65
  warn ":initial_length is deprecated. Replacing with :read_length"
@@ -79,7 +76,7 @@ module BinData
79
76
  params[:pad_char] = ch
80
77
  end
81
78
 
82
- super(sanitizer, params, *args)
79
+ super(sanitizer, params)
83
80
  end
84
81
  end
85
82
 
@@ -87,7 +84,9 @@ module BinData
87
84
  # trimmed as required.
88
85
  def value
89
86
  v = val_to_str(_value)
90
- v.sub!(/#{eval_param(:pad_char)}*$/, "") if param(:trim_value) == true
87
+ if no_eval_param(:trim_value) == true
88
+ v.sub!(/#{eval_param(:pad_char)}*$/, "")
89
+ end
91
90
  v
92
91
  end
93
92
 
@@ -31,7 +31,7 @@ module BinData
31
31
  register(self.name, self)
32
32
 
33
33
  # These are the parameters used by this class.
34
- optional_parameters :max_length
34
+ bindata_optional_parameters :max_length
35
35
 
36
36
  # Overrides value to return the value of this data excluding the trailing
37
37
  # zero byte.
@@ -75,24 +75,24 @@ module BinData
75
75
  # will not be longer than +max_length+.
76
76
  def zero_terminate(str, max_length = nil)
77
77
  # str must not be empty
78
- str = "\0" if str == ""
78
+ result = (str == "") ? "\0" : str
79
79
 
80
80
  # remove anything after the first \0
81
- str = str.sub(/([^\0]*\0).*/, '\1')
81
+ result = result.sub(/([^\0]*\0).*/, '\1')
82
82
 
83
83
  # trim string to be no longer than max_length including zero byte
84
84
  if max_length
85
85
  max_length = 1 if max_length < 1
86
- str = str[0, max_length]
87
- if str.length == max_length and str[-1, 1] != "\0"
88
- str[-1, 1] = "\0"
86
+ result = result[0, max_length]
87
+ if result.length == max_length and result[-1, 1] != "\0"
88
+ result[-1, 1] = "\0"
89
89
  end
90
90
  end
91
91
 
92
92
  # ensure last byte in the string is a zero byte
93
- str << "\0" if str[-1, 1] != "\0"
93
+ result << "\0" if result[-1, 1] != "\0"
94
94
 
95
- str
95
+ result
96
96
  end
97
97
  end
98
98
  end
@@ -44,7 +44,8 @@ module BinData
44
44
  %w{alias and begin break case class def defined do else elsif
45
45
  end ensure false for if in module next nil not or redo
46
46
  rescue retry return self super then true undef unless until
47
- when while yield }).uniq
47
+ when while yield} +
48
+ %w{array element index offset value} ).uniq
48
49
 
49
50
  # Register this class
50
51
  register(self.name, self)
@@ -57,101 +58,20 @@ module BinData
57
58
  end
58
59
 
59
60
  class << self
60
- #### DEPRECATION HACK to allow inheriting from BinData::Struct
61
+ #### DEPRECATION HACK to warn about inheriting from BinData::Struct
61
62
  #
62
63
  def inherited(subclass) #:nodoc:
63
64
  if subclass != MultiValue
64
65
  # warn about deprecated method - remove before releasing 1.0
65
- warn "warning: inheriting from BinData::Struct in deprecated. Inherit from BinData::MultiValue instead."
66
-
67
- register(subclass.name, subclass)
66
+ fail "error: inheriting from BinData::Struct has been deprecated. Inherit from BinData::MultiValue instead."
68
67
  end
69
68
  end
70
- def endian(endian = nil)
71
- @endian ||= nil
72
- if [:little, :big].include?(endian)
73
- @endian = endian
74
- elsif endian != nil
75
- raise ArgumentError, "unknown value for endian '#{endian}'"
76
- end
77
- @endian
78
- end
79
- def hide(*args)
80
- # note that fields are stored in an instance variable not a class var
81
- @hide ||= []
82
- args.each do |name|
83
- @hide << name.to_s
84
- end
85
- @hide
86
- end
87
- def fields
88
- @fields || []
89
- end
90
- def method_missing(symbol, *args)
91
- name, params = args
92
-
93
- type = symbol
94
- name = name.to_s
95
- params ||= {}
96
-
97
- # note that fields are stored in an instance variable not a class var
98
- @fields ||= []
99
-
100
- # check that type is known
101
- unless Sanitizer.type_exists?(type, endian)
102
- raise TypeError, "unknown type '#{type}' for #{self}", caller
103
- end
104
-
105
- # check for duplicate names
106
- @fields.each do |t, n, p|
107
- if n == name
108
- raise SyntaxError, "duplicate field '#{name}' in #{self}", caller
109
- end
110
- end
111
-
112
- # check that name doesn't shadow an existing method
113
- if self.instance_methods.include?(name)
114
- raise NameError.new("", name),
115
- "field '#{name}' shadows an existing method", caller
116
- end
117
-
118
- # check that name isn't reserved
119
- if self::RESERVED.include?(name)
120
- raise NameError.new("", name),
121
- "field '#{name}' is a reserved name", caller
122
- end
123
-
124
- # remember this field. These fields will be recalled upon creating
125
- # an instance of this class
126
- @fields.push([type, name, params])
127
- end
128
- def deprecated_hack(params)
129
- params = params.dup
130
-
131
- # possibly override endian
132
- endian = params[:endian] || self.endian
133
- params[:endian] = endian unless endian.nil?
134
-
135
- params[:fields] = params[:fields] || self.fields
136
- params[:hide] = params[:hide] || self.hide
137
-
138
- params
139
- end
140
69
  #
141
70
  #### DEPRECATION HACK to allow inheriting from BinData::Struct
142
71
 
143
72
 
144
- # Returns a sanitized +params+ that is of the form expected
145
- # by #initialize.
146
- def sanitize_parameters(sanitizer, params)
147
- #### DEPRECATION HACK to allow inheriting from BinData::Struct
148
- #
149
- params = deprecated_hack(params)
150
- #
151
- #### DEPRECATION HACK to allow inheriting from BinData::Struct
152
-
153
- params = params.dup
154
-
73
+ # Ensures that +params+ is of the form expected by #initialize.
74
+ def sanitize_parameters!(sanitizer, params)
155
75
  # possibly override endian
156
76
  endian = params[:endian]
157
77
  if endian != nil
@@ -167,68 +87,65 @@ module BinData
167
87
  # ensure names of fields are strings and that params is sanitized
168
88
  all_fields = params[:fields].collect do |ftype, fname, fparams|
169
89
  fname = fname.to_s
170
- klass, new_params = sanitizer.sanitize(ftype, fparams)
171
- [klass, fname, new_params]
90
+ klass = sanitizer.lookup_klass(ftype)
91
+ sanitized_fparams = sanitizer.sanitize_params(klass, fparams)
92
+ [klass, fname, sanitized_fparams]
172
93
  end
173
94
  params[:fields] = all_fields
174
95
  end
175
96
 
176
- # collect all hidden names that correspond to a field name
177
- hide = []
178
- if params.has_key?(:hide)
179
- hidden = (params[:hide] || []).collect { |h| h.to_s }
180
- all_field_names = params[:fields].collect { |k,n,p| n }
181
- hide = hidden & all_field_names
182
- end
183
- params[:hide] = hide
184
- end
185
-
186
- # obtain SanitizedParameters
187
- params = super(sanitizer, params)
97
+ # now params are sanitized, check that parameter names are okay
98
+ field_names = []
99
+ instance_methods = self.instance_methods
100
+ reserved_names = RESERVED
188
101
 
189
- # now params are sanitized, check that parameter names are okay
102
+ params[:fields].each do |fklass, fname, fparams|
190
103
 
191
- field_names = []
192
- instance_methods = self.instance_methods
193
- reserved_names = RESERVED
104
+ # check that name doesn't shadow an existing method
105
+ if instance_methods.include?(fname)
106
+ raise NameError.new("Rename field '#{fname}' in #{self}, " +
107
+ "as it shadows an existing method.", fname)
108
+ end
194
109
 
195
- params[:fields].each do |fklass, fname, fparams|
110
+ # check that name isn't reserved
111
+ if reserved_names.include?(fname)
112
+ raise NameError.new("Rename field '#{fname}' in #{self}, " +
113
+ "as it is a reserved name.", fname)
114
+ end
196
115
 
197
- # check that name doesn't shadow an existing method
198
- if instance_methods.include?(fname)
199
- raise NameError.new("Rename field '#{fname}' in #{self}, " +
200
- "as it shadows an existing method.", fname)
201
- end
116
+ # check for multiple definitions
117
+ if field_names.include?(fname)
118
+ raise NameError.new("field '#{fname}' in #{self}, " +
119
+ "is defined multiple times.", fname)
120
+ end
202
121
 
203
- # check that name isn't reserved
204
- if reserved_names.include?(fname)
205
- raise NameError.new("Rename field '#{fname}' in #{self}, " +
206
- "as it is a reserved name.", fname)
122
+ field_names << fname
207
123
  end
208
124
 
209
- # check for multiple definitions
210
- if field_names.include?(fname)
211
- raise NameError.new("field '#{fname}' in #{self}, " +
212
- "is defined multiple times.", fname)
125
+ # collect all hidden names that correspond to a field name
126
+ hide = []
127
+ if params.has_key?(:hide)
128
+ hidden = (params[:hide] || []).collect { |h| h.to_s }
129
+ all_field_names = params[:fields].collect { |k,n,p| n }
130
+ hide = hidden & all_field_names
213
131
  end
214
-
215
- field_names << fname
132
+ params[:hide] = hide
216
133
  end
217
134
 
218
- params
135
+ super(sanitizer, params)
219
136
  end
220
137
  end
221
138
 
222
139
  # These are the parameters used by this class.
223
- mandatory_parameter :fields
224
- optional_parameters :endian, :hide
140
+ bindata_mandatory_parameter :fields
141
+ bindata_optional_parameters :endian, :hide
225
142
 
226
143
  # Creates a new Struct.
227
- def initialize(params = {}, env = nil)
228
- super(params, env)
144
+ def initialize(params = {}, parent = nil)
145
+ super(params, parent)
229
146
 
230
147
  # extract field names but don't instantiate the fields
231
- @field_names = param(:fields).collect { |k, n, p| n }
148
+ @field_names = no_eval_param(:fields).collect { |k, n, p| n }
232
149
  @field_objs = []
233
150
  end
234
151
 
@@ -269,7 +186,7 @@ module BinData
269
186
  def field_names(include_hidden = false)
270
187
  # collect field names
271
188
  names = []
272
- hidden = param(:hide)
189
+ hidden = no_eval_param(:hide)
273
190
  @field_names.each do |name|
274
191
  if include_hidden or not hidden.include?(name)
275
192
  names << name
@@ -283,17 +200,6 @@ module BinData
283
200
  @field_objs.each { |f| f.done_read unless f.nil? }
284
201
  end
285
202
 
286
- # Returns the data object that stores values for +name+.
287
- def find_obj_for_name(name)
288
- idx = @field_names.index(name)
289
- if idx
290
- instantiate_obj(idx)
291
- @field_objs[idx]
292
- else
293
- nil
294
- end
295
- end
296
-
297
203
  def offset_of(field)
298
204
  idx = @field_names.index(field.to_s)
299
205
  if idx
@@ -344,16 +250,27 @@ module BinData
344
250
  #---------------
345
251
  private
346
252
 
253
+ # Returns the data object that stores values for +name+.
254
+ def find_obj_for_name(name)
255
+ idx = @field_names.index(name)
256
+ if idx
257
+ instantiate_obj(idx)
258
+ @field_objs[idx].obj
259
+ else
260
+ nil
261
+ end
262
+ end
263
+
347
264
  # Instantiates all fields.
348
265
  def instantiate_all
349
- (0...@field_names.length).each { |idx| instantiate_obj(idx) }
266
+ @field_names.each_with_index { |name, i| instantiate_obj(i) }
350
267
  end
351
268
 
352
269
  # Instantiates the field object at position +idx+.
353
270
  def instantiate_obj(idx)
354
271
  if @field_objs[idx].nil?
355
- fklass, fname, fparams = param(:fields)[idx]
356
- @field_objs[idx] = fklass.new(fparams, create_env)
272
+ fklass, fname, fparams = no_eval_param(:fields)[idx]
273
+ @field_objs[idx] = fklass.new(fparams, self)
357
274
  end
358
275
  end
359
276
 
data/spec/array_spec.rb CHANGED
@@ -34,7 +34,7 @@ describe BinData::Array, "with no elements" do
34
34
  @data.should_not be_single_value
35
35
  end
36
36
 
37
- it "should return correct length" do
37
+ it "should return zero length" do
38
38
  @data.length.should be_zero
39
39
  end
40
40
 
@@ -127,7 +127,7 @@ describe BinData::Array, "with several elements" do
127
127
  @data.should_not be_empty
128
128
  end
129
129
 
130
- it "should return a nicely formatted array for inspect" do
130
+ it "should return a nicely formatted array for inspect" do
131
131
  @data.inspect.should == "[1, 2, 3, 4, 5]"
132
132
  end
133
133
 
@@ -264,6 +264,22 @@ describe BinData::Array, "with :read_until containing +array+ and +index+" do
264
264
  end
265
265
  end
266
266
 
267
+ describe BinData::Array, "with :read_until => :eof" do
268
+ it "should read records until eof" do
269
+ obj = BinData::Array.new(:type => :int8, :read_until => :eof)
270
+ data = "\x01\x02\x03"
271
+ obj.read(data)
272
+ obj.snapshot.should == [1, 2, 3]
273
+ end
274
+
275
+ it "should read records until eof, ignoring partial records" do
276
+ obj = BinData::Array.new(:type => :int16be, :read_until => :eof)
277
+ data = "\x00\x01\x00\x02\x03"
278
+ obj.read(data)
279
+ obj.snapshot.should == [1, 2]
280
+ end
281
+ end
282
+
267
283
  describe BinData::Array, "of bits" do
268
284
  before(:each) do
269
285
  @data = BinData::Array.new(:type => :bit1, :initial_length => 15)
@@ -299,3 +315,22 @@ describe BinData::Array, "of bits" do
299
315
  end
300
316
  end
301
317
 
318
+ describe BinData::Array, "nested within an Array" do
319
+ before(:each) do
320
+ nested_array_params = { :type => [:int8, { :initial_value => :index }],
321
+ :initial_length => lambda { index + 1 } }
322
+ @data = BinData::Array.new(:type => [:array, nested_array_params],
323
+ :initial_length => 3)
324
+ end
325
+
326
+ it "should use correct index" do
327
+ @data.snapshot.should == [ [0], [0, 1], [0, 1, 2] ]
328
+ end
329
+
330
+ it "should maintain structure when reading" do
331
+ str = "\x04\x05\x06\x07\x08\x09"
332
+ @data.read(str)
333
+ @data.snapshot.should == [ [4], [5, 6], [7, 8, 9] ]
334
+ end
335
+ end
336
+