bindata 2.1.0 → 2.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fba829df2a0f618021920683747584daef8f572a
4
- data.tar.gz: efe2ac6d0ab61895a09f271fb9d7712e289f1897
3
+ metadata.gz: ef9bdd3883fe70283af7a90ef1d7a7aabdbc1043
4
+ data.tar.gz: a0e441bd2a6fc0fcebe932b21737364baa53a373
5
5
  SHA512:
6
- metadata.gz: eef3a6fd17fcb5fe9afcffa35c566cd4e0752063f20bc4d9d135aa3300184454b8974d3161d90e37390dfa3b6606b5f1bfe1217705075e28bd2e5641b11f878d
7
- data.tar.gz: 55bc265de56013c33f1e9abf7d38a796deff58cedf7faa1c20e77ee6dbad5e42a080c3ab46c8f06503e7268888cedd38b51667e1d091fa23cb89afc39b5b124e
6
+ metadata.gz: 45b2a84cd80c08590463773919d93cb8aececa94fc391d620e897a4b3b1d2a512dd2e8f91c9ec608008b6007a1828ff1dae80938de1d961eab7403a802d1a696
7
+ data.tar.gz: 179ea9774c018fa6d90f2e864d99ae829ee8f41d8289fc30da514481b2dddff94c6b1e6ca9c316f98657a9cfee6c307f001d6d1449db713569c17cb171e06645
@@ -1,7 +1,12 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
3
  - 2.0.0
5
- - 2.1.1
4
+ - 2.1.8
5
+ - 2.2.4
6
+ - 2.3.0
6
7
  - jruby
7
8
  - ruby-head
9
+
10
+ matrix:
11
+ allow_failures:
12
+ - rvm: ruby-head
data/COPYING CHANGED
@@ -1,4 +1,4 @@
1
- BinData is copyrighted free software by Dion Mendel <dion@lostrealm.com>.
1
+ BinData is copyrighted free software by Dion Mendel <bindata@dm9.info>.
2
2
  You can redistribute it and/or modify it under either the terms of the
3
3
  2-clause BSDL (see the file BSDL), or the conditions below:
4
4
 
@@ -1,5 +1,13 @@
1
1
  = BinData Changelog
2
2
 
3
+ == Version 2.2.0 (2016-01-30)
4
+
5
+ * Warn if String has :value but no :read_length. Requested by Michael
6
+ Genereux.
7
+ * Prevent running under Ruby 2.1.0p0 due to ruby bug 44525.
8
+ * Added #to_hex convenience method. Thanks to Gregory Romé.
9
+ * Added namespacing via search_prefix. Requested by sumofparts.
10
+
3
11
  == Version 2.1.0 (2014-04-16)
4
12
 
5
13
  * Performance improvements.
data/README.md CHANGED
@@ -59,4 +59,4 @@ or if running ruby 1.8
59
59
  # Contact
60
60
 
61
61
  If you have any queries / bug reports / suggestions, please contact me
62
- (Dion Mendel) via email at dion@lostrealm.com
62
+ (Dion Mendel) via email at bindata@dm9.info
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.summary = 'A declarative way to read and write binary file formats'
9
9
  s.author = 'Dion Mendel'
10
- s.email = 'dion@lostrealm.com'
10
+ s.email = 'bindata@dm9.info'
11
11
  s.homepage = 'http://github.com/dmendel/bindata'
12
12
  s.rubyforge_project = 'bindata'
13
13
  s.require_path = 'lib'
@@ -1,10 +1,14 @@
1
1
  # BinData -- Binary data manipulator.
2
- # Copyright (c) 2007 - 2014 Dion Mendel.
2
+ # Copyright (c) 2007 - 2016 Dion Mendel.
3
3
 
4
4
  if RUBY_VERSION <= "1.9"
5
5
  fail "BinData requires ruby >= 1.9.3. Use BinData version 1.8.x instead"
6
6
  end
7
7
 
8
+ if RUBY_VERSION == "2.1.0" and RUBY_PATCHLEVEL == "0"
9
+ fail "Ruby 2.1.0p0 has a bug that causes BinData to fail. Upgrade your ruby version"
10
+ end
11
+
8
12
  require 'bindata/version'
9
13
  require 'bindata/array'
10
14
  require 'bindata/bits'
@@ -36,4 +40,4 @@ require 'bindata/warnings'
36
40
  #
37
41
  # BinData is released under the same license as Ruby.
38
42
  #
39
- # Copyright (c) 2007 - 2014 Dion Mendel.
43
+ # Copyright (c) 2007 - 2016 Dion Mendel.
@@ -182,6 +182,11 @@ module BinData
182
182
  io.read
183
183
  end
184
184
 
185
+ # Returns the hexadecimal string representation of this data object.
186
+ def to_hex
187
+ to_binary_s.unpack('H*')[0]
188
+ end
189
+
185
190
  # Return a human readable representation of this data object.
186
191
  def inspect
187
192
  snapshot.inspect
@@ -20,10 +20,10 @@ module BinData
20
20
  # obj.assign(5)
21
21
  # obj #=> 42
22
22
  #
23
- # obj = BinData::Uint8.new(:assert_value => 3)
23
+ # obj = BinData::Uint8.new(:assert => 3)
24
24
  # obj.read("\005") #=> BinData::ValidityError: value is '5' but expected '3'
25
25
  #
26
- # obj = BinData::Uint8.new(:assert_value => lambda { value < 5 })
26
+ # obj = BinData::Uint8.new(:assert => lambda { value < 5 })
27
27
  # obj.read("\007") #=> BinData::ValidityError: value not as expected
28
28
  #
29
29
  # == Parameters
@@ -67,7 +67,6 @@ module BinData
67
67
  @the_class = the_class
68
68
  @parser_type = parser_type
69
69
  @validator = DSLFieldValidator.new(the_class, self)
70
- @endian_handler = DSLBigAndLittleEndianHandler.new(the_class)
71
70
  @endian = nil
72
71
  end
73
72
 
@@ -77,12 +76,28 @@ module BinData
77
76
  if endian
78
77
  set_endian(endian)
79
78
  elsif @endian.nil?
80
- pendian = parent_attribute(:endian, nil)
81
- set_endian(pendian) if pendian
79
+ set_endian(parent_attribute(:endian))
82
80
  end
83
81
  @endian
84
82
  end
85
83
 
84
+ def search_prefix(*args)
85
+ unless defined? @search_prefix
86
+ @search_prefix = parent_attribute(:search_prefix, []).dup
87
+ end
88
+
89
+ prefix = args.collect { |name| name.to_sym }.compact
90
+ if prefix.size > 0
91
+ if has_fields?
92
+ dsl_raise SyntaxError, "search_prefix must be called before defining fields"
93
+ end
94
+
95
+ @search_prefix = prefix.concat(@search_prefix)
96
+ end
97
+
98
+ @search_prefix
99
+ end
100
+
86
101
  def hide(*args)
87
102
  if option?(:hidden_fields)
88
103
  hidden = args.collect { |name| name.to_sym }
@@ -98,8 +113,8 @@ module BinData
98
113
 
99
114
  def fields
100
115
  unless defined? @fields
101
- fields = @endian_handler.ancestor_fields || parent_attribute(:fields)
102
- @fields = SanitizedFields.new(endian)
116
+ fields = parent_fields
117
+ @fields = SanitizedFields.new(hints)
103
118
  @fields.copy_fields(fields) if fields
104
119
  end
105
120
 
@@ -111,11 +126,8 @@ module BinData
111
126
  end
112
127
 
113
128
  def method_missing(*args, &block)
114
- if endian == :big_and_little
115
- @endian_handler.forward_field_definition(*args, &block)
116
- else
117
- parse_and_append_field(*args, &block)
118
- end
129
+ ensure_hints
130
+ parse_and_append_field(*args, &block)
119
131
  end
120
132
 
121
133
  #-------------
@@ -125,7 +137,7 @@ module BinData
125
137
  @abilities ||= {
126
138
  :struct => [:to_struct_params, [:multiple_fields, :optional_fieldnames, :hidden_fields]],
127
139
  :array => [:to_array_params, [:multiple_fields, :optional_fieldnames]],
128
- :buffer => [:to_array_params, [:multiple_fields, :optional_fieldnames]],
140
+ :buffer => [:to_array_params, [:multiple_fields, :optional_fieldnames, :hidden_fields]],
129
141
  :choice => [:to_choice_params, [:multiple_fields, :all_or_none_fieldnames, :fieldnames_are_values]],
130
142
  :primitive => [:to_struct_params, [:multiple_fields, :optional_fieldnames]]
131
143
  }
@@ -135,41 +147,49 @@ module BinData
135
147
  parser_abilities[@parser_type].at(1).include?(opt)
136
148
  end
137
149
 
138
- def set_endian(endian)
139
- if has_fields?
140
- dsl_raise SyntaxError, "endian must not be called after defining fields"
141
- end
142
- if not valid_endian?(endian)
143
- dsl_raise ArgumentError, "unknown value for endian '#{endian}'"
144
- end
145
-
146
- if endian == :big_and_little
147
- @endian_handler.prepare_subclasses
148
- end
150
+ def ensure_hints
151
+ endian
152
+ search_prefix
153
+ end
149
154
 
150
- @endian = endian
155
+ def hints
156
+ {
157
+ :endian => endian,
158
+ :search_prefix => search_prefix,
159
+ }
151
160
  end
152
161
 
153
- def has_fields?
154
- @fields && @fields.length > 0
162
+ def set_endian(endian)
163
+ if endian
164
+ if has_fields?
165
+ dsl_raise SyntaxError, "endian must be called before defining fields"
166
+ end
167
+ if not valid_endian?(endian)
168
+ dsl_raise ArgumentError, "unknown value for endian '#{endian}'"
169
+ end
170
+
171
+ if endian == :big_and_little
172
+ DSLBigAndLittleEndianHandler.handle(@the_class)
173
+ end
174
+
175
+ @endian = endian
176
+ end
155
177
  end
156
178
 
157
179
  def valid_endian?(endian)
158
180
  [:big, :little, :big_and_little].include?(endian)
159
181
  end
160
182
 
161
- def parent_attribute(attr, default = nil)
162
- parent = @the_class.superclass
163
- parser = parent.respond_to?(:dsl_parser) ? parent.dsl_parser : nil
164
- if parser and parser.respond_to?(attr)
165
- parser.send(attr)
166
- else
167
- default
168
- end
183
+ def parent_fields
184
+ parent_attribute(:fields)
185
+ end
186
+
187
+ def has_fields?
188
+ @fields && @fields.length > 0
169
189
  end
170
190
 
171
191
  def parse_and_append_field(*args, &block)
172
- parser = DSLFieldParser.new(endian, *args, &block)
192
+ parser = DSLFieldParser.new(hints, *args, &block)
173
193
  begin
174
194
  @validator.validate_field(parser.name)
175
195
  append_field(parser.type, parser.name, parser.params)
@@ -184,6 +204,16 @@ module BinData
184
204
  raise TypeError, "unknown type '#{err.message}'"
185
205
  end
186
206
 
207
+ def parent_attribute(attr, default = nil)
208
+ parent = @the_class.superclass
209
+ parser = parent.respond_to?(:dsl_parser) ? parent.dsl_parser : nil
210
+ if parser and parser.respond_to?(attr)
211
+ parser.send(attr)
212
+ else
213
+ default
214
+ end
215
+ end
216
+
187
217
  def dsl_raise(exception, message)
188
218
  backtrace = caller
189
219
  backtrace.shift while %r{bindata/dsl.rb} =~ backtrace.first
@@ -219,6 +249,9 @@ module BinData
219
249
  if not endian.nil?
220
250
  result[:endian] = endian
221
251
  end
252
+ if not search_prefix.empty?
253
+ result[:search_prefix] = search_prefix
254
+ end
222
255
  if option?(:hidden_fields) and not hide.empty?
223
256
  result[:hide] = hide
224
257
  end
@@ -231,87 +264,96 @@ module BinData
231
264
  # This option creates two subclasses, each handling
232
265
  # :big or :little endian.
233
266
  class DSLBigAndLittleEndianHandler
234
- def initialize(the_class)
235
- @the_class = the_class
236
- end
237
-
238
- def prepare_subclasses
239
- create_subclasses_with_endian
240
- make_class_abstract
241
- override_new_in_class
242
- end
243
-
244
- def forward_field_definition(*args, &block)
245
- class_with_endian(@the_class, :big).send(*args, &block)
246
- class_with_endian(@the_class, :little).send(*args, &block)
247
- end
267
+ class << self
268
+ def handle(bnl_class)
269
+ make_class_abstract(bnl_class)
270
+ create_subclasses_with_endian(bnl_class)
271
+ override_new_in_class(bnl_class)
272
+ delegate_field_creation(bnl_class)
273
+ fixup_subclass_hierarchy(bnl_class)
274
+ end
248
275
 
249
- def ancestor_fields
250
- if subclass_of_big_and_little_endian?
251
- pparent = @the_class.superclass.superclass
252
- ancestor_with_endian = class_with_endian(pparent, @the_class.endian)
253
- obj_attribute(ancestor_with_endian, :fields)
254
- else
255
- nil
276
+ def make_class_abstract(bnl_class)
277
+ bnl_class.send(:unregister_self)
256
278
  end
257
- end
258
279
 
259
- #-------------
260
- private
280
+ def create_subclasses_with_endian(bnl_class)
281
+ instance_eval "class ::#{bnl_class}Be < ::#{bnl_class}; endian :big; end"
282
+ instance_eval "class ::#{bnl_class}Le < ::#{bnl_class}; endian :little; end"
283
+ end
261
284
 
262
- def create_subclasses_with_endian
263
- instance_eval "class ::#{@the_class}Be < ::#{@the_class}; endian :big; end"
264
- instance_eval "class ::#{@the_class}Le < ::#{@the_class}; endian :little; end"
265
- end
285
+ def override_new_in_class(bnl_class)
286
+ endian_classes = {
287
+ :big => class_with_endian(bnl_class, :big),
288
+ :little => class_with_endian(bnl_class, :little),
289
+ }
290
+ bnl_class.define_singleton_method(:new) do |*args|
291
+ if self == bnl_class
292
+ value, options, parent = arg_processor.separate_args(self, args)
293
+ delegate = endian_classes[options[:endian]]
294
+ return delegate.new(*args) if delegate
295
+ end
296
+
297
+ super(*args)
298
+ end
299
+ end
266
300
 
267
- def make_class_abstract
268
- @the_class.send(:unregister_self)
269
- end
301
+ def delegate_field_creation(bnl_class)
302
+ endian_classes = {
303
+ :big => class_with_endian(bnl_class, :big),
304
+ :little => class_with_endian(bnl_class, :little),
305
+ }
270
306
 
271
- def override_new_in_class
272
- saved_class = @the_class
273
- endian_classes = {
274
- :big => class_with_endian(saved_class, :big),
275
- :little => class_with_endian(saved_class, :little),
276
- }
277
- @the_class.define_singleton_method(:new) do |*args|
278
- if self == saved_class
279
- value, options, parent = arg_processor.separate_args(self, args)
280
- delegate = endian_classes[options[:endian]]
281
- return delegate.new(*args) if delegate
307
+ parser = bnl_class.dsl_parser
308
+ parser.define_singleton_method(:parse_and_append_field) do |*args, &block|
309
+ endian_classes[:big].send(*args, &block)
310
+ endian_classes[:little].send(*args, &block)
282
311
  end
283
-
284
- super(*args)
285
312
  end
286
- end
287
-
288
- def subclass_of_big_and_little_endian?
289
- parent = @the_class.superclass
290
- pparent = parent.superclass
291
313
 
292
- obj_attribute(parent, :endian) == :big_and_little and
293
- obj_attribute(pparent, :endian) == :big_and_little and
294
- [:big, :little].include?(@the_class.endian)
295
- end
314
+ def fixup_subclass_hierarchy(bnl_class)
315
+ parent = bnl_class.superclass
316
+ if obj_attribute(parent, :endian) == :big_and_little
317
+ be_subclass = class_with_endian(bnl_class, :big)
318
+ be_parent = class_with_endian(parent, :big)
319
+ be_fields = obj_attribute(be_parent, :fields)
320
+
321
+ le_subclass = class_with_endian(bnl_class, :little)
322
+ le_parent = class_with_endian(parent, :little)
323
+ le_fields = obj_attribute(le_parent, :fields)
324
+
325
+ be_subclass.dsl_parser.define_singleton_method(:parent_fields) do
326
+ be_fields
327
+ end
328
+ le_subclass.dsl_parser.define_singleton_method(:parent_fields) do
329
+ le_fields
330
+ end
331
+ end
332
+ end
296
333
 
297
- def class_with_endian(class_name, endian)
298
- RegisteredClasses.lookup(class_name, endian)
299
- end
334
+ def class_with_endian(class_name, endian)
335
+ hints = {
336
+ :endian => endian,
337
+ :search_prefix => class_name.dsl_parser.search_prefix,
338
+ }
339
+ RegisteredClasses.lookup(class_name, hints)
340
+ end
300
341
 
301
- def obj_attribute(obj, attr, default = nil)
302
- parser = obj.respond_to?(:dsl_parser) ? obj.dsl_parser : nil
303
- if parser and parser.respond_to?(attr)
304
- parser.send(attr)
305
- else
306
- default
342
+ def obj_attribute(obj, attr, default = nil)
343
+ parser = obj.respond_to?(:dsl_parser) ? obj.dsl_parser : nil
344
+ if parser and parser.respond_to?(attr)
345
+ parser.send(attr)
346
+ else
347
+ default
348
+ end
307
349
  end
308
350
  end
309
351
  end
310
352
 
311
353
  # Extracts the details from a field declaration.
312
354
  class DSLFieldParser
313
- def initialize(endian, symbol, *args, &block)
314
- @endian = endian
355
+ def initialize(hints, symbol, *args, &block)
356
+ @hints = hints
315
357
  @type = symbol
316
358
  @name = name_from_field_declaration(args)
317
359
  @params = params_from_field_declaration(args, &block)
@@ -355,7 +397,8 @@ module BinData
355
397
 
356
398
  if bindata_classes.include?(@type)
357
399
  parser = DSLParser.new(bindata_classes[@type], @type)
358
- parser.endian(@endian)
400
+ parser.endian(@hints[:endian])
401
+ parser.search_prefix(*@hints[:search_prefix])
359
402
  parser.instance_eval(&block)
360
403
 
361
404
  parser.dsl_params