using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml; using System.Xml.Linq; using System.Xml.XPath; namespace ImaginationOverflow.UniversalDeepLinking.Editor.External { /// /// Represents an Apple's plist document. /// public class PlistDocument { /// /// The root element of the plist document. /// public PlistElementDict root; /// /// The version of the plist document. At the moment Apple uses '1.0' for all plist files. /// public string version; /// /// Creates a new plist document instance. /// public PlistDocument() { this.root = new PlistElementDict(); this.version = "1.0"; } internal static XDocument ParseXmlNoDtd(string text) { return XDocument.Load(XmlReader.Create((TextReader)new StringReader(text), new XmlReaderSettings() { ProhibitDtd = false, XmlResolver = (XmlResolver)null })); } internal static string CleanDtdToString(XDocument doc) { if (doc.DocumentType != null) { XDocument xdocument = new XDocument(new XDeclaration("1.0", "utf-8", (string)null), new object[2] { (object) new XDocumentType(doc.DocumentType.Name, doc.DocumentType.PublicId, doc.DocumentType.SystemId, (string) null), (object) new XElement(doc.Root.Name) }); return "" + (object)xdocument.Declaration + "\n" + (object)xdocument.DocumentType + "\n" + (object)doc.Root; } return "" + (object)new XDocument(new XDeclaration("1.0", "utf-8", (string)null), new object[1] { (object) new XElement(doc.Root.Name) }).Declaration + Environment.NewLine + (object)doc.Root; } private static string GetText(XElement xml) { return string.Join("", xml.Nodes().OfType().Select((Func)(x => x.Value)).ToArray()); } private static PlistElement ReadElement(XElement xml) { switch (xml.Name.LocalName) { case "dict": List list1 = xml.Elements().ToList(); PlistElementDict plistElementDict = new PlistElementDict(); if (list1.Count % 2 == 1) throw new Exception("Malformed plist file"); for (int index1 = 0; index1 < list1.Count - 1; ++index1) { if (list1[index1].Name != (XName)"key") throw new Exception("Malformed plist file"); string index2 = PlistDocument.GetText(list1[index1]).Trim(); PlistElement plistElement = PlistDocument.ReadElement(list1[index1 + 1]); if ((object)plistElement != null) { ++index1; plistElementDict[index2] = plistElement; } } return (PlistElement)plistElementDict; case "array": List list2 = xml.Elements().ToList(); PlistElementArray plistElementArray = new PlistElementArray(); foreach (XElement xml1 in list2) { PlistElement plistElement = PlistDocument.ReadElement(xml1); if ((object)plistElement != null) plistElementArray.values.Add(plistElement); } return (PlistElement)plistElementArray; case "string": return (PlistElement)new PlistElementString(PlistDocument.GetText(xml)); case "integer": int result; if (int.TryParse(PlistDocument.GetText(xml), out result)) return (PlistElement)new PlistElementInteger(result); return (PlistElement)null; case "true": return (PlistElement)new PlistElementBoolean(true); case "false": return (PlistElement)new PlistElementBoolean(false); default: return (PlistElement)null; } } /// /// Reads the document from a file identified by the given path. /// /// Path of the file. public void ReadFromFile(string path) { this.ReadFromString(File.ReadAllText(path)); } /// /// Reads the project from the given text reader. /// /// The project contents. public void ReadFromStream(TextReader tr) { this.ReadFromString(tr.ReadToEnd()); } /// /// Reads the document from the given string. /// /// The project contents. public void ReadFromString(string text) { XDocument xmlNoDtd = PlistDocument.ParseXmlNoDtd(text); this.version = (string)xmlNoDtd.Root.Attribute((XName)"version"); PlistElement plistElement = PlistDocument.ReadElement(xmlNoDtd.XPathSelectElement("plist/dict")); if (plistElement == null) throw new Exception("Error parsing plist file"); this.root = plistElement as PlistElementDict; if (this.root == null) throw new Exception("Malformed plist file"); } private static XElement WriteElement(PlistElement el) { if (el is PlistElementBoolean) return new XElement((XName)(!(el as PlistElementBoolean).value ? "false" : "true")); if (el is PlistElementInteger) return new XElement((XName)"integer", (object)(el as PlistElementInteger).value.ToString()); if (el is PlistElementString) return new XElement((XName)"string", (object)(el as PlistElementString).value); if (el is PlistElementDict) { PlistElementDict plistElementDict = el as PlistElementDict; XElement xelement1 = new XElement((XName)"dict"); foreach (KeyValuePair keyValuePair in (IEnumerable>)plistElementDict.values) { XElement xelement2 = new XElement((XName)"key", (object)keyValuePair.Key); XElement xelement3 = PlistDocument.WriteElement(keyValuePair.Value); if (xelement3 != null) { xelement1.Add((object)xelement2); xelement1.Add((object)xelement3); } } return xelement1; } if (!(el is PlistElementArray)) return (XElement)null; PlistElementArray plistElementArray = el as PlistElementArray; XElement xelement4 = new XElement((XName)"array"); foreach (PlistElement el1 in plistElementArray.values) { XElement xelement1 = PlistDocument.WriteElement(el1); if (xelement1 != null) xelement4.Add((object)xelement1); } return xelement4; } /// /// Writes the project contents to the specified file. /// /// Path to write the document contents to. public void WriteToFile(string path) { File.WriteAllText(path, this.WriteToString()); } /// /// Writes the document contents to the specified text writer. /// /// Text writer to write to. public void WriteToStream(TextWriter tw) { tw.Write(this.WriteToString()); } /// /// Writes the document contents to a string. /// /// /// The project contents converted to string. /// public string WriteToString() { XElement xelement1 = PlistDocument.WriteElement((PlistElement)this.root); XElement xelement2 = new XElement((XName)"plist"); xelement2.Add((object)new XAttribute((XName)"version", (object)this.version)); xelement2.Add((object)xelement1); XDocument doc = new XDocument(); doc.Add((object)xelement2); return PlistDocument.CleanDtdToString(doc); } } }