| using System; | 
| using System.Collections.Generic; | 
| using System.Text; | 
| using System.Text.RegularExpressions; | 
| using System.IO; | 
|   | 
| #if UNITY_XCODE_API_BUILD | 
| namespace UnityEditor.iOS.Xcode.PBX | 
| #else | 
| namespace UnityEditor.iOS.Xcode.Custom.PBX | 
| #endif | 
| { | 
|     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,  | 
|         ShellScript | 
|     } | 
|   | 
|     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) }, | 
|             { "aif",       new FileTypeDesc("sound.aif",               PBXFileType.Resource) }, | 
|             { "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 ) }, | 
|             { "mp3",       new FileTypeDesc("sound.mp3",               PBXFileType.Resource) }, | 
|             { "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) }, | 
|             { "wav",       new FileTypeDesc("sound.wav",               PBXFileType.Resource) } | 
|         }; | 
|   | 
|         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 |