lib/bindata/base.rb in bindata-0.9.0 vs lib/bindata/base.rb in bindata-0.9.1
- old
+ new
@@ -1,5 +1,6 @@
+require 'bindata/io'
require 'bindata/lazy'
require 'bindata/sanitize'
require 'bindata/registry'
require 'stringio'
@@ -14,10 +15,13 @@
# Parameters may be provided at initialisation to control the behaviour of
# an object. These params are:
#
# [<tt>:readwrite</tt>] If false, calls to #read or #write will
# not perform any I/O. Default is true.
+ # [<tt>:onlyif</tt>] This is an alias for :readwrite. It is generally
+ # used to indicate a data object is optional.
+ # not perform any I/O. Default is true.
# [<tt>:check_offset</tt>] Raise an error if the current IO offset doesn't
# meet this criteria. A boolean return indicates
# success or failure. Any other return is compared
# to the current offset. The variable +offset+
# is made available to any lambda assigned to
@@ -114,10 +118,15 @@
# Returns a sanitized +params+ that is of the form expected
# by #initialize.
def sanitize_parameters(params, *args)
params = params.dup
+ # replace :onlyif with :readwrite
+ if params.has_key?(:onlyif)
+ params[:readwrite] = params.delete(:onlyif)
+ end
+
# add default parameters
default_parameters.each do |k,v|
params[k] = v unless params.has_key?(k)
end
@@ -196,51 +205,72 @@
@env.data_object = self
end
# Reads data into this data object by calling #do_read then #done_read.
def read(io)
- # wrap strings in a StringIO
- io = StringIO.new(io) if io.respond_to?(:to_str)
+ io = BinData::IO.new(io) unless BinData::IO === io
- # remove previous method to prevent warnings
- class << io
- remove_method(:bindata_mark) if method_defined?(:bindata_mark)
- end
-
- # remember the current position in the IO object
- io.instance_eval "def bindata_mark; #{io.pos}; end"
-
do_read(io)
done_read
self
end
# Reads the value for this data from +io+.
def do_read(io)
+ raise ArgumentError, "io must be a BinData::IO" unless BinData::IO === io
+
clear
check_offset(io)
- _do_read(io) if eval_param(:readwrite) != false
+
+ if eval_param(:readwrite)
+ _do_read(io)
+ end
end
- # Writes the value for this data to +io+.
+ # Writes the value for this data to +io+ by calling #do_write.
def write(io)
- _write(io) if eval_param(:readwrite) != false
+ io = BinData::IO.new(io) unless BinData::IO === io
+
+ do_write(io)
+ io.flush
+ self
end
+
+ # Writes the value for this data to +io+.
+ def do_write(io)
+ raise ArgumentError, "io must be a BinData::IO" unless BinData::IO === io
+
+ if eval_param(:readwrite)
+ _do_write(io)
+ end
+ end
+
+ # Returns the number of bytes it will take to write this data by calling
+ # #do_num_bytes.
+ def num_bytes(what = nil)
+ num = do_num_bytes(what)
+ num.ceil
+ end
+
+ # Returns the number of bytes it will take to write this data.
+ def do_num_bytes(what = nil)
+ if eval_param(:readwrite)
+ _do_num_bytes(what)
+ else
+ 0
+ end
+ end
+
# Returns the string representation of this data object.
def to_s
io = StringIO.new
write(io)
io.rewind
io.read
end
- # Returns the number of bytes it will take to write this data.
- def num_bytes(what = nil)
- (eval_param(:readwrite) != false) ? _num_bytes(what) : 0
- end
-
# Return a human readable representation of this object.
def inspect
snapshot.inspect
end
@@ -275,26 +305,26 @@
# Checks that the current offset of +io+ is as expected. This should
# be called from #do_read before performing the reading.
def check_offset(io)
if has_param?(:check_offset)
- actual_offset = io.pos - io.bindata_mark
+ actual_offset = io.offset
expected = eval_param(:check_offset, :offset => actual_offset)
if not expected
raise ValidityError, "offset not as expected"
elsif actual_offset != expected and expected != true
raise ValidityError, "offset is '#{actual_offset}' but " +
"expected '#{expected}'"
end
elsif has_param?(:adjust_offset)
- actual_offset = io.pos - io.bindata_mark
+ actual_offset = io.offset
expected = eval_param(:adjust_offset)
if actual_offset != expected
begin
seek = expected - actual_offset
- io.seek(seek, IO::SEEK_CUR)
+ io.seekbytes(seek)
warn "adjusting stream position by #{seek} bytes" if $VERBOSE
rescue
# could not seek so raise an error
raise ValidityError, "offset is '#{actual_offset}' but " +
"couldn't seek to expected '#{expected}'"
@@ -315,49 +345,49 @@
# Resets the internal state to that of a newly created object.
def clear
raise NotImplementedError
end
- # Reads the data for this data object from +io+.
- def _do_read(io)
+ # Returns whether this data object contains a single value. Single
+ # value data objects respond to <tt>#value</tt> and <tt>#value=</tt>.
+ def single_value?
raise NotImplementedError
end
- # To be called after calling #do_read.
- def done_read
+ # Returns a list of the names of all fields accessible through this
+ # object.
+ def field_names
raise NotImplementedError
end
- # Writes the value for this data to +io+.
- def _write(io)
+ # Returns a snapshot of this data object.
+ def snapshot
raise NotImplementedError
end
- # Returns the number of bytes it will take to write this data.
- def _num_bytes
+ # To be called after calling #do_read.
+ def done_read
raise NotImplementedError
end
- # Returns a snapshot of this data object.
- def snapshot
+ # Reads the data for this data object from +io+.
+ def _do_read(io)
raise NotImplementedError
end
- # Returns whether this data object contains a single value. Single
- # value data objects respond to <tt>#value</tt> and <tt>#value=</tt>.
- def single_value?
+ # Writes the value for this data to +io+.
+ def _do_write(io)
raise NotImplementedError
end
- # Returns a list of the names of all fields accessible through this
- # object.
- def field_names
+ # Returns the number of bytes it will take to write this data.
+ def _do_num_bytes
raise NotImplementedError
end
# Set visibility requirements of methods to implement
- public :clear, :done_read, :snapshot, :single_value?, :field_names
- private :_do_read, :_write, :_num_bytes
+ public :clear, :single_value?, :field_names, :snapshot, :done_read
+ private :_do_read, :_do_write, :_do_num_bytes
# End To be implemented by subclasses
###########################################################################
end
end