Skip to content

Commit

Permalink
Refactored IO
Browse files Browse the repository at this point in the history
  • Loading branch information
dmendel committed Jun 20, 2023
1 parent c4770b2 commit ac8c2e3
Show file tree
Hide file tree
Showing 7 changed files with 467 additions and 538 deletions.
4 changes: 2 additions & 2 deletions ChangeLog.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
== Version 2.5.0 (2023-xx-xx)

* Removed experimental :check_offset and :adjust_offset parameters.
* Nested tracing is no longer an error.
* Ruby 2.4 no longer supported.
* Allow for nested tracing.
* Ruby 2.5 is now required.

== Version 2.4.15 (2023-02-07)

Expand Down
104 changes: 93 additions & 11 deletions lib/bindata/buffer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module BinData
# end
# end
# end
#
#
#
# == Parameters
#
Expand Down Expand Up @@ -80,29 +80,111 @@ 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, raw_io|
@type.do_read(transformed_io)
raw_io.read_rest
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, raw_io|
@type.do_write(transformed_io)
raw_io.write_rest
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 chained(io)
super.tap do
@buf_start = offset
@buf_end = @buf_start + @bytes_remaining
end
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

super(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)
super(n)
end

def read(n)
nbytes = buffer_limited_n(n)
@bytes_remaining -= nbytes

super(nbytes)
end

def write(data)
nbytes = buffer_limited_n(data.size)
@bytes_remaining -= nbytes
if nbytes < data.size
data = data[0, nbytes]
end

super(data)
end

def read_rest
read(nil)
end

def write_rest
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 seeking
# elsif n.negative?
# limit = @bytes_remaining + @buf_start - @buf_end
# n < limit ? limit : n
else
0
end
end
end
end

class BufferArgProcessor < BaseArgProcessor
Expand Down
20 changes: 10 additions & 10 deletions lib/bindata/delayed_io.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ def num_bytes
@type.num_bytes
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

Expand All @@ -104,20 +104,20 @@ def rel_offset
abs_offset
end

def do_read(io) #:nodoc:
def do_read(io) # :nodoc:
@read_io = io
end

def do_write(io) #:nodoc:
def do_write(io) # :nodoc:
@write_io = io
end

def do_num_bytes #:nodoc:
def do_num_bytes # :nodoc:
0
end

def include_obj?
! has_parameter?(:onlyif) || eval_parameter(:onlyif)
!has_parameter?(:onlyif) || eval_parameter(:onlyif)
end

# DelayedIO objects aren't read when #read is called.
Expand All @@ -126,7 +126,7 @@ def read_now!
return unless include_obj?
raise IOError, "read from where?" unless @read_io

@read_io.seekbytes(abs_offset - @read_io.offset)
@read_io.seek_to_abs_offset(abs_offset)
start_read do
@type.do_read(@read_io)
end
Expand All @@ -138,7 +138,7 @@ def write_now!
return unless include_obj?
raise IOError, "write to where?" unless @write_io

@write_io.seekbytes(abs_offset - @write_io.offset)
@write_io.seek_to_abs_offset(abs_offset)
@type.do_write(@write_io)
end
end
Expand All @@ -153,8 +153,8 @@ def sanitize_parameters!(obj_class, params)
end
end

# Add +auto_call_delayed_io+ keyword to BinData::Base.
class Base
# Add +auto_call_delayed_io+ keyword to BinData::Base.
class << self
# The +auto_call_delayed_io+ keyword sets a data object tree to perform
# multi pass I/O automatically.
Expand Down

0 comments on commit ac8c2e3

Please sign in to comment.