# class Gem::SafeMarshal::Reader

### Constants

EMPTY_ARRAY
EMPTY_HASH
EMPTY_STRING
MARSHAL_VERSION
OBJECT_LINKS

  profiling bundle install –full-index shows that offset 6 is by far the most common object link, so we special case it to avoid allocating a new object a third of the time. the following are all the object links that appear more than 10000 times in my profiling

STRING_E_SYMBOL

### Public Class Methods

new (io)
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 29
    def initialize(io)
      @io = io
    end

### Public Instance Methods

read! ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 33
    def read!
      read_header
      root = read_element
      raise UnconsumedBytesError, "expected EOF, got #{@io.read(10).inspect}... after top-level element #{root.class}" unless @io.eof?
      root
    end

### Private Instance Methods

read_array ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 172
    def read_array
      length = read_integer
      return EMPTY_ARRAY if length == 0
      raise NegativeLengthError if length < 0
      elements = Array.new(length) do
        read_element
      end
      Elements::Array.new(elements)
    end

read_bignum ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 284
    def read_bignum
      sign = read_byte
      data = read_bytes(read_integer * 2)
      Elements::Bignum.new(sign, data)
    end

read_byte ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 58
    def read_byte
      @io.getbyte || raise(EOFError, "Unexpected EOF")
    end

read_bytes (n)
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 50
    def read_bytes(n)
      raise NegativeLengthError if n < 0
      str = @io.read(n)
      raise EOFError, "expected #{n} bytes, got EOF" if str.nil?
      raise DataTooShortError, "expected #{n} bytes, got #{str.inspect}" unless str.bytesize == n
      str
    end

read_class ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 294
    def read_class
      raise NotImplementedError, "Reading Marshal objects of type class is not implemented"
    end

read_class_or_module ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 302
    def read_class_or_module
      raise NotImplementedError, "Reading Marshal objects of type class_or_module is not implemented"
    end

read_data ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 306
    def read_data
      raise NotImplementedError, "Reading Marshal objects of type data is not implemented"
    end

read_element ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 94
    def read_element
      type = read_byte
      case type
      when 34 then read_string # ?"
      when 48 then read_nil # ?0
      when 58 then read_symbol # ?:
      when 59 then read_symbol_link # ?;
      when 64 then read_object_link # ?@
      when 70 then read_false # ?F
      when 73 then read_object_with_ivars # ?I
      when 84 then read_true # ?T
      when 85 then read_user_marshal # ?U
      when 91 then read_array # ?[
      when 102 then read_float # ?f
      when 105 then Elements::Integer.new(read_integer) # ?i
      when 108 then read_bignum # ?l
      when 111 then read_object # ?o
      when 117 then read_user_defined # ?u
      when 123 then read_hash # ?{
      when 125 then read_hash_with_default_value # ?}
      when 101 then read_extended_object # ?e
      when 99 then read_class # ?c
      when 109 then read_module # ?m
      when 77 then read_class_or_module # ?M
      when 100 then read_data # ?d
      when 47 then read_regexp # ?/
      when 83 then read_struct # ?S
      when 67 then read_user_class # ?C
      else
        raise Error, "Unknown marshal type discriminator #{type.chr.inspect} (#{type})"
      end
    end

read_extended_object ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 290
    def read_extended_object
      raise NotImplementedError, "Reading Marshal objects of type extended_object is not implemented"
    end

read_false ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 159
    def read_false
      Elements::False::FALSE
    end

read_float ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 279
    def read_float
      string = read_bytes(read_integer)
      Elements::Float.new(string)
    end

read_hash ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 245
    def read_hash
      length = read_integer
      return EMPTY_HASH if length == 0
      pairs = Array.new(length) do
        [read_element, read_element]
      end
      Elements::Hash.new(pairs)
    end

read_hash_with_default_value ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 254
    def read_hash_with_default_value
      length = read_integer
      raise NegativeLengthError if length < 0
      pairs = Array.new(length) do
        [read_element, read_element]
      end
      default = read_element
      Elements::HashWithDefaultValue.new(pairs, default)
    end

read_header ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 45
    def read_header
      v = @io.read(2)
      raise UnsupportedVersionError, "Unsupported marshal version #{v.bytes.map(&:ord).join(".")}, expected #{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}" unless v == MARSHAL_VERSION
    end

read_integer ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 62
    def read_integer
      b = read_byte

      case b
      when 0x00
        0
      when 0x01
        read_byte
      when 0x02
        read_byte | (read_byte << 8)
      when 0x03
        read_byte | (read_byte << 8) | (read_byte << 16)
      when 0x04
        read_byte | (read_byte << 8) | (read_byte << 16) | (read_byte << 24)
      when 0xFC
        read_byte | (read_byte << 8) | (read_byte << 16) | (read_byte << 24) | -0x100000000
      when 0xFD
        read_byte | (read_byte << 8) | (read_byte << 16) | -0x1000000
      when 0xFE
        read_byte | (read_byte << 8) | -0x10000
      when 0xFF
        read_byte | -0x100
      else
        signed = (b ^ 128) - 128
        if b >= 128
          signed + 5
        else
          signed - 5
        end
      end
    end

read_module ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 298
    def read_module
      raise NotImplementedError, "Reading Marshal objects of type module is not implemented"
    end

read_nil ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 275
    def read_nil
      Elements::Nil::NIL
    end

read_object ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 264
    def read_object
      name = read_element
      object = Elements::Object.new(name)
      length = read_integer
      raise NegativeLengthError if length < 0
      ivars = Array.new(length) do
        [read_element, read_element]
      end
      Elements::WithIvars.new(object, ivars)
    end

read_object_link ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 237
    def read_object_link
      offset = read_integer
      OBJECT_LINKS[offset] || Elements::ObjectLink.new(offset)
    end

read_object_with_ivars ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 182
    def read_object_with_ivars
      object = read_element
      length = read_integer
      raise NegativeLengthError if length < 0
      ivars = Array.new(length) do
        [read_element, read_element]
      end
      Elements::WithIvars.new(object, ivars)
    end

read_regexp ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 310
    def read_regexp
      raise NotImplementedError, "Reading Marshal objects of type regexp is not implemented"
    end

read_string ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 148
    def read_string
      length = read_integer
      return EMPTY_STRING if length == 0
      str = read_bytes(length)
      Elements::String.new(str)
    end

read_struct ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 314
    def read_struct
      raise NotImplementedError, "Reading Marshal objects of type struct is not implemented"
    end

read_symbol ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 130
    def read_symbol
      len = read_integer
      if len == 1
        byte = read_byte
        if byte == 69 # ?E
          STRING_E_SYMBOL
        else
          Elements::Symbol.new(byte.chr)
        end
      else
        name = read_bytes(len)
        Elements::Symbol.new(name)
      end
    end

read_symbol_link ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 192
    def read_symbol_link
      offset = read_integer
      Elements::SymbolLink.new(offset)
    end

read_true ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 155
    def read_true
      Elements::True::TRUE
    end

read_user_class ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 318
    def read_user_class
      name = read_element
      wrapped_object = read_element
      Elements::UserClass.new(name, wrapped_object)
    end

read_user_defined ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 163
    def read_user_defined
      name = read_element
      binary_string = read_bytes(read_integer)
      Elements::UserDefined.new(name, binary_string)
    end

read_user_marshal ()
Source

    # File lib/rubygems/safe_marshal/reader.rb, line 197
    def read_user_marshal
      name = read_element
      data = read_element
      Elements::UserMarshal.new(name, data)
    end