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