#!/usr/bin/ruby

## plist.rb v0.1 : Parses XML PropertyList
## Copyright (C) 2010  Franck GUENICHOT
## franck {dot} guenichot {at} orange {dot} fr
##
## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License
## as published by the Free Software Foundation; either version 3
## of the License, or any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.


## Written for the Network Forensics Puzzle #3
## http://forensicscontest.com



require "rexml/document"
require "rexml/streamlistener"


## CLASSES
## these ones are taken from the book: "Practical Ruby for System Administration" by André Ben Amou
## with minor changes.

class PListArray < Array
  attr_accessor :parent
  alias :add_object :push

	def print_all
		elems = []
		self.each {|elem|
			if elem.class == PListHash
				elems << " "
				elems << elem.print_all
			elsif elem.class == PListArray
				elems << " "
				elems << elem.print_all
			else
				elems << elem
			end
		}
		elems
	end

end

class PListHash < Hash
  attr_accessor :next_key, :parent

	def print_all
		result = []
		self.each {|key,value|
			if value.class == PListHash
				result << "#{key}: "
				result << value.print_all
				result << " "
			elsif value.class == PListArray
				result << value.print_all
				result << " "
			else
					result << "#{key}: #{value}"
			end
		}
		result
	end

	def add_object(object)
    raise "no key set" unless @next_key
    self[@next_key] = object
    @next_key = nil
  end
end



class PListParser
  include REXML::StreamListener
  
	attr_reader :root

	def initialize
  	@to_read = nil
  	@root = nil
  	@version = 1.0
	end


  def tag_start(name, attributes)
    # handle a start tag
		case name
 			when "plist" then @version = attributes["version"]
  		when "array" then add_object(PListArray.new)
  		when "dict" then add_object(PListHash.new)
  		when "data", "integer", "key", "real", "string","true","false","date" then @to_read = name
  		else raise "unknown tag: #{name}"
		end

  end
                        
  def tag_end(name)
    if @to_read then @to_read = nil
		else @root = @root.parent || @root
		end

  end

  def text(string)
  	return unless @to_read
  	if @to_read == "key"
    	raise "cannot use key as not within hash" unless @root.is_a?(Hash)
    	@root.next_key = string
    	return
  	end
		object = case @to_read
    	when "data" then string.strip
    	when "integer" then string.to_i
    	when "real" then string.to_f
    	when "string" then string
			when "date" then string
			when "true" then "true"
			when "false" then "false"
  	end
  	add_object(object)
	end

	def self.parse(source)
  	parser = new
  	REXML::Document.parse_stream(source, parser)
  	parser.root
	end


	private
	def add_object(object)
 	 @root.add_object(object) if @root
 	 if object.is_a?(Array) or object.is_a?(Hash)
    object.parent = @root
    @root = object
 	 end
	end


end


## well, the minimum...
	

filename = ARGV[ARGV.length-2]
query = ARGV[ARGV.length-1]

plist = PListParser.parse(File.open(filename))


pagetype = plist['page-type']['template-name']
pagetitle = plist['title']
items_array = plist['items']


puts "Page type is #{pagetype}"
puts "Title: #{pagetitle}"

puts items_array.print_all

#End of plist.rb
