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 +4 -4
- data/.travis.yml +7 -2
- data/COPYING +1 -1
- data/ChangeLog.rdoc +8 -0
- data/README.md +1 -1
- data/bindata.gemspec +1 -1
- data/lib/bindata.rb +6 -2
- data/lib/bindata/base.rb +5 -0
- data/lib/bindata/base_primitive.rb +2 -2
- data/lib/bindata/dsl.rb +142 -99
- data/lib/bindata/int.rb +50 -50
- data/lib/bindata/registry.rb +38 -14
- data/lib/bindata/sanitize.rb +33 -21
- data/lib/bindata/string.rb +16 -0
- data/lib/bindata/struct.rb +17 -2
- data/lib/bindata/version.rb +1 -1
- data/test/alignment_test.rb +3 -3
- data/test/array_test.rb +11 -11
- data/test/base_primitive_test.rb +21 -1
- data/test/base_test.rb +7 -1
- data/test/bits_test.rb +1 -1
- data/test/buffer_test.rb +6 -6
- data/test/choice_test.rb +14 -19
- data/test/count_bytes_remaining_test.rb +3 -3
- data/test/float_test.rb +5 -5
- data/test/int_test.rb +4 -4
- data/test/io_test.rb +1 -1
- data/test/lazy_test.rb +1 -1
- data/test/offset_test.rb +1 -1
- data/test/params_test.rb +1 -1
- data/test/primitive_test.rb +6 -6
- data/test/record_test.rb +86 -12
- data/test/registry_test.rb +43 -22
- data/test/rest_test.rb +2 -2
- data/test/skip_test.rb +4 -4
- data/test/string_test.rb +35 -7
- data/test/stringz_test.rb +6 -6
- data/test/struct_test.rb +56 -6
- data/test/system_test.rb +7 -7
- data/test/{common.rb → test_helper.rb} +11 -34
- data/test/virtual_test.rb +2 -2
- data/test/warnings_test.rb +1 -1
- metadata +16 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef9bdd3883fe70283af7a90ef1d7a7aabdbc1043
|
4
|
+
data.tar.gz: a0e441bd2a6fc0fcebe932b21737364baa53a373
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45b2a84cd80c08590463773919d93cb8aececa94fc391d620e897a4b3b1d2a512dd2e8f91c9ec608008b6007a1828ff1dae80938de1d961eab7403a802d1a696
|
7
|
+
data.tar.gz: 179ea9774c018fa6d90f2e864d99ae829ee8f41d8289fc30da514481b2dddff94c6b1e6ca9c316f98657a9cfee6c307f001d6d1449db713569c17cb171e06645
|
data/.travis.yml
CHANGED
data/COPYING
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
BinData is copyrighted free software by Dion Mendel <
|
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
|
|
data/ChangeLog.rdoc
CHANGED
@@ -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
data/bindata.gemspec
CHANGED
@@ -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 = '
|
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'
|
data/lib/bindata.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# BinData -- Binary data manipulator.
|
2
|
-
# Copyright (c) 2007 -
|
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 -
|
43
|
+
# Copyright (c) 2007 - 2016 Dion Mendel.
|
data/lib/bindata/base.rb
CHANGED
@@ -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(:
|
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(:
|
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
|
data/lib/bindata/dsl.rb
CHANGED
@@ -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
|
-
|
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 =
|
102
|
-
@fields = SanitizedFields.new(
|
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
|
-
|
115
|
-
|
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
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
-
|
155
|
+
def hints
|
156
|
+
{
|
157
|
+
:endian => endian,
|
158
|
+
:search_prefix => search_prefix,
|
159
|
+
}
|
151
160
|
end
|
152
161
|
|
153
|
-
def
|
154
|
-
|
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
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
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(
|
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
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
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
|
-
|
250
|
-
|
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
|
-
|
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
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
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
|
-
|
268
|
-
|
269
|
-
|
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
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
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
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
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
|
-
|
298
|
-
|
299
|
-
|
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
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
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(
|
314
|
-
@
|
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
|