lib/bindata/io.rb in bindata-2.3.1 vs lib/bindata/io.rb in bindata-2.3.2
- old
+ new
@@ -16,11 +16,11 @@
if io.respond_to?(:to_str)
io = BinData::IO.create_string_io(io.to_str)
end
@raw_io = io
- @buffer_end_pos = nil
+ @buffer_end_points = nil
extend seekable? ? SeekableStream : UnSeekableStream
stream_init
end
@@ -36,49 +36,68 @@
def seek(n)
seek_raw(buffer_limited_n(n))
end
def buffer_limited_n(n)
- if @buffer_end_pos
+ if @buffer_end_points
if n.nil? or n > 0
- max = @buffer_end_pos[1] - offset
+ max = @buffer_end_points[1] - offset
n = max if n.nil? or n > max
else
- min = @buffer_end_pos[0] - offset
+ min = @buffer_end_points[0] - offset
n = min if n < min
end
end
n
end
def with_buffer_common(n, &block)
- prev = @buffer_end_pos
+ prev = @buffer_end_points
if prev
avail = prev[1] - offset
n = avail if n > avail
end
- @buffer_end_pos = [offset, offset + n]
+ @buffer_end_points = [offset, offset + n]
begin
- block.call(*@buffer_end_pos)
+ block.call(*@buffer_end_points)
ensure
- @buffer_end_pos = prev
+ @buffer_end_points = prev
end
end
# Use #seek and #pos on seekable streams
module SeekableStream
# The number of bytes remaining in the input stream.
def num_bytes_remaining
- mark = @raw_io.pos
+ start_mark = @raw_io.pos
@raw_io.seek(0, ::IO::SEEK_END)
- bytes_remaining = @raw_io.pos - mark
- @raw_io.seek(mark, ::IO::SEEK_SET)
+ end_mark = @raw_io.pos
+ if @buffer_end_points
+ if @buffer_end_points[1] < end_mark
+ end_mark = @buffer_end_points[1]
+ end
+ end
+
+ bytes_remaining = end_mark - start_mark
+ @raw_io.seek(start_mark, ::IO::SEEK_SET)
+
bytes_remaining
end
+ # All io calls in +block+ are rolled back after this
+ # method completes.
+ def with_readahead(&block)
+ mark = @raw_io.pos
+ begin
+ block.call
+ ensure
+ @raw_io.seek(mark, ::IO::SEEK_SET)
+ end
+ end
+
#-----------
private
def stream_init
@initial_pos = @raw_io.pos
@@ -110,19 +129,66 @@
# The number of bytes remaining in the input stream.
def num_bytes_remaining
raise IOError, "stream is unseekable"
end
+ # All io calls in +block+ are rolled back after this
+ # method completes.
+ def with_readahead(&block)
+ mark = @offset
+ @read_data = ""
+ @in_readahead = true
+
+ class << self
+ alias_method :read_raw_without_readahead, :read_raw
+ alias_method :read_raw, :read_raw_with_readahead
+ end
+
+ begin
+ block.call
+ ensure
+ @offset = mark
+ @in_readahead = false
+ end
+ end
+
#-----------
private
def stream_init
@offset = 0
end
def read_raw(n)
data = @raw_io.read(n)
@offset += data.size if data
+ data
+ end
+
+ def read_raw_with_readahead(n)
+ data = ""
+
+ if @read_data.length > 0 and not @in_readahead
+ bytes_to_consume = [n, @read_data.length].min
+ data << @read_data.slice!(0, bytes_to_consume)
+ n -= bytes_to_consume
+
+ if @read_data.length == 0
+ class << self
+ alias_method :read_raw, :read_raw_without_readahead
+ end
+ end
+ end
+
+ raw_data = @raw_io.read(n)
+ data << raw_data if raw_data
+
+ if @in_readahead
+ @read_data << data
+ end
+
+ @offset += data.size
+
data
end
def write_raw(data)
@offset += data.size