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"
  when 'U'
    @doc.scan(/.{4}/).hex.chr('utf-8')
  end
end
import_plain() click to toggle source

import the XML values

# File lib/cfpropertylist/rbPlainCFPropertyList.rb, line 177
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 169
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 130
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 149
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