| using System; | 
| using System.Collections.Generic; | 
| using System.Text; | 
| using System.Text.RegularExpressions; | 
| using System.IO; | 
| using System.Linq; | 
|   | 
| #if UNITY_XCODE_API_BUILD | 
| namespace UnityEditor.iOS.Xcode.PBX | 
| #else | 
| namespace UnityEditor.iOS.Xcode.Custom.PBX | 
| #endif | 
| { | 
|     class PropertyCommentChecker | 
|     { | 
|         private int m_Level; | 
|         private bool m_All; | 
|         private List<List<string>> m_Props; | 
|          | 
|         /*  The argument is an array of matcher strings each of which determine  | 
|                 whether a property with a certain path needs to be decorated with a | 
|                 comment. | 
|                  | 
|                 A path is a number of path elements concatenated by '/'. The last path  | 
|                 element is either: | 
|                     the key if we're referring to a dict key | 
|                     the value if we're referring to a value in an array | 
|                     the value if we're referring to a value in a dict | 
|                 All other path elements are either: | 
|                     the key if the container is dict | 
|                     '*' if the container is array | 
|                  | 
|                 Path matcher has the same structure as a path, except that any of the | 
|                 elements may be '*'. Matcher matches a path if both have the same number | 
|                 of elements and for each pair matcher element is the same as path element | 
|                 or is '*'. | 
|                  | 
|                 a/b/c matches a/b/c but not a/b nor a/b/c/d | 
|                 a/* /c matches a/d/c but not a/b nor a/b/c/d | 
|                 * /* /* matches any path from three elements | 
|             */ | 
|         protected PropertyCommentChecker(int level, List<List<string>> props) | 
|         { | 
|             m_Level = level; | 
|             m_All = false; | 
|             m_Props = props; | 
|         } | 
|   | 
|         public PropertyCommentChecker() | 
|         { | 
|             m_Level = 0; | 
|             m_All = false; | 
|             m_Props = new List<List<string>>(); | 
|         } | 
|   | 
|         public PropertyCommentChecker(IEnumerable<string> props) | 
|         { | 
|             m_Level = 0; | 
|             m_All = false; | 
|             m_Props = new List<List<string>>(); | 
|             foreach (var prop in props) | 
|             { | 
|                 m_Props.Add(new List<string>(prop.Split('/'))); | 
|             } | 
|         } | 
|          | 
|         bool CheckContained(string prop) | 
|         { | 
|             if (m_All)  | 
|                 return true; | 
|             foreach (var list in m_Props) | 
|             { | 
|                 if (list.Count == m_Level+1) | 
|                 { | 
|                     if (list[m_Level] == prop) | 
|                         return true; | 
|                     if (list[m_Level] == "*") | 
|                     { | 
|                         m_All = true; // short-circuit all at this level | 
|                         return true; | 
|                     } | 
|                 } | 
|             } | 
|             return false; | 
|         } | 
|          | 
|         public bool CheckStringValueInArray(string value) { return CheckContained(value); } | 
|         public bool CheckKeyInDict(string key) { return CheckContained(key); } | 
|          | 
|         public bool CheckStringValueInDict(string key, string value) | 
|         { | 
|             foreach (var list in m_Props) | 
|             { | 
|                 if (list.Count == m_Level + 2) | 
|                 { | 
|                     if ((list[m_Level] == "*" || list[m_Level] == key) && | 
|                         list[m_Level+1] == "*" || list[m_Level+1] == value) | 
|                         return true; | 
|                 } | 
|             } | 
|             return false;        | 
|         } | 
|          | 
|         public PropertyCommentChecker NextLevel(string prop) | 
|         { | 
|             var newList = new List<List<string>>(); | 
|             foreach (var list in m_Props) | 
|             { | 
|                 if (list.Count <= m_Level+1) | 
|                     continue; | 
|                 if (list[m_Level] == "*" || list[m_Level] == prop) | 
|                     newList.Add(list); | 
|             } | 
|             return new PropertyCommentChecker(m_Level + 1, newList); | 
|         } | 
|     } | 
|   | 
|     class Serializer  | 
|     { | 
|         public static PBXElementDict ParseTreeAST(TreeAST ast, TokenList tokens, string text) | 
|         { | 
|             var el = new PBXElementDict(); | 
|             foreach (var kv in ast.values) | 
|             { | 
|                 PBXElementString key = ParseIdentifierAST(kv.key, tokens, text); | 
|                 PBXElement value = ParseValueAST(kv.value, tokens, text); | 
|                 el[key.value] = value; | 
|             } | 
|             return el; | 
|         } | 
|          | 
|         public static PBXElementArray ParseArrayAST(ArrayAST ast, TokenList tokens, string text) | 
|         { | 
|             var el = new PBXElementArray(); | 
|             foreach (var v in ast.values) | 
|             { | 
|                 el.values.Add(ParseValueAST(v, tokens, text)); | 
|             } | 
|             return el; | 
|         } | 
|          | 
|         public static PBXElement ParseValueAST(ValueAST ast, TokenList tokens, string text) | 
|         { | 
|             if (ast is TreeAST) | 
|                 return ParseTreeAST((TreeAST)ast, tokens, text); | 
|             if (ast is ArrayAST) | 
|                 return ParseArrayAST((ArrayAST)ast, tokens, text); | 
|             if (ast is IdentifierAST) | 
|                 return ParseIdentifierAST((IdentifierAST)ast, tokens, text); | 
|             return null; | 
|         } | 
|          | 
|         public static PBXElementString ParseIdentifierAST(IdentifierAST ast, TokenList tokens, string text) | 
|         { | 
|             Token tok = tokens[ast.value]; | 
|             string value; | 
|             switch (tok.type) | 
|             { | 
|                 case TokenType.String: | 
|                     value = text.Substring(tok.begin, tok.end - tok.begin); | 
|                     return new PBXElementString(value); | 
|                 case TokenType.QuotedString: | 
|                     value = text.Substring(tok.begin, tok.end - tok.begin); | 
|                     value = PBXStream.UnquoteString(value); | 
|                     return new PBXElementString(value); | 
|                 default: | 
|                     throw new Exception("Internal parser error"); | 
|             }            | 
|         } | 
|          | 
|         static string k_Indent = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; | 
|          | 
|         static string GetIndent(int indent) | 
|         { | 
|             return k_Indent.Substring(0, indent); | 
|         } | 
|   | 
|         static void WriteStringImpl(StringBuilder sb, string s, bool comment, GUIDToCommentMap comments) | 
|         { | 
|             if (comment) | 
|                 comments.WriteStringBuilder(sb, s); | 
|             else | 
|                 sb.Append(PBXStream.QuoteStringIfNeeded(s)); | 
|         } | 
|                                           | 
|         public static void WriteDictKeyValue(StringBuilder sb, string key, PBXElement value, int indent, bool compact,  | 
|                                              PropertyCommentChecker checker, GUIDToCommentMap comments) | 
|         { | 
|             if (!compact) | 
|             { | 
|                 sb.Append("\n"); | 
|                 sb.Append(GetIndent(indent)); | 
|             } | 
|             WriteStringImpl(sb, key, checker.CheckKeyInDict(key), comments); | 
|             sb.Append(" = "); | 
|   | 
|             if (value is PBXElementString) | 
|                 WriteStringImpl(sb, value.AsString(), checker.CheckStringValueInDict(key, value.AsString()), comments); | 
|             else if (value is PBXElementDict) | 
|                 WriteDict(sb, value.AsDict(), indent, compact, checker.NextLevel(key), comments); | 
|             else if (value is PBXElementArray) | 
|                 WriteArray(sb, value.AsArray(), indent, compact, checker.NextLevel(key), comments); | 
|             sb.Append(";"); | 
|             if (compact) | 
|                 sb.Append(" "); | 
|         } | 
|          | 
|         public static void WriteDict(StringBuilder sb, PBXElementDict el, int indent, bool compact,  | 
|                                      PropertyCommentChecker checker, GUIDToCommentMap comments) | 
|         { | 
|             sb.Append("{"); | 
|              | 
|             if (el.Contains("isa")) | 
|                 WriteDictKeyValue(sb, "isa", el["isa"], indent+1, compact, checker, comments); | 
|             var keys = new List<string>(el.values.Keys); | 
|             keys.Sort(StringComparer.Ordinal); | 
|             foreach (var key in keys) | 
|             { | 
|                 if (key != "isa") | 
|                     WriteDictKeyValue(sb, key, el[key], indent+1, compact, checker, comments); | 
|             } | 
|             if (!compact) | 
|             { | 
|                 sb.Append("\n"); | 
|                 sb.Append(GetIndent(indent)); | 
|             } | 
|             sb.Append("}"); | 
|         } | 
|   | 
|         public static void WriteArray(StringBuilder sb, PBXElementArray el, int indent, bool compact,  | 
|                                       PropertyCommentChecker checker, GUIDToCommentMap comments) | 
|         { | 
|             sb.Append("("); | 
|             foreach (var value in el.values) | 
|             { | 
|                 if (!compact) | 
|                 { | 
|                     sb.Append("\n"); | 
|                     sb.Append(GetIndent(indent+1)); | 
|                 } | 
|                  | 
|                 if (value is PBXElementString) | 
|                     WriteStringImpl(sb, value.AsString(), checker.CheckStringValueInArray(value.AsString()), comments); | 
|                 else if (value is PBXElementDict) | 
|                     WriteDict(sb, value.AsDict(), indent+1, compact, checker.NextLevel("*"), comments); | 
|                 else if (value is PBXElementArray) | 
|                     WriteArray(sb, value.AsArray(), indent+1, compact, checker.NextLevel("*"), comments); | 
|                 sb.Append(","); | 
|                 if (compact) | 
|                     sb.Append(" "); | 
|             } | 
|              | 
|             if (!compact) | 
|             { | 
|                 sb.Append("\n"); | 
|                 sb.Append(GetIndent(indent)); | 
|             } | 
|             sb.Append(")"); | 
|         } | 
|     } | 
|      | 
| } // namespace UnityEditor.iOS.Xcode |