namespace Nwc.XmlRpc { using System; using System.Collections; using System.IO; using System.Xml; using System.Globalization; /// Parser context, we maintain contexts in a stack to avoiding recursion. struct Context { public String Name; public Object Container; } /// Basic XML-RPC data deserializer. /// Uses XmlTextReader to parse the XML data. This level of the class /// only handles the tokens common to both Requests and Responses. This class is not useful in and of itself /// but is designed to be subclassed. public class XmlRpcDeserializer : XmlRpcXmlTokens { private static DateTimeFormatInfo _dateFormat = new DateTimeFormatInfo(); private Object _container; private Stack _containerStack; /// Protected reference to last text. protected String _text; /// Protected reference to last deserialized value. protected Object _value; /// Protected reference to last name field. protected String _name; /// Basic constructor. public XmlRpcDeserializer() { Reset(); _dateFormat.FullDateTimePattern = ISO_DATETIME; } /// Static method that parses XML data into a response using the Singleton. /// StreamReader containing an XML-RPC response. /// Object object resulting from the deserialization. virtual public Object Deserialize(TextReader xmlData) { return null; } /// Protected method to parse a node in an XML-RPC XML stream. /// Method deals with elements common to all XML-RPC data, subclasses of /// this object deal with request/response spefic elements. /// XmlTextReader of the in progress parsing data stream. protected void DeserializeNode(XmlTextReader reader) { switch (reader.NodeType) { case XmlNodeType.Element: if (Logger.Delegate != null) Logger.WriteEntry("START " + reader.Name, LogLevel.Information); switch (reader.Name) { case VALUE: _value = null; _text = null; break; case STRUCT: PushContext(); _container = new Hashtable(); break; case ARRAY: PushContext(); _container = new ArrayList(); break; } break; case XmlNodeType.EndElement: if (Logger.Delegate != null) Logger.WriteEntry("END " + reader.Name, LogLevel.Information); switch (reader.Name) { case BASE64: _value = Convert.FromBase64String(_text); break; case BOOLEAN: int val = Int16.Parse(_text); if (val == 0) _value = false; else if (val == 1) _value = true; break; case STRING: _value = _text; break; case DOUBLE: _value = Double.Parse(_text); break; case INT: case ALT_INT: _value = Int32.Parse(_text); break; case DATETIME: #if __MONO__ _value = DateParse(_text); #else _value = DateTime.ParseExact(_text, "F", _dateFormat); #endif break; case NAME: _name = _text; break; case VALUE: if (_value == null) _value = _text; // some kits don't use tag, they just do if ((_container != null) && (_container is IList)) // in an array? If so add value to it. ((IList)_container).Add(_value); break; case MEMBER: if ((_container != null) && (_container is IDictionary)) // in an struct? If so add value to it. ((IDictionary)_container).Add(_name, _value); break; case ARRAY: case STRUCT: _value = _container; PopContext(); break; } break; case XmlNodeType.Text: if (Logger.Delegate != null) Logger.WriteEntry("Text " + reader.Value, LogLevel.Information); _text = reader.Value; break; default: break; } } /// Static method that parses XML in a String into a /// request using the Singleton. /// String containing an XML-RPC request. /// XmlRpcRequest object resulting from the parse. public Object Deserialize(String xmlData) { StringReader sr = new StringReader(xmlData); return Deserialize(sr); } /// Pop a Context of the stack, an Array or Struct has closed. private void PopContext() { Context c = (Context)_containerStack.Pop(); _container = c.Container; _name = c.Name; } /// Push a Context on the stack, an Array or Struct has opened. private void PushContext() { Context context; context.Container = _container; context.Name = _name; _containerStack.Push(context); } /// Reset the internal state of the deserializer. protected void Reset() { _text = null; _value = null; _name = null; _container = null; _containerStack = new Stack(); } #if __MONO__ private DateTime DateParse(String str) { int year = Int32.Parse(str.Substring(0,4)); int month = Int32.Parse(str.Substring(4,2)); int day = Int32.Parse(str.Substring(6,2)); int hour = Int32.Parse(str.Substring(9,2)); int min = Int32.Parse(str.Substring(12,2)); int sec = Int32.Parse(str.Substring(15,2)); return new DateTime(year,month,day,hour,min,sec); } #endif } }