/* Copyright (c) Citrix Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Text; namespace XenAdmin.ServerDBs { /// /// A class which provides various XAPI parsing methods. /// public class Parser { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// /// Parses the specified value to the specified . /// /// The type to which the value should be parsed to. /// The value to be parsed. /// public static Object Parse(Type type, String value) { Util.ThrowIfParameterNull(type, "type"); Util.ThrowIfParameterNull(value, "value"); try { if (type == typeof(String[])) { return ParseSXPList(value); } if (type == typeof(String)) { return DeEscapeWhiteSpace(value); } if (type == typeof(bool)) { return Boolean.Parse(value); } if (type == typeof(DateTime)) { return Util.TryParseIso8601DateTime(value, out var result) ? result : DateTime.MinValue; } if (type == typeof(double)) { return Double.Parse(value); } if (type == typeof(long)) { return long.Parse(value); } return ParseSXPDict(value); } catch (Exception e) { log.Debug(e, e); return null; } } /// /// Xapi has some additional whitespace escaping rules which we need to catch /// two spaces become %_ /// '\n' becomes %n /// '\r' becomes %r /// '\t' becomes %t /// '%' becomes '%%' /// /// /// DeEscapedString private static string DeEscapeWhiteSpace(string value) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < value.Length; i++) { if (value[i] == '%') { i++; // skip to next char as long as it's not the end, and interpret if (i < value.Length) { switch (value[i]) { case '_': sb.Append(" "); break; case 'n': sb.Append("\n"); break; case 'r': sb.Append("\r"); break; case 't': sb.Append("\t"); break; case '%': sb.Append("%"); break; } } } else sb.Append(value[i]); } return sb.ToString(); } /// /// Unparses the value for the specified . /// /// The type to be unparsed from. /// The value to be unparsed. /// public static string Unparse(Type type, object value) { Util.ThrowIfParameterNull(type, "type"); Util.ThrowIfParameterNull(value, "value"); try { if (type == typeof(string[])) { return ToSXPList((string[])value); } if (type == typeof(DateTime)) { return Util.ToISO8601DateTime((DateTime)value); } if (type == typeof(string) || type == typeof(bool) || type == typeof(double)) { return value.ToString(); } return ToSXPDict((Hashtable)value); } catch (Exception e) { log.Debug(e, e); return null; } } public static Hashtable ParseSXPDict(String p) { Hashtable result = new Hashtable(); IEnumerator enumerator = Tokenize(p).GetEnumerator(); if (!enumerator.MoveNext()) { return result; } while (enumerator.MoveNext()) { if (enumerator.Current == ")") { break; } enumerator.MoveNext(); String key = enumerator.Current; enumerator.MoveNext(); String value = enumerator.Current; enumerator.MoveNext(); result.Add(key, value); } return result; } public static string ToSXPDict(IDictionary dict) { string ans = "("; bool first = true; foreach (object k in dict.Keys) { if (!first) { ans += " "; } ans += "('" + EscapeString((string)k) + "' '" + EscapeString((string)dict[k]) + "')"; first = false; } ans += ")"; return ans; } public static String[] ParseSXPList(String p) { List result = new List(); foreach (String token in Tokenize(p)) { if (token == "(" || token == ")") { continue; } result.Add(token); } return result.ToArray(); } public static string ToSXPList(IEnumerable vals) { string ans = "("; bool first = true; foreach (string val in vals) { if (!first) { ans += " "; } ans += "'" + EscapeString(val) + "'"; first = false; } ans += ")"; return ans; } private static string EscapeString(string s) { return s.Replace("\"", "\\\"") .Replace("\'", "\\\'"); } public static IEnumerable Tokenize(String str) { bool inStr = false; int j = 0; for (int i = 0; i < str.Length; i++) { switch (str[i]) { case '(': if (!inStr) { yield return "("; } break; case ')': if (!inStr) { yield return ")"; } break; case '\'': case '"': if (!inStr) { inStr = true; j = i; } else if (str[i - 1] != '\\') { inStr = false; yield return str.Substring(j + 1, i - j - 1).Replace("\\\"", "\"").Replace("\\\'", "\'"); } break; } } } } }