xenadmin/XenModel/ServerDBs/Parser.cs

297 lines
9.4 KiB
C#
Raw Normal View History

/* 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 XenCenterLib;
using System.Text;
namespace XenAdmin.ServerDBs
{
/// <summary>
/// A class which provides various XAPI parsing methods.
/// </summary>
public class Parser
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Parses the specified value to the specified <see cref="Type"/>.
/// </summary>
/// <param name="type">The type to which the value should be parsed to.</param>
/// <param name="value">The value to be parsed.</param>
/// <returns></returns>
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 TimeUtil.ParseISO8601DateTime(value);
}
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;
}
}
/// <summary>
/// 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 '%%'
/// </summary>
/// <param name="value"></param>
/// <returns>DeEscapedString</returns>
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();
}
/// <summary>
/// Unparses the value for the specified <see cref="Type"/>.
/// </summary>
/// <param name="type">The type to be unparsed from.</param>
/// <param name="value">The value to be unparsed.</param>
/// <returns></returns>
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 TimeUtil.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<String> 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<String> result = new List<String>();
foreach (String token in Tokenize(p))
{
if (token == "(" || token == ")")
{
continue;
}
result.Add(token);
}
return result.ToArray();
}
public static string ToSXPList(IEnumerable<string> 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<String> 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;
}
}
}
}
}