bindata 2.4.15 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.rdoc +11 -0
- data/README.md +6 -9
- data/bindata.gemspec +3 -3
- data/examples/list.rb +1 -1
- data/lib/bindata/alignment.rb +15 -7
- data/lib/bindata/array.rb +54 -54
- data/lib/bindata/base.rb +14 -25
- data/lib/bindata/base_primitive.rb +24 -20
- data/lib/bindata/bits.rb +5 -5
- data/lib/bindata/buffer.rb +89 -11
- data/lib/bindata/choice.rb +9 -6
- data/lib/bindata/count_bytes_remaining.rb +1 -1
- data/lib/bindata/delayed_io.rb +10 -10
- data/lib/bindata/dsl.rb +34 -32
- data/lib/bindata/float.rb +3 -3
- data/lib/bindata/framework.rb +8 -10
- data/lib/bindata/int.rb +9 -9
- data/lib/bindata/io.rb +276 -253
- data/lib/bindata/name.rb +1 -1
- data/lib/bindata/params.rb +9 -7
- data/lib/bindata/primitive.rb +3 -3
- data/lib/bindata/registry.rb +18 -18
- data/lib/bindata/rest.rb +1 -1
- data/lib/bindata/sanitize.rb +9 -16
- data/lib/bindata/section.rb +97 -0
- data/lib/bindata/skip.rb +140 -51
- data/lib/bindata/string.rb +9 -9
- data/lib/bindata/stringz.rb +12 -10
- data/lib/bindata/struct.rb +83 -66
- data/lib/bindata/trace.rb +35 -42
- data/lib/bindata/transform/brotli.rb +35 -0
- data/lib/bindata/transform/lz4.rb +35 -0
- data/lib/bindata/transform/lzma.rb +35 -0
- data/lib/bindata/transform/xor.rb +19 -0
- data/lib/bindata/transform/xz.rb +35 -0
- data/lib/bindata/transform/zlib.rb +33 -0
- data/lib/bindata/transform/zstd.rb +35 -0
- data/lib/bindata/uint8_array.rb +2 -2
- data/lib/bindata/version.rb +1 -1
- data/lib/bindata/virtual.rb +4 -7
- data/lib/bindata/warnings.rb +1 -1
- data/lib/bindata.rb +1 -0
- data/test/array_test.rb +10 -8
- data/test/buffer_test.rb +9 -0
- data/test/choice_test.rb +1 -1
- data/test/delayed_io_test.rb +16 -0
- data/test/io_test.rb +54 -246
- data/test/registry_test.rb +1 -1
- data/test/section_test.rb +111 -0
- data/test/skip_test.rb +55 -10
- data/test/string_test.rb +4 -4
- data/test/stringz_test.rb +8 -0
- data/test/struct_test.rb +87 -12
- data/test/system_test.rb +119 -1
- data/test/test_helper.rb +24 -13
- data/test/warnings_test.rb +12 -0
- metadata +17 -16
- data/lib/bindata/offset.rb +0 -94
- data/test/offset_test.rb +0 -100
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6fb38e8b0ef072a6acb74e9a623307791ba9619423e445635bf949c6ede9a90a
|
4
|
+
data.tar.gz: 026e68ad13001b0ae2922bbe909882d5bec2c44c3380ab894cf73e3fbce8de61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a46d236c6206417f271782956e3aaa376f793ef9cc58f88de92577b10537a5cd2ce8cc8f2399e1a58d0bb1f1ab749d57f0ea6aa8532c78fd80dc0e998b3abb4
|
7
|
+
data.tar.gz: a1d2988f1bcfda8c3f1177338d34b5af0e7f62dd4eea55905ef3c49e5cb989a7b07e30d1b7d42606a4ca005bcfa3ef034829520b52df86ca9bafe25cb7f2bf1c
|
data/ChangeLog.rdoc
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
= BinData Changelog
|
2
2
|
|
3
|
+
== Version 2.5.0 (2024-02-16)
|
4
|
+
|
5
|
+
* Removed experimental :check_offset and :adjust_offset parameters.
|
6
|
+
* Ruby 2.5 is now required.
|
7
|
+
* Allow for nested tracing.
|
8
|
+
* Skip :until_valid is now fast for :asserted_value.
|
9
|
+
* Added Section - a way to transform the data stream.
|
10
|
+
* Added transforms for brotli, lz4, xor, zlib, zstd.
|
11
|
+
* Updated to current minitest
|
12
|
+
* Fixed typos. Thanks to Patrick Linnane.
|
13
|
+
|
3
14
|
== Version 2.4.15 (2023-02-07)
|
4
15
|
|
5
16
|
* Added ruby 2.4.0 requirement to gemspec. Thanks to theldoria.
|
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# What is BinData?
|
2
2
|
|
3
|
-
[![
|
4
|
-
[![
|
5
|
-
[![
|
3
|
+
[![Github CI](https://github.com/dmendel/bindata/actions/workflows/ci.yml/badge.svg)](https://github.com/dmendel/bindata/actions/workflows/ci.yml)
|
4
|
+
[![Version](https://img.shields.io/gem/v/bindata.svg)](https://rubygems.org/gems/bindata)
|
5
|
+
[![Downloads](https://img.shields.io/gem/dt/bindata.svg)](https://rubygems.org/gems/bindata)
|
6
|
+
[![Coverage](https://img.shields.io/coveralls/dmendel/bindata.svg)](https://coveralls.io/r/dmendel/bindata)
|
6
7
|
|
7
8
|
Do you ever find yourself writing code like this?
|
8
9
|
|
@@ -14,7 +15,7 @@ width, height = io.read(8).unpack("VV")
|
|
14
15
|
puts "Rectangle #{name} is #{width} x #{height}"
|
15
16
|
```
|
16
17
|
|
17
|
-
It’s ugly, violates DRY and
|
18
|
+
It’s ugly, violates DRY and doesn't feel like Ruby.
|
18
19
|
|
19
20
|
There is a better way. Here’s how you’d write the above using BinData.
|
20
21
|
|
@@ -47,13 +48,9 @@ for dependent and variable length fields is built in.
|
|
47
48
|
|
48
49
|
$ gem install bindata
|
49
50
|
|
50
|
-
or if running ruby 1.8
|
51
|
-
|
52
|
-
$ gem install bindata -v '~> 1.8.0'
|
53
|
-
|
54
51
|
# Documentation
|
55
52
|
|
56
|
-
[
|
53
|
+
[BinData manual](http://github.com/dmendel/bindata/wiki).
|
57
54
|
|
58
55
|
# Contact
|
59
56
|
|
data/bindata.gemspec
CHANGED
@@ -18,11 +18,11 @@ Gem::Specification.new do |s|
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
s.license = 'BSD-2-Clause'
|
21
|
-
s.required_ruby_version = ">= 2.
|
21
|
+
s.required_ruby_version = ">= 2.5.0"
|
22
22
|
|
23
23
|
s.add_development_dependency('rake')
|
24
|
-
s.add_development_dependency('minitest', "> 5.0.0"
|
25
|
-
s.add_development_dependency('
|
24
|
+
s.add_development_dependency('minitest', "> 5.0.0")
|
25
|
+
s.add_development_dependency('simplecov')
|
26
26
|
s.description = <<-END.gsub(/^ +/, "")
|
27
27
|
BinData is a declarative way to read and write binary file formats.
|
28
28
|
|
data/examples/list.rb
CHANGED
@@ -35,7 +35,7 @@ require 'bindata'
|
|
35
35
|
# end
|
36
36
|
# end
|
37
37
|
#
|
38
|
-
# Notice how we get stuck on
|
38
|
+
# Notice how we get stuck on attempting to write a declaration for
|
39
39
|
# the contents of the list. We can't determine if the list item is
|
40
40
|
# an atom or list because we haven't read it yet. It appears that
|
41
41
|
# we can't proceed.
|
data/lib/bindata/alignment.rb
CHANGED
@@ -19,11 +19,11 @@ module BinData
|
|
19
19
|
def do_num_bytes; 0; end
|
20
20
|
|
21
21
|
def do_read(io)
|
22
|
-
io.
|
22
|
+
io.readbytes(0)
|
23
23
|
end
|
24
24
|
|
25
25
|
def do_write(io)
|
26
|
-
io.
|
26
|
+
io.writebytes("")
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -45,18 +45,26 @@ module BinData
|
|
45
45
|
def initialize(io)
|
46
46
|
@io = io
|
47
47
|
end
|
48
|
+
|
49
|
+
def binary_string(str)
|
50
|
+
str.to_s.dup.force_encoding(Encoding::BINARY)
|
51
|
+
end
|
52
|
+
|
48
53
|
def readbytes(n)
|
49
|
-
n.times.inject("") do |bytes, _|
|
50
|
-
bytes
|
54
|
+
n.times.inject(binary_string("")) do |bytes, _|
|
55
|
+
bytes + @io.readbits(8, :big).chr
|
51
56
|
end
|
52
57
|
end
|
58
|
+
def writebytes(str)
|
59
|
+
str.each_byte { |v| @io.writebits(v, 8, :big) }
|
60
|
+
end
|
53
61
|
end
|
54
62
|
|
55
63
|
def bit_aligned?
|
56
64
|
true
|
57
65
|
end
|
58
66
|
|
59
|
-
def
|
67
|
+
def do_read(io)
|
60
68
|
super(BitAlignedIO.new(io))
|
61
69
|
end
|
62
70
|
|
@@ -65,7 +73,7 @@ module BinData
|
|
65
73
|
end
|
66
74
|
|
67
75
|
def do_write(io)
|
68
|
-
|
76
|
+
super(BitAlignedIO.new(io))
|
69
77
|
end
|
70
78
|
end
|
71
79
|
|
@@ -74,6 +82,6 @@ module BinData
|
|
74
82
|
end
|
75
83
|
|
76
84
|
def Primitive.bit_aligned
|
77
|
-
fail "'bit_aligned' is not
|
85
|
+
fail "'bit_aligned' is not supported for BinData::Primitives"
|
78
86
|
end
|
79
87
|
end
|
data/lib/bindata/array.rb
CHANGED
@@ -72,18 +72,18 @@ module BinData
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def initialize_instance
|
75
|
-
@
|
75
|
+
@elements = nil
|
76
76
|
end
|
77
77
|
|
78
78
|
def clear?
|
79
|
-
@
|
79
|
+
@elements.nil? || elements.all?(&:clear?)
|
80
80
|
end
|
81
81
|
|
82
82
|
def assign(array)
|
83
83
|
return if self.equal?(array) # prevent self assignment
|
84
84
|
raise ArgumentError, "can't set a nil value for #{debug_name}" if array.nil?
|
85
85
|
|
86
|
-
@
|
86
|
+
@elements = []
|
87
87
|
concat(array)
|
88
88
|
end
|
89
89
|
|
@@ -220,23 +220,23 @@ module BinData
|
|
220
220
|
elements.each { |el| yield el }
|
221
221
|
end
|
222
222
|
|
223
|
-
def debug_name_of(child)
|
223
|
+
def debug_name_of(child) # :nodoc:
|
224
224
|
index = find_index_of(child)
|
225
225
|
"#{debug_name}[#{index}]"
|
226
226
|
end
|
227
227
|
|
228
|
-
def offset_of(child)
|
228
|
+
def offset_of(child) # :nodoc:
|
229
229
|
index = find_index_of(child)
|
230
230
|
sum = sum_num_bytes_below_index(index)
|
231
231
|
|
232
232
|
child.bit_aligned? ? sum.floor : sum.ceil
|
233
233
|
end
|
234
234
|
|
235
|
-
def do_write(io)
|
235
|
+
def do_write(io) # :nodoc:
|
236
236
|
elements.each { |el| el.do_write(io) }
|
237
237
|
end
|
238
238
|
|
239
|
-
def do_num_bytes
|
239
|
+
def do_num_bytes # :nodoc:
|
240
240
|
sum_num_bytes_for_all_elements
|
241
241
|
end
|
242
242
|
|
@@ -251,7 +251,7 @@ module BinData
|
|
251
251
|
end
|
252
252
|
|
253
253
|
def elements
|
254
|
-
@
|
254
|
+
@elements ||= []
|
255
255
|
end
|
256
256
|
|
257
257
|
def append_new_element
|
@@ -279,66 +279,66 @@ module BinData
|
|
279
279
|
end
|
280
280
|
end
|
281
281
|
end
|
282
|
-
end
|
283
282
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
283
|
+
# Logic for the :read_until parameter
|
284
|
+
module ReadUntilPlugin
|
285
|
+
def do_read(io)
|
286
|
+
loop do
|
287
|
+
element = append_new_element
|
288
|
+
element.do_read(io)
|
289
|
+
variables = { index: self.length - 1, element: self.last, array: self }
|
290
|
+
break if eval_parameter(:read_until, variables)
|
291
|
+
end
|
289
292
|
end
|
290
|
-
|
291
|
-
params.warn_replacement_parameter(:length, :initial_length)
|
292
|
-
params.warn_replacement_parameter(:read_length, :initial_length)
|
293
|
-
params.must_be_integer(:initial_length)
|
294
|
-
|
295
|
-
params.merge!(obj_class.dsl_params)
|
296
|
-
params.sanitize_object_prototype(:type)
|
297
293
|
end
|
298
|
-
end
|
299
294
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
295
|
+
# Logic for the read_until: :eof parameter
|
296
|
+
module ReadUntilEOFPlugin
|
297
|
+
def do_read(io)
|
298
|
+
loop do
|
299
|
+
element = append_new_element
|
300
|
+
begin
|
301
|
+
element.do_read(io)
|
302
|
+
rescue EOFError, IOError
|
303
|
+
elements.pop
|
304
|
+
break
|
305
|
+
end
|
306
|
+
end
|
308
307
|
end
|
309
308
|
end
|
310
|
-
end
|
311
309
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
elements
|
321
|
-
|
310
|
+
# Logic for the :initial_length parameter
|
311
|
+
module InitialLengthPlugin
|
312
|
+
def do_read(io)
|
313
|
+
elements.each { |el| el.do_read(io) }
|
314
|
+
end
|
315
|
+
|
316
|
+
def elements
|
317
|
+
if @elements.nil?
|
318
|
+
@elements = []
|
319
|
+
eval_parameter(:initial_length).times do
|
320
|
+
@elements << new_element
|
321
|
+
end
|
322
322
|
end
|
323
|
+
|
324
|
+
@elements
|
323
325
|
end
|
324
326
|
end
|
325
327
|
end
|
326
328
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
def elements
|
334
|
-
if @element_list.nil?
|
335
|
-
@element_list = []
|
336
|
-
eval_parameter(:initial_length).times do
|
337
|
-
@element_list << new_element
|
338
|
-
end
|
329
|
+
class ArrayArgProcessor < BaseArgProcessor
|
330
|
+
def sanitize_parameters!(obj_class, params) # :nodoc:
|
331
|
+
# ensure one of :initial_length and :read_until exists
|
332
|
+
unless params.has_at_least_one_of?(:initial_length, :read_until)
|
333
|
+
params[:initial_length] = 0
|
339
334
|
end
|
340
335
|
|
341
|
-
|
336
|
+
params.warn_replacement_parameter(:length, :initial_length)
|
337
|
+
params.warn_replacement_parameter(:read_length, :initial_length)
|
338
|
+
params.must_be_integer(:initial_length)
|
339
|
+
|
340
|
+
params.merge!(obj_class.dsl_params)
|
341
|
+
params.sanitize_object_prototype(:type)
|
342
342
|
end
|
343
343
|
end
|
344
344
|
end
|
data/lib/bindata/base.rb
CHANGED
@@ -17,7 +17,7 @@ module BinData
|
|
17
17
|
# Instantiates this class and reads from +io+, returning the newly
|
18
18
|
# created data object. +args+ will be used when instantiating.
|
19
19
|
def read(io, *args, &block)
|
20
|
-
obj =
|
20
|
+
obj = new(*args)
|
21
21
|
obj.read(io, &block)
|
22
22
|
obj
|
23
23
|
end
|
@@ -48,7 +48,7 @@ module BinData
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# Registers all subclasses of this class for use
|
51
|
-
def register_subclasses
|
51
|
+
def register_subclasses # :nodoc:
|
52
52
|
singleton_class.send(:undef_method, :inherited)
|
53
53
|
define_singleton_method(:inherited) do |subclass|
|
54
54
|
RegisteredClasses.register(subclass.name, subclass)
|
@@ -90,6 +90,8 @@ module BinData
|
|
90
90
|
|
91
91
|
# Creates a new data object based on this instance.
|
92
92
|
#
|
93
|
+
# This implements the prototype design pattern.
|
94
|
+
#
|
93
95
|
# All parameters will be be duplicated. Use this method
|
94
96
|
# when creating multiple objects with the same parameters.
|
95
97
|
def new(value = nil, parent = nil)
|
@@ -117,8 +119,8 @@ module BinData
|
|
117
119
|
end
|
118
120
|
|
119
121
|
# Returns a lazy evaluator for this object.
|
120
|
-
def lazy_evaluator
|
121
|
-
@
|
122
|
+
def lazy_evaluator # :nodoc:
|
123
|
+
@lazy_evaluator ||= LazyEvaluator.new(self)
|
122
124
|
end
|
123
125
|
|
124
126
|
# Returns the parameter referenced by +key+.
|
@@ -177,7 +179,7 @@ module BinData
|
|
177
179
|
|
178
180
|
# Returns the hexadecimal string representation of this data object.
|
179
181
|
def to_hex(&block)
|
180
|
-
to_binary_s(&block).
|
182
|
+
to_binary_s(&block).unpack1('H*')
|
181
183
|
end
|
182
184
|
|
183
185
|
# Return a human readable representation of this data object.
|
@@ -191,7 +193,7 @@ module BinData
|
|
191
193
|
end
|
192
194
|
|
193
195
|
# Work with Ruby's pretty-printer library.
|
194
|
-
def pretty_print(pp)
|
196
|
+
def pretty_print(pp) # :nodoc:
|
195
197
|
pp.pp(snapshot)
|
196
198
|
end
|
197
199
|
|
@@ -202,40 +204,28 @@ module BinData
|
|
202
204
|
|
203
205
|
# Returns a user friendly name of this object for debugging purposes.
|
204
206
|
def debug_name
|
205
|
-
|
206
|
-
@parent.debug_name_of(self)
|
207
|
-
else
|
208
|
-
"obj"
|
209
|
-
end
|
207
|
+
@parent ? @parent.debug_name_of(self) : 'obj'
|
210
208
|
end
|
211
209
|
|
212
210
|
# Returns the offset (in bytes) of this object with respect to its most
|
213
211
|
# distant ancestor.
|
214
212
|
def abs_offset
|
215
|
-
|
216
|
-
@parent.abs_offset + @parent.offset_of(self)
|
217
|
-
else
|
218
|
-
0
|
219
|
-
end
|
213
|
+
@parent ? @parent.abs_offset + @parent.offset_of(self) : 0
|
220
214
|
end
|
221
215
|
|
222
216
|
# Returns the offset (in bytes) of this object with respect to its parent.
|
223
217
|
def rel_offset
|
224
|
-
|
225
|
-
@parent.offset_of(self)
|
226
|
-
else
|
227
|
-
0
|
228
|
-
end
|
218
|
+
@parent ? @parent.offset_of(self) : 0
|
229
219
|
end
|
230
220
|
|
231
|
-
def ==(other)
|
221
|
+
def ==(other) # :nodoc:
|
232
222
|
# double dispatch
|
233
223
|
other == snapshot
|
234
224
|
end
|
235
225
|
|
236
226
|
# A version of +respond_to?+ used by the lazy evaluator. It doesn't
|
237
227
|
# reinvoke the evaluator so as to avoid infinite evaluation loops.
|
238
|
-
def safe_respond_to?(symbol, include_private = false)
|
228
|
+
def safe_respond_to?(symbol, include_private = false) # :nodoc:
|
239
229
|
base_respond_to?(symbol, include_private)
|
240
230
|
end
|
241
231
|
|
@@ -329,7 +319,6 @@ module BinData
|
|
329
319
|
# Performs sanity checks on the given parameters.
|
330
320
|
# This method converts the parameters to the form expected
|
331
321
|
# by the data object.
|
332
|
-
def sanitize_parameters!(obj_class, obj_params)
|
333
|
-
end
|
322
|
+
def sanitize_parameters!(obj_class, obj_params); end
|
334
323
|
end
|
335
324
|
end
|
@@ -65,7 +65,7 @@ module BinData
|
|
65
65
|
@value = nil
|
66
66
|
end
|
67
67
|
|
68
|
-
def clear?
|
68
|
+
def clear? # :nodoc:
|
69
69
|
@value.nil?
|
70
70
|
end
|
71
71
|
|
@@ -73,13 +73,7 @@ module BinData
|
|
73
73
|
raise ArgumentError, "can't set a nil value for #{debug_name}" if val.nil?
|
74
74
|
|
75
75
|
raw_val = val.respond_to?(:snapshot) ? val.snapshot : val
|
76
|
-
@value =
|
77
|
-
begin
|
78
|
-
raw_val.dup
|
79
|
-
rescue TypeError
|
80
|
-
# can't dup Fixnums
|
81
|
-
raw_val
|
82
|
-
end
|
76
|
+
@value = raw_val.dup
|
83
77
|
end
|
84
78
|
|
85
79
|
def snapshot
|
@@ -94,18 +88,19 @@ module BinData
|
|
94
88
|
assign(val)
|
95
89
|
end
|
96
90
|
|
97
|
-
def
|
91
|
+
def respond_to_missing?(symbol, include_all = false) # :nodoc:
|
98
92
|
child = snapshot
|
99
|
-
child.respond_to?(symbol,
|
93
|
+
child.respond_to?(symbol, include_all) || super
|
100
94
|
end
|
101
95
|
|
102
|
-
def method_missing(symbol, *args, &block)
|
96
|
+
def method_missing(symbol, *args, &block) # :nodoc:
|
103
97
|
child = snapshot
|
104
98
|
if child.respond_to?(symbol)
|
105
|
-
self.class.class_eval
|
106
|
-
|
107
|
-
|
108
|
-
|
99
|
+
self.class.class_eval <<-END, __FILE__, __LINE__ + 1
|
100
|
+
def #{symbol}(*args, &block) # def clamp(*args, &block)
|
101
|
+
snapshot.#{symbol}(*args, &block) # snapshot.clamp(*args, &block)
|
102
|
+
end # end
|
103
|
+
END
|
109
104
|
child.__send__(symbol, *args, &block)
|
110
105
|
else
|
111
106
|
super
|
@@ -125,15 +120,15 @@ module BinData
|
|
125
120
|
snapshot.hash
|
126
121
|
end
|
127
122
|
|
128
|
-
def do_read(io)
|
123
|
+
def do_read(io) # :nodoc:
|
129
124
|
@value = read_and_return_value(io)
|
130
125
|
end
|
131
126
|
|
132
|
-
def do_write(io)
|
127
|
+
def do_write(io) # :nodoc:
|
133
128
|
io.writebytes(value_to_binary_string(_value))
|
134
129
|
end
|
135
130
|
|
136
|
-
def do_num_bytes
|
131
|
+
def do_num_bytes # :nodoc:
|
137
132
|
value_to_binary_string(_value).length
|
138
133
|
end
|
139
134
|
|
@@ -172,7 +167,7 @@ module BinData
|
|
172
167
|
assert!
|
173
168
|
end
|
174
169
|
|
175
|
-
def do_read(io)
|
170
|
+
def do_read(io) # :nodoc:
|
176
171
|
super(io)
|
177
172
|
assert!
|
178
173
|
end
|
@@ -205,7 +200,16 @@ module BinData
|
|
205
200
|
reading? ? @value : eval_parameter(:asserted_value)
|
206
201
|
end
|
207
202
|
|
208
|
-
|
203
|
+
# The asserted value as a binary string.
|
204
|
+
#
|
205
|
+
# Rationale: while reading, +#to_binary_s+ will use the
|
206
|
+
# value read in, rather than the +:asserted_value+.
|
207
|
+
# This feature is used by Skip.
|
208
|
+
def asserted_binary_s
|
209
|
+
value_to_binary_string(eval_parameter(:asserted_value))
|
210
|
+
end
|
211
|
+
|
212
|
+
def do_read(io) # :nodoc:
|
209
213
|
super(io)
|
210
214
|
assert!
|
211
215
|
end
|
data/lib/bindata/bits.rb
CHANGED
@@ -5,7 +5,7 @@ module BinData
|
|
5
5
|
# Defines a number of classes that contain a bit based integer.
|
6
6
|
# The integer is defined by endian and number of bits.
|
7
7
|
|
8
|
-
module BitField
|
8
|
+
module BitField # :nodoc: all
|
9
9
|
@@mutex = Mutex.new
|
10
10
|
|
11
11
|
class << self
|
@@ -156,10 +156,10 @@ module BinData
|
|
156
156
|
|
157
157
|
# Create classes for dynamic bitfields
|
158
158
|
{
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
159
|
+
'Bit' => :big,
|
160
|
+
'BitLe' => :little,
|
161
|
+
'Sbit' => [:big, :signed],
|
162
|
+
'SbitLe' => [:little, :signed]
|
163
163
|
}.each_pair { |name, args| BitField.define_class(name, :nbits, *args) }
|
164
164
|
|
165
165
|
# Create classes on demand
|
data/lib/bindata/buffer.rb
CHANGED
@@ -41,7 +41,7 @@ module BinData
|
|
41
41
|
# end
|
42
42
|
# end
|
43
43
|
# end
|
44
|
-
#
|
44
|
+
#
|
45
45
|
#
|
46
46
|
# == Parameters
|
47
47
|
#
|
@@ -80,29 +80,107 @@ module BinData
|
|
80
80
|
@type.snapshot
|
81
81
|
end
|
82
82
|
|
83
|
-
def
|
84
|
-
@type.respond_to?(symbol,
|
83
|
+
def respond_to_missing?(symbol, include_all = false) # :nodoc:
|
84
|
+
@type.respond_to?(symbol, include_all) || super
|
85
85
|
end
|
86
86
|
|
87
|
-
def method_missing(symbol, *args, &block)
|
87
|
+
def method_missing(symbol, *args, &block) # :nodoc:
|
88
88
|
@type.__send__(symbol, *args, &block)
|
89
89
|
end
|
90
90
|
|
91
|
-
def do_read(io)
|
92
|
-
|
93
|
-
|
91
|
+
def do_read(io) # :nodoc:
|
92
|
+
buf_len = eval_parameter(:length)
|
93
|
+
io.transform(BufferIO.new(buf_len)) do |transformed_io, _|
|
94
|
+
@type.do_read(transformed_io)
|
94
95
|
end
|
95
96
|
end
|
96
97
|
|
97
|
-
def do_write(io)
|
98
|
-
|
99
|
-
|
98
|
+
def do_write(io) # :nodoc:
|
99
|
+
buf_len = eval_parameter(:length)
|
100
|
+
io.transform(BufferIO.new(buf_len)) do |transformed_io, _|
|
101
|
+
@type.do_write(transformed_io)
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
103
|
-
def do_num_bytes
|
105
|
+
def do_num_bytes # :nodoc:
|
104
106
|
eval_parameter(:length)
|
105
107
|
end
|
108
|
+
|
109
|
+
# Transforms the IO stream to restrict access inside
|
110
|
+
# a buffer of specified length.
|
111
|
+
class BufferIO < IO::Transform
|
112
|
+
def initialize(length)
|
113
|
+
super()
|
114
|
+
@bytes_remaining = length
|
115
|
+
end
|
116
|
+
|
117
|
+
def before_transform
|
118
|
+
@buf_start = offset
|
119
|
+
@buf_end = @buf_start + @bytes_remaining
|
120
|
+
end
|
121
|
+
|
122
|
+
def num_bytes_remaining
|
123
|
+
[@bytes_remaining, super].min
|
124
|
+
rescue IOError
|
125
|
+
@bytes_remaining
|
126
|
+
end
|
127
|
+
|
128
|
+
def skip(n)
|
129
|
+
nbytes = buffer_limited_n(n)
|
130
|
+
@bytes_remaining -= nbytes
|
131
|
+
|
132
|
+
chain_skip(nbytes)
|
133
|
+
end
|
134
|
+
|
135
|
+
def seek_abs(n)
|
136
|
+
if n < @buf_start || n >= @buf_end
|
137
|
+
raise IOError, "can not seek to abs_offset outside of buffer"
|
138
|
+
end
|
139
|
+
|
140
|
+
@bytes_remaining -= (n - offset)
|
141
|
+
chain_seek_abs(n)
|
142
|
+
end
|
143
|
+
|
144
|
+
def read(n)
|
145
|
+
nbytes = buffer_limited_n(n)
|
146
|
+
@bytes_remaining -= nbytes
|
147
|
+
|
148
|
+
chain_read(nbytes)
|
149
|
+
end
|
150
|
+
|
151
|
+
def write(data)
|
152
|
+
nbytes = buffer_limited_n(data.size)
|
153
|
+
@bytes_remaining -= nbytes
|
154
|
+
if nbytes < data.size
|
155
|
+
data = data[0, nbytes]
|
156
|
+
end
|
157
|
+
|
158
|
+
chain_write(data)
|
159
|
+
end
|
160
|
+
|
161
|
+
def after_read_transform
|
162
|
+
read(nil)
|
163
|
+
end
|
164
|
+
|
165
|
+
def after_write_transform
|
166
|
+
write("\x00" * @bytes_remaining)
|
167
|
+
end
|
168
|
+
|
169
|
+
def buffer_limited_n(n)
|
170
|
+
if n.nil?
|
171
|
+
@bytes_remaining
|
172
|
+
elsif n.positive?
|
173
|
+
limit = @bytes_remaining
|
174
|
+
n > limit ? limit : n
|
175
|
+
# uncomment if we decide to allow backwards skipping
|
176
|
+
# elsif n.negative?
|
177
|
+
# limit = @bytes_remaining + @buf_start - @buf_end
|
178
|
+
# n < limit ? limit : n
|
179
|
+
else
|
180
|
+
0
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
106
184
|
end
|
107
185
|
|
108
186
|
class BufferArgProcessor < BaseArgProcessor
|