class CFPropertyList::PlainParser

XML parser

Constants

SPACES_AND_COMMENTS

Public Instance Methods

load(opts) click to toggle source

read a XML file

opts
  • :file - The filename of the file to load

  • :data - The data to parse

# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 11
def load(opts)
  @doc = nil

  if(opts.has_key?(:file)) then
    File.open(opts[:file], :external_encoding => "ASCII") do |fd|
      @doc = StringScanner.new(fd.read)
    end
  else
    @doc = StringScanner.new(opts[:data])
  end

  if @doc
    root = import_plain
    raise CFFormatError.new('content after root object') unless @doc.eos?

    return root
  end

  raise CFFormatError.new('invalid plist string or file not found')
end
to_str(opts={}) click to toggle source

serialize CFPropertyList object to XML

opts = {}

Specify options: :formatted - Use indention and line breaks

# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 36
def to_str(opts={})
  opts[:root].to_plain(self)
end

Protected Instance Methods

escape_char() click to toggle source
# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 105
def escape_char
  case @doc.matched
  when '"'
    '"'
  when '\'
    '\'
  when 'a'
    "\a"
  when 'b'
    "\b"
  when 'f'
    "\f"
  when 'n'
    "\n"
  when 'v'
    "\v"
  when 'r'
    "\r"
  when 't'
    "\t"
  end
end
import_plain() click to toggle source

import the XML values

# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 175
def import_plain
  skip_whitespaces
  ret = nil

  if @doc.scan(/\{/) # dict
    ret = read_dict
  elsif @doc.scan(/\(/) # array
    ret = read_array
  elsif @doc.scan(/"/) # string
    ret = read_quoted
  elsif @doc.scan(/</) # binary
    ret = read_binary
  else # string w/o quotes
    ret = read_unquoted
  end

  return ret
end
read_array() click to toggle source
# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 79
def read_array
  skip_whitespaces
  ary = []

  while not @doc.scan(/\)/)
    val = import_plain

    return nil if not val or not val.value
    skip_whitespaces

    if not @doc.skip(/,\s*/)
      if @doc.scan(/\)/)
        ary << val
        return CFArray.new(ary)
      end

      raise CFFormatError.new("invalid array format")
    end

    ary << val
    raise CFFormatError.new("invalid array format") if @doc.eos?
  end

  CFArray.new(ary)
end
read_binary() click to toggle source
# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 167
def read_binary
  @doc.scan(/(.*?)>/)

  hex_str = @doc[1].gsub(/ /, '')
  CFData.new([hex_str].pack("H*"), CFData::DATA_RAW)
end
read_dict() click to toggle source
# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 45
def read_dict
  skip_whitespaces
  hsh = {}

  while not @doc.scan(/\}/)
    key = import_plain
    raise CFFormatError.new("invalid dictionary format") if !key

    if key.is_a?(CFString)
      key = key.value
    elsif key.is_a?(CFInteger) or key.is_a?(CFReal)
      key = key.value.to_s
    else
      raise CFFormatError.new("invalid key format")
    end

    skip_whitespaces

    raise CFFormatError.new("invalid dictionary format") unless @doc.scan(/=/)

    skip_whitespaces
    val = import_plain

    skip_whitespaces
    raise CFFormatError.new("invalid dictionary format") unless @doc.scan(/;/)
    skip_whitespaces

    hsh[key] = val
    raise CFFormatError.new("invalid dictionary format") if @doc.eos?
  end

  CFDictionary.new(hsh)
end
read_quoted() click to toggle source
# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 128
def read_quoted
  str = ''

  while not @doc.scan(/"/)
    if @doc.scan(/\/)
      @doc.scan(/./)
      str << escape_char

    elsif @doc.eos?
      raise CFFormatError.new("unterminated string")

    else @doc.scan(/./)
      str << @doc.matched
    end
  end

  CFString.new(str)
end
read_unquoted() click to toggle source
# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 147
def read_unquoted
  raise CFFormatError.new("unexpected end of file") if @doc.eos?

  if @doc.scan(/(\d\d\d\d)-(\d\d)-(\d\d)\s+(\d\d):(\d\d):(\d\d)(?:\s+(\+|-)(\d\d)(\d\d))?/)
    year,month,day,hour,min,sec,pl_min,tz_hour, tz_min = @doc[1], @doc[2], @doc[3], @doc[4], @doc[5], @doc[6], @doc[7], @doc[8], @doc[9]
    CFDate.new(Time.new(year, month, day, hour, min, sec, pl_min ? sprintf("%s%s:%s", pl_min, tz_hour, tz_min) : nil))

  elsif @doc.scan(/-?\d+?\.\d+\b/)
    CFReal.new(@doc.matched.to_f)

  elsif @doc.scan(/-?\d+\b/)
    CFInteger.new(@doc.matched.to_i)

  elsif @doc.scan(/\b(true|false)\b/)
    CFBoolean.new(@doc.matched == 'true')
  else
    CFString.new(@doc.scan(/\w+/))
  end
end
skip_whitespaces() click to toggle source
# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 41
def skip_whitespaces
  @doc.skip SPACES_AND_COMMENTS
end