bindata 0.10.0 → 0.11.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 CHANGED
@@ -1,6 +1,12 @@
1
1
  = BinData Changelog
2
2
 
3
- == Version
3
+ == Version 0.11.0 (2009-06-28)
4
+
5
+ * Sanitizing code was refactored for speed.
6
+ * Arbitrary sized integers and bit fields are now automatically instantiated.
7
+ * Add ability to wrap existing types and override their parameters.
8
+
9
+ == Version 0.10.0 (2009-04-17)
4
10
 
5
11
  * Arbitrary byte sized integers are now supported (e.g. 24bit, 808bit).
6
12
  * Renamed String :trim_value parameter to :trim_padding.
data/INSTALL CHANGED
@@ -1,3 +1,7 @@
1
+ This package is designed to be installed with rubygems. If you don't
2
+ have rubygems installed on your system, the older setup.rb is
3
+ included as a convenience.
4
+
1
5
  ($ su)
2
6
  # ruby setup.rb
3
7
 
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
2
+
3
+ require 'bindata'
4
+ require 'rake/clean'
5
+
6
+ CURRENT_VERSION = BinData::VERSION
7
+
8
+ PKG_FILES = FileList[
9
+ "[A-Z]*",
10
+ "{examples,spec,lib}/**/*.rb",
11
+ "tasks/**/*.rake",
12
+ "setup.rb",
13
+ ]
14
+
15
+ task :default => :spec
16
+
17
+ Dir['tasks/**/*.rake'].each { |t| load t }
data/TODO CHANGED
@@ -1,26 +1,5 @@
1
- * Write a Rakefile
2
-
3
- * Registry should auto create integers and bits. (e.g. 24bit int, 191bit int)
4
-
5
- * Improve speed of Sanitizer for recursive records
6
- rework it so that sanitizing is done during definition (before initialising).
7
-
8
1
  * Write a detailed tutorial (probably as a web page).
9
2
 
10
3
  * Need more examples.
11
4
 
12
- * Need wrapper to be able to define new wrapped classes - with parameters
13
-
14
- -----------------------------------------------------------------------------
15
- define_wrapped_class("MyInt", :uint32be, :initial_value => 3) #=> MyInt
16
- define_wrapped_class("ByteArray", :array, :type => :uint8) #=> ByteArray
17
- define_wrapped_class("MyInt", :uint32be, {:initial_value => :mult}, [], [], {:mult => 3}) #=> MyInt
18
- # mandatory, optional, default
19
- -----------------------------------------------------------------------------
20
-
21
-
22
-
23
-
24
-
25
- refactor snapshot -> _snapshot et al
26
-
5
+ * Perhaps refactor snapshot -> _snapshot et al
data/lib/bindata.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # BinData -- Binary data manipulator.
2
- # Copyright (c) 2007,2008 Dion Mendel.
2
+ # Copyright (c) 2007 - 2009 Dion Mendel.
3
3
 
4
4
  require 'bindata/array'
5
5
  require 'bindata/bits'
@@ -13,11 +13,13 @@ require 'bindata/string'
13
13
  require 'bindata/stringz'
14
14
  require 'bindata/struct'
15
15
  require 'bindata/trace'
16
+ require 'bindata/wrapper'
17
+ require 'bindata/deprecated'
16
18
 
17
19
  # = BinData
18
20
  #
19
21
  # A declarative way to read and write structured binary data.
20
22
  #
21
23
  module BinData
22
- VERSION = "0.10.0"
24
+ VERSION = "0.11.0"
23
25
  end
data/lib/bindata/array.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'bindata/base'
2
- require 'bindata/sanitize'
3
2
 
4
3
  module BinData
5
4
  # An Array is a list of data objects of the same type.
@@ -63,72 +62,38 @@ module BinData
63
62
 
64
63
  class << self
65
64
 
66
- def sanitize_parameters!(sanitizer, params)
67
- unless params.has_key?(:initial_length) or params.has_key?(:read_until)
65
+ def sanitize_parameters!(params, sanitizer)
66
+ unless params.has_parameter?(:initial_length) or
67
+ params.has_parameter?(:read_until)
68
68
  # ensure one of :initial_length and :read_until exists
69
69
  params[:initial_length] = 0
70
70
  end
71
71
 
72
72
  warn_replacement_parameter(params, :read_length, :initial_length)
73
73
 
74
- if params.has_key?(:type)
75
- type, el_params = params[:type]
76
- klass = sanitizer.lookup_class(type)
77
- sanitized_params = sanitizer.sanitized_params(klass, el_params)
78
- params[:type] = [klass, sanitized_params]
74
+ if params.needs_sanitizing?(:type)
75
+ el_type, el_params = params[:type]
76
+ params[:type] = sanitizer.create_sanitized_object_prototype(el_type, el_params)
79
77
  end
80
-
81
- super(sanitizer, params)
82
78
  end
83
79
  end
84
80
 
85
81
  def initialize(params = {}, parent = nil)
86
82
  super(params, parent)
87
83
 
88
- el_class, el_params = get_parameter(:type)
89
-
90
- @element_list = nil
91
- @element_class = el_class
92
- @element_params = el_params
84
+ @element_list = nil
85
+ @element_prototype = get_parameter(:type)
93
86
  end
94
87
 
95
- # Returns if the element at position +index+ is clear?. If +index+
96
- # is not given, then returns whether all elements are clear.
97
- def clear?(index = nil)
98
- if index.nil?
99
- @element_list.nil? or elements.inject(true) { |all_clear, f| all_clear and f.clear? }
100
- elsif index < elements.length
101
- warn "'obj.clear?(n)' is deprecated. Replacing with 'obj[n].clear?'"
102
- elements[index].clear?
103
- else
104
- true
105
- end
88
+ def clear?
89
+ @element_list.nil? or
90
+ elements.inject(true) { |all_clear, el| all_clear and el.clear? }
106
91
  end
107
92
 
108
- # Clears the element at position +index+. If +index+ is not given, then
109
- # the internal state of the array is reset to that of a newly created
110
- # object.
111
- def clear(index = nil)
112
- if index.nil?
113
- @element_list = nil
114
- elsif index < elements.length
115
- warn "'obj.clear(n)' is deprecated. Replacing with 'obj[n].clear'"
116
- elements[index].clear
117
- end
93
+ def clear
94
+ @element_list = nil
118
95
  end
119
96
 
120
- # Returns the first index of +obj+ in self.
121
- #
122
- # a = BinData::String.new; a.value = "a"
123
- # b = BinData::String.new; b.value = "b"
124
- # c = BinData::String.new; c.value = "c"
125
- #
126
- # arr = BinData::Array.new(:type => :string)
127
- # arr.push(a, b, c)
128
- #
129
- # arr.find_index("b") #=> 1
130
- # arr.find_index(c) #=> 2
131
- #
132
97
  def find_index(obj)
133
98
  elements.find_index(obj)
134
99
  end
@@ -163,16 +128,6 @@ module BinData
163
128
  self
164
129
  end
165
130
 
166
- def append(value = nil)
167
- warn "#append is deprecated, use push or slice instead"
168
- if value.nil?
169
- slice(length)
170
- else
171
- push(value)
172
- end
173
- self.last
174
- end
175
-
176
131
  # Returns the element at +index+.
177
132
  def [](arg1, arg2 = nil)
178
133
  if arg1.respond_to?(:to_int) and arg2.nil?
@@ -240,13 +195,11 @@ module BinData
240
195
  end
241
196
  end
242
197
 
243
- # The number of elements in this array.
244
198
  def length
245
199
  elements.length
246
200
  end
247
201
  alias_method :size, :length
248
202
 
249
- # Returns true if self array contains no elements.
250
203
  def empty?
251
204
  length.zero?
252
205
  end
@@ -256,7 +209,6 @@ module BinData
256
209
  collect { |el| el }
257
210
  end
258
211
 
259
- # Iterate over each element in the array.
260
212
  def each
261
213
  elements.each { |el| yield el }
262
214
  end
@@ -297,7 +249,7 @@ module BinData
297
249
 
298
250
  def _do_read(io)
299
251
  if has_parameter?(:initial_length)
300
- elements.each { |f| f.do_read(io) }
252
+ elements.each { |el| el.do_read(io) }
301
253
  elsif has_parameter?(:read_until)
302
254
  read_until(io)
303
255
  end
@@ -312,46 +264,37 @@ module BinData
312
264
  end
313
265
 
314
266
  def read_until_eof(io)
315
- finished = false
316
- while not finished
267
+ loop do
317
268
  element = append_new_element
318
269
  begin
319
270
  element.do_read(io)
320
271
  rescue
321
272
  elements.pop
322
- finished = true
273
+ break
323
274
  end
324
275
  end
325
276
  end
326
277
 
327
278
  def read_until_condition(io)
328
- finished = false
329
- while not finished
279
+ loop do
330
280
  element = append_new_element
331
281
  element.do_read(io)
332
282
  variables = { :index => self.length - 1, :element => self.last,
333
283
  :array => self }
334
- finished = eval_parameter(:read_until, variables)
284
+ break if eval_parameter(:read_until, variables)
335
285
  end
336
286
  end
337
287
 
338
288
  def _done_read
339
- elements.each { |f| f.done_read }
289
+ elements.each { |el| el.done_read }
340
290
  end
341
291
 
342
292
  def _do_write(io)
343
- elements.each { |f| f.do_write(io) }
293
+ elements.each { |el| el.do_write(io) }
344
294
  end
345
295
 
346
- def _do_num_bytes(index)
347
- if index.nil?
348
- sum_num_bytes_for_all_elements.ceil
349
- elsif index < elements.length
350
- warn "'obj.num_bytes(n)' is deprecated. Replacing with 'obj[n].num_bytes'"
351
- elements[index].do_num_bytes
352
- else
353
- 0
354
- end
296
+ def _do_num_bytes(deprecated)
297
+ sum_num_bytes_for_all_elements.ceil
355
298
  end
356
299
 
357
300
  def _assign(array)
@@ -361,7 +304,7 @@ module BinData
361
304
  end
362
305
 
363
306
  def _snapshot
364
- elements.collect { |e| e.snapshot }
307
+ elements.collect { |el| el.snapshot }
365
308
  end
366
309
 
367
310
  def elements
@@ -383,7 +326,7 @@ module BinData
383
326
  end
384
327
 
385
328
  def new_element
386
- @element_class.new(@element_params, self)
329
+ @element_prototype.instantiate(self)
387
330
  end
388
331
 
389
332
  def sum_num_bytes_for_all_elements
data/lib/bindata/base.rb CHANGED
@@ -39,28 +39,45 @@ module BinData
39
39
  data
40
40
  end
41
41
 
42
- def recursive?
43
- # data objects do not self reference by default
44
- false
42
+ def mandatory_parameters(*args)
43
+ accepted_parameters.mandatory(*args)
45
44
  end
46
45
 
47
- AcceptedParameters.define_all_accessors(self, :internal)
46
+ def optional_parameters(*args)
47
+ accepted_parameters.optional(*args)
48
+ end
49
+
50
+ def default_parameters(*args)
51
+ accepted_parameters.default(*args)
52
+ end
53
+
54
+ def mutually_exclusive_parameters(*args)
55
+ accepted_parameters.mutually_exclusive(*args)
56
+ end
48
57
 
49
- def accepted_internal_parameters
50
- internal = AcceptedParameters.get(self, :internal)
51
- internal.all
58
+ alias_method :mandatory_parameter, :mandatory_parameters
59
+ alias_method :optional_parameter, :optional_parameters
60
+ alias_method :default_parameter, :default_parameters
61
+
62
+ def accepted_parameters
63
+ unless defined? @accepted_parameters
64
+ ancestor = ancestors[1..-1].find { |cls|
65
+ cls.respond_to?(:accepted_parameters)
66
+ }
67
+ ancestor_params = ancestor.nil? ? nil : ancestor.accepted_parameters
68
+ @accepted_parameters = AcceptedParameters.new(ancestor_params)
69
+ end
70
+ @accepted_parameters
52
71
  end
53
72
 
54
- def sanitize_parameters!(sanitizer, params)
55
- internal = AcceptedParameters.get(self, :internal)
56
- internal.sanitize_parameters!(sanitizer, params)
73
+ def sanitize_parameters!(params, sanitizer)
57
74
  end
58
75
 
59
76
  #-------------
60
77
  private
61
78
 
62
79
  def warn_replacement_parameter(params, bad_key, suggested_key)
63
- if params.has_key?(bad_key)
80
+ if params.has_parameter?(bad_key)
64
81
  warn ":#{bad_key} is not used with #{self}. " +
65
82
  "You probably want to change this to :#{suggested_key}"
66
83
  end
@@ -81,7 +98,7 @@ module BinData
81
98
  # parent data object (e.g. struct, array, choice) this object resides
82
99
  # under.
83
100
  def initialize(params = {}, parent = nil)
84
- @params = Sanitizer.sanitize(self.class, params)
101
+ @params = Sanitizer.sanitize(params, self.class)
85
102
  @parent = parent
86
103
  end
87
104
 
@@ -104,7 +121,7 @@ module BinData
104
121
 
105
122
  # Returns whether +key+ exists in the +parameters+ hash.
106
123
  def has_parameter?(key)
107
- @params.has_key?(key)
124
+ @params.has_parameter?(key)
108
125
  end
109
126
 
110
127
  # Reads data into this data object.
@@ -142,13 +159,13 @@ module BinData
142
159
  protected :do_write
143
160
 
144
161
  # Returns the number of bytes it will take to write this data.
145
- def num_bytes(what = nil)
146
- num = do_num_bytes(what)
162
+ def num_bytes(deprecated = nil)
163
+ num = do_num_bytes(deprecated)
147
164
  num.ceil
148
165
  end
149
166
 
150
- def do_num_bytes(what = nil)
151
- _do_num_bytes(what)
167
+ def do_num_bytes(deprecated = nil)
168
+ _do_num_bytes(deprecated)
152
169
  end
153
170
  protected :do_num_bytes
154
171
 
@@ -253,7 +270,7 @@ module BinData
253
270
  end
254
271
 
255
272
  # Returns true if the object has not been changed since creation.
256
- def clear?(*args)
273
+ def clear?
257
274
  raise NotImplementedError
258
275
  end
259
276
 
@@ -285,7 +302,7 @@ module BinData
285
302
  end
286
303
 
287
304
  # Returns the number of bytes it will take to write this data.
288
- def _do_num_bytes(what)
305
+ def _do_num_bytes(deprecated)
289
306
  raise NotImplementedError
290
307
  end
291
308
 
@@ -304,12 +321,6 @@ module BinData
304
321
  public :clear, :clear?, :debug_name_of, :offset_of
305
322
  private :_do_read, :_done_read, :_do_write, :_do_num_bytes, :_assign, :_snapshot
306
323
 
307
- def single_value?
308
- warn "#single_value? is deprecated. It should no longer be needed"
309
- false
310
- end
311
- public :single_value?
312
-
313
324
  # End To be implemented by subclasses
314
325
  ###########################################################################
315
326
  end
@@ -89,6 +89,15 @@ module BinData
89
89
  end
90
90
  end
91
91
 
92
+ def eql?(other)
93
+ # double dispatch
94
+ other.eql?(snapshot)
95
+ end
96
+
97
+ def hash
98
+ snapshot.hash
99
+ end
100
+
92
101
  #---------------
93
102
  private
94
103
 
@@ -1,6 +1,4 @@
1
- require 'forwardable'
2
1
  require 'bindata/base'
3
- require 'bindata/sanitize'
4
2
  require 'bindata/trace'
5
3
 
6
4
  module BinData
@@ -55,7 +53,6 @@ module BinData
55
53
  # selection to the current selection whenever the
56
54
  # selection changes. Default is false.
57
55
  class Choice < BinData::Base
58
- extend Forwardable
59
56
 
60
57
  register(self.name, self)
61
58
 
@@ -64,14 +61,12 @@ module BinData
64
61
 
65
62
  class << self
66
63
 
67
- def sanitize_parameters!(sanitizer, params)
68
- if params.has_key?(:choices)
64
+ def sanitize_parameters!(params, sanitizer)
65
+ if params.needs_sanitizing?(:choices)
69
66
  choices = choices_as_hash(params[:choices])
70
67
  ensure_valid_keys(choices)
71
- params[:choices] = sanitized_choices(sanitizer, choices)
68
+ params[:choices] = sanitizer.create_sanitized_choices(choices)
72
69
  end
73
-
74
- super(sanitizer, params)
75
70
  end
76
71
 
77
72
  #-------------
@@ -97,21 +92,10 @@ module BinData
97
92
  if choices.has_key?(nil)
98
93
  raise ArgumentError, ":choices hash may not have nil key"
99
94
  end
100
- if choices.keys.detect { |k| Symbol === k }
95
+ if choices.keys.detect { |key| Symbol === key }
101
96
  raise ArgumentError, ":choices hash may not have symbols for keys"
102
97
  end
103
98
  end
104
-
105
- def sanitized_choices(sanitizer, choices)
106
- result = {}
107
- choices.each_pair do |key, val|
108
- type, param = val
109
- the_class = sanitizer.lookup_class(type)
110
- sanitized_params = sanitizer.sanitized_params(the_class, param)
111
- result[key] = [the_class, sanitized_params]
112
- end
113
- result
114
- end
115
99
  end
116
100
 
117
101
  def initialize(params = {}, parent = nil)
@@ -133,9 +117,9 @@ module BinData
133
117
  # If you really *must* be able to programmatically adjust the selection
134
118
  # then try something like the following.
135
119
  #
136
- # class ProgrammaticChoice < BinData::Record
137
- # choice :data, :choices => :choices, :selection => :selection
138
- # attrib_accessor :selection
120
+ # class ProgrammaticChoice < BinData::Wrapper
121
+ # choice :selection => :selection
122
+ # attr_accessor :selection
139
123
  # end
140
124
  #
141
125
  # type1 = [:string, {:value => "Type1"}]
@@ -145,26 +129,20 @@ module BinData
145
129
  # pc = ProgrammaticChoice.new(:choices => choices)
146
130
  #
147
131
  # pc.selection = 5
148
- # pc.data #=> "Type1"
132
+ # pc #=> "Type1"
149
133
  #
150
134
  # pc.selection = 17
151
- # pc.data #=> "Type2"
135
+ # pc #=> "Type2"
152
136
  def selection=(v)
153
137
  raise NoMethodError
154
138
  end
155
139
 
156
- def_delegators :current_choice, :clear, :clear?
157
-
158
- def respond_to?(symbol, include_private = false)
159
- super || current_choice.respond_to?(symbol, include_private)
140
+ def clear
141
+ current_choice.clear
160
142
  end
161
143
 
162
- def method_missing(symbol, *args, &block)
163
- if current_choice.respond_to?(symbol)
164
- current_choice.__send__(symbol, *args, &block)
165
- else
166
- super
167
- end
144
+ def clear?
145
+ current_choice.clear?
168
146
  end
169
147
 
170
148
  def debug_name_of(child)
@@ -175,6 +153,14 @@ module BinData
175
153
  offset
176
154
  end
177
155
 
156
+ def respond_to?(symbol, include_private = false)
157
+ super || current_choice.respond_to?(symbol, include_private)
158
+ end
159
+
160
+ def method_missing(symbol, *args, &block)
161
+ current_choice.__send__(symbol, *args, &block)
162
+ end
163
+
178
164
  #---------------
179
165
  private
180
166
 
@@ -202,8 +188,8 @@ module BinData
202
188
  current_choice.do_write(io)
203
189
  end
204
190
 
205
- def _do_num_bytes(what)
206
- current_choice.do_num_bytes(what)
191
+ def _do_num_bytes(deprecated)
192
+ current_choice.do_num_bytes(deprecated)
207
193
  end
208
194
 
209
195
  def _assign(val)
@@ -236,11 +222,11 @@ module BinData
236
222
  end
237
223
 
238
224
  def instantiate_choice(selection)
239
- choice_class, choice_params = get_parameter(:choices)[selection]
240
- if choice_class.nil?
225
+ prototype = get_parameter(:choices)[selection]
226
+ if prototype.nil?
241
227
  raise IndexError, "selection '#{selection}' does not exist in :choices for #{debug_name}"
242
228
  end
243
- choice_class.new(choice_params, self)
229
+ prototype.instantiate(self)
244
230
  end
245
231
 
246
232
  def copy_previous_value_if_required(selection, obj)