bindata 0.9.3 → 0.10.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.
- data/ChangeLog +18 -0
- data/NEWS +59 -0
- data/README +22 -23
- data/TODO +18 -12
- data/examples/gzip.rb +4 -4
- data/lib/bindata.rb +4 -3
- data/lib/bindata/array.rb +202 -132
- data/lib/bindata/base.rb +147 -166
- data/lib/bindata/{single.rb → base_primitive.rb} +82 -56
- data/lib/bindata/bits.rb +31 -770
- data/lib/bindata/choice.rb +157 -82
- data/lib/bindata/float.rb +25 -27
- data/lib/bindata/int.rb +144 -177
- data/lib/bindata/io.rb +59 -49
- data/lib/bindata/lazy.rb +80 -50
- data/lib/bindata/params.rb +134 -26
- data/lib/bindata/{single_value.rb → primitive.rb} +71 -64
- data/lib/bindata/{multi_value.rb → record.rb} +52 -70
- data/lib/bindata/registry.rb +49 -17
- data/lib/bindata/rest.rb +6 -10
- data/lib/bindata/sanitize.rb +55 -70
- data/lib/bindata/string.rb +60 -42
- data/lib/bindata/stringz.rb +34 -35
- data/lib/bindata/struct.rb +197 -152
- data/lib/bindata/trace.rb +35 -0
- data/spec/array_spec.rb +128 -112
- data/spec/{single_spec.rb → base_primitive_spec.rb} +102 -61
- data/spec/base_spec.rb +190 -185
- data/spec/bits_spec.rb +126 -98
- data/spec/choice_spec.rb +89 -98
- data/spec/example.rb +19 -0
- data/spec/float_spec.rb +28 -44
- data/spec/int_spec.rb +217 -127
- data/spec/io_spec.rb +41 -24
- data/spec/lazy_spec.rb +95 -49
- data/spec/primitive_spec.rb +191 -0
- data/spec/{multi_value_spec.rb → record_spec.rb} +124 -89
- data/spec/registry_spec.rb +53 -12
- data/spec/rest_spec.rb +2 -3
- data/spec/sanitize_spec.rb +47 -73
- data/spec/spec_common.rb +13 -1
- data/spec/string_spec.rb +34 -23
- data/spec/stringz_spec.rb +10 -18
- data/spec/struct_spec.rb +91 -63
- data/spec/system_spec.rb +291 -0
- metadata +12 -8
- data/spec/single_value_spec.rb +0 -131
data/lib/bindata/base.rb
CHANGED
@@ -16,11 +16,6 @@ module BinData
|
|
16
16
|
# Parameters may be provided at initialisation to control the behaviour of
|
17
17
|
# an object. These params are:
|
18
18
|
#
|
19
|
-
# [<tt>:readwrite</tt>] Deprecated. An alias for :onlyif.
|
20
|
-
# [<tt>:onlyif</tt>] Used to indicate a data object is optional.
|
21
|
-
# if false, calls to #read or #write will not
|
22
|
-
# perform any I/O, #num_bytes will return 0 and
|
23
|
-
# #snapshot will return nil. Default is true.
|
24
19
|
# [<tt>:check_offset</tt>] Raise an error if the current IO offset doesn't
|
25
20
|
# meet this criteria. A boolean return indicates
|
26
21
|
# success or failure. Any other return is compared
|
@@ -35,94 +30,49 @@ module BinData
|
|
35
30
|
class Base
|
36
31
|
|
37
32
|
class << self
|
38
|
-
extend Parameters
|
39
33
|
|
40
|
-
#
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
define_x_parameters(:bindata_mandatory, []) do |array, args|
|
47
|
-
args.each { |arg| array << arg.to_sym }
|
48
|
-
array.uniq!
|
49
|
-
end
|
50
|
-
|
51
|
-
define_x_parameters(:bindata_optional, []) do |array, args|
|
52
|
-
args.each { |arg| array << arg.to_sym }
|
53
|
-
array.uniq!
|
34
|
+
# Instantiates this class and reads from +io+, returning the newly
|
35
|
+
# created data object.
|
36
|
+
def read(io)
|
37
|
+
data = self.new
|
38
|
+
data.read(io)
|
39
|
+
data
|
54
40
|
end
|
55
41
|
|
56
|
-
|
57
|
-
|
58
|
-
|
42
|
+
def recursive?
|
43
|
+
# data objects do not self reference by default
|
44
|
+
false
|
59
45
|
end
|
60
46
|
|
61
|
-
|
62
|
-
array << [args[0].to_sym, args[1].to_sym]
|
63
|
-
end
|
47
|
+
AcceptedParameters.define_all_accessors(self, :internal)
|
64
48
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
bindata_default_parameters.keys).uniq
|
49
|
+
def accepted_internal_parameters
|
50
|
+
internal = AcceptedParameters.get(self, :internal)
|
51
|
+
internal.all
|
69
52
|
end
|
70
53
|
|
71
|
-
# Ensures that +params+ is of the form expected by #initialize.
|
72
54
|
def sanitize_parameters!(sanitizer, params)
|
73
|
-
|
74
|
-
|
75
|
-
warn ":readwrite is deprecated. Replacing with :onlyif"
|
76
|
-
params[:onlyif] = params.delete(:readwrite)
|
77
|
-
end
|
78
|
-
|
79
|
-
# add default parameters
|
80
|
-
bindata_default_parameters.each do |k,v|
|
81
|
-
params[k] = v unless params.has_key?(k)
|
82
|
-
end
|
83
|
-
|
84
|
-
# ensure mandatory parameters exist
|
85
|
-
bindata_mandatory_parameters.each do |prm|
|
86
|
-
if not params.has_key?(prm)
|
87
|
-
raise ArgumentError, "parameter ':#{prm}' must be specified " +
|
88
|
-
"in #{self}"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# ensure mutual exclusion
|
93
|
-
bindata_mutually_exclusive_parameters.each do |param1, param2|
|
94
|
-
if params.has_key?(param1) and params.has_key?(param2)
|
95
|
-
raise ArgumentError, "params #{param1} and #{param2} " +
|
96
|
-
"are mutually exclusive"
|
97
|
-
end
|
98
|
-
end
|
55
|
+
internal = AcceptedParameters.get(self, :internal)
|
56
|
+
internal.sanitize_parameters!(sanitizer, params)
|
99
57
|
end
|
100
58
|
|
101
|
-
|
102
|
-
|
103
|
-
false
|
104
|
-
end
|
59
|
+
#-------------
|
60
|
+
private
|
105
61
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
data.read(io)
|
112
|
-
data.single_value? ? data.value : data
|
62
|
+
def warn_replacement_parameter(params, bad_key, suggested_key)
|
63
|
+
if params.has_key?(bad_key)
|
64
|
+
warn ":#{bad_key} is not used with #{self}. " +
|
65
|
+
"You probably want to change this to :#{suggested_key}"
|
66
|
+
end
|
113
67
|
end
|
114
68
|
|
115
|
-
|
116
|
-
|
117
|
-
Registry.instance.register(name, klass)
|
69
|
+
def register(name, class_to_register)
|
70
|
+
RegisteredClasses.register(name, class_to_register)
|
118
71
|
end
|
119
|
-
private :register
|
120
72
|
end
|
121
73
|
|
122
|
-
|
123
|
-
|
124
|
-
bindata_default_parameters :onlyif => true
|
125
|
-
bindata_mutually_exclusive_parameters :check_offset, :adjust_offset
|
74
|
+
optional_parameters :check_offset, :adjust_offset
|
75
|
+
mutually_exclusive_parameters :check_offset, :adjust_offset
|
126
76
|
|
127
77
|
# Creates a new data object.
|
128
78
|
#
|
@@ -135,15 +85,29 @@ module BinData
|
|
135
85
|
@parent = parent
|
136
86
|
end
|
137
87
|
|
138
|
-
|
139
|
-
|
88
|
+
attr_reader :parent
|
89
|
+
|
90
|
+
# Returns the result of evaluating the parameter identified by +key+.
|
91
|
+
# +overrides+ is an optional +parameters+ like hash that allow the
|
92
|
+
# parameters given at object construction to be overridden.
|
93
|
+
# Returns nil if +key+ does not refer to any parameter.
|
94
|
+
def eval_parameter(key, overrides = {})
|
95
|
+
LazyEvaluator.eval(self, get_parameter(key), overrides)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns the parameter referenced by +key+.
|
99
|
+
# Use this method if you are sure the parameter is not to be evaluated.
|
100
|
+
# You most likely want #eval_parameter.
|
101
|
+
def get_parameter(key)
|
102
|
+
@params[key]
|
103
|
+
end
|
140
104
|
|
141
|
-
# Returns
|
142
|
-
def
|
143
|
-
@params.
|
105
|
+
# Returns whether +key+ exists in the +parameters+ hash.
|
106
|
+
def has_parameter?(key)
|
107
|
+
@params.has_key?(key)
|
144
108
|
end
|
145
109
|
|
146
|
-
# Reads data into this data object
|
110
|
+
# Reads data into this data object.
|
147
111
|
def read(io)
|
148
112
|
io = BinData::IO.new(io) unless BinData::IO === io
|
149
113
|
|
@@ -152,19 +116,18 @@ module BinData
|
|
152
116
|
self
|
153
117
|
end
|
154
118
|
|
155
|
-
# Reads the value for this data from +io+.
|
156
119
|
def do_read(io)
|
157
|
-
|
158
|
-
|
120
|
+
check_or_adjust_offset(io)
|
159
121
|
clear
|
160
|
-
|
122
|
+
_do_read(io)
|
123
|
+
end
|
161
124
|
|
162
|
-
|
163
|
-
|
164
|
-
end
|
125
|
+
def done_read
|
126
|
+
_done_read
|
165
127
|
end
|
128
|
+
protected :do_read, :done_read
|
166
129
|
|
167
|
-
# Writes the value for this data to +io
|
130
|
+
# Writes the value for this data to +io+.
|
168
131
|
def write(io)
|
169
132
|
io = BinData::IO.new(io) unless BinData::IO === io
|
170
133
|
|
@@ -173,110 +136,110 @@ module BinData
|
|
173
136
|
self
|
174
137
|
end
|
175
138
|
|
176
|
-
|
177
|
-
# Writes the value for this data to +io+.
|
178
139
|
def do_write(io)
|
179
|
-
|
180
|
-
|
181
|
-
if eval_param(:onlyif)
|
182
|
-
_do_write(io)
|
183
|
-
end
|
140
|
+
_do_write(io)
|
184
141
|
end
|
142
|
+
protected :do_write
|
185
143
|
|
186
|
-
# Returns the number of bytes it will take to write this data
|
187
|
-
# #do_num_bytes.
|
144
|
+
# Returns the number of bytes it will take to write this data.
|
188
145
|
def num_bytes(what = nil)
|
189
146
|
num = do_num_bytes(what)
|
190
147
|
num.ceil
|
191
148
|
end
|
192
149
|
|
193
|
-
# Returns the number of bytes it will take to write this data.
|
194
150
|
def do_num_bytes(what = nil)
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
151
|
+
_do_num_bytes(what)
|
152
|
+
end
|
153
|
+
protected :do_num_bytes
|
154
|
+
|
155
|
+
# Assigns the value of +val+ to this data object. Note that +val+ will
|
156
|
+
# always be deep copied to ensure no aliasing problems can occur.
|
157
|
+
def assign(val)
|
158
|
+
_assign(val)
|
200
159
|
end
|
201
160
|
|
202
161
|
# Returns a snapshot of this data object.
|
203
|
-
# Returns nil if :onlyif is false
|
204
162
|
def snapshot
|
205
|
-
|
206
|
-
_snapshot
|
207
|
-
else
|
208
|
-
nil
|
209
|
-
end
|
163
|
+
_snapshot
|
210
164
|
end
|
211
165
|
|
212
166
|
# Returns the string representation of this data object.
|
213
|
-
def
|
167
|
+
def to_binary_s
|
214
168
|
io = StringIO.new
|
215
169
|
write(io)
|
216
170
|
io.rewind
|
217
171
|
io.read
|
218
172
|
end
|
219
173
|
|
220
|
-
# Return a human readable representation of this object.
|
174
|
+
# Return a human readable representation of this data object.
|
221
175
|
def inspect
|
222
176
|
snapshot.inspect
|
223
177
|
end
|
224
178
|
|
225
|
-
#
|
226
|
-
def
|
227
|
-
|
179
|
+
# Return a string representing this data object.
|
180
|
+
def to_s
|
181
|
+
snapshot.to_s
|
228
182
|
end
|
229
183
|
|
230
|
-
|
231
|
-
|
184
|
+
# Returns a user friendly name of this object for debugging purposes.
|
185
|
+
def debug_name
|
186
|
+
if parent
|
187
|
+
parent.debug_name_of(self)
|
188
|
+
else
|
189
|
+
"obj"
|
190
|
+
end
|
191
|
+
end
|
232
192
|
|
233
|
-
# Returns the
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
193
|
+
# Returns the offset of this object wrt to its most distant ancestor.
|
194
|
+
def offset
|
195
|
+
if parent
|
196
|
+
parent.offset_of(self)
|
197
|
+
else
|
198
|
+
0
|
199
|
+
end
|
239
200
|
end
|
240
201
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
def no_eval_param(key)
|
245
|
-
@params.internal_parameters[key]
|
202
|
+
def ==(other)
|
203
|
+
# double dispatch
|
204
|
+
other == snapshot
|
246
205
|
end
|
247
206
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
207
|
+
#---------------
|
208
|
+
private
|
209
|
+
|
210
|
+
def check_or_adjust_offset(io)
|
211
|
+
if has_parameter?(:check_offset)
|
212
|
+
check_offset(io)
|
213
|
+
elsif has_parameter?(:adjust_offset)
|
214
|
+
adjust_offset(io)
|
215
|
+
end
|
252
216
|
end
|
253
217
|
|
254
|
-
# Checks that the current offset of +io+ is as expected. This should
|
255
|
-
# be called from #do_read before performing the reading.
|
256
218
|
def check_offset(io)
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
219
|
+
actual_offset = io.offset
|
220
|
+
expected = eval_parameter(:check_offset, :offset => actual_offset)
|
221
|
+
|
222
|
+
if not expected
|
223
|
+
raise ValidityError, "offset not as expected for #{debug_name}"
|
224
|
+
elsif actual_offset != expected and expected != true
|
225
|
+
raise ValidityError,
|
226
|
+
"offset is '#{actual_offset}' but " +
|
227
|
+
"expected '#{expected}' for #{debug_name}"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def adjust_offset(io)
|
232
|
+
actual_offset = io.offset
|
233
|
+
expected = eval_parameter(:adjust_offset)
|
234
|
+
if actual_offset != expected
|
235
|
+
begin
|
236
|
+
seek = expected - actual_offset
|
237
|
+
io.seekbytes(seek)
|
238
|
+
warn "adjusting stream position by #{seek} bytes" if $VERBOSE
|
239
|
+
rescue
|
240
|
+
raise ValidityError,
|
241
|
+
"offset is '#{actual_offset}' but couldn't seek to " +
|
242
|
+
"expected '#{expected}' for #{debug_name}"
|
280
243
|
end
|
281
244
|
end
|
282
245
|
end
|
@@ -294,14 +257,15 @@ module BinData
|
|
294
257
|
raise NotImplementedError
|
295
258
|
end
|
296
259
|
|
297
|
-
# Returns
|
298
|
-
#
|
299
|
-
def
|
260
|
+
# Returns the debug name of +child+. This only needs to be implemented
|
261
|
+
# by objects that contain child objects.
|
262
|
+
def debug_name_of(child)
|
300
263
|
raise NotImplementedError
|
301
264
|
end
|
302
265
|
|
303
|
-
#
|
304
|
-
|
266
|
+
# Returns the offset of +child+. This only needs to be implemented
|
267
|
+
# by objects that contain child objects.
|
268
|
+
def offset_of(child)
|
305
269
|
raise NotImplementedError
|
306
270
|
end
|
307
271
|
|
@@ -310,13 +274,24 @@ module BinData
|
|
310
274
|
raise NotImplementedError
|
311
275
|
end
|
312
276
|
|
277
|
+
# Trigger function that is called after #do_read.
|
278
|
+
def _done_read
|
279
|
+
raise NotImplementedError
|
280
|
+
end
|
281
|
+
|
313
282
|
# Writes the value for this data to +io+.
|
314
283
|
def _do_write(io)
|
315
284
|
raise NotImplementedError
|
316
285
|
end
|
317
286
|
|
318
287
|
# Returns the number of bytes it will take to write this data.
|
319
|
-
def _do_num_bytes
|
288
|
+
def _do_num_bytes(what)
|
289
|
+
raise NotImplementedError
|
290
|
+
end
|
291
|
+
|
292
|
+
# Assigns the value of +val+ to this data object. Note that +val+ will
|
293
|
+
# always be deep copied to ensure no aliasing problems can occur.
|
294
|
+
def _assign(val)
|
320
295
|
raise NotImplementedError
|
321
296
|
end
|
322
297
|
|
@@ -326,8 +301,14 @@ module BinData
|
|
326
301
|
end
|
327
302
|
|
328
303
|
# Set visibility requirements of methods to implement
|
329
|
-
public :clear, :clear?, :
|
330
|
-
private :_do_read, :_do_write, :_do_num_bytes, :_snapshot
|
304
|
+
public :clear, :clear?, :debug_name_of, :offset_of
|
305
|
+
private :_do_read, :_done_read, :_do_write, :_do_num_bytes, :_assign, :_snapshot
|
306
|
+
|
307
|
+
def single_value?
|
308
|
+
warn "#single_value? is deprecated. It should no longer be needed"
|
309
|
+
false
|
310
|
+
end
|
311
|
+
public :single_value?
|
331
312
|
|
332
313
|
# End To be implemented by subclasses
|
333
314
|
###########################################################################
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'bindata/base'
|
2
|
+
require 'bindata/trace'
|
2
3
|
|
3
4
|
module BinData
|
4
|
-
# A BinData::
|
5
|
-
# binary representation. A value corresponds to a primitive type
|
6
|
-
# as integer, float or string. Only one value can be contained by
|
7
|
-
# object. This value can be read from or written to an IO stream.
|
5
|
+
# A BinData::BasePrimitive object is a container for a value that has a
|
6
|
+
# particular binary representation. A value corresponds to a primitive type
|
7
|
+
# such as as integer, float or string. Only one value can be contained by
|
8
|
+
# this object. This value can be read from or written to an IO stream.
|
8
9
|
#
|
9
10
|
# require 'bindata'
|
10
11
|
#
|
@@ -34,7 +35,7 @@ module BinData
|
|
34
35
|
# [<tt>:initial_value</tt>] This is the initial value to use before one is
|
35
36
|
# either #read or explicitly set with #value=.
|
36
37
|
# [<tt>:value</tt>] The object will always have this value.
|
37
|
-
#
|
38
|
+
# Calls to #value= are ignored when
|
38
39
|
# using this param. In the interval between
|
39
40
|
# calls to #do_read and #done_read, #value
|
40
41
|
# will return the value of the data read from the
|
@@ -45,90 +46,115 @@ module BinData
|
|
45
46
|
# parameter. A boolean return indicates success
|
46
47
|
# or failure. Any other return is compared to
|
47
48
|
# the value just read in.
|
48
|
-
class
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
class BasePrimitive < BinData::Base
|
50
|
+
|
51
|
+
optional_parameters :initial_value, :value, :check_value
|
52
|
+
mutually_exclusive_parameters :initial_value, :value
|
52
53
|
|
53
54
|
def initialize(params = {}, parent = nil)
|
54
55
|
super(params, parent)
|
55
|
-
|
56
|
+
|
57
|
+
@value = nil
|
58
|
+
@in_read = false
|
56
59
|
end
|
57
60
|
|
58
|
-
# Resets the internal state to that of a newly created object.
|
59
61
|
def clear
|
60
62
|
@value = nil
|
61
63
|
@in_read = false
|
62
64
|
end
|
63
65
|
|
64
|
-
# Returns if the value of this data has been read or explicitly set.
|
65
66
|
def clear?
|
66
67
|
@value.nil?
|
67
68
|
end
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
def value
|
71
|
+
# TODO: warn "#value is deprecated, use #snapshot instead"
|
72
|
+
snapshot
|
72
73
|
end
|
73
74
|
|
74
|
-
|
75
|
-
|
76
|
-
|
75
|
+
def value=(val)
|
76
|
+
# TODO: warn "#value= is deprecated, use #assign instead"
|
77
|
+
assign(val)
|
77
78
|
end
|
78
79
|
|
79
|
-
|
80
|
-
|
81
|
-
_value
|
80
|
+
def respond_to?(symbol, include_private=false)
|
81
|
+
super || value.respond_to?(symbol, include_private)
|
82
82
|
end
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
@value = v
|
90
|
-
|
91
|
-
# Note that this doesn't do anything in ruby 1.8.x so ignore for now
|
92
|
-
# # explicitly return the output of #value as v may be different
|
93
|
-
# self.value
|
84
|
+
def method_missing(symbol, *args, &block)
|
85
|
+
if value.respond_to?(symbol)
|
86
|
+
value.__send__(symbol, *args, &block)
|
87
|
+
else
|
88
|
+
super
|
94
89
|
end
|
95
90
|
end
|
96
91
|
|
97
92
|
#---------------
|
98
93
|
private
|
99
94
|
|
100
|
-
# Reads the value for this data from +io+.
|
101
95
|
def _do_read(io)
|
102
96
|
@in_read = true
|
103
|
-
@value =
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
97
|
+
@value = read_and_return_value(io)
|
98
|
+
|
99
|
+
trace_value
|
100
|
+
|
101
|
+
if has_parameter?(:check_value)
|
102
|
+
check_value(value)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def trace_value
|
107
|
+
BinData::trace_message do |tracer|
|
108
|
+
value_string = _value.inspect
|
109
|
+
if value_string.length > 30
|
110
|
+
value_string = value_string.slice(0 .. 30) + "..."
|
114
111
|
end
|
112
|
+
|
113
|
+
tracer.trace("#{debug_name} => #{value_string}")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def check_value(current_value)
|
118
|
+
expected = eval_parameter(:check_value, :value => current_value)
|
119
|
+
if not expected
|
120
|
+
raise ValidityError,
|
121
|
+
"value '#{current_value}' not as expected for #{debug_name}"
|
122
|
+
elsif current_value != expected and expected != true
|
123
|
+
raise ValidityError,
|
124
|
+
"value is '#{current_value}' but " +
|
125
|
+
"expected '#{expected}' for #{debug_name}"
|
115
126
|
end
|
116
127
|
end
|
117
128
|
|
118
|
-
|
129
|
+
def _done_read
|
130
|
+
@in_read = false
|
131
|
+
end
|
132
|
+
|
119
133
|
def _do_write(io)
|
120
|
-
raise "can't write whilst reading" if @in_read
|
121
|
-
io.writebytes(
|
134
|
+
raise "can't write whilst reading #{debug_name}" if @in_read
|
135
|
+
io.writebytes(value_to_binary_string(_value))
|
122
136
|
end
|
123
137
|
|
124
|
-
# Returns the number of bytes it will take to write this data.
|
125
138
|
def _do_num_bytes(ignored)
|
126
|
-
|
139
|
+
value_to_binary_string(_value).length
|
140
|
+
end
|
141
|
+
|
142
|
+
def _assign(val)
|
143
|
+
raise ArgumentError, "can't set a nil value for #{debug_name}" if val.nil?
|
144
|
+
|
145
|
+
unless has_parameter?(:value)
|
146
|
+
raw_val = val.respond_to?(:snapshot) ? val.snapshot : val
|
147
|
+
@value = begin
|
148
|
+
raw_val.dup
|
149
|
+
rescue TypeError
|
150
|
+
# can't dup Fixnums
|
151
|
+
raw_val
|
152
|
+
end
|
153
|
+
end
|
127
154
|
end
|
128
155
|
|
129
|
-
# Returns a snapshot of this data object.
|
130
156
|
def _snapshot
|
131
|
-
|
157
|
+
_value
|
132
158
|
end
|
133
159
|
|
134
160
|
# The unmodified value of this data object. Note that #value calls this
|
@@ -143,13 +169,13 @@ module BinData
|
|
143
169
|
# 5. clear? -> sensible_default
|
144
170
|
# 6. !clear? -> @value
|
145
171
|
|
146
|
-
if not @in_read and (
|
172
|
+
if not @in_read and has_parameter?(:value)
|
147
173
|
# rule 1 above
|
148
|
-
|
174
|
+
eval_parameter(:value)
|
149
175
|
else
|
150
176
|
# combining all other rules gives this simplified expression
|
151
|
-
@value ||
|
152
|
-
|
177
|
+
@value || eval_parameter(:value) ||
|
178
|
+
eval_parameter(:initial_value) || sensible_default()
|
153
179
|
end
|
154
180
|
end
|
155
181
|
|
@@ -157,12 +183,12 @@ module BinData
|
|
157
183
|
# To be implemented by subclasses
|
158
184
|
|
159
185
|
# Return the string representation that +val+ will take when written.
|
160
|
-
def
|
186
|
+
def value_to_binary_string(val)
|
161
187
|
raise NotImplementedError
|
162
188
|
end
|
163
189
|
|
164
190
|
# Read a number of bytes from +io+ and return the value they represent.
|
165
|
-
def
|
191
|
+
def read_and_return_value(io)
|
166
192
|
raise NotImplementedError
|
167
193
|
end
|
168
194
|
|