299 lines
11 KiB
C#
299 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace ImaginationOverflow.UniversalDeepLinking.Editor.Xcode.PBX
|
|
{
|
|
internal class GUIDToCommentMap
|
|
{
|
|
private Dictionary<string, string> m_Dict = new Dictionary<string, string>();
|
|
|
|
public string this[string guid]
|
|
{
|
|
get {
|
|
if (m_Dict.ContainsKey(guid))
|
|
return m_Dict[guid];
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void Add(string guid, string comment)
|
|
{
|
|
if (m_Dict.ContainsKey(guid))
|
|
return;
|
|
m_Dict.Add(guid, comment);
|
|
}
|
|
|
|
public void Remove(string guid)
|
|
{
|
|
m_Dict.Remove(guid);
|
|
}
|
|
|
|
public string Write(string guid)
|
|
{
|
|
string comment = this[guid];
|
|
if (comment == null)
|
|
return guid;
|
|
return String.Format("{0} /* {1} */", guid, comment);
|
|
}
|
|
|
|
public void WriteStringBuilder(StringBuilder sb, string guid)
|
|
{
|
|
string comment = this[guid];
|
|
if (comment == null)
|
|
sb.Append(guid);
|
|
else
|
|
{
|
|
// {0} /* {1} */
|
|
sb.Append(guid).Append(" /* ").Append(comment).Append(" */");
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class PBXGUID
|
|
{
|
|
internal delegate string GuidGenerator();
|
|
|
|
// We allow changing Guid generator to make testing of PBXProject possible
|
|
private static GuidGenerator guidGenerator = DefaultGuidGenerator;
|
|
|
|
internal static string DefaultGuidGenerator()
|
|
{
|
|
return Guid.NewGuid().ToString("N").Substring(8).ToUpper();
|
|
}
|
|
|
|
internal static void SetGuidGenerator(GuidGenerator generator)
|
|
{
|
|
guidGenerator = generator;
|
|
}
|
|
|
|
// Generates a GUID.
|
|
public static string Generate()
|
|
{
|
|
return guidGenerator();
|
|
}
|
|
}
|
|
|
|
internal class PBXRegex
|
|
{
|
|
public static string GuidRegexString = "[A-Fa-f0-9]{24}";
|
|
}
|
|
|
|
internal class PBXStream
|
|
{
|
|
static bool DontNeedQuotes(string src)
|
|
{
|
|
// using a regex instead of explicit matching slows down common cases by 40%
|
|
if (src.Length == 0)
|
|
return false;
|
|
|
|
bool hasSlash = false;
|
|
for (int i = 0; i < src.Length; ++i)
|
|
{
|
|
char c = src[i];
|
|
if (Char.IsLetterOrDigit(c) || c == '.' || c == '*' || c == '_')
|
|
continue;
|
|
if (c == '/')
|
|
{
|
|
hasSlash = true;
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
if (hasSlash)
|
|
{
|
|
if (src.Contains("//") || src.Contains("/*") || src.Contains("*/"))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Quotes the given string if it contains special characters. Note: if the string already
|
|
// contains quotes, then they are escaped and the entire string quoted again
|
|
public static string QuoteStringIfNeeded(string src)
|
|
{
|
|
if (DontNeedQuotes(src))
|
|
return src;
|
|
return "\"" + src.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n") + "\"";
|
|
}
|
|
|
|
// If the given string is quoted, removes the quotes and unescapes any quotes within the string
|
|
public static string UnquoteString(string src)
|
|
{
|
|
if (!src.StartsWith("\"") || !src.EndsWith("\""))
|
|
return src;
|
|
return src.Substring(1, src.Length - 2).Replace("\\\\", "\u569f").Replace("\\\"", "\"")
|
|
.Replace("\\n", "\n").Replace("\u569f", "\\"); // U+569f is a rarely used Chinese character
|
|
}
|
|
}
|
|
|
|
internal enum PBXFileType
|
|
{
|
|
NotBuildable,
|
|
Framework,
|
|
Source,
|
|
Resource,
|
|
CopyFile
|
|
}
|
|
|
|
internal class FileTypeUtils
|
|
{
|
|
internal class FileTypeDesc
|
|
{
|
|
public FileTypeDesc(string typeName, PBXFileType type)
|
|
{
|
|
this.name = typeName;
|
|
this.type = type;
|
|
this.isExplicit = false;
|
|
}
|
|
|
|
public FileTypeDesc(string typeName, PBXFileType type, bool isExplicit)
|
|
{
|
|
this.name = typeName;
|
|
this.type = type;
|
|
this.isExplicit = isExplicit;
|
|
}
|
|
|
|
public string name;
|
|
public PBXFileType type;
|
|
public bool isExplicit;
|
|
}
|
|
|
|
private static readonly Dictionary<string, FileTypeDesc> types =
|
|
new Dictionary<string, FileTypeDesc>
|
|
{
|
|
{ "a", new FileTypeDesc("archive.ar", PBXFileType.Framework) },
|
|
{ "app", new FileTypeDesc("wrapper.application", PBXFileType.NotBuildable, true) },
|
|
{ "appex", new FileTypeDesc("wrapper.app-extension", PBXFileType.CopyFile) },
|
|
{ "bin", new FileTypeDesc("archive.macbinary", PBXFileType.Resource) },
|
|
{ "s", new FileTypeDesc("sourcecode.asm", PBXFileType.Source) },
|
|
{ "c", new FileTypeDesc("sourcecode.c.c", PBXFileType.Source) },
|
|
{ "cc", new FileTypeDesc("sourcecode.cpp.cpp", PBXFileType.Source) },
|
|
{ "cpp", new FileTypeDesc("sourcecode.cpp.cpp", PBXFileType.Source) },
|
|
{ "swift", new FileTypeDesc("sourcecode.swift", PBXFileType.Source) },
|
|
{ "dll", new FileTypeDesc("file", PBXFileType.NotBuildable) },
|
|
{ "framework", new FileTypeDesc("wrapper.framework", PBXFileType.Framework) },
|
|
{ "h", new FileTypeDesc("sourcecode.c.h", PBXFileType.NotBuildable) },
|
|
{ "pch", new FileTypeDesc("sourcecode.c.h", PBXFileType.NotBuildable) },
|
|
{ "icns", new FileTypeDesc("image.icns", PBXFileType.Resource) },
|
|
{ "xcassets", new FileTypeDesc("folder.assetcatalog", PBXFileType.Resource) },
|
|
{ "inc", new FileTypeDesc("sourcecode.inc", PBXFileType.NotBuildable) },
|
|
{ "m", new FileTypeDesc("sourcecode.c.objc", PBXFileType.Source) },
|
|
{ "mm", new FileTypeDesc("sourcecode.cpp.objcpp", PBXFileType.Source ) },
|
|
{ "nib", new FileTypeDesc("wrapper.nib", PBXFileType.Resource) },
|
|
{ "plist", new FileTypeDesc("text.plist.xml", PBXFileType.Resource) },
|
|
{ "png", new FileTypeDesc("image.png", PBXFileType.Resource) },
|
|
{ "rtf", new FileTypeDesc("text.rtf", PBXFileType.Resource) },
|
|
{ "tiff", new FileTypeDesc("image.tiff", PBXFileType.Resource) },
|
|
{ "txt", new FileTypeDesc("text", PBXFileType.Resource) },
|
|
{ "json", new FileTypeDesc("text.json", PBXFileType.Resource) },
|
|
{ "xcodeproj", new FileTypeDesc("wrapper.pb-project", PBXFileType.NotBuildable) },
|
|
{ "xib", new FileTypeDesc("file.xib", PBXFileType.Resource) },
|
|
{ "strings", new FileTypeDesc("text.plist.strings", PBXFileType.Resource) },
|
|
{ "storyboard",new FileTypeDesc("file.storyboard", PBXFileType.Resource) },
|
|
{ "bundle", new FileTypeDesc("wrapper.plug-in", PBXFileType.Resource) },
|
|
{ "dylib", new FileTypeDesc("compiled.mach-o.dylib", PBXFileType.Framework) },
|
|
{ "tbd", new FileTypeDesc("sourcecode.text-based-dylib-definition", PBXFileType.Framework) }
|
|
};
|
|
|
|
public static string TrimExtension(string ext)
|
|
{
|
|
return ext.TrimStart('.');
|
|
}
|
|
|
|
public static bool IsKnownExtension(string ext)
|
|
{
|
|
ext = TrimExtension(ext);
|
|
return types.ContainsKey(ext);
|
|
}
|
|
|
|
internal static bool IsFileTypeExplicit(string ext)
|
|
{
|
|
ext = TrimExtension(ext);
|
|
if (types.ContainsKey(ext))
|
|
return types[ext].isExplicit;
|
|
return false;
|
|
}
|
|
|
|
public static PBXFileType GetFileType(string ext, bool isFolderRef)
|
|
{
|
|
ext = TrimExtension(ext);
|
|
if (isFolderRef)
|
|
return PBXFileType.Resource;
|
|
if (!types.ContainsKey(ext))
|
|
return PBXFileType.Resource;
|
|
return types[ext].type;
|
|
}
|
|
|
|
public static string GetTypeName(string ext)
|
|
{
|
|
ext = TrimExtension(ext);
|
|
if (types.ContainsKey(ext))
|
|
return types[ext].name;
|
|
// Xcode actually checks the file contents to determine the file type.
|
|
// Text files have "text" type and all other files have "file" type.
|
|
// Since we can't reasonably determine whether the file in question is
|
|
// a text file, we just take the safe route and return "file" type.
|
|
return "file";
|
|
}
|
|
|
|
public static bool IsBuildableFile(string ext)
|
|
{
|
|
ext = TrimExtension(ext);
|
|
if (!types.ContainsKey(ext))
|
|
return true;
|
|
if (types[ext].type != PBXFileType.NotBuildable)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public static bool IsBuildable(string ext, bool isFolderReference)
|
|
{
|
|
ext = TrimExtension(ext);
|
|
if (isFolderReference)
|
|
return true;
|
|
return IsBuildableFile(ext);
|
|
}
|
|
|
|
private static readonly Dictionary<PBXSourceTree, string> sourceTree = new Dictionary<PBXSourceTree, string>
|
|
{
|
|
{ PBXSourceTree.Absolute, "<absolute>" },
|
|
{ PBXSourceTree.Group, "<group>" },
|
|
{ PBXSourceTree.Build, "BUILT_PRODUCTS_DIR" },
|
|
{ PBXSourceTree.Developer, "DEVELOPER_DIR" },
|
|
{ PBXSourceTree.Sdk, "SDKROOT" },
|
|
{ PBXSourceTree.Source, "SOURCE_ROOT" },
|
|
};
|
|
|
|
private static readonly Dictionary<string, PBXSourceTree> stringToSourceTreeMap = new Dictionary<string, PBXSourceTree>
|
|
{
|
|
{ "<absolute>", PBXSourceTree.Absolute },
|
|
{ "<group>", PBXSourceTree.Group },
|
|
{ "BUILT_PRODUCTS_DIR", PBXSourceTree.Build },
|
|
{ "DEVELOPER_DIR", PBXSourceTree.Developer },
|
|
{ "SDKROOT", PBXSourceTree.Sdk },
|
|
{ "SOURCE_ROOT", PBXSourceTree.Source },
|
|
};
|
|
|
|
internal static string SourceTreeDesc(PBXSourceTree tree)
|
|
{
|
|
return sourceTree[tree];
|
|
}
|
|
|
|
// returns PBXSourceTree.Source on error
|
|
internal static PBXSourceTree ParseSourceTree(string tree)
|
|
{
|
|
if (stringToSourceTreeMap.ContainsKey(tree))
|
|
return stringToSourceTreeMap[tree];
|
|
return PBXSourceTree.Source;
|
|
}
|
|
|
|
internal static List<PBXSourceTree> AllAbsoluteSourceTrees()
|
|
{
|
|
return new List<PBXSourceTree>{PBXSourceTree.Absolute, PBXSourceTree.Build,
|
|
PBXSourceTree.Developer, PBXSourceTree.Sdk, PBXSourceTree.Source};
|
|
}
|
|
}
|
|
|
|
} // UnityEditor.iOS.Xcode
|