class Gem::SafeMarshal::Reader

Constants

EMPTY_ARRAY
EMPTY_HASH
EMPTY_STRING
MARSHAL_VERSION

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) click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 23
def initialize(io)
  @io = io
end

Public Instance Methods

read!() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 27
def read!
  read_header
  root = read_element
  raise UnconsumedBytesError unless @io.eof?
  root
end

Private Instance Methods

read_array() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 162
def read_array
  length = read_integer
  return EMPTY_ARRAY if length == 0
  elements = Array.new(length) do
    read_element
  end
  Elements::Array.new(elements)
end
read_bignum() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 267
def read_bignum
  sign = read_byte
  data = @io.read(read_integer * 2)
  Elements::Bignum.new(sign, data)
end
read_byte() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 44
def read_byte
  @io.getbyte
end
read_class() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 277
def read_class
  raise NotImplementedError, "Reading Marshal objects of type class is not implemented"
end
read_class_or_module() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 285
def read_class_or_module
  raise NotImplementedError, "Reading Marshal objects of type class_or_module is not implemented"
end
read_data() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 289
def read_data
  raise NotImplementedError, "Reading Marshal objects of type data is not implemented"
end
read_element() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 82
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
  when nil
    raise EOFError, "Unexpected EOF"
  else
    raise Error, "Unknown marshal type discriminator #{type.chr.inspect} (#{type})"
  end
end
read_extended_object() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 273
def read_extended_object
  raise NotImplementedError, "Reading Marshal objects of type extended_object is not implemented"
end
read_false() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 149
def read_false
  Elements::False::FALSE
end
read_float() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 262
def read_float
  string = @io.read(read_integer)
  Elements::Float.new(string)
end
read_hash() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 232
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() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 241
def read_hash_with_default_value
  pairs = Array.new(read_integer) do
    [read_element, read_element]
  end
  default = read_element
  Elements::HashWithDefaultValue.new(pairs, default)
end
read_header() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 39
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() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 48
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
  when nil
    raise EOFError, "Unexpected EOF"
  else
    signed = (b ^ 128) - 128
    if b >= 128
      signed + 5
    else
      signed - 5
    end
  end
end
read_module() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 281
def read_module
  raise NotImplementedError, "Reading Marshal objects of type module is not implemented"
end
read_nil() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 258
def read_nil
  Elements::Nil::NIL
end
read_object() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 249
def read_object
  name = read_element
  object = Elements::Object.new(name)
  ivars = Array.new(read_integer) do
    [read_element, read_element]
  end
  Elements::WithIvars.new(object, ivars)
end
read_object_with_ivars() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 171
def read_object_with_ivars
  object = read_element
  ivars = Array.new(read_integer) do
    [read_element, read_element]
  end
  Elements::WithIvars.new(object, ivars)
end
read_regexp() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 293
def read_regexp
  raise NotImplementedError, "Reading Marshal objects of type regexp is not implemented"
end
read_string() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 138
def read_string
  length = read_integer
  return EMPTY_STRING if length == 0
  str = @io.read(length)
  Elements::String.new(str)
end
read_struct() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 297
def read_struct
  raise NotImplementedError, "Reading Marshal objects of type struct is not implemented"
end
read_symbol() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 120
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 = -@io.read(len)
    Elements::Symbol.new(name)
  end
end
read_true() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 145
def read_true
  Elements::True::TRUE
end
read_user_class() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 301
def read_user_class
  name = read_element
  wrapped_object = read_element
  Elements::UserClass.new(name, wrapped_object)
end
read_user_defined() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 153
def read_user_defined
  name = read_element
  binary_string = @io.read(read_integer)
  Elements::UserDefined.new(name, binary_string)
end
read_user_marshal() click to toggle source
# File lib/rubygems/safe_marshal/reader.rb, line 184
def read_user_marshal
  name = read_element
  data = read_element
  Elements::UserMarshal.new(name, data)
end