lib/bindata/buffer.rb in bindata-2.4.15 vs lib/bindata/buffer.rb in bindata-2.5.0

- old
+ new

@@ -39,12 +39,12 @@ # uint8 :len # string :str, length: :len # end # end # end - # # + # # == Parameters # # Parameters may be provided at initialisation to control the behaviour of # an object. These params are: # @@ -78,31 +78,109 @@ def snapshot @type.snapshot end - def respond_to?(symbol, include_private = false) #:nodoc: - @type.respond_to?(symbol, include_private) || super + def respond_to_missing?(symbol, include_all = false) # :nodoc: + @type.respond_to?(symbol, include_all) || super end - def method_missing(symbol, *args, &block) #:nodoc: + def method_missing(symbol, *args, &block) # :nodoc: @type.__send__(symbol, *args, &block) end - def do_read(io) #:nodoc: - io.with_buffer(eval_parameter(:length)) do - @type.do_read(io) + def do_read(io) # :nodoc: + buf_len = eval_parameter(:length) + io.transform(BufferIO.new(buf_len)) do |transformed_io, _| + @type.do_read(transformed_io) end end - def do_write(io) #:nodoc: - io.with_buffer(eval_parameter(:length)) do - @type.do_write(io) + def do_write(io) # :nodoc: + buf_len = eval_parameter(:length) + io.transform(BufferIO.new(buf_len)) do |transformed_io, _| + @type.do_write(transformed_io) end end - def do_num_bytes #:nodoc: + def do_num_bytes # :nodoc: eval_parameter(:length) + end + + # Transforms the IO stream to restrict access inside + # a buffer of specified length. + class BufferIO < IO::Transform + def initialize(length) + super() + @bytes_remaining = length + end + + def before_transform + @buf_start = offset + @buf_end = @buf_start + @bytes_remaining + end + + def num_bytes_remaining + [@bytes_remaining, super].min + rescue IOError + @bytes_remaining + end + + def skip(n) + nbytes = buffer_limited_n(n) + @bytes_remaining -= nbytes + + chain_skip(nbytes) + end + + def seek_abs(n) + if n < @buf_start || n >= @buf_end + raise IOError, "can not seek to abs_offset outside of buffer" + end + + @bytes_remaining -= (n - offset) + chain_seek_abs(n) + end + + def read(n) + nbytes = buffer_limited_n(n) + @bytes_remaining -= nbytes + + chain_read(nbytes) + end + + def write(data) + nbytes = buffer_limited_n(data.size) + @bytes_remaining -= nbytes + if nbytes < data.size + data = data[0, nbytes] + end + + chain_write(data) + end + + def after_read_transform + read(nil) + end + + def after_write_transform + write("\x00" * @bytes_remaining) + end + + def buffer_limited_n(n) + if n.nil? + @bytes_remaining + elsif n.positive? + limit = @bytes_remaining + n > limit ? limit : n +# uncomment if we decide to allow backwards skipping +# elsif n.negative? +# limit = @bytes_remaining + @buf_start - @buf_end +# n < limit ? limit : n + else + 0 + end + end end end class BufferArgProcessor < BaseArgProcessor include MultiFieldArgSeparator