1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
namespace Nwc.XmlRpc
{
using System;
using System.Collections;
using System.IO;
using System.Xml;
using System.Globalization;
/// <summary>Parser context, we maintain contexts in a stack to avoiding recursion. </summary>
struct Context
{
public String Name;
public Object Container;
}
/// <summary>Basic XML-RPC data deserializer.</summary>
/// <remarks>Uses <c>XmlTextReader</c> 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.</remarks>
public class XmlRpcDeserializer : XmlRpcXmlTokens
{
private static DateTimeFormatInfo _dateFormat = new DateTimeFormatInfo();
private Object _container;
private Stack _containerStack;
/// <summary>Protected reference to last text.</summary>
protected String _text;
/// <summary>Protected reference to last deserialized value.</summary>
protected Object _value;
/// <summary>Protected reference to last name field.</summary>
protected String _name;
/// <summary>Basic constructor.</summary>
public XmlRpcDeserializer()
{
Reset();
_dateFormat.FullDateTimePattern = ISO_DATETIME;
}
/// <summary>Static method that parses XML data into a response using the Singleton.</summary>
/// <param name="xmlData"><c>StreamReader</c> containing an XML-RPC response.</param>
/// <returns><c>Object</c> object resulting from the deserialization.</returns>
virtual public Object Deserialize(TextReader xmlData)
{
return null;
}
/// <summary>Protected method to parse a node in an XML-RPC XML stream.</summary>
/// <remarks>Method deals with elements common to all XML-RPC data, subclasses of
/// this object deal with request/response spefic elements.</remarks>
/// <param name="reader"><c>XmlTextReader</c> of the in progress parsing data stream.</param>
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 <string> tag, they just do <value>
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;
}
}
/// <summary>Static method that parses XML in a <c>String</c> into a
/// request using the Singleton.</summary>
/// <param name="xmlData"><c>String</c> containing an XML-RPC request.</param>
/// <returns><c>XmlRpcRequest</c> object resulting from the parse.</returns>
public Object Deserialize(String xmlData)
{
StringReader sr = new StringReader(xmlData);
return Deserialize(sr);
}
/// <summary>Pop a Context of the stack, an Array or Struct has closed.</summary>
private void PopContext()
{
Context c = (Context)_containerStack.Pop();
_container = c.Container;
_name = c.Name;
}
/// <summary>Push a Context on the stack, an Array or Struct has opened.</summary>
private void PushContext()
{
Context context;
context.Container = _container;
context.Name = _name;
_containerStack.Push(context);
}
/// <summary>Reset the internal state of the deserializer.</summary>
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
}
}
|