bindata 1.2.2 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bindata might be problematic. Click here for more details.
- data/ChangeLog +12 -0
- data/NEWS +53 -0
- data/Rakefile +2 -1
- data/examples/NBT.txt +149 -0
- data/examples/ip_address.rb +1 -2
- data/examples/list.rb +124 -0
- data/examples/nbt.rb +195 -0
- data/lib/bindata.rb +4 -3
- data/lib/bindata/alignment.rb +86 -0
- data/lib/bindata/array.rb +21 -29
- data/lib/bindata/base.rb +82 -81
- data/lib/bindata/base_primitive.rb +66 -48
- data/lib/bindata/choice.rb +18 -28
- data/lib/bindata/deprecated.rb +17 -0
- data/lib/bindata/dsl.rb +25 -15
- data/lib/bindata/int.rb +2 -2
- data/lib/bindata/io.rb +8 -6
- data/lib/bindata/offset.rb +91 -0
- data/lib/bindata/primitive.rb +22 -11
- data/lib/bindata/record.rb +40 -10
- data/lib/bindata/sanitize.rb +15 -30
- data/lib/bindata/string.rb +16 -17
- data/lib/bindata/stringz.rb +0 -1
- data/lib/bindata/struct.rb +17 -6
- data/lib/bindata/trace.rb +52 -0
- data/lib/bindata/wrapper.rb +28 -6
- data/manual.haml +56 -10
- data/manual.md +318 -113
- data/spec/alignment_spec.rb +61 -0
- data/spec/array_spec.rb +139 -178
- data/spec/base_primitive_spec.rb +86 -111
- data/spec/base_spec.rb +200 -172
- data/spec/bits_spec.rb +45 -53
- data/spec/choice_spec.rb +91 -87
- data/spec/deprecated_spec.rb +36 -14
- data/spec/float_spec.rb +16 -68
- data/spec/int_spec.rb +26 -27
- data/spec/io_spec.rb +105 -105
- data/spec/lazy_spec.rb +50 -50
- data/spec/primitive_spec.rb +36 -36
- data/spec/record_spec.rb +134 -134
- data/spec/registry_spec.rb +34 -38
- data/spec/rest_spec.rb +8 -11
- data/spec/skip_spec.rb +9 -17
- data/spec/spec_common.rb +4 -0
- data/spec/string_spec.rb +92 -115
- data/spec/stringz_spec.rb +41 -74
- data/spec/struct_spec.rb +132 -153
- data/spec/system_spec.rb +115 -60
- data/spec/wrapper_spec.rb +63 -31
- data/tasks/pkg.rake +1 -1
- metadata +15 -7
data/lib/bindata.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# BinData -- Binary data manipulator.
|
2
|
-
# Copyright (c) 2007 -
|
2
|
+
# Copyright (c) 2007 - 2011 Dion Mendel.
|
3
3
|
|
4
4
|
require 'bindata/array'
|
5
5
|
require 'bindata/bits'
|
@@ -15,6 +15,7 @@ require 'bindata/stringz'
|
|
15
15
|
require 'bindata/struct'
|
16
16
|
require 'bindata/trace'
|
17
17
|
require 'bindata/wrapper'
|
18
|
+
require 'bindata/alignment'
|
18
19
|
require 'bindata/deprecated'
|
19
20
|
|
20
21
|
# = BinData
|
@@ -28,7 +29,7 @@ require 'bindata/deprecated'
|
|
28
29
|
#
|
29
30
|
# BinData is released under the same license as Ruby.
|
30
31
|
#
|
31
|
-
# Copyright (c) 2007 -
|
32
|
+
# Copyright (c) 2007 - 2011 Dion Mendel.
|
32
33
|
module BinData
|
33
|
-
VERSION = "1.
|
34
|
+
VERSION = "1.3.1"
|
34
35
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'bindata/base_primitive'
|
2
|
+
|
3
|
+
module BinData
|
4
|
+
# Resets the stream alignment to the next byte. This is
|
5
|
+
# only useful when using bit-based primitives.
|
6
|
+
#
|
7
|
+
# class MyRec < BinData::Record
|
8
|
+
# bit4 :a
|
9
|
+
# resume_byte_alignment
|
10
|
+
# bit4 :b
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# MyRec.read("\x12\x34") #=> {"a" => 1, "b" => 3}
|
14
|
+
#
|
15
|
+
class ResumeByteAlignment < BinData::Base
|
16
|
+
register_self
|
17
|
+
|
18
|
+
def clear; end
|
19
|
+
def clear?; true; end
|
20
|
+
def assign(val); end
|
21
|
+
def snapshot; nil; end
|
22
|
+
def do_num_bytes; 0; end
|
23
|
+
|
24
|
+
def do_read(io)
|
25
|
+
io.reset_read_bits
|
26
|
+
end
|
27
|
+
|
28
|
+
def do_write(io)
|
29
|
+
io.flushbits
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# A monkey patch to force byte-aligned primitives to
|
34
|
+
# become bit-aligned. This allows them to be used at
|
35
|
+
# non byte based boundaries.
|
36
|
+
#
|
37
|
+
# class BitString < BinData::String
|
38
|
+
# bit_aligned
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# class MyRecord < BinData::Record
|
42
|
+
# bit4 :preamble
|
43
|
+
# bit_string :str, :length => 2
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
module BitAligned
|
47
|
+
class BitAlignedIO
|
48
|
+
def initialize(io)
|
49
|
+
@io = io
|
50
|
+
end
|
51
|
+
def readbytes(n)
|
52
|
+
n.times.inject("") do |bytes, i|
|
53
|
+
bytes + @io.readbits(8, :big).chr
|
54
|
+
end
|
55
|
+
end
|
56
|
+
def method_missing(sym, *args, &block)
|
57
|
+
@io.send(sym, *args, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def read_and_return_value(io)
|
62
|
+
super(BitAlignedIO.new(io))
|
63
|
+
end
|
64
|
+
|
65
|
+
def do_num_bytes
|
66
|
+
super.to_f
|
67
|
+
end
|
68
|
+
|
69
|
+
def do_write(io)
|
70
|
+
value_to_binary_string(_value).each_byte { |v| io.writebits(v, 8, :big) }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class BasePrimitive < BinData::Base
|
75
|
+
def self.bit_aligned
|
76
|
+
include BitAligned
|
77
|
+
register_self
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Primitive < BinData::BasePrimitive
|
82
|
+
def self.bit_aligned
|
83
|
+
fail "'bit_aligned' is not needed for BinData::Primitives"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/bindata/array.rb
CHANGED
@@ -8,27 +8,22 @@ module BinData
|
|
8
8
|
# data = "\x03\x04\x05\x06\x07\x08\x09"
|
9
9
|
#
|
10
10
|
# obj = BinData::Array.new(:type => :int8, :initial_length => 6)
|
11
|
-
# obj.read(data)
|
12
|
-
# obj.snapshot #=> [3, 4, 5, 6, 7, 8]
|
11
|
+
# obj.read(data) #=> [3, 4, 5, 6, 7, 8]
|
13
12
|
#
|
14
13
|
# obj = BinData::Array.new(:type => :int8,
|
15
14
|
# :read_until => lambda { index == 1 })
|
16
|
-
# obj.read(data)
|
17
|
-
# obj.snapshot #=> [3, 4]
|
15
|
+
# obj.read(data) #=> [3, 4]
|
18
16
|
#
|
19
17
|
# obj = BinData::Array.new(:type => :int8,
|
20
18
|
# :read_until => lambda { element >= 6 })
|
21
|
-
# obj.read(data)
|
22
|
-
# obj.snapshot #=> [3, 4, 5, 6]
|
19
|
+
# obj.read(data) #=> [3, 4, 5, 6]
|
23
20
|
#
|
24
21
|
# obj = BinData::Array.new(:type => :int8,
|
25
22
|
# :read_until => lambda { array[index] + array[index - 1] == 13 })
|
26
|
-
# obj.read(data)
|
27
|
-
# obj.snapshot #=> [3, 4, 5, 6, 7]
|
23
|
+
# obj.read(data) #=> [3, 4, 5, 6, 7]
|
28
24
|
#
|
29
25
|
# obj = BinData::Array.new(:type => :int8, :read_until => :eof)
|
30
|
-
# obj.read(data)
|
31
|
-
# obj.snapshot #=> [3, 4, 5, 6, 7, 8, 9]
|
26
|
+
# obj.read(data) #=> [3, 4, 5, 6, 7, 8, 9]
|
32
27
|
#
|
33
28
|
# == Parameters
|
34
29
|
#
|
@@ -78,13 +73,14 @@ module BinData
|
|
78
73
|
end
|
79
74
|
end
|
80
75
|
|
81
|
-
def
|
82
|
-
super
|
83
|
-
|
84
|
-
@element_list = nil
|
76
|
+
def initialize_shared_instance
|
85
77
|
@element_prototype = get_parameter(:type)
|
86
78
|
end
|
87
79
|
|
80
|
+
def initialize_instance
|
81
|
+
@element_list = nil
|
82
|
+
end
|
83
|
+
|
88
84
|
def clear?
|
89
85
|
@element_list.nil? or elements.all? { |el| el.clear? }
|
90
86
|
end
|
@@ -247,7 +243,7 @@ module BinData
|
|
247
243
|
end
|
248
244
|
|
249
245
|
def do_num_bytes #:nodoc:
|
250
|
-
sum_num_bytes_for_all_elements
|
246
|
+
sum_num_bytes_for_all_elements
|
251
247
|
end
|
252
248
|
|
253
249
|
#---------------
|
@@ -261,13 +257,7 @@ module BinData
|
|
261
257
|
end
|
262
258
|
|
263
259
|
def to_storage_formats(els)
|
264
|
-
els.collect { |el|
|
265
|
-
end
|
266
|
-
|
267
|
-
def to_storage_format(obj)
|
268
|
-
element = new_element
|
269
|
-
element.assign(obj)
|
270
|
-
element
|
260
|
+
els.collect { |el| new_element(el) }
|
271
261
|
end
|
272
262
|
|
273
263
|
def read_until(io)
|
@@ -318,8 +308,8 @@ module BinData
|
|
318
308
|
element
|
319
309
|
end
|
320
310
|
|
321
|
-
def new_element
|
322
|
-
@element_prototype.instantiate(self)
|
311
|
+
def new_element(value = nil)
|
312
|
+
@element_prototype.instantiate(value, self)
|
323
313
|
end
|
324
314
|
|
325
315
|
def sum_num_bytes_for_all_elements
|
@@ -327,13 +317,15 @@ module BinData
|
|
327
317
|
end
|
328
318
|
|
329
319
|
def sum_num_bytes_below_index(index)
|
330
|
-
sum
|
331
|
-
(0...index).each do |i|
|
320
|
+
(0...index).inject(0) do |sum, i|
|
332
321
|
nbytes = elements[i].do_num_bytes
|
333
|
-
sum = (nbytes.is_a?(Integer) ? sum.ceil : sum) + nbytes
|
334
|
-
end
|
335
322
|
|
336
|
-
|
323
|
+
if nbytes.is_a?(Integer)
|
324
|
+
(sum + nbytes).ceil
|
325
|
+
else
|
326
|
+
sum + nbytes
|
327
|
+
end
|
328
|
+
end
|
337
329
|
end
|
338
330
|
end
|
339
331
|
end
|
data/lib/bindata/base.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'bindata/io'
|
2
2
|
require 'bindata/lazy'
|
3
|
+
require 'bindata/offset'
|
3
4
|
require 'bindata/params'
|
4
5
|
require 'bindata/registry'
|
5
6
|
require 'bindata/sanitize'
|
@@ -8,39 +9,49 @@ module BinData
|
|
8
9
|
# Error raised when unexpected results occur when reading data from IO.
|
9
10
|
class ValidityError < StandardError ; end
|
10
11
|
|
12
|
+
# ArgExtractors take the arguments to BinData::Base.new and
|
13
|
+
# separate them into [value, parameters, parent].
|
14
|
+
class BaseArgExtractor
|
15
|
+
def self.extract(the_class, the_args)
|
16
|
+
args = the_args.dup
|
17
|
+
value = parameters = parent = nil
|
18
|
+
|
19
|
+
if args.length > 1 and args.last.is_a? BinData::Base
|
20
|
+
parent = args.pop
|
21
|
+
end
|
22
|
+
|
23
|
+
if args.length > 0 and args.last.is_a? Hash
|
24
|
+
parameters = args.pop
|
25
|
+
end
|
26
|
+
|
27
|
+
if args.length > 0
|
28
|
+
value = args.pop
|
29
|
+
end
|
30
|
+
|
31
|
+
parameters ||= {}
|
32
|
+
|
33
|
+
return [value, parameters, parent]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
11
37
|
# This is the abstract base class for all data objects.
|
12
|
-
#
|
13
|
-
# == Parameters
|
14
|
-
#
|
15
|
-
# Parameters may be provided at initialisation to control the behaviour of
|
16
|
-
# an object. These parameters are:
|
17
|
-
#
|
18
|
-
# [<tt>:check_offset</tt>] Raise an error if the current IO offset doesn't
|
19
|
-
# meet this criteria. A boolean return indicates
|
20
|
-
# success or failure. Any other return is compared
|
21
|
-
# to the current offset. The variable +offset+
|
22
|
-
# is made available to any lambda assigned to
|
23
|
-
# this parameter. This parameter is only checked
|
24
|
-
# before reading.
|
25
|
-
# [<tt>:adjust_offset</tt>] Ensures that the current IO offset is at this
|
26
|
-
# position before reading. This is like
|
27
|
-
# <tt>:check_offset</tt>, except that it will
|
28
|
-
# adjust the IO offset instead of raising an error.
|
29
38
|
class Base
|
30
39
|
include AcceptedParametersMixin
|
31
|
-
|
32
|
-
optional_parameters :check_offset, :adjust_offset
|
33
|
-
optional_parameter :onlyif # Used by Struct
|
34
|
-
mutually_exclusive_parameters :check_offset, :adjust_offset
|
40
|
+
include CheckOrAdjustOffsetMixin
|
35
41
|
|
36
42
|
class << self
|
37
43
|
|
38
44
|
# Instantiates this class and reads from +io+, returning the newly
|
39
45
|
# created data object.
|
40
46
|
def read(io)
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
obj = self.new
|
48
|
+
obj.read(io)
|
49
|
+
obj
|
50
|
+
end
|
51
|
+
|
52
|
+
# The arg extractor for this class.
|
53
|
+
def arg_extractor
|
54
|
+
BaseArgExtractor
|
44
55
|
end
|
45
56
|
|
46
57
|
# The name of this class as used by Records, Arrays etc.
|
@@ -71,19 +82,42 @@ module BinData
|
|
71
82
|
|
72
83
|
# Creates a new data object.
|
73
84
|
#
|
85
|
+
# Args are optional, but if present, must be in the following order.
|
86
|
+
#
|
87
|
+
# +value+ is a value that is +assign+ed immediately after initialization.
|
88
|
+
#
|
74
89
|
# +parameters+ is a hash containing symbol keys. Some parameters may
|
75
90
|
# reference callable objects (methods or procs).
|
76
91
|
#
|
77
92
|
# +parent+ is the parent data object (e.g. struct, array, choice) this
|
78
93
|
# object resides under.
|
79
|
-
def initialize(
|
94
|
+
def initialize(*args)
|
95
|
+
value, parameters, parent = extract_args(args)
|
80
96
|
@params = Sanitizer.sanitize(parameters, self.class)
|
81
|
-
@parent = parent
|
82
97
|
|
83
|
-
|
98
|
+
add_methods_for_check_or_adjust_offset
|
99
|
+
|
100
|
+
@parent = parent if parent
|
101
|
+
initialize_shared_instance
|
102
|
+
initialize_instance
|
103
|
+
assign(value) if value
|
84
104
|
end
|
85
105
|
|
86
|
-
|
106
|
+
attr_accessor :parent
|
107
|
+
protected :parent=
|
108
|
+
|
109
|
+
# Creates a new data object based on this instance.
|
110
|
+
#
|
111
|
+
# All parameters will be be duplicated. Use this method
|
112
|
+
# when creating multiple objects with the same parameters.
|
113
|
+
def new(value = nil, parent = nil)
|
114
|
+
obj = clone
|
115
|
+
obj.parent = parent if parent
|
116
|
+
obj.initialize_instance
|
117
|
+
obj.assign(value) if value
|
118
|
+
|
119
|
+
obj
|
120
|
+
end
|
87
121
|
|
88
122
|
# Returns the result of evaluating the parameter identified by +key+.
|
89
123
|
#
|
@@ -202,6 +236,10 @@ module BinData
|
|
202
236
|
#---------------
|
203
237
|
private
|
204
238
|
|
239
|
+
def extract_args(the_args)
|
240
|
+
self.class.arg_extractor.extract(self.class, the_args)
|
241
|
+
end
|
242
|
+
|
205
243
|
def furthest_ancestor
|
206
244
|
if parent.nil?
|
207
245
|
self
|
@@ -212,58 +250,6 @@ module BinData
|
|
212
250
|
end
|
213
251
|
end
|
214
252
|
|
215
|
-
def prepare_for_read_with_offset
|
216
|
-
if has_parameter?(:check_offset) or has_parameter?(:adjust_offset)
|
217
|
-
class << self
|
218
|
-
alias_method :do_read_without_offset, :do_read
|
219
|
-
alias_method :do_read, :do_read_with_offset
|
220
|
-
public :do_read # Ruby 1.9.2 bug. Should be protected
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
def do_read_with_offset(io) #:nodoc:
|
226
|
-
check_or_adjust_offset(io)
|
227
|
-
do_read_without_offset(io)
|
228
|
-
end
|
229
|
-
|
230
|
-
def check_or_adjust_offset(io)
|
231
|
-
if has_parameter?(:check_offset)
|
232
|
-
check_offset(io)
|
233
|
-
elsif has_parameter?(:adjust_offset)
|
234
|
-
adjust_offset(io)
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
def check_offset(io)
|
239
|
-
actual_offset = io.offset
|
240
|
-
expected = eval_parameter(:check_offset, :offset => actual_offset)
|
241
|
-
|
242
|
-
if not expected
|
243
|
-
raise ValidityError, "offset not as expected for #{debug_name}"
|
244
|
-
elsif actual_offset != expected and expected != true
|
245
|
-
raise ValidityError,
|
246
|
-
"offset is '#{actual_offset}' but " +
|
247
|
-
"expected '#{expected}' for #{debug_name}"
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
def adjust_offset(io)
|
252
|
-
actual_offset = io.offset
|
253
|
-
expected = eval_parameter(:adjust_offset)
|
254
|
-
if actual_offset != expected
|
255
|
-
begin
|
256
|
-
seek = expected - actual_offset
|
257
|
-
io.seekbytes(seek)
|
258
|
-
warn "adjusting stream position by #{seek} bytes" if $VERBOSE
|
259
|
-
rescue
|
260
|
-
raise ValidityError,
|
261
|
-
"offset is '#{actual_offset}' but couldn't seek to " +
|
262
|
-
"expected '#{expected}' for #{debug_name}"
|
263
|
-
end
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
253
|
###########################################################################
|
268
254
|
# To be implemented by subclasses
|
269
255
|
|
@@ -272,6 +258,20 @@ module BinData
|
|
272
258
|
def self.sanitize_parameters!(parameters, sanitizer) #:nodoc:
|
273
259
|
end
|
274
260
|
|
261
|
+
# Initializes the state of the object. All instance variables that
|
262
|
+
# are used by the object must be initialized here.
|
263
|
+
def initialize_instance
|
264
|
+
end
|
265
|
+
|
266
|
+
# Initialises state that is shared by objects with the same parameters.
|
267
|
+
#
|
268
|
+
# This should only be used when optimising for performance. Instance
|
269
|
+
# variables set here, and changes to the singleton class will be shared
|
270
|
+
# between all objects that are initialized with the same parameters.
|
271
|
+
# This method is called only once for a particular set of parameters.
|
272
|
+
def initialize_shared_instance
|
273
|
+
end
|
274
|
+
|
275
275
|
# Resets the internal state to that of a newly created object.
|
276
276
|
def clear
|
277
277
|
raise NotImplementedError
|
@@ -282,7 +282,7 @@ module BinData
|
|
282
282
|
raise NotImplementedError
|
283
283
|
end
|
284
284
|
|
285
|
-
# Assigns the value of +val+ to this data object. Note that +val+
|
285
|
+
# Assigns the value of +val+ to this data object. Note that +val+ must
|
286
286
|
# always be deep copied to ensure no aliasing problems can occur.
|
287
287
|
def assign(val)
|
288
288
|
raise NotImplementedError
|
@@ -322,6 +322,7 @@ module BinData
|
|
322
322
|
|
323
323
|
# Set visibility requirements of methods to implement
|
324
324
|
public :clear, :clear?, :assign, :snapshot, :debug_name_of, :offset_of
|
325
|
+
protected :initialize_instance, :initialize_shared_instance
|
325
326
|
protected :do_read, :do_write, :do_num_bytes
|
326
327
|
|
327
328
|
# End To be implemented by subclasses
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'bindata/base'
|
2
|
-
require 'bindata/trace'
|
3
2
|
|
4
3
|
module BinData
|
5
4
|
# A BinData::BasePrimitive object is a container for a value that has a
|
@@ -10,16 +9,16 @@ module BinData
|
|
10
9
|
# require 'bindata'
|
11
10
|
#
|
12
11
|
# obj = BinData::Uint8.new(:initial_value => 42)
|
13
|
-
# obj
|
14
|
-
# obj.
|
15
|
-
# obj
|
12
|
+
# obj #=> 42
|
13
|
+
# obj.assign(5)
|
14
|
+
# obj #=> 5
|
16
15
|
# obj.clear
|
17
|
-
# obj
|
16
|
+
# obj #=> 42
|
18
17
|
#
|
19
18
|
# obj = BinData::Uint8.new(:value => 42)
|
20
|
-
# obj
|
21
|
-
# obj.
|
22
|
-
# obj
|
19
|
+
# obj #=> 42
|
20
|
+
# obj.assign(5)
|
21
|
+
# obj #=> 42
|
23
22
|
#
|
24
23
|
# obj = BinData::Uint8.new(:check_value => 3)
|
25
24
|
# obj.read("\005") #=> BinData::ValidityError: value is '5' but expected '3'
|
@@ -50,9 +49,26 @@ module BinData
|
|
50
49
|
optional_parameters :initial_value, :value, :check_value
|
51
50
|
mutually_exclusive_parameters :initial_value, :value
|
52
51
|
|
53
|
-
def
|
54
|
-
|
52
|
+
def initialize_shared_instance
|
53
|
+
if has_parameter?(:check_value)
|
54
|
+
class << self
|
55
|
+
alias_method :do_read_without_check_value, :do_read
|
56
|
+
alias_method :do_read, :do_read_with_check_value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
if has_parameter?(:value)
|
60
|
+
class << self
|
61
|
+
alias_method :_value, :_value_with_value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
if has_parameter?(:initial_value)
|
65
|
+
class << self
|
66
|
+
alias_method :_value, :_value_with_initial_value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
55
70
|
|
71
|
+
def initialize_instance
|
56
72
|
@value = nil
|
57
73
|
end
|
58
74
|
|
@@ -83,27 +99,28 @@ module BinData
|
|
83
99
|
end
|
84
100
|
|
85
101
|
def value
|
86
|
-
# TODO: warn "#value is deprecated, use #snapshot instead"
|
87
102
|
snapshot
|
88
103
|
end
|
89
|
-
|
90
|
-
def value=(val)
|
91
|
-
# TODO: warn "#value= is deprecated, use #assign instead"
|
92
|
-
assign(val)
|
93
|
-
end
|
104
|
+
alias_method :value=, :assign
|
94
105
|
|
95
106
|
def respond_to?(symbol, include_private = false) #:nodoc:
|
96
|
-
|
107
|
+
child = snapshot
|
108
|
+
child.respond_to?(symbol, include_private) || super
|
97
109
|
end
|
98
110
|
|
99
111
|
def method_missing(symbol, *args, &block) #:nodoc:
|
100
|
-
|
101
|
-
|
112
|
+
child = snapshot
|
113
|
+
if child.respond_to?(symbol)
|
114
|
+
child.__send__(symbol, *args, &block)
|
102
115
|
else
|
103
116
|
super
|
104
117
|
end
|
105
118
|
end
|
106
119
|
|
120
|
+
def <=>(other)
|
121
|
+
snapshot <=> other
|
122
|
+
end
|
123
|
+
|
107
124
|
def eql?(other)
|
108
125
|
# double dispatch
|
109
126
|
other.eql?(snapshot)
|
@@ -114,13 +131,13 @@ module BinData
|
|
114
131
|
end
|
115
132
|
|
116
133
|
def do_read(io) #:nodoc:
|
117
|
-
@value
|
118
|
-
|
119
|
-
|
134
|
+
@value = read_and_return_value(io)
|
135
|
+
hook_after_do_read
|
136
|
+
end
|
120
137
|
|
121
|
-
|
122
|
-
|
123
|
-
|
138
|
+
def do_read_with_check_value(io) #:nodoc:
|
139
|
+
do_read_without_check_value(io)
|
140
|
+
check_value(snapshot)
|
124
141
|
end
|
125
142
|
|
126
143
|
def do_write(io) #:nodoc:
|
@@ -134,12 +151,7 @@ module BinData
|
|
134
151
|
#---------------
|
135
152
|
private
|
136
153
|
|
137
|
-
def
|
138
|
-
BinData::trace_message do |tracer|
|
139
|
-
value_string = _value.inspect
|
140
|
-
tracer.trace_obj(debug_name, value_string)
|
141
|
-
end
|
142
|
-
end
|
154
|
+
def hook_after_do_read; end
|
143
155
|
|
144
156
|
def check_value(current_value)
|
145
157
|
expected = eval_parameter(:check_value, :value => current_value)
|
@@ -153,28 +165,34 @@ module BinData
|
|
153
165
|
end
|
154
166
|
end
|
155
167
|
|
156
|
-
# The unmodified value of this data object. Note that #
|
157
|
-
# method. This indirection is so that #
|
158
|
-
# subclasses to modify the value.
|
168
|
+
# The unmodified value of this data object. Note that #snapshot calls this
|
169
|
+
# method. This indirection is so that #snapshot can be overridden in
|
170
|
+
# subclasses to modify the presentation value.
|
171
|
+
#
|
172
|
+
# Table of possible preconditions and expected outcome
|
173
|
+
# 1. :value and !reading? -> :value
|
174
|
+
# 2. :value and reading? -> @value
|
175
|
+
# 3. :initial_value and clear? -> :initial_value
|
176
|
+
# 4. :initial_value and !clear? -> @value
|
177
|
+
# 5. clear? -> sensible_default
|
178
|
+
# 6. !clear? -> @value
|
179
|
+
|
159
180
|
def _value
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
# 6. !clear? -> @value
|
167
|
-
|
168
|
-
if has_parameter?(:value) and not reading?
|
169
|
-
# rule 1 above
|
170
|
-
eval_parameter(:value)
|
181
|
+
@value || sensible_default()
|
182
|
+
end
|
183
|
+
|
184
|
+
def _value_with_value #:nodoc:
|
185
|
+
if reading?
|
186
|
+
@value
|
171
187
|
else
|
172
|
-
|
173
|
-
@value || eval_parameter(:value) ||
|
174
|
-
eval_parameter(:initial_value) || sensible_default()
|
188
|
+
eval_parameter(:value)
|
175
189
|
end
|
176
190
|
end
|
177
191
|
|
192
|
+
def _value_with_initial_value #:nodoc:
|
193
|
+
@value || eval_parameter(:initial_value)
|
194
|
+
end
|
195
|
+
|
178
196
|
###########################################################################
|
179
197
|
# To be implemented by subclasses
|
180
198
|
|