Class: Kaitai::Struct::SubIO

Inherits:
Object
  • Object
show all
Defined in:
lib/kaitai/struct/struct.rb

Overview

Substream IO implementation: a IO object which wraps existing IO object and provides similar byte/bytes reading functionality, but only for a limited set of bytes starting from specified offset and spanning up to specified length.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent_io, parent_start, size) ⇒ SubIO

Returns a new instance of SubIO.



618
619
620
621
622
623
624
# File 'lib/kaitai/struct/struct.rb', line 618

def initialize(parent_io, parent_start, size)
  @parent_io = parent_io
  @parent_start = parent_start
  @size = size
  @pos = 0
  @closed = false
end

Instance Attribute Details

#parent_ioObject (readonly)

Parent IO object that this substream is projecting data from.



602
603
604
# File 'lib/kaitai/struct/struct.rb', line 602

def parent_io
  @parent_io
end

#parent_startObject (readonly)

Offset of start of substream in coordinates of parent stream. In coordinates of substream itself start will be always 0.



607
608
609
# File 'lib/kaitai/struct/struct.rb', line 607

def parent_start
  @parent_start
end

#posObject (readonly)

Current position in a substream. Independent from a position in a parent IO.



616
617
618
# File 'lib/kaitai/struct/struct.rb', line 616

def pos
  @pos
end

#sizeObject (readonly)

Size of substream in bytes.



611
612
613
# File 'lib/kaitai/struct/struct.rb', line 611

def size
  @size
end

Instance Method Details

#closeObject



701
702
703
704
# File 'lib/kaitai/struct/struct.rb', line 701

def close
  @closed = true
  nil
end

#closed?Boolean

Returns:

  • (Boolean)


706
707
708
# File 'lib/kaitai/struct/struct.rb', line 706

def closed?
  @closed
end

#eof?Boolean

Returns:

  • (Boolean)

Raises:

  • (IOError)


626
627
628
629
630
# File 'lib/kaitai/struct/struct.rb', line 626

def eof?
  raise IOError.new('not opened for reading') if @closed

  @pos >= @size
end

#getcObject

Raises:

  • (IOError)


642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
# File 'lib/kaitai/struct/struct.rb', line 642

def getc
  raise IOError.new('not opened for reading') if @closed

  return nil if @pos >= @size

  # remember position in parent IO
  old_pos = @parent_io.pos
  @parent_io.seek(@parent_start + @pos)
  begin
    res = @parent_io.getc
    @pos += 1
  ensure
    # restore position in parent IO
    @parent_io.seek(old_pos)
  end

  res
end

#read(len = nil) ⇒ Object

Raises:

  • (IOError)


661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
# File 'lib/kaitai/struct/struct.rb', line 661

def read(len = nil)
  raise IOError.new('not opened for reading') if @closed

  # read until the end of substream
  if len.nil?
    len = @size - @pos
    return String.new if len <= 0
  elsif len.respond_to?(:to_int)
    len = len.to_int
    # special case for requesting exactly 0 bytes
    return String.new if len == 0

    if len > 0
      # cap intent to read if going beyond substream boundary
      left = @size - @pos

      # if actually requested reading and we're beyond the boundary, return nil
      return nil if left <= 0

      # otherwise, still return something, but less than requested
      len = left if len > left
    end
  end

  # remember position in parent IO
  old_pos = @parent_io.pos

  @parent_io.seek(@parent_start + @pos)
  begin
    res = @parent_io.read(len)
    read_len = res.bytesize
    @pos += read_len
  ensure
    # restore position in parent IO
    @parent_io.seek(old_pos)
  end

  res
end

#seek(offset, whence = IO::SEEK_SET) ⇒ Object

Raises:

  • (ArgumentError)


632
633
634
635
636
637
638
639
640
# File 'lib/kaitai/struct/struct.rb', line 632

def seek(offset, whence = IO::SEEK_SET)
  raise ArgumentError.new('only IO::SEEK_SET is supported by SubIO#seek') unless whence == IO::SEEK_SET

  offset = Internal.num2long(offset)
  raise IOError.new('closed stream') if @closed
  raise Errno::EINVAL if offset < 0
  @pos = offset.to_int
  return 0
end