class KeyedArchive

Constants

VERSION

Attributes

archiver[RW]
objects[RW]
top[RW]
version[RW]

Public Class Methods

new(opts={}) click to toggle source

Take the same sort of arguments as CFPropertyList :file => filename to load :data => variable with the data to load directly

# File lib/keyed_archive.rb, line 13
def initialize(opts={})
  blob = opts[:data]
  filename = opts[:file]

  plist = CFPropertyList::List.new(:file => filename) unless filename.nil? or !File.exists?(filename)
  plist = CFPropertyList::List.new(:data => blob) unless blob.nil? or blob.length < 1

  if !plist.nil?
    data = CFPropertyList.native_types(plist.value)

    @archiver = data['$archiver']
    @objects = data['$objects']
    @top = data['$top']
    @version = data['$version']
  else
    raise "Plist not created"
  end
end

Public Instance Methods

unpacked_top() click to toggle source

Loops through the entries within '$top' to replace any values that are pointers to objects.

# File lib/keyed_archive/unpacked_objects.rb, line 5
def unpacked_top

  # Create the return value
  unpacked_top = Hash.new

  # Loop over each pair in the '$top' hash
  # to recursively replace the values
  @top.each_pair do |key, value|
    unpacked_top[key] = recursive_replace(value, -1, [])
  end

  # Politely return, our job is done
  return unpacked_top
end

Private Instance Methods

recursive_replace(value, current_location, locations) click to toggle source

Handles the recursive replacement of values within the '$objects' array. Tracks the object locations it has already touched to prevent infinite loops.

# File lib/keyed_archive/unpacked_objects.rb, line 25
def recursive_replace(value, current_location, locations)
  # By default we just return the value itself, usually a String
  to_return = value

  # If the value is really representing nil, change it to nil
  if value.is_a? String and value == "$null"
    to_return = nil
  end

  # If we have an Integer, we want to bring in the object
  # that Integer points to
  if value.is_a? Integer

    # If we ever find a reference to one of our parents, just stop where we are
    if locations.include?(current_location)
      to_return = value
    else
      to_return = recursive_replace(@objects[value], value, locations.clone.push(current_location)) 
    end

  # If we have a Hash, we want to check each entry
  # and replace any values which need it
  elsif value.is_a? Hash

    # Build up a new Hash
    to_return = Hash.new

    # Loop over the pairs to check the key, value, or both
    value.each_pair do |tmp_key, tmp_value|

      # If this points to an array of objects,
      # then we should bring those values in
      if tmp_key == "NS.objects" or tmp_key == "NS.keys"
        new_array = Array.new
        tmp_value.each do |entry|
          new_array.push(recursive_replace(entry, entry, locations.clone.push(current_location)))
        end
        to_return[tmp_key] = new_array

      # Otherwise, we just want to replace the value with
      # its recursive version
      else
        to_return[tmp_key] = recursive_replace(tmp_value, tmp_value, locations.clone.push(current_location))
      end
    end
  end

  # Give back the value, politely
  return to_return
end