23 |
* Authors: |
* Authors: |
24 |
* Nicolai P Guba |
* Nicolai P Guba |
25 |
*/ |
*/ |
26 |
|
using System.Collections; |
27 |
using System.Globalization; |
using System.Globalization; |
28 |
using System.IO; |
using System.IO; |
29 |
using System.Xml; |
using System.Xml; |
32 |
{ |
{ |
33 |
public class XmlRpcReader |
public class XmlRpcReader |
34 |
{ |
{ |
|
private String request; |
|
35 |
private XmlRpcMethod method; |
private XmlRpcMethod method; |
36 |
private XmlTextReader xmlReader; |
private XmlTextReader xmlReader; |
37 |
private XmlRpcStruct structure; |
private XmlRpcStruct structure; |
38 |
private XmlRpcArray array; |
private XmlRpcArray array; |
39 |
private DateTimeFormatInfo dateFormat; |
private DateTimeFormatInfo dateFormat; |
40 |
|
private XmlRpcNode node; |
41 |
|
|
42 |
public XmlRpcReader( String buffer ) |
public XmlRpcReader( String buffer ) |
43 |
: this( new StringReader( buffer ) ){ |
: this( new StringReader( buffer ) ){ |
50 |
method = new XmlRpcMethod(); |
method = new XmlRpcMethod(); |
51 |
xmlReader = new XmlTextReader( reader ); |
xmlReader = new XmlTextReader( reader ); |
52 |
dateFormat = new DateTimeFormatInfo(); |
dateFormat = new DateTimeFormatInfo(); |
53 |
dateFormat.FullDateTimePattern = dateFormat.RFC1123Pattern; |
//dateFormat.FullDateTimePattern = dateFormat.SortableDateTimePattern ; |
54 |
|
|
55 |
// Itereate through the tree and construct an n-ary tree with |
// Itereate through the tree and construct an n-ary tree with |
56 |
// XmlRpcNodes so we can detect protocol errors and the current |
// XmlRpcNodes so we can detect protocol errors and the current |
57 |
// scope/context of a value parameter. |
// scope/context of a value parameter. |
58 |
while( xmlReader.Read() ) { |
while( xmlReader.Read() ) { |
|
XmlRpcNode node; |
|
59 |
switch( xmlReader.NodeType ) { |
switch( xmlReader.NodeType ) { |
60 |
|
|
61 |
// Open the scope |
// Open the scope |
133 |
|
|
134 |
default: |
default: |
135 |
node = new UnknownNode( xmlReader, node ); |
node = new UnknownNode( xmlReader, node ); |
136 |
//throw new XmlRpcBadFormatException( 100, "Unknown Element: " + |
throw new XmlRpcBadFormatException( 100, "Unknown Element: " + |
137 |
// xmlReader.Name, xmlReader ); |
xmlReader.Name ); |
138 |
break; |
break; |
139 |
} |
} |
140 |
#if __DEBUG__ |
#if __DEBUG__ |
143 |
#endif |
#endif |
144 |
break; |
break; |
145 |
|
|
146 |
|
// |
147 |
// set any values |
// set any values |
148 |
|
// |
149 |
case XmlNodeType.Text: |
case XmlNodeType.Text: |
150 |
switch( node.Tag ) { |
switch( node.Tag ) { |
151 |
case "methodName": |
case "methodName": |
153 |
break; |
break; |
154 |
case "base64": |
case "base64": |
155 |
byte[] barr = Convert.FromBase64String( xmlReader.Value ); |
byte[] barr = Convert.FromBase64String( xmlReader.Value ); |
156 |
Add( barr ); |
AddValue( barr ); |
157 |
break; |
break; |
158 |
case "i4": |
case "i4": |
159 |
case "int": |
case "int": |
160 |
int intval = Int32.Parse( xmlReader.Value ); |
int intval = Int32.Parse( xmlReader.Value ); |
161 |
Add( intval ); |
AddValue( intval ); |
162 |
break; |
break; |
163 |
case "boolean": |
case "boolean": |
164 |
string boolstr = xmlReader.Value; |
string boolstr = xmlReader.Value; |
169 |
boolstr = "true"; |
boolstr = "true"; |
170 |
} |
} |
171 |
bool boolval = Convert.ToBoolean( boolstr ); |
bool boolval = Convert.ToBoolean( boolstr ); |
172 |
Add( boolval ); |
AddValue( boolval ); |
173 |
break; |
break; |
174 |
case "double": |
case "double": |
175 |
double dval = Convert.ToDouble( xmlReader.Value ); |
double dval = Convert.ToDouble( xmlReader.Value ); |
176 |
Add( dval ); |
AddValue( dval ); |
177 |
break; |
break; |
178 |
case "dateTime.iso8601": |
case "dateTime.iso8601": |
179 |
try { |
try { |
180 |
DateTime dtval = DateTime.ParseExact( xmlReader.Value, "s", dateFormat ); |
DateTime dtval = DateTime.ParseExact( xmlReader.Value, "s", dateFormat ); |
181 |
Add( dtval ); |
AddValue( dtval ); |
182 |
} |
} |
183 |
catch( FormatException e ){ |
catch( FormatException e ){ |
184 |
string str = |
string str = |
185 |
String.Format( "Cannot parse DateTime value: {0}, expected format is: {1}", |
String.Format |
186 |
xmlReader.Value, dateFormat.UniversalSortableDateTimePattern ); |
( "Cannot parse DateTime value: {0}, expected format is: {1}", |
187 |
|
xmlReader.Value, dateFormat.SortableDateTimePattern ); |
188 |
|
|
189 |
throw new XmlRpcBadFormatException( 200, str , xmlReader ); |
throw new XmlRpcBadFormatException( 200, str ); |
190 |
} |
} |
191 |
break; |
break; |
192 |
case "string": |
case "string": |
193 |
Add( xmlReader.Value ); |
AddValue( xmlReader.Value ); |
194 |
break; |
break; |
195 |
|
|
196 |
case "name": |
case "name": |
197 |
if( structure != null ) { |
//Console.Out.WriteLine( "NameNode: {0}", xmlReader.Value ); |
198 |
structure.MemberName = xmlReader.Value; |
|
199 |
} |
//Add( xmlReader.Value ); |
200 |
else { |
|
201 |
|
//else { |
202 |
// TODO: make and throw an exception here... |
// TODO: make and throw an exception here... |
203 |
Console.Out.WriteLine( "Error: not in struct context: {0} name='{1}'", |
//Console.Out.WriteLine( "Error: not in struct context: {0} name='{1}'", |
204 |
node, xmlReader.Value ); |
// node, xmlReader.Value ); |
205 |
} |
//} |
206 |
break; |
break; |
207 |
// anything below here should never have a value. slap and bark at user. |
// anything below here should never have a value. slap and bark at user. |
208 |
case "methodResponse": |
case "methodResponse": |
216 |
case "data": |
case "data": |
217 |
default: |
default: |
218 |
throw new XmlRpcBadFormatException( 300, "Node Does Not Set Value: " + |
throw new XmlRpcBadFormatException( 300, "Node Does Not Set Value: " + |
219 |
node.Tag, xmlReader ); |
node.Tag ); |
220 |
break; |
break; |
221 |
} |
} |
222 |
break; |
break; |
231 |
node, node.Parent, xmlReader.Name ); |
node, node.Parent, xmlReader.Name ); |
232 |
#endif |
#endif |
233 |
switch( xmlReader.Name ) { |
switch( xmlReader.Name ) { |
234 |
|
case "methodResponse": |
235 |
case "methodCall" : |
case "methodCall" : |
236 |
case "methodName": |
case "methodName": |
237 |
case "params": |
case "params": |
256 |
break; |
break; |
257 |
case "member": |
case "member": |
258 |
node = node.Parent; |
node = node.Parent; |
259 |
structure.Commit(); |
//structure.Commit(); |
260 |
break; |
break; |
261 |
case "data": |
case "data": |
262 |
node = node.Parent; |
node = node.Parent; |
271 |
default: |
default: |
272 |
node = new UnknownNode( xmlReader, node ); |
node = new UnknownNode( xmlReader, node ); |
273 |
throw new XmlRpcBadFormatException( 400, "Unknown Element: " + |
throw new XmlRpcBadFormatException( 400, "Unknown Element: " + |
274 |
xmlReader.Name, xmlReader ); |
xmlReader.Name ); |
275 |
break; |
break; |
276 |
} |
} |
277 |
break; // case XmlNodeType.EndElement |
break; // case XmlNodeType.EndElement |
280 |
Console.Out.WriteLine( method ); |
Console.Out.WriteLine( method ); |
281 |
} |
} |
282 |
|
|
283 |
private void Add( object o ) |
// Add a value according to its context. Cunningly the XmlRpcSpec |
284 |
|
// has no seperate tags for values that are part of a struct or an |
285 |
|
// array. Nice one Balderick!!!! "I have a cunning plan..." |
286 |
|
private void AddValue( object o ) |
287 |
{ |
{ |
288 |
// HACK!!!: this could be done more elegantly |
XmlRpcNode context; |
289 |
if( (structure == null) && (array == null) ) { |
|
290 |
method.Parameters.Add( o ); |
if( (context = node.Parent.Parent.Parent) is StructNode ) { |
291 |
|
#if __DEBUG__ |
292 |
|
Console.Out.WriteLine( "Struct Context: {0} {1}", context, o ); |
293 |
|
#endif |
294 |
} |
} |
295 |
else if( (structure != null) && (array == null) ) { |
else if( (context = node.Parent.Parent.Parent) is ArrayNode ) { |
296 |
structure.MemberValue = o; |
#if __DEBUG__ |
297 |
|
Console.Out.WriteLine( "Array Context: {0}", context ); |
298 |
|
#endif |
299 |
} |
} |
300 |
else if( (structure == null) && (array != null) ) { |
else if( (context = node.Parent.Parent) is ParameterNode ) { |
301 |
array.Add( o ); |
#if __DEBUG__ |
302 |
} |
Console.Out.WriteLine( "Parameter Context: {0}", context ); |
303 |
|
#endif |
304 |
|
} |
305 |
else { |
else { |
306 |
// Oh dear. This should never happen |
// Oh dear. This should never happen |
307 |
// TODO: make and throw exception |
// TODO: make and throw exception |
308 |
Console.Out.WriteLine( "Parameter BUMMER: Unknown state {0} [structure={1}, array={2}]", o, structure, array ); |
Console.Out.WriteLine( "Parameter BUMMER: Unknown state {0} ", context ); |
309 |
} |
} |
310 |
} |
} |
311 |
|
|