bindata 2.4.15 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.rdoc +11 -0
  3. data/README.md +6 -9
  4. data/bindata.gemspec +3 -3
  5. data/examples/list.rb +1 -1
  6. data/lib/bindata/alignment.rb +15 -7
  7. data/lib/bindata/array.rb +54 -54
  8. data/lib/bindata/base.rb +14 -25
  9. data/lib/bindata/base_primitive.rb +24 -20
  10. data/lib/bindata/bits.rb +5 -5
  11. data/lib/bindata/buffer.rb +89 -11
  12. data/lib/bindata/choice.rb +9 -6
  13. data/lib/bindata/count_bytes_remaining.rb +1 -1
  14. data/lib/bindata/delayed_io.rb +10 -10
  15. data/lib/bindata/dsl.rb +34 -32
  16. data/lib/bindata/float.rb +3 -3
  17. data/lib/bindata/framework.rb +8 -10
  18. data/lib/bindata/int.rb +9 -9
  19. data/lib/bindata/io.rb +276 -253
  20. data/lib/bindata/name.rb +1 -1
  21. data/lib/bindata/params.rb +9 -7
  22. data/lib/bindata/primitive.rb +3 -3
  23. data/lib/bindata/registry.rb +18 -18
  24. data/lib/bindata/rest.rb +1 -1
  25. data/lib/bindata/sanitize.rb +9 -16
  26. data/lib/bindata/section.rb +97 -0
  27. data/lib/bindata/skip.rb +140 -51
  28. data/lib/bindata/string.rb +9 -9
  29. data/lib/bindata/stringz.rb +12 -10
  30. data/lib/bindata/struct.rb +83 -66
  31. data/lib/bindata/trace.rb +35 -42
  32. data/lib/bindata/transform/brotli.rb +35 -0
  33. data/lib/bindata/transform/lz4.rb +35 -0
  34. data/lib/bindata/transform/lzma.rb +35 -0
  35. data/lib/bindata/transform/xor.rb +19 -0
  36. data/lib/bindata/transform/xz.rb +35 -0
  37. data/lib/bindata/transform/zlib.rb +33 -0
  38. data/lib/bindata/transform/zstd.rb +35 -0
  39. data/lib/bindata/uint8_array.rb +2 -2
  40. data/lib/bindata/version.rb +1 -1
  41. data/lib/bindata/virtual.rb +4 -7
  42. data/lib/bindata/warnings.rb +1 -1
  43. data/lib/bindata.rb +1 -0
  44. data/test/array_test.rb +10 -8
  45. data/test/buffer_test.rb +9 -0
  46. data/test/choice_test.rb +1 -1
  47. data/test/delayed_io_test.rb +16 -0
  48. data/test/io_test.rb +54 -246
  49. data/test/registry_test.rb +1 -1
  50. data/test/section_test.rb +111 -0
  51. data/test/skip_test.rb +55 -10
  52. data/test/string_test.rb +4 -4
  53. data/test/stringz_test.rb +8 -0
  54. data/test/struct_test.rb +87 -12
  55. data/test/system_test.rb +119 -1
  56. data/test/test_helper.rb +24 -13
  57. data/test/warnings_test.rb +12 -0
  58. metadata +17 -16
  59. data/lib/bindata/offset.rb +0 -94
  60. data/test/offset_test.rb +0 -100
data/test/string_test.rb CHANGED
@@ -298,15 +298,15 @@ end
298
298
  describe BinData::String, "warnings" do
299
299
  it "warns if has :asserted_value but no :length" do
300
300
  obj = BinData::String.new(asserted_value: "ABC")
301
- obj.must_warn "obj does not have a :read_length parameter - returning empty string" do
301
+ _ {
302
302
  _ { obj.read("abcde") }.must_raise BinData::ValidityError
303
- end
303
+ }.must_warn "obj does not have a :read_length parameter - returning empty string"
304
304
  end
305
305
 
306
306
  it "warns if has :value but no :read_length" do
307
307
  obj = BinData::String.new(value: "ABC")
308
- obj.must_warn "obj does not have a :read_length parameter - returning empty string" do
308
+ _ {
309
309
  obj.read("abcde")
310
- end
310
+ }.must_warn "obj does not have a :read_length parameter - returning empty string"
311
311
  end
312
312
  end
data/test/stringz_test.rb CHANGED
@@ -76,6 +76,14 @@ end
76
76
  describe BinData::Stringz, "with max_length" do
77
77
  let(:obj) { BinData::Stringz.new(max_length: 5) }
78
78
 
79
+ it "fails if max_length is less that 1" do
80
+ obj = BinData::Stringz.new(max_length: 0)
81
+
82
+ _{ obj.read "abc\0" }.must_raise ArgumentError
83
+ _{ obj.to_binary_s }.must_raise ArgumentError
84
+ _{ obj.num_bytes }.must_raise ArgumentError
85
+ end
86
+
79
87
  it "reads less than max_length" do
80
88
  io = StringIO.new("abc\0xyz")
81
89
  obj.read(io)
data/test/struct_test.rb CHANGED
@@ -45,24 +45,65 @@ describe BinData::Struct, "with anonymous fields" do
45
45
  params = { fields: [
46
46
  [:int8, :a, {initial_value: 5}],
47
47
  [:int8, nil],
48
- [:int8, '', {value: :a}]
48
+ [:int8, '', {value: :a}],
49
+ [:int8, :b]
49
50
  ] }
50
51
  BinData::Struct.new(params)
51
52
  }
52
53
 
53
54
  it "only shows non anonymous fields" do
54
- _(obj.field_names).must_equal [:a]
55
+ _(obj.field_names).must_equal [:a, :b]
55
56
  end
56
57
 
57
58
  it "does not include anonymous fields in snapshot" do
58
- obj.a = 5
59
- _(obj.snapshot).must_equal({a: 5})
59
+ obj.a = 6
60
+ _(obj.snapshot).must_equal({a: 6, b: 0})
60
61
  end
61
62
 
62
63
  it "writes anonymous fields" do
63
- obj.read("\001\002\003")
64
+ obj.read("\001\002\003\004")
64
65
  obj.a.clear
65
- _(obj.to_binary_s).must_equal_binary "\005\002\005"
66
+ _(obj.to_binary_s).must_equal_binary "\005\002\005\004"
67
+ end
68
+
69
+ it "does not include anonymous fields in each_pair" do
70
+ _(obj.each_pair.count).must_equal 2
71
+ end
72
+
73
+ it "includes anonymous fields in each_pair when specified" do
74
+ _(obj.each_pair(true).count).must_equal 4
75
+ end
76
+
77
+ it "clears" do
78
+ obj.b = 3
79
+ refute obj.clear?
80
+
81
+ obj.clear
82
+ assert obj.clear?
83
+ end
84
+ end
85
+
86
+ describe BinData::Struct, "with onlyif fields" do
87
+ let(:obj) {
88
+ params = { fields: [
89
+ [:int8, :a, {initial_value: 2}],
90
+ [:int8, :b, {onlyif: -> { a.odd? }}]
91
+ ] }
92
+ BinData::Struct.new(params)
93
+ }
94
+
95
+ it "#fieldnames includes all fields" do
96
+ _(obj.field_names).must_equal [:a, :b]
97
+ end
98
+
99
+ it "#snapshot checks for onlyif" do
100
+ _(obj.snapshot.keys).must_equal [:a]
101
+ end
102
+
103
+ it "includes fields when required" do
104
+ refute obj.b?
105
+ obj.a = 3
106
+ assert obj.b?
66
107
  end
67
108
  end
68
109
 
@@ -140,10 +181,16 @@ describe BinData::Struct, "with multiple fields" do
140
181
  _(obj[:a]).must_equal 1
141
182
  end
142
183
 
143
- it "handles not existing elements" do
184
+ it "handles nonexistent elements" do
144
185
  _(obj[:does_not_exist]).must_be_nil
145
186
  end
146
187
 
188
+ it "ignores setting nonexistent elements" do
189
+ snap = obj.snapshot
190
+ obj[:does_not_exist] = 3
191
+ _(obj.snapshot).must_equal snap
192
+ end
193
+
147
194
  it "writes elements dynamically" do
148
195
  obj[:a] = 2
149
196
  _(obj.a).must_equal 2
@@ -225,6 +272,20 @@ describe BinData::Struct, "with multiple fields" do
225
272
  obj.snapshot.each_pair { |k, v| keys << k }
226
273
  _(keys).must_equal [:a, :b]
227
274
  end
275
+
276
+ it "accesses field" do
277
+ _(obj.snapshot[:a]).must_equal 1
278
+ end
279
+
280
+ it "fails on unknown method call" do
281
+ _ { obj.snapshot.does_not_exist }.must_raise NoMethodError
282
+ end
283
+
284
+ it "will not set attribute with nil value" do
285
+ refute obj.snapshot.key?(:foo)
286
+ obj.snapshot[:foo] = nil
287
+ refute obj.snapshot.key?(:foo)
288
+ end
228
289
  end
229
290
  end
230
291
 
@@ -402,30 +463,44 @@ describe BinData::Struct, "with byte_align" do
402
463
  let(:obj) {
403
464
  params = { fields: [[:int8, :a],
404
465
  [:int8, :b, byte_align: 5],
405
- [:bit2, :c],
466
+ [:bit2, :c, onlyif: -> { a == 1}],
406
467
  [:int8, :d, byte_align: 3]] }
407
468
  BinData::Struct.new(params)
408
469
  }
409
470
 
410
471
  it "has #num_bytes" do
472
+ _(obj.num_bytes).must_equal 7
473
+ end
474
+
475
+ it "has #num_bytes with onlyif" do
476
+ obj.a = 1
411
477
  _(obj.num_bytes).must_equal 10
412
478
  end
413
479
 
414
- it "reads" do
480
+ it "reads with onlyif" do
415
481
  obj.read("\x01\x00\x00\x00\x00\x02\xc0\x00\x00\x04")
416
482
  _(obj.snapshot).must_equal({ a: 1, b: 2, c: 3, d: 4 })
417
483
  end
418
484
 
419
- it "writes" do
485
+ it "reads without onlyif" do
486
+ obj.read("\x00\x00\x00\x00\x00\x02\x04")
487
+ _(obj.snapshot).must_equal({ a: 0, b: 2, d: 4 })
488
+ end
489
+
490
+ it "writes with onlyif" do
420
491
  obj.assign(a: 1, b: 2, c: 3, d: 4)
421
492
  _(obj.to_binary_s).must_equal_binary "\x01\x00\x00\x00\x00\x02\xc0\x00\x00\x04"
422
493
  end
423
494
 
495
+ it "writes without onlyif" do
496
+ obj.assign(a: 0, b: 2, c: 3, d: 4)
497
+ _(obj.to_binary_s).must_equal_binary "\x00\x00\x00\x00\x00\x02\x04"
498
+ end
499
+
424
500
  it "has correct offsets" do
425
501
  _(obj.a.rel_offset).must_equal 0
426
502
  _(obj.b.rel_offset).must_equal 5
427
- _(obj.c.rel_offset).must_equal 6
428
- _(obj.d.rel_offset).must_equal 9
503
+ _(obj.d.rel_offset).must_equal 6
429
504
  end
430
505
  end
431
506
 
data/test/system_test.rb CHANGED
@@ -229,6 +229,19 @@ describe "Tracing" do
229
229
 
230
230
  _(io.value).must_equal "obj => \"000000000011111111112222222222...\n"
231
231
  end
232
+
233
+ it "can be nested" do
234
+ obj = BinData::String.new(read_length: 5)
235
+
236
+ io = StringIO.new
237
+ BinData::trace_reading(io) {
238
+ BinData::trace_reading(io) {
239
+ obj.read("12345")
240
+ }
241
+ }
242
+
243
+ _(io.value).must_equal "obj => \"12345\"\n"
244
+ end
232
245
  end
233
246
 
234
247
  describe "Forward referencing with Primitive" do
@@ -381,7 +394,7 @@ describe BinData::Record, "encoding" do
381
394
  end
382
395
 
383
396
  it "returns binary encoded data despite Encoding.default_internal" do
384
- w, $-w = $-w, false
397
+ w, $-w = $-w, nil
385
398
  before_enc = Encoding.default_internal
386
399
 
387
400
  begin
@@ -394,3 +407,108 @@ describe BinData::Record, "encoding" do
394
407
  end
395
408
  end
396
409
  end
410
+
411
+ describe BinData::Record, "buffer num_bytes" do
412
+ class BufferNumBytesRecord < BinData::Record
413
+ buffer :b, length: 10 do
414
+ int8 :a
415
+ count_bytes_remaining :nbytes
416
+ end
417
+ end
418
+
419
+ it "counts bytes remaining in the buffer" do
420
+ obj = BufferNumBytesRecord.read "12345678901234567890"
421
+ _(obj.b.nbytes).must_equal 9
422
+ end
423
+
424
+ it "counts bytes remaining in the buffer with short streams" do
425
+ obj = BufferNumBytesRecord.read "12345"
426
+ _(obj.b.nbytes).must_equal 4
427
+ end
428
+
429
+ it "assumes buffer is full with non-seekable short streams" do
430
+ rd, wr = IO::pipe
431
+ io = BinData::IO::Read.new(rd)
432
+ wr.write "12345"
433
+ wr.close
434
+
435
+ obj = BufferNumBytesRecord.read(io)
436
+ _(obj.b.nbytes).must_equal 9
437
+ rd.close
438
+ end
439
+ end
440
+
441
+ describe BinData::Buffer, "with seek_abs" do
442
+ class BufferSkipRecord < BinData::Record
443
+ endian :little
444
+ mandatory_parameter :seek_offset
445
+
446
+ uint8
447
+ buffer :buf, length: 5 do
448
+ uint8
449
+ uint8
450
+ skip to_abs_offset: :seek_offset
451
+ uint8 :a
452
+ end
453
+ uint8
454
+ end
455
+
456
+ let(:str) { "\001\002\003\004\005\006\007" }
457
+
458
+ ## TODO: enable this if we decide to allow backwards seeking
459
+ #backwards_seeking = false
460
+ #
461
+ #it "won't seek backwards before buffer" do
462
+ # skip unless backwards_seeking
463
+ # _ { BufferSkipRecord.new(seek_offset: 0).read(str) }.must_raise(IOError)
464
+ #end
465
+ #
466
+ #it "seeks backwards to start of buffer" do
467
+ # skip unless backwards_seeking
468
+ # obj = BufferSkipRecord.new(seek_offset: 1).read(str)
469
+ # _(obj.buf.a).must_equal 2
470
+ #end
471
+ #
472
+ #it "seeks backwards inside buffer" do
473
+ # skip unless backwards_seeking
474
+ # obj = BufferSkipRecord.new(seek_offset: 2).read(str)
475
+ # _(obj.buf.a).must_equal 3
476
+ #end
477
+
478
+ it "seeks forwards inside buffer" do
479
+ obj = BufferSkipRecord.new(seek_offset: 4).read(str)
480
+ _(obj.buf.a).must_equal 5
481
+ end
482
+
483
+ it "seeks to end of buffer" do
484
+ obj = BufferSkipRecord.new(seek_offset: 5).read(str)
485
+ _(obj.buf.a).must_equal 6
486
+ end
487
+
488
+ it "won't seek after buffer" do
489
+ _ { BufferSkipRecord.new(seek_offset: 6).read(str) }.must_raise(IOError)
490
+ end
491
+ end
492
+
493
+
494
+ describe BinData::Record, "buffered readahead" do
495
+ class BufferedReadaheadRecord < BinData::Record
496
+ buffer :a, length: 5 do
497
+ skip do
498
+ string read_length: 1, assert: "X"
499
+ end
500
+ string :b, read_length: 1
501
+ end
502
+ string :c, read_length: 1
503
+ end
504
+
505
+ it "reads ahead inside the buffer" do
506
+ obj = BufferedReadaheadRecord.read "12X4567890"
507
+ _(obj.a.b).must_equal "X"
508
+ _(obj.c).must_equal "6"
509
+ end
510
+
511
+ it "doesn't readahead outside the buffer" do
512
+ _ { BufferedReadaheadRecord.read "123456X890" }.must_raise IOError
513
+ end
514
+ end
data/test/test_helper.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require 'rubygems'
2
2
 
3
- require 'coveralls'
4
- Coveralls.wear!
3
+ require 'simplecov'
4
+ SimpleCov.start do
5
+ enable_coverage :branch
6
+ end
5
7
 
6
8
  require 'minitest/autorun'
7
9
  require 'stringio'
@@ -30,32 +32,41 @@ module Kernel
30
32
  def value_read_from_written
31
33
  self.class.read(self.to_binary_s)
32
34
  end
35
+ end
33
36
 
34
- def must_equal_binary(expected)
35
- must_equal expected.dup.force_encoding(Encoding::BINARY)
37
+ module Minitest::Assertions
38
+ def assert_equals_binary(expected, actual)
39
+ assert_equal expected.dup.force_encoding(Encoding::BINARY), actual
36
40
  end
37
41
 
38
- def must_raise_on_line(exp, line, msg = nil)
39
- ex = self.must_raise exp
40
- (ex.message).must_equal msg if msg
42
+ def assert_raises_on_line(exp, line, msg = nil, &block)
43
+ ex = assert_raises(exp, &block)
44
+ assert_equal(msg, ex.message) if msg
41
45
 
42
- idx = ex.backtrace.find_index { |bt| /:in `must_raise_on_line'$/ =~ bt }
46
+ idx = ex.backtrace.find_index { |bt| /:in `assert_raises_on_line'$/ =~ bt }
43
47
 
44
48
  line_num_regex = /.*:(\d+)(:.*|$)/
45
49
  err_line = line_num_regex.match(ex.backtrace[0])[1].to_i
46
- ref_line = line_num_regex.match(ex.backtrace[idx + 1])[1].to_i
50
+ ref_line = line_num_regex.match(ex.backtrace[idx + 2])[1].to_i
47
51
 
48
- (err_line - ref_line).must_equal line
52
+ assert_equal((err_line - ref_line), line)
49
53
  end
50
54
 
51
- def must_warn(msg, &block)
55
+ def assert_warns(msg, &block)
52
56
  result = ""
53
57
  callable = proc { |str|
54
58
  result = str
55
59
  }
56
- self.stub(:warn, callable) do
60
+ Kernel.stub(:warn, callable) do
57
61
  block.call
58
62
  end
59
- (result).must_equal msg
63
+
64
+ assert_equal msg, result
60
65
  end
61
66
  end
67
+
68
+ module Minitest::Expectations
69
+ infect_an_assertion :assert_equals_binary, :must_equal_binary
70
+ infect_an_assertion :assert_raises_on_line, :must_raise_on_line, :block
71
+ infect_an_assertion :assert_warns, :must_warn, :block
72
+ end
@@ -15,6 +15,18 @@ describe BinData::Base, "when defining" do
15
15
  }.must_raise RuntimeError
16
16
  end
17
17
 
18
+ it "fails if #initialize is overridden on BasePrimitive" do
19
+ class BasePrimitiveWithInitialize < BinData::String
20
+ def initialize(params = {}, parent = nil)
21
+ super
22
+ end
23
+ end
24
+
25
+ _ {
26
+ BasePrimitiveWithInitialize.new
27
+ }.must_raise RuntimeError
28
+ end
29
+
18
30
  it "handles if #initialize is naively renamed to #initialize_instance" do
19
31
  class BaseWithInitializeInstance < BinData::Base
20
32
  def initialize_instance(params = {}, parent = nil)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bindata
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.15
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dion Mendel
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-07 00:00:00.000000000 Z
11
+ date: 1980-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -31,9 +31,6 @@ dependencies:
31
31
  - - ">"
32
32
  - !ruby/object:Gem::Version
33
33
  version: 5.0.0
34
- - - "<"
35
- - !ruby/object:Gem::Version
36
- version: 5.12.0
37
34
  type: :development
38
35
  prerelease: false
39
36
  version_requirements: !ruby/object:Gem::Requirement
@@ -41,11 +38,8 @@ dependencies:
41
38
  - - ">"
42
39
  - !ruby/object:Gem::Version
43
40
  version: 5.0.0
44
- - - "<"
45
- - !ruby/object:Gem::Version
46
- version: 5.12.0
47
41
  - !ruby/object:Gem::Dependency
48
- name: coveralls
42
+ name: simplecov
49
43
  requirement: !ruby/object:Gem::Requirement
50
44
  requirements:
51
45
  - - ">="
@@ -101,18 +95,25 @@ files:
101
95
  - lib/bindata/io.rb
102
96
  - lib/bindata/lazy.rb
103
97
  - lib/bindata/name.rb
104
- - lib/bindata/offset.rb
105
98
  - lib/bindata/params.rb
106
99
  - lib/bindata/primitive.rb
107
100
  - lib/bindata/record.rb
108
101
  - lib/bindata/registry.rb
109
102
  - lib/bindata/rest.rb
110
103
  - lib/bindata/sanitize.rb
104
+ - lib/bindata/section.rb
111
105
  - lib/bindata/skip.rb
112
106
  - lib/bindata/string.rb
113
107
  - lib/bindata/stringz.rb
114
108
  - lib/bindata/struct.rb
115
109
  - lib/bindata/trace.rb
110
+ - lib/bindata/transform/brotli.rb
111
+ - lib/bindata/transform/lz4.rb
112
+ - lib/bindata/transform/lzma.rb
113
+ - lib/bindata/transform/xor.rb
114
+ - lib/bindata/transform/xz.rb
115
+ - lib/bindata/transform/zlib.rb
116
+ - lib/bindata/transform/zstd.rb
116
117
  - lib/bindata/uint8_array.rb
117
118
  - lib/bindata/version.rb
118
119
  - lib/bindata/virtual.rb
@@ -130,12 +131,12 @@ files:
130
131
  - test/int_test.rb
131
132
  - test/io_test.rb
132
133
  - test/lazy_test.rb
133
- - test/offset_test.rb
134
134
  - test/params_test.rb
135
135
  - test/primitive_test.rb
136
136
  - test/record_test.rb
137
137
  - test/registry_test.rb
138
138
  - test/rest_test.rb
139
+ - test/section_test.rb
139
140
  - test/skip_test.rb
140
141
  - test/string_test.rb
141
142
  - test/stringz_test.rb
@@ -149,7 +150,7 @@ homepage: https://github.com/dmendel/bindata
149
150
  licenses:
150
151
  - BSD-2-Clause
151
152
  metadata: {}
152
- post_install_message:
153
+ post_install_message:
153
154
  rdoc_options:
154
155
  - "--main"
155
156
  - NEWS.rdoc
@@ -159,15 +160,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
159
160
  requirements:
160
161
  - - ">="
161
162
  - !ruby/object:Gem::Version
162
- version: 2.4.0
163
+ version: 2.5.0
163
164
  required_rubygems_version: !ruby/object:Gem::Requirement
164
165
  requirements:
165
166
  - - ">="
166
167
  - !ruby/object:Gem::Version
167
168
  version: '0'
168
169
  requirements: []
169
- rubygems_version: 3.3.7
170
- signing_key:
170
+ rubygems_version: 3.4.22
171
+ signing_key:
171
172
  specification_version: 4
172
173
  summary: A declarative way to read and write binary file formats
173
174
  test_files: []
@@ -1,94 +0,0 @@
1
- module BinData
2
- # WARNING: THIS IS UNSUPPORTED!!
3
- #
4
- # This was a (failed) experimental feature that allowed seeking within the
5
- # input stream. It remains here for backwards compatability for the few
6
- # people that used it.
7
- #
8
- # The official way to skip around the stream is to use BinData::Skip with
9
- # the `:to_abs_offset` parameter.
10
- #
11
- # == Parameters
12
- #
13
- # Parameters may be provided at initialisation to control the behaviour of
14
- # an object. These parameters are:
15
- #
16
- # [<tt>:check_offset</tt>] Raise an error if the current IO offset doesn't
17
- # meet this criteria. A boolean return indicates
18
- # success or failure. Any other return is compared
19
- # to the current offset. The variable +offset+
20
- # is made available to any lambda assigned to
21
- # this parameter. This parameter is only checked
22
- # before reading.
23
- # [<tt>:adjust_offset</tt>] Ensures that the current IO offset is at this
24
- # position before reading. This is like
25
- # <tt>:check_offset</tt>, except that it will
26
- # adjust the IO offset instead of raising an error.
27
- module CheckOrAdjustOffsetPlugin
28
-
29
- def self.included(base) #:nodoc:
30
- base.optional_parameters :check_offset, :adjust_offset
31
- base.mutually_exclusive_parameters :check_offset, :adjust_offset
32
- end
33
-
34
- def initialize_shared_instance
35
- extend CheckOffsetMixin if has_parameter?(:check_offset)
36
- extend AdjustOffsetMixin if has_parameter?(:adjust_offset)
37
- super
38
- end
39
-
40
- module CheckOffsetMixin
41
- def do_read(io) #:nodoc:
42
- check_offset(io)
43
- super(io)
44
- end
45
-
46
- #---------------
47
- private
48
-
49
- def check_offset(io)
50
- actual_offset = io.offset
51
- expected = eval_parameter(:check_offset, offset: actual_offset)
52
-
53
- if !expected
54
- raise ValidityError, "offset not as expected for #{debug_name}"
55
- elsif actual_offset != expected && expected != true
56
- raise ValidityError,
57
- "offset is '#{actual_offset}' but " +
58
- "expected '#{expected}' for #{debug_name}"
59
- end
60
- end
61
- end
62
-
63
- module AdjustOffsetMixin
64
- def do_read(io) #:nodoc:
65
- adjust_offset(io)
66
- super(io)
67
- end
68
-
69
- #---------------
70
- private
71
-
72
- def adjust_offset(io)
73
- actual_offset = io.offset
74
- expected = eval_parameter(:adjust_offset)
75
- if actual_offset != expected
76
- begin
77
- seek = expected - actual_offset
78
- io.seekbytes(seek)
79
- warn "adjusting stream position by #{seek} bytes" if $VERBOSE
80
- rescue
81
- raise ValidityError,
82
- "offset is '#{actual_offset}' but couldn't seek to " +
83
- "expected '#{expected}' for #{debug_name}"
84
- end
85
- end
86
- end
87
- end
88
- end
89
-
90
- # Add these offset options to Base
91
- class Base
92
- include CheckOrAdjustOffsetPlugin
93
- end
94
- end