Singularity/Assets/Plugins/ImaginationOverflow/UniversalDeepLinking/Editor/Xcode/PBX/Serializer.cs

257 lines
9.4 KiB
C#
Raw Normal View History

2024-05-06 14:45:45 -04:00
using System;
using System.Collections.Generic;
using System.Text;
namespace ImaginationOverflow.UniversalDeepLinking.Editor.Xcode.PBX
{
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 UnityModule.iOS.Xcode