class Marshal::Structure::Parser

Parses a tokenized Marshal stream into a structure that resembles how the stream would be loaded.

Marshal can contain references to previous objects. These references are included in the structure following referenceable items. For example, a recursive array:

a = []
a << self

Has the following Marshal stream:

"\x04\x08[\x06@\x00" # @\x00 is a link to the first Object in the stream

And has the following Marshal structure:

[:array, 0, 1,
  [:link, 0]]

The first item after :array, the 0 is the object's stream ID. The :link references this ID.

Public Class Methods

new(tokens) click to toggle source

Creates a new Parser using a token stream Enumerator tokens.

# File lib/marshal/structure/parser.rb, line 29
def initialize tokens
  @tokens = tokens
  @objects = -1
  @symbols = -1
end

Public Instance Methods

get_symbol() click to toggle source

Constructs a Symbol from the token stream

# File lib/marshal/structure/parser.rb, line 262
def get_symbol
  token = @tokens.next

  case token
  when :symbol then
    [:symbol, *parse_symbol]
  when :symbol_link then
    [:symbol_link, @tokens.next]
  else
    raise ArgumentError, "expected SYMBOL or SYMLINK, got #{token.inspect}"
  end
end
object_ref() click to toggle source

Creates a new object reference

# File lib/marshal/structure/parser.rb, line 38
def object_ref
  @objects += 1
end
parse() click to toggle source

Creates the structure for the remaining stream.

# File lib/marshal/structure/parser.rb, line 45
def parse
  token = @tokens.next

  return token if [:nil, :true, :false].include? token

  obj = [token]

  rest =
    case token
    when :array                       then parse_array
    when :bignum                      then parse_bignum
    when :class, :module              then parse_class
    when :data                        then parse_data
    when :extended                    then parse_extended
    when :fixnum, :link, :symbol_link then [@tokens.next]
    when :float                       then parse_float
    when :hash                        then parse_hash
    when :hash_default                then parse_hash_def
    when :object                      then parse_object
    when :regexp                      then parse_regexp
    when :string                      then parse_string
    when :struct                      then parse_struct
    when :symbol                      then parse_symbol
    when :user_class                  then parse_extended
    when :user_defined                then parse_user_defined
    when :user_marshal                then parse_user_marshal
    when :instance_variables          then
      [parse].concat parse_instance_variables
    when :module_old                  then
      obj[0] = :module
      parse_class
    else
      raise Marshal::Structure::Error, "bug: unknown token #{token.inspect}"
    end

  obj.concat rest
rescue Marshal::Structure::EndOfMarshal
  raise ArgumentError, 'marshal data too short'
end
parse_array() click to toggle source

Creates the body of an :array object

# File lib/marshal/structure/parser.rb, line 88
def parse_array
  obj = [object_ref]

  items = @tokens.next

  obj << items

  items.times do
    obj << parse
  end

  obj
end
parse_bignum() click to toggle source

Creates the body of a :bignum object

# File lib/marshal/structure/parser.rb, line 105
def parse_bignum
  result = @tokens.next

  [object_ref, result]
end
parse_class() click to toggle source

Creates the body of a :class object

# File lib/marshal/structure/parser.rb, line 114
def parse_class
  [object_ref, @tokens.next]
end
parse_data() click to toggle source

Creates the body of a wrapped C pointer object

# File lib/marshal/structure/parser.rb, line 121
def parse_data
  [object_ref, get_symbol, parse]
end
parse_extended() click to toggle source

Creates the body of an extended object

# File lib/marshal/structure/parser.rb, line 128
def parse_extended
  [get_symbol, parse]
end
parse_float() click to toggle source

Creates the body of a :float object

# File lib/marshal/structure/parser.rb, line 135
def parse_float
  float = @tokens.next

  [object_ref, float]
end
parse_hash() click to toggle source

Creates the body of a :hash object

# File lib/marshal/structure/parser.rb, line 144
def parse_hash
  obj = [object_ref]

  pairs = @tokens.next
  obj << pairs

  pairs.times do
    obj << parse
    obj << parse
  end

  obj
end
parse_hash_def() click to toggle source

Creates the body of a :hash_def object

# File lib/marshal/structure/parser.rb, line 161
def parse_hash_def
  ref, hash = parse_hash

  [ref, hash, parse]
end
parse_instance_variables() click to toggle source

Instance variables contain an object followed by a count of instance variables and their contents

# File lib/marshal/structure/parser.rb, line 171
def parse_instance_variables
  instance_variables = []

  pairs = @tokens.next
  instance_variables << pairs

  pairs.times do
    instance_variables << get_symbol
    instance_variables << parse
  end

  instance_variables
end
parse_object() click to toggle source

Creates an Object

# File lib/marshal/structure/parser.rb, line 188
def parse_object
  [object_ref, get_symbol, parse_instance_variables]
end
parse_regexp() click to toggle source

Creates a Regexp

# File lib/marshal/structure/parser.rb, line 195
def parse_regexp
  [object_ref, @tokens.next, @tokens.next]
end
parse_string() click to toggle source

Creates a String

# File lib/marshal/structure/parser.rb, line 202
def parse_string
  [object_ref, @tokens.next]
end
parse_struct() click to toggle source

Creates a Struct

# File lib/marshal/structure/parser.rb, line 209
def parse_struct
  obj = [object_ref, get_symbol]

  members = @tokens.next
  obj << members

  members.times do
    obj << get_symbol
    obj << parse
  end

  obj
end
parse_symbol() click to toggle source

Creates a Symbol

# File lib/marshal/structure/parser.rb, line 226
def parse_symbol
  sym = @tokens.next

  [symbol_ref, sym]
end
parse_user_defined() click to toggle source

Creates an object saved by _dump

# File lib/marshal/structure/parser.rb, line 235
def parse_user_defined
  name = get_symbol

  data = @tokens.next

  [object_ref, name, data]
end
parse_user_marshal() click to toggle source

Creates an object saved by marshal_dump

# File lib/marshal/structure/parser.rb, line 246
def parse_user_marshal
  name = get_symbol

  [object_ref, name, parse]
end
symbol_ref() click to toggle source

Creates a new symbol reference

# File lib/marshal/structure/parser.rb, line 255
def symbol_ref
  @symbols += 1
end