object[] DeserializeParameter(Type serviceType, XmlNode[] paramNodes, ParameterInfo[] parameterInfos) { var parser = new XmlParser(Configuration); var parameterObjects = new List <object>(); var paramterCount = GetParamsPos(parameterInfos) ?? parameterInfos.Length; for (int i = 0; i < paramterCount; i++) { var paramNode = paramNodes[i]; var valueNode = paramNode.SelectSingleNode("value"); if (valueNode == null) { throw new XmlRpcInvalidXmlRpcException("Missing value element."); } var node = valueNode.SelectValueNode(); if (serviceType != null) { _parseStack.Push($"parameter {i + 1}"); var parsedValue = parser.ParseValue(node, parameterInfos[i].ParameterType, _parseStack); parameterObjects.Add(parsedValue); } else { _parseStack.Push($"parameter {i}"); var parsedValue = parser.ParseValue(node, null, _parseStack); parameterObjects.Add(parsedValue); } _parseStack.Pop(); } return(parameterObjects.ToArray()); }
public object ParseLong(XmlNode node, Type valueType, ParseStack parseStack) { if (valueType.IsNoLong()) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains i8 value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(valueType) + " expected " + parseStack.Dump()); } parseStack.Push("i8"); try { var valueNode = node.FirstChild; if (valueNode == null) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid i8 element " + parseStack.Dump()); } var strValue = valueNode.Value; if (!long.TryParse(strValue, out var parseResult)) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid i8 value " + parseStack.Dump()); } return(parseResult); } finally { parseStack.Pop(); } }
public object ParseBase64(XmlNode node, Type valueType, ParseStack parseStack) { if (valueType.IsNoByteArray()) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains base64 value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(valueType) + " expected " + parseStack.Dump()); } parseStack.Push("base64"); try { if (node.FirstChild == null) { return(new byte[0]); } var base64String = node.FirstChild.Value; var buffer = new Span <byte>(); if (!Convert.TryFromBase64String(base64String, buffer, out _)) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid base64 value " + parseStack.Dump()); } return(buffer.ToArray()); } finally { parseStack.Pop(); } }
public object ParseBoolean(XmlNode node, Type valueType, ParseStack parseStack) { if (valueType.IsNoBoolean()) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains boolean value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(valueType) + " expected " + parseStack.Dump()); } parseStack.Push("boolean"); try { var textbool = node.FirstChild.Value; if (!bool.TryParse(textbool, out var parseResult)) { if (!textbool.Equals("0") && !textbool.Equals("1")) { throw new XmlRpcInvalidXmlRpcException($"reponse contains invalid boolean value '{textbool}' " + parseStack.Dump()); } parseResult = textbool.Equals("1"); } return(valueType == typeof(XmlRpcBoolean) ? new XmlRpcBoolean(parseResult) : (object)parseResult); } finally { parseStack.Pop(); } }
public object ParseString(XmlNode node, Type valueType, ParseStack parseStack) { if (valueType.IsNoString()) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains string value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(valueType) + " expected " + parseStack.Dump()); } parseStack.Push("string"); try { return(node.FirstChild == null ? string.Empty : node.FirstChild.Value); } finally { parseStack.Pop(); } }
public object ParseDateTime(XmlNode node, Type valueType, ParseStack parseStack) { if (valueType.IsNoDateTime()) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains dateTime.iso8601 value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(valueType) + " expected " + parseStack.Dump()); } parseStack.Push("dateTime"); try { var child = node.FirstChild; if (child == null) { if (_config.MapEmptyDateTimeToMinValue()) { return(DateTime.MinValue); } else { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains empty dateTime value " + parseStack.Dump()); } } var datestring = child.Value; if (!DateTime8601.TryParseDateTime8601(datestring, out var retVal)) { if (_config.MapZerosDateTimeToMinValue() && datestring.StartsWith("0000") && (datestring == "00000000T00:00:00" || datestring == "0000-00-00T00:00:00Z" || datestring == "00000000T00:00:00Z" || datestring == "0000-00-00T00:00:00")) { retVal = DateTime.MinValue; } else { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid dateTime value " + parseStack.Dump()); } } return(valueType == typeof(XmlRpcDateTime) ? new XmlRpcDateTime(retVal) : (object)retVal); } finally { parseStack.Pop(); } }
public object ParseDouble(XmlNode node, Type ValueType, ParseStack parseStack) { if (ValueType.IsNoDouble()) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains double value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(ValueType) + " expected " + parseStack.Dump()); } parseStack.Push("double"); try { if (!double.TryParse(node.FirstChild.Value, out var parseResult)) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid double value " + parseStack.Dump()); } return(ValueType == typeof(XmlRpcDouble) ? new XmlRpcDouble(parseResult) : (object)parseResult); } finally { parseStack.Pop(); } }
public XmlRpcRequest DeserializeRequest(XmlDocument xdoc, Type svcType) { XmlRpcRequest request = new XmlRpcRequest(); XmlNode callNode = xdoc.SelectSingleNode("./methodCall"); if (callNode == null) { throw new XmlRpcInvalidXmlRpcException( "Request XML not valid XML-RPC - missing methodCall element."); } XmlNode methodNode = callNode.SelectSingleNode("./methodName"); if (methodNode == null) { throw new XmlRpcInvalidXmlRpcException( "Request XML not valid XML-RPC - missing methodName element."); } request.method = methodNode.FirstChild.Value; if (request.method == "") { throw new XmlRpcInvalidXmlRpcException( "Request XML not valid XML-RPC - empty methodName."); } request.mi = null; ParameterInfo[] pis = new ParameterInfo[0]; if (svcType != null) { // retrieve info for the method which handles this XML-RPC method XmlRpcServiceInfo svcInfo = XmlRpcServiceInfo.CreateServiceInfo(svcType); request.mi = svcInfo.GetMethodInfo(request.method); // if a service type has been specified and we cannot find the requested // method then we must throw an exception if (request.mi == null) { string msg = String.Format("unsupported method called: {0}", request.method); throw new XmlRpcUnsupportedMethodException(msg); } // method must be marked with XmlRpcMethod attribute Attribute attr = Attribute.GetCustomAttribute(request.mi, typeof(XmlRpcMethodAttribute)); if (attr == null) { throw new XmlRpcMethodAttributeException( "Method must be marked with the XmlRpcMethod attribute."); } pis = request.mi.GetParameters(); } XmlNode paramsNode = callNode.SelectSingleNode("./params"); if (paramsNode == null) { if (svcType != null) { if (pis.Length == 0) { request.args = new object[0]; return request; } else { throw new XmlRpcInvalidParametersException( "Method takes parameters and params element is missing."); } } else { request.args = new object[0]; return request; } } XmlNodeList paramNodes = paramsNode.SelectNodes("./param"); int paramsPos = GetParamsPos(pis); if (paramNodes.Count < paramsPos) { throw new XmlRpcInvalidParametersException( "Method takes parameters and there is incorrect number of param " + "elements."); } ParseStack parseStack = new ParseStack("request"); // TODO: use global action setting MappingAction mappingAction = MappingAction.Error; int paramObjCount = (paramsPos == -1 ?paramNodes.Count : paramsPos + 1); Object[] paramObjs = new Object[paramObjCount]; // parse ordinary parameters int ordinaryParams = (paramsPos == -1 ?paramNodes.Count :paramsPos); for (int i = 0; i < ordinaryParams; i++) { XmlNode paramNode = paramNodes[i]; XmlNode valueNode = paramNode.SelectSingleNode("./value"); if (valueNode == null) throw new XmlRpcInvalidXmlRpcException("Missing value element."); XmlNode node = valueNode.SelectSingleNode("./*"); if (node == null) node = valueNode.FirstChild; if (svcType != null) { parseStack.Push(String.Format("parameter {0}", i + 1)); // TODO: why following commented out? // parseStack.Push(String.Format("parameter {0} mapped to type {1}", // i, pis[i].ParameterType.Name)); paramObjs[i] = ParseValue(node, pis[i].ParameterType, parseStack, mappingAction); } else { parseStack.Push(String.Format("parameter {0}", i)); paramObjs[i] = ParseValue(node, null, parseStack, mappingAction); } parseStack.Pop(); } // parse params parameters if (paramsPos != -1) { Type paramsType = pis[paramsPos].ParameterType.GetElementType(); Object[] args = new Object[1]; args[0] = paramNodes.Count - paramsPos; Array varargs = (Array)CreateArrayInstance(pis[paramsPos].ParameterType, args); for (int i = 0; i < varargs.Length; i++) { XmlNode paramNode = paramNodes[i + paramsPos]; XmlNode valueNode = paramNode.SelectSingleNode("value"); if (valueNode == null) throw new XmlRpcInvalidXmlRpcException("Missing value element."); XmlNode node = valueNode.SelectSingleNode("./*"); if (node == null) node = valueNode.FirstChild; parseStack.Push(String.Format("parameter {0}", i + 1 + paramsPos)); varargs.SetValue(ParseValue(node, paramsType, parseStack, mappingAction), i); parseStack.Pop(); } paramObjs[paramsPos] = varargs; } request.args = paramObjs; return request; }
Object ParseStruct( XmlNode node, Type valueType, ParseStack parseStack, MappingAction mappingAction) { if (valueType.IsPrimitive) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains struct value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(valueType) + " expected " + StackDump(parseStack)); } #if !FX1_0 if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>)) { valueType = valueType.GetGenericArguments()[0]; } #endif object retObj; try { retObj = Activator.CreateInstance(valueType); } catch (Exception ex) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains struct value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(valueType) + " expected (as type " + valueType.Name + ") " + StackDump(parseStack)); } // Note: mapping action on a struct is only applied locally - it // does not override the global mapping action when members of the // struct are parsed MappingAction localAction = mappingAction; if (valueType != null) { parseStack.Push("struct mapped to type " + valueType.Name); localAction = StructMappingAction(valueType, mappingAction); } else { parseStack.Push("struct"); } // create map of field names and remove each name from it as // processed so we can determine which fields are missing // TODO: replace HashTable with lighter collection Hashtable names = new Hashtable(); foreach (FieldInfo fi in valueType.GetFields()) { names.Add(fi.Name, fi.Name); } foreach (PropertyInfo pi in valueType.GetProperties()) { names.Add(pi.Name, pi.Name); } XmlNodeList members = node.SelectNodes("./member"); int fieldCount = 0; foreach (XmlNode member in members) { if (member.Name != "member") continue; XmlNode nameNode; bool dupName; XmlNode valueNode; bool dupValue; SelectTwoNodes(member, "name", out nameNode, out dupName, "value", out valueNode, out dupValue); if (nameNode == null) throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains a member with missing name element" + " " + StackDump(parseStack)); if (dupName) throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains member with more than one name element" + " " + StackDump(parseStack)); string name = nameNode.FirstChild.Value; if (valueNode == null) throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains struct member " + name + " with missing value " + " " + StackDump(parseStack)); if (dupValue) throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains member with more than one value element" + " " + StackDump(parseStack)); string structName = GetStructName(valueType, name); if (structName != null) name = structName; if (names.Contains(name)) names.Remove(name); else { if (!IgnoreDuplicateMembers && (valueType.GetField(name) != null || valueType.GetProperty(name) != null)) throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains struct value with duplicate member " + nameNode.FirstChild.Value + " " + StackDump(parseStack)); else continue; // ignore duplicate member } MemberInfo[] mis = valueType.GetMember(name); if (mis.Length == 0) { continue; // allow unexpected members } Object valObj = null; switch (mis[0].MemberType) { case MemberTypes.Field: FieldInfo fi = (FieldInfo)mis[0]; if (valueType == null) parseStack.Push(String.Format("member {0}", name)); else parseStack.Push(String.Format("member {0} mapped to type {1}", name,fi.FieldType.Name)); try { XmlNode vvvNode = valueNode.SelectSingleNode("./*"); if (vvvNode == null) vvvNode = valueNode.FirstChild; valObj = ParseValue(vvvNode, fi.FieldType, parseStack, mappingAction); } catch(XmlRpcInvalidXmlRpcException) { if (valueType != null && localAction == MappingAction.Error) { MappingAction memberAction = MemberMappingAction(valueType, name, MappingAction.Error); if (memberAction == MappingAction.Error) throw; } } finally { parseStack.Pop(); } fi.SetValue(retObj, valObj); break ; case MemberTypes.Property : PropertyInfo pi = (PropertyInfo)mis[0] ; if (valueType == null) parseStack.Push(String.Format("member {0}", name)); else parseStack.Push(String.Format("member {0} mapped to type {1}", name,pi.PropertyType.Name)); XmlNode vvNode = valueNode.SelectSingleNode("./*"); if (vvNode == null) vvNode = valueNode.FirstChild; valObj = ParseValue(vvNode, pi.PropertyType, parseStack, mappingAction); parseStack.Pop(); pi.SetValue(retObj, valObj, null); break ; } fieldCount++; } if (localAction == MappingAction.Error && names.Count > 0) ReportMissingMembers(valueType, names, parseStack); parseStack.Pop(); return retObj; }
Object ParseString( XmlNode node, Type ValueType, ParseStack parseStack, MappingAction mappingAction) { if (ValueType != null && ValueType != typeof(System.String) && ValueType != typeof(Object)) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains string value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(ValueType) + " expected " + StackDump(parseStack)); } string ret; parseStack.Push("string"); try { if (node.FirstChild == null) ret = ""; else ret = node.FirstChild.Value; } finally { parseStack.Pop(); } return ret; }
Object ParseInt( XmlNode node, Type ValueType, ParseStack parseStack, MappingAction mappingAction) { if (ValueType != null && ValueType != typeof(Object) && ValueType != typeof(System.Int32) #if !FX1_0 && ValueType != typeof(int?) #endif && ValueType != typeof(XmlRpcInt)) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains int value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(ValueType) + " expected " + StackDump(parseStack)); } int retVal; parseStack.Push("integer"); try { XmlNode valueNode = node.FirstChild; if (valueNode == null) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType +" contains invalid int element " + StackDump(parseStack)); } try { String strValue = valueNode.Value; retVal = Int32.Parse(strValue); } catch(Exception) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid int value " + StackDump(parseStack)); } } finally { parseStack.Pop(); } if (ValueType == typeof(XmlRpcInt)) return new XmlRpcInt(retVal); else return retVal; }
Object ParseHashtable( XmlNode node, Type valueType, ParseStack parseStack, MappingAction mappingAction) { XmlRpcStruct retObj = new XmlRpcStruct(); parseStack.Push("struct mapped to XmlRpcStruct"); try { XmlNodeList members = node.SelectNodes("./member"); foreach (XmlNode member in members) { if (member.Name != "member") continue; XmlNode nameNode; bool dupName; XmlNode valueNode; bool dupValue; SelectTwoNodes(member, "name", out nameNode, out dupName, "value", out valueNode, out dupValue); if (nameNode == null) throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains a member with missing name element" + " " + StackDump(parseStack)); if (dupName) throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains member with more than one name element" + " " + StackDump(parseStack)); string rpcName = nameNode.FirstChild.Value; if (valueNode == null) throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains struct member " + rpcName + " with missing value " + " " + StackDump(parseStack)); if (dupValue) throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains member with more than one value element" + " " + StackDump(parseStack)); if (retObj.Contains(rpcName)) { if (!IgnoreDuplicateMembers) throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains struct value with duplicate member " + nameNode.FirstChild.Value + " " + StackDump(parseStack)); else continue; } object valObj; parseStack.Push(String.Format("member {0}", rpcName)); try { XmlNode vvNode = valueNode.SelectSingleNode("./*"); if (vvNode == null) vvNode = valueNode.FirstChild; valObj = ParseValue(vvNode, null, parseStack, mappingAction); } finally { parseStack.Pop(); } retObj.Add(rpcName, valObj); } } finally { parseStack.Pop(); } return retObj; }
Object ParseDouble( XmlNode node, Type ValueType, ParseStack parseStack, MappingAction mappingAction) { if (ValueType != null && ValueType != typeof(Object) && ValueType != typeof(System.Double) #if !FX1_0 && ValueType != typeof(double?) #endif && ValueType != typeof(XmlRpcDouble)) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains double value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(ValueType) + " expected " + StackDump(parseStack)); } Double retVal; parseStack.Push("double"); try { retVal = Double.Parse(node.FirstChild.Value, CultureInfo.InvariantCulture.NumberFormat); } catch(Exception) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid double value " + StackDump(parseStack)); } finally { parseStack.Pop(); } if (ValueType == typeof(XmlRpcDouble)) return new XmlRpcDouble(retVal); else return retVal; }
Object ParseDateTime( XmlNode node, Type ValueType, ParseStack parseStack, MappingAction mappingAction) { if (ValueType != null && ValueType != typeof(Object) && ValueType != typeof(System.DateTime) #if !FX1_0 && ValueType != typeof(DateTime?) #endif && ValueType != typeof(XmlRpcDateTime)) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains dateTime.iso8601 value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(ValueType) + " expected " + StackDump(parseStack)); } DateTime retVal; parseStack.Push("dateTime"); try { XmlNode child = node.FirstChild; if (child == null) { if (MapEmptyDateTimeToMinValue) return DateTime.MinValue; else throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains empty dateTime value " + StackDump(parseStack)); } string s = child.Value; // Allow various iso8601 formats, e.g. // XML-RPC spec yyyyMMddThh:mm:ss // WordPress yyyyMMddThh:mm:ssZ // TypePad yyyy-MM-ddThh:mm:ssZ // other yyyy-MM-ddThh:mm:ss if (!DateTime8601.TryParseDateTime8601(s, out retVal)) { if (MapZerosDateTimeToMinValue && s.StartsWith("0000") && (s == "00000000T00:00:00" || s == "0000-00-00T00:00:00Z" || s == "00000000T00:00:00Z" || s == "0000-00-00T00:00:00")) retVal = DateTime.MinValue; else throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid dateTime value " + StackDump(parseStack)); } } finally { parseStack.Pop(); } if (ValueType == typeof(XmlRpcDateTime)) return new XmlRpcDateTime(retVal); else return retVal; }
object ParseArray(XmlNode node, Type valueType, ParseStack parseStack) { // required type must be an array if (valueType != null && !(valueType.IsArray == true || valueType == typeof(Array) || valueType == typeof(object))) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains array value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(valueType) + " expected " + parseStack.Dump()); } if (valueType != null) { XmlRpcType xmlRpcType = XmlRpcServiceInfo.GetXmlRpcType(valueType); if (xmlRpcType == XmlRpcType.MultiDimArray) { parseStack.Push("array mapped to type " + valueType.Name); object ret = ParseMultiDimArray(node, valueType, parseStack); return(ret); } parseStack.Push("array mapped to type " + valueType.Name); } else { parseStack.Push("array"); } var dataNode = node.SelectSingleNode("data"); var childNodes = dataNode.SelectChildNodes("value"); var nodeCount = childNodes.Length; var elements = new object[nodeCount]; // determine type of array elements Type elemType; if (valueType != null && valueType != typeof(Array) && valueType != typeof(object)) { elemType = valueType.GetElementType(); } else { elemType = typeof(object); } bool bGotType = false; Type useType = null; int i = 0; foreach (XmlNode vNode in childNodes) { parseStack.Push(String.Format("element {0}", i)); XmlNode vvNode = vNode.SelectValueNode(); elements[i++] = ParseValue(vvNode, elemType, parseStack, out Type parsedType, out Type parsedArrayType); if (bGotType == false) { useType = parsedArrayType; bGotType = true; } else { if (useType != parsedArrayType) { useType = null; } } parseStack.Pop(); } object[] args = new object[1]; args[0] = nodeCount; object retObj; if (valueType != null && valueType != typeof(Array) && valueType != typeof(object)) { retObj = Activator.CreateInstance(valueType, args); } else { if (useType == null) { retObj = Activator.CreateInstance(typeof(object[]), args); } else { retObj = Activator.CreateInstance(useType, args); } } for (int j = 0; j < elements.Length; j++) { ((Array)retObj).SetValue(elements[j], j); } parseStack.Pop(); return(retObj); }
Object ParseBoolean( XmlNode node, Type ValueType, ParseStack parseStack, MappingAction mappingAction) { if (ValueType != null && ValueType != typeof(Object) && ValueType != typeof(System.Boolean) #if !FX1_0 && ValueType != typeof(bool?) #endif && ValueType != typeof(XmlRpcBoolean)) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains boolean value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(ValueType) + " expected " + StackDump(parseStack)); } bool retVal; parseStack.Push("boolean"); try { string s = node.FirstChild.Value; if (s == "1") { retVal = true; } else if (s == "0") { retVal = false; } else { throw new XmlRpcInvalidXmlRpcException( "reponse contains invalid boolean value " + StackDump(parseStack)); } } finally { parseStack.Pop(); } if (ValueType == typeof(XmlRpcBoolean)) return new XmlRpcBoolean(retVal); else return retVal; }
Object ParseArray( XmlNode node, Type ValueType, ParseStack parseStack, MappingAction mappingAction) { // required type must be an array if (ValueType != null && !(ValueType.IsArray == true || ValueType == typeof(Array) || ValueType == typeof(object))) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains array value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(ValueType) + " expected " + StackDump(parseStack)); } if (ValueType != null) { XmlRpcType xmlRpcType = XmlRpcServiceInfo.GetXmlRpcType(ValueType); if (xmlRpcType == XmlRpcType.tMultiDimArray) { parseStack.Push("array mapped to type " + ValueType.Name); Object ret = ParseMultiDimArray(node, ValueType, parseStack, mappingAction); return ret; } parseStack.Push("array mapped to type " + ValueType.Name); } else parseStack.Push("array"); XmlNode dataNode = node.SelectSingleNode("./data"); XmlNodeList childNodes = dataNode.SelectNodes("./value"); int nodeCount = childNodes.Count; Object[] elements = new Object[nodeCount]; // determine type of array elements Type elemType = null; if (ValueType != null && ValueType != typeof(Array) && ValueType != typeof(object)) { #if (!COMPACT_FRAMEWORK) elemType = ValueType.GetElementType(); #else string[] checkMultiDim = Regex.Split(ValueType.FullName, "\\[\\]$"); // determine assembly of array element type Assembly asmbly = ValueType.Assembly; string[] asmblyName = asmbly.FullName.Split(','); string elemTypeName = checkMultiDim[0] + ", " + asmblyName[0]; elemType = Type.GetType(elemTypeName); #endif } else { elemType = typeof(object); } bool bGotType = false; Type useType = null; int i = 0; foreach (XmlNode vNode in childNodes) { parseStack.Push(String.Format("element {0}", i)); XmlNode vvNode = vNode.SelectSingleNode("./*"); if (vvNode == null) vvNode = vNode.FirstChild; Type parsedType; Type parsedArrayType; elements[i++] = ParseValue(vvNode, elemType, parseStack, mappingAction, out parsedType, out parsedArrayType); if (bGotType == false) { useType = parsedArrayType; bGotType = true; } else { if (useType != parsedArrayType) useType = null; } parseStack.Pop(); } Object[] args = new Object[1]; args[0] = nodeCount; Object retObj = null; if (ValueType != null && ValueType != typeof(Array) && ValueType != typeof(object)) { retObj = CreateArrayInstance(ValueType, args); } else { if (useType == null) retObj = CreateArrayInstance(typeof(object[]), args); else retObj = CreateArrayInstance(useType, args); } for (int j=0; j < elements.Length; j++) { ((Array)retObj).SetValue(elements[j], j); } parseStack.Pop(); return retObj; }
public object ParseHashtable(XmlNode node, ParseStack parseStack) { var retObj = new XmlRpcStruct(); parseStack.Push("class mapped to XmlRpcStruct"); try { var members = node.SelectChildNodes("member"); foreach (var member in members) { var(nameNode, hasMultipleNameNodes) = member.SelectPossibleDoupletteNode("name"); var(valueNode, hasMultipleValueNodes) = member.SelectPossibleDoupletteNode("value"); if (nameNode == null || nameNode.FirstChild == null) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains a member with missing name" + " " + parseStack.Dump()); } if (hasMultipleNameNodes) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains member with more than one name element" + " " + parseStack.Dump()); } var rpcName = nameNode.FirstChild.Value; if (valueNode == null) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains class member " + rpcName + " with missing value " + " " + parseStack.Dump()); } if (hasMultipleValueNodes) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains member with more than one value element" + " " + parseStack.Dump()); } if (retObj.Contains(rpcName)) { if (_config.IgnoreDuplicateMembers()) { continue; } throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains class value with duplicate member " + nameNode.FirstChild.Value + " " + parseStack.Dump()); } parseStack.Push($"member {rpcName}"); try { var vvNode = valueNode.SelectValueNode(); var valObj = ParseValue(vvNode, null, parseStack); retObj.Add(rpcName, valObj); } finally { parseStack.Pop(); } } } finally { parseStack.Pop(); } return(retObj); }
object ParseStruct( XmlNode node, Type valueType, ParseStack parseStack) { if (valueType.IsPrimitive) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains class value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(valueType) + " expected " + parseStack.Dump()); } if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable <>)) { valueType = valueType.GetGenericArguments()[0]; } object retObj; try { retObj = Activator.CreateInstance(valueType); } catch (Exception) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains class value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(valueType) + " expected (as type " + valueType.Name + ") " + parseStack.Dump()); } // Note: mapping action on a class is only applied locally - it // does not override the global mapping action when members of the // class are parsed MappingAction localAction = _config.MappingAction; if (valueType != null) { parseStack.Push("class mapped to type " + valueType.Name); localAction = AttributeHelper.StructMappingAction(valueType, localAction); } else { parseStack.Push("struct"); } // create map of field names and remove each name from it as // processed so we can determine which fields are missing // TODO: replace HashTable with lighter collection Hashtable names = new Hashtable(); foreach (FieldInfo fi in valueType.GetFields()) { if (Attribute.IsDefined(fi, typeof(NonSerializedAttribute))) { continue; } names.Add(fi.Name, fi.Name); } foreach (PropertyInfo pi in valueType.GetProperties()) { if (Attribute.IsDefined(pi, typeof(NonSerializedAttribute))) { continue; } names.Add(pi.Name, pi.Name); } XmlNode[] members = node.SelectChildNodes("member"); int fieldCount = 0; foreach (XmlNode member in members) { if (member.Name != "member") { continue; } var(nameNode, nameIsDuplicated) = member.SelectPossibleDoupletteNode("name"); var(valueNode, valueIsDuplicated) = member.SelectPossibleDoupletteNode("value"); if (nameNode == null || nameNode.FirstChild == null) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains a member with missing name" + " " + parseStack.Dump()); } if (nameIsDuplicated) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains member with more than one name element" + " " + parseStack.Dump()); } string name = nameNode.FirstChild.Value; if (valueNode == null) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains class member " + name + " with missing value " + " " + parseStack.Dump()); } if (valueIsDuplicated) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains member with more than one value element" + " " + parseStack.Dump()); } string structName = AttributeHelper.GetStructName(valueType, name); if (structName != null) { name = structName; } MemberInfo mi = valueType.GetField(name); if (mi == null) { mi = valueType.GetProperty(name); } if (mi == null) { continue; } if (names.Contains(name)) { names.Remove(name); } else { if (Attribute.IsDefined(mi, typeof(NonSerializedAttribute))) { parseStack.Push(String.Format("member {0}", name)); throw new XmlRpcNonSerializedMember("Cannot map XML-RPC class " + "member onto member marked as [NonSerialized]: " + " " + parseStack.Dump()); } if (!_config.IgnoreDuplicateMembers()) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains class value with duplicate member " + nameNode.FirstChild.Value + " " + parseStack.Dump()); } else { continue; // ignore duplicate member } } object valObj = null; switch (mi.MemberType) { case MemberTypes.Field: FieldInfo fi = (FieldInfo)mi; if (valueType == null) { parseStack.Push(String.Format("member {0}", name)); } else { parseStack.Push(String.Format("member {0} mapped to type {1}", name, fi.FieldType.Name)); } try { XmlNode vvvNode = valueNode.SelectValueNode(); valObj = ParseValue(vvvNode, fi.FieldType, parseStack); } catch (XmlRpcInvalidXmlRpcException) { if (valueType != null && localAction == MappingAction.Error) { MappingAction memberAction = AttributeHelper.MemberMappingAction(valueType, name, MappingAction.Error); if (memberAction == MappingAction.Error) { throw; } } } finally { parseStack.Pop(); } fi.SetValue(retObj, valObj); break; case MemberTypes.Property: PropertyInfo pi = (PropertyInfo)mi; if (valueType == null) { parseStack.Push(String.Format("member {0}", name)); } else { parseStack.Push(String.Format("member {0} mapped to type {1}", name, pi.PropertyType.Name)); } XmlNode vvNode = valueNode.SelectValueNode(); valObj = ParseValue(vvNode, pi.PropertyType, parseStack); parseStack.Pop(); pi.SetValue(retObj, valObj, null); break; } fieldCount++; } if (localAction == MappingAction.Error && names.Count > 0) { ReportMissingMembers(valueType, names, parseStack); } parseStack.Pop(); return(retObj); }
Object ParseBase64( XmlNode node, Type ValueType, ParseStack parseStack, MappingAction mappingAction) { if (ValueType != null && ValueType != typeof(byte[]) && ValueType != typeof(Object)) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains base64 value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(ValueType) + " expected " + StackDump(parseStack)); } byte[] ret; parseStack.Push("base64"); try { if (node.FirstChild == null) ret = new byte[0]; else { string s = node.FirstChild.Value; try { ret = Convert.FromBase64String(s); } catch (Exception) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid base64 value " + StackDump(parseStack)); } } } finally { parseStack.Pop(); } return ret; }
public XmlRpcRequest DeserializeRequest(XmlDocument xdoc, Type svcType) { XmlRpcRequest request = new XmlRpcRequest(); XmlNode callNode = SelectSingleNode(xdoc, "methodCall"); if (callNode == null) { throw new XmlRpcInvalidXmlRpcException( "Request XML not valid XML-RPC - missing methodCall element."); } XmlNode methodNode = SelectSingleNode(callNode, "methodName"); if (methodNode == null) { throw new XmlRpcInvalidXmlRpcException( "Request XML not valid XML-RPC - missing methodName element."); } if (methodNode.FirstChild == null) { throw new XmlRpcInvalidXmlRpcException( "Request XML not valid XML-RPC - missing methodName element."); } request.method = methodNode.FirstChild.Value; if (request.method == "") { throw new XmlRpcInvalidXmlRpcException( "Request XML not valid XML-RPC - empty methodName."); } request.mi = null; ParameterInfo[] pis = new ParameterInfo[0]; if (svcType != null) { // retrieve info for the method which handles this XML-RPC method XmlRpcServiceInfo svcInfo = XmlRpcServiceInfo.CreateServiceInfo(svcType); request.mi = svcInfo.GetMethodInfo(request.method); // if a service type has been specified and we cannot find the requested // method then we must throw an exception if (request.mi == null) { string msg = String.Format("unsupported method called: {0}", request.method); throw new XmlRpcUnsupportedMethodException(msg); } // method must be marked with XmlRpcMethod attribute Attribute attr = Attribute.GetCustomAttribute(request.mi, typeof(XmlRpcMethodAttribute)); if (attr == null) { throw new XmlRpcMethodAttributeException( "Method must be marked with the XmlRpcMethod attribute."); } pis = request.mi.GetParameters(); } XmlNode paramsNode = SelectSingleNode(callNode, "params"); if (paramsNode == null) { if (svcType != null) { if (pis.Length == 0) { request.args = new object[0]; return request; } // JB Change // Sometimes tapatalk calls the same method with both parameters and no parameters // This allows us to handle that by changing the no parameter case into an empty parameter array else if(pis.Length == 1 && pis[0].ParameterType == typeof(object[])) { paramsNode = xdoc.CreateNode(XmlNodeType.Element, "params", ""); //var paramNode = xdoc.CreateNode(XmlNodeType.Element, "param", ""); //paramsNode.AppendChild(paramNode); // var valueNode = xdoc.CreateNode(XmlNodeType.Element, "value", ""); //paramNode.AppendChild(valueNode); // var arrayNode = xdoc.CreateNode(XmlNodeType.Element, "string", ""); //valueNode.AppendChild(arrayNode); // var dataNode = xdoc.CreateNode(XmlNodeType.Element, "data", ""); //arrayNode.AppendChild(dataNode); } else { throw new XmlRpcInvalidParametersException( "Method takes parameters and params element is missing."); } } else { request.args = new object[0]; return request; } } XmlNode[] paramNodes = SelectNodes(paramsNode, "param"); int paramsPos = GetParamsPos(pis); int minParamCount = paramsPos == -1 ? pis.Length : paramsPos; if (svcType != null && paramNodes.Length < minParamCount) { throw new XmlRpcInvalidParametersException( "Request contains too few param elements based on method signature."); } if (svcType != null && paramsPos == -1 && paramNodes.Length > pis.Length) { throw new XmlRpcInvalidParametersException( "Request contains too many param elements based on method signature."); } ParseStack parseStack = new ParseStack("request"); // TODO: use global action setting MappingAction mappingAction = MappingAction.Error; int paramObjCount = (paramsPos == -1 ? paramNodes.Length : paramsPos + 1); Object[] paramObjs = new Object[paramObjCount]; // parse ordinary parameters int ordinaryParams = (paramsPos == -1 ? paramNodes.Length : paramsPos); for (int i = 0; i < ordinaryParams; i++) { XmlNode paramNode = paramNodes[i]; XmlNode valueNode = SelectSingleNode(paramNode, "value"); if (valueNode == null) throw new XmlRpcInvalidXmlRpcException("Missing value element."); XmlNode node = SelectValueNode(valueNode); if (svcType != null) { parseStack.Push(String.Format("parameter {0}", i + 1)); // TODO: why following commented out? // parseStack.Push(String.Format("parameter {0} mapped to type {1}", // i, pis[i].ParameterType.Name)); paramObjs[i] = ParseValue(node, pis[i].ParameterType, parseStack, mappingAction); } else { parseStack.Push(String.Format("parameter {0}", i)); paramObjs[i] = ParseValue(node, null, parseStack, mappingAction); } parseStack.Pop(); } // parse params parameters if (paramsPos != -1) { Type paramsType = pis[paramsPos].ParameterType.GetElementType(); Object[] args = new Object[1]; args[0] = paramNodes.Length - paramsPos; Array varargs = (Array)CreateArrayInstance(pis[paramsPos].ParameterType, args); for (int i = 0; i < varargs.Length; i++) { XmlNode paramNode = paramNodes[i + paramsPos]; XmlNode valueNode = SelectSingleNode(paramNode, "value"); if (valueNode == null) throw new XmlRpcInvalidXmlRpcException("Missing value element."); XmlNode node = SelectValueNode(valueNode); parseStack.Push(String.Format("parameter {0}", i + 1 + paramsPos)); varargs.SetValue(ParseValue(node, paramsType, parseStack, mappingAction), i); parseStack.Pop(); } paramObjs[paramsPos] = varargs; } request.args = paramObjs; return request; }
Object ParseDateTime( XmlNode node, Type ValueType, ParseStack parseStack, MappingAction mappingAction) { if (ValueType != null && ValueType != typeof(Object) && ValueType != typeof(System.DateTime) #if !FX1_0 && ValueType != typeof(DateTime?) #endif && ValueType != typeof(XmlRpcDateTime)) { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains dateTime.iso8601 value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(ValueType) + " expected " + StackDump(parseStack)); } DateTime retVal; parseStack.Push("dateTime"); try { XmlNode child = node.FirstChild; if (child == null) { if (MapEmptyDateTimeToMinValue) return DateTime.MinValue; else throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains empty dateTime value " + StackDump(parseStack)); } string s = child.Value; try { // XML-RPC spec yyyyMMddThh:mm:ss string dateTimeFormat = "yyyyMMdd'T'HH':'mm':'ss"; if (AllowNonStandardDateTime) { if (s.IndexOf("T") == 8) { if (s.EndsWith("Z")) { // WordPress yyyyMMddThh:mm:ssZ dateTimeFormat = "yyyyMMdd'T'HH':'mm':'ss'Z'"; } else if (s.EndsWith("-00") || s.EndsWith("-0000") || s.EndsWith("+00") || s.EndsWith("+0000")) { s = s.Substring(0, 17); } } else { if (s.EndsWith("Z")) { // TypePad yyyy-MM-ddThh:mm:ssZ dateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"; } else { // other yyyy-MM-ddThh:mm:ss dateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss"; } } } if (MapZerosDateTimeToMinValue && s.StartsWith("0000") && (s == "00000000T00:00:00" || s == "0000-00-00T00:00:00Z" || s == "00000000T00:00:00Z" || s == "0000-00-00T00:00:00")) retVal = DateTime.MinValue; else retVal = DateTime.ParseExact(s, dateTimeFormat, DateTimeFormatInfo.InvariantInfo); } catch(Exception) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid dateTime value " + StackDump(parseStack)); } } finally { parseStack.Pop(); } if (ValueType == typeof(XmlRpcDateTime)) return new XmlRpcDateTime(retVal); else return retVal; }
Object ParseLong( XmlNode node, Type ValueType, ParseStack parseStack, MappingAction mappingAction) { if (ValueType != null && ValueType != typeof(Object) && ValueType != typeof(System.Int64) #if !FX1_0 && ValueType != typeof(long?)) #endif { throw new XmlRpcTypeMismatchException(parseStack.ParseType + " contains i8 value where " + XmlRpcServiceInfo.GetXmlRpcTypeString(ValueType) + " expected " + StackDump(parseStack)); } long retVal; parseStack.Push("i8"); try { XmlNode valueNode = node.FirstChild; if (valueNode == null) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid i8 element " + StackDump(parseStack)); } try { String strValue = valueNode.Value; retVal = Int64.Parse(strValue); } catch (Exception) { throw new XmlRpcInvalidXmlRpcException(parseStack.ParseType + " contains invalid i8 value " + StackDump(parseStack)); } } finally { parseStack.Pop(); } return retVal; }