// // // // // $Revision: 3863 $ // using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Text; namespace ICSharpCode.Core { /// /// This class parses internal ${xyz} tags of #Develop. /// All environment variables are avaible under the name env.[NAME] /// where [NAME] represents the string under which it is avaiable in /// the environment. /// public static class StringParser { readonly static Dictionary properties; readonly static Dictionary stringTagProviders; readonly static Dictionary propertyObjects; public static Dictionary Properties { get { return properties; } } public static Dictionary PropertyObjects { get { return propertyObjects; } } static StringParser() { properties = new Dictionary(StringComparer.OrdinalIgnoreCase); stringTagProviders = new Dictionary(StringComparer.OrdinalIgnoreCase); propertyObjects = new Dictionary(); // entryAssembly == null might happen in unit test mode Assembly entryAssembly = Assembly.GetEntryAssembly(); if (entryAssembly != null) { string exeName = entryAssembly.Location; propertyObjects["exe"] = FileVersionInfo.GetVersionInfo(exeName); } properties["USER"] = Environment.UserName; properties["Version"] = RevisionClass.FullVersion; // Maybe test for Mono? if (IntPtr.Size == 4) { properties["Platform"] = "Win32"; } else if (IntPtr.Size == 8) { properties["Platform"] = "Win64"; } else { properties["Platform"] = "unknown"; } } /// /// Expands ${xyz} style property values. /// public static string Parse(string input) { return Parse(input, null); } /// /// Parses an array and replaces the elements in the existing array. /// public static void Parse(string[] inputs) { for (int i = 0; i < inputs.Length; ++i) { inputs[i] = Parse(inputs[i], null); } } public static void RegisterStringTagProvider(IStringTagProvider tagProvider) { foreach (string str in tagProvider.Tags) { stringTagProviders[str] = tagProvider; } } //readonly static Regex pattern = new Regex(@"\$\{([^\}]*)\}", RegexOptions.Compiled | RegexOptions.CultureInvariant); /// /// Expands ${xyz} style property values. /// public static string Parse(string input, string[,] customTags) { if (input == null) return null; int pos = 0; StringBuilder output = null; // don't use StringBuilder if input is a single property do { int oldPos = pos; pos = input.IndexOf("${", pos, StringComparison.Ordinal); if (pos < 0) { if (output == null) { return input; } else { if (oldPos < input.Length) { // normal text after last property output.Append(input, oldPos, input.Length - oldPos); } return output.ToString(); } } if (output == null) { if (pos == 0) output = new StringBuilder(); else output = new StringBuilder(input, 0, pos, pos + 16); } else { if (pos > oldPos) { // normal text between two properties output.Append(input, oldPos, pos - oldPos); } } int end = input.IndexOf('}', pos + 1); if (end < 0) { output.Append("${"); pos += 2; } else { string property = input.Substring(pos + 2, end - pos - 2); string val = GetValue(property, customTags); if (val == null) { output.Append("${"); output.Append(property); output.Append('}'); } else { output.Append(val); } pos = end + 1; } } while (pos < input.Length); return output.ToString(); } static string GetValue(string propertyName, string[,] customTags) { // most properties start with res: in lowercase, // so we can save 2 string allocations here, in addition to all the jumps // All other prefixed properties {prefix:Key} shoulg get handled in the switch below. if (propertyName.StartsWith("res:", StringComparison.OrdinalIgnoreCase)) { try { return Parse(ResourceService.GetString(propertyName.Substring(4)), customTags); } catch (ResourceNotFoundException) { return null; } } if (propertyName.StartsWith("DATE:", StringComparison.OrdinalIgnoreCase)) { try { return DateTime.Now.ToString(propertyName.Split(':')[1]); } catch (Exception ex) { return ex.Message; } } if (propertyName.Equals("DATE", StringComparison.OrdinalIgnoreCase)) return DateTime.Today.ToShortDateString(); if (propertyName.Equals("TIME", StringComparison.OrdinalIgnoreCase)) return DateTime.Now.ToShortTimeString(); if (propertyName.Equals("ProductName", StringComparison.OrdinalIgnoreCase)) return MessageService.ProductName; if (propertyName.Equals("GUID", StringComparison.OrdinalIgnoreCase)) return Guid.NewGuid().ToString().ToUpperInvariant(); if (customTags != null) { for (int j = 0; j < customTags.GetLength(0); ++j) { if (propertyName.Equals(customTags[j, 0], StringComparison.OrdinalIgnoreCase)) { return customTags[j, 1]; } } } if (properties.ContainsKey(propertyName)) { return properties[propertyName]; } if (stringTagProviders.ContainsKey(propertyName)) { return stringTagProviders[propertyName].Convert(propertyName); } int k = propertyName.IndexOf(':'); if (k <= 0) return null; string prefix = propertyName.Substring(0, k); propertyName = propertyName.Substring(k + 1); switch (prefix.ToUpperInvariant()) { case "SDKTOOLPATH": return FileUtility.GetSdkPath(propertyName); case "ADDINPATH": foreach (AddIn addIn in AddInTree.AddIns) { if (addIn.Manifest.Identities.ContainsKey(propertyName)) { return System.IO.Path.GetDirectoryName(addIn.FileName); } } return null; case "ENV": return Environment.GetEnvironmentVariable(propertyName); case "RES": try { return Parse(ResourceService.GetString(propertyName), customTags); } catch (ResourceNotFoundException) { return null; } case "PROPERTY": return GetProperty(propertyName); default: if (propertyObjects.ContainsKey(prefix)) { return Get(propertyObjects[prefix], propertyName); } else { return null; } } } /// /// Allow special syntax to retrieve property values: /// ${property:PropertyName} /// ${property:PropertyName??DefaultValue} /// ${property:ContainerName/PropertyName} /// ${property:ContainerName/PropertyName??DefaultValue} /// A container is a Properties instance stored in the PropertyService. This is /// used by many AddIns to group all their properties into one container. /// static string GetProperty(string propertyName) { string defaultValue = ""; int pos = propertyName.LastIndexOf("??", StringComparison.Ordinal); if (pos >= 0) { defaultValue = propertyName.Substring(pos + 2); propertyName = propertyName.Substring(0, pos); } pos = propertyName.IndexOf('/'); if (pos >= 0) { Properties properties = PropertyService.Get(propertyName.Substring(0, pos), new Properties()); propertyName = propertyName.Substring(pos + 1); pos = propertyName.IndexOf('/'); while (pos >= 0) { properties = properties.Get(propertyName.Substring(0, pos), new Properties()); propertyName = propertyName.Substring(pos + 1); } return properties.Get(propertyName, defaultValue); } else { return PropertyService.Get(propertyName, defaultValue); } } static string Get(object obj, string name) { Type type = obj.GetType(); PropertyInfo prop = type.GetProperty(name); if (prop != null) { return prop.GetValue(obj, null).ToString(); } FieldInfo field = type.GetField(name); if (field != null) { return field.GetValue(obj).ToString(); } return null; } } }