1 /*
2  * Copyright (C) 2009 by Dr. Marc Boris Duerner
3  * Copyright (C) 2009 by Tommi Meakitalo
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * As a special exception, you may use this file as part of a free
11  * software library without restriction. Specifically, if other files
12  * instantiate templates or use macros or inline functions from this
13  * file, or you compile this file and link it with other files to
14  * produce an executable, this file does not by itself cause the
15  * resulting executable to be covered by the GNU General Public
16  * License. This exception does not however invalidate any other
17  * reasons why the executable file might be covered by the GNU Library
18  * General Public License.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Lesser General Public License for more details.
24  *
25  * You should have received a copy of the GNU Lesser General Public
26  * License along with this library; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
28  */
29 #include <cxxtools/xmlrpc/scanner.h>
30 #include <cxxtools/xml/startelement.h>
31 #include <cxxtools/xml/endelement.h>
32 #include <cxxtools/xml/characters.h>
33 #include <cxxtools/serializationinfo.h>
34 #include <cxxtools/serializationerror.h>
35 #include <cxxtools/deserializerbase.h>
36 #include <cxxtools/composer.h>
37 
38 namespace cxxtools
39 {
40 
41 namespace xmlrpc
42 {
43 
44 namespace
45 {
throwSerializationError(const char * msg="invalid XML-RPC parameter")46     void throwSerializationError(const char* msg = "invalid XML-RPC parameter")
47     {
48         SerializationError::doThrow(msg);
49     }
50 }
51 
begin(DeserializerBase & handler,IComposer & composer)52 void Scanner::begin(DeserializerBase& handler, IComposer& composer)
53 {
54     _state = OnParam;
55     _deserializer = &handler;
56     _composer = &composer;
57     _deserializer->begin();
58 }
59 
advance(const cxxtools::xml::Node & node)60 bool Scanner::advance(const cxxtools::xml::Node& node)
61 {
62     switch(_state)
63     {
64         case OnParam:
65         {
66             if(node.type() == xml::Node::StartElement) // value
67             {
68                 const xml::StartElement& se = static_cast<const xml::StartElement&>(node);
69 
70                 if(se.name() != L"value")
71                     throwSerializationError();
72 
73                 _state = OnValueBegin;
74             }
75             else if(node.type() == xml::Node::EndElement)
76             {
77                 throwSerializationError();
78             }
79 
80             break;
81         }
82 
83         case OnValueBegin:
84         {
85             if(node.type() == xml::Node::StartElement) // i4, struct, array...
86             {
87                 const xml::StartElement& se = static_cast<const xml::StartElement&>(node);
88 
89                 if(se.name() == L"struct")
90                 {
91                     _state = OnStructBegin;
92                 }
93                 else if(se.name() == L"array")
94                 {
95                     _state = OnArrayBegin;
96                 }
97                 else
98                 {
99                     _state = OnScalarBegin;
100                 }
101 
102                 _value.clear();
103                 _type = se.name();
104             }
105             else if(node.type() == xml::Node::Characters)
106             {
107                 // maybe <value>...<type>...</type>...</value>  (case 1)
108                 //    or <value>...</value>                     (case 2)
109                 const xml::Characters& chars = static_cast<const xml::Characters&>(node);
110                 _value = chars.content();
111             }
112             else if(node.type() == xml::Node::EndElement)
113             {
114                 const xml::EndElement& ee = static_cast<const xml::EndElement&>(node);
115                 if(ee.name() != L"value")
116                     throwSerializationError();
117 
118                 // is always type string
119                 _deserializer->setValue( _value );
120                 _value.clear();
121 
122                 _state = OnValueEnd;
123             }
124             else
125             {
126                 throwSerializationError();
127             }
128 
129             break;
130         }
131 
132         case OnValueEnd:
133         {
134             if(node.type() == xml::Node::EndElement)
135             {
136                 const xml::EndElement& ee = static_cast<const xml::EndElement&>(node);
137 
138                 if(ee.name() == L"member")
139                 {
140                     _deserializer->leaveMember();
141                     _state = OnStructBegin;
142                 }
143                 else if(ee.name() == L"data")
144                 {
145                     _deserializer->leaveMember();
146                     _state = OnDataEnd;
147                 }
148                 else if(ee.name() == L"param")
149                 {
150                     _composer->fixup(*_deserializer->si());
151                     _state = OnValueEnd;
152                     return true;
153                 }
154                 else if(ee.name() == L"fault")
155                 {
156                     _composer->fixup(*_deserializer->si());
157                     _state = OnValueEnd;
158                     return true;
159                 }
160                 else
161                 {
162                     throwSerializationError();
163                 }
164             }
165             else if(node.type() == xml::Node::StartElement)
166             {
167                 const xml::StartElement& se = static_cast<const xml::StartElement&>(node);
168                 if(se.name() == L"value")
169                 {
170                     _deserializer->leaveMember();
171                     _deserializer->beginMember(std::string(), _type.narrow(), SerializationInfo::Value);
172                     _state = OnValueBegin;
173                 }
174                 else
175                 {
176                     throwSerializationError();
177                 }
178             }
179 
180             break;
181         }
182 
183         case OnStructBegin:
184         {
185             if(node.type() == xml::Node::StartElement) // <member>
186             {
187                 const xml::StartElement& se = static_cast<const xml::StartElement&>(node);
188 
189                 if(se.name() != L"member")
190                     throwSerializationError();
191 
192                 _state = OnMemberBegin;
193             }
194             else if(node.type() == xml::Node::EndElement) // </struct>
195             {
196                 _state = OnStructEnd;
197             }
198             break;
199         }
200 
201         case OnStructEnd:
202         {
203             if(node.type() == xml::Node::EndElement) // </value>
204             {
205                 const xml::EndElement& ee = static_cast<const xml::EndElement&>(node);
206 
207                 if(ee.name() != L"value")
208                     throwSerializationError();
209 
210                 _state = OnValueEnd;
211             }
212             else if(node.type() == xml::Node::StartElement)
213             {
214                 throwSerializationError();
215             }
216 
217             break;
218         }
219 
220         case OnMemberBegin:
221         {
222             if(node.type() == xml::Node::StartElement) // name
223             {
224                 const xml::StartElement& se = static_cast<const xml::StartElement&>(node);
225 
226                 if(se.name() != L"name")
227                     throwSerializationError();
228 
229                 _state = OnNameBegin;
230             }
231             else if(node.type() == xml::Node::EndElement)
232             {
233                 throwSerializationError();
234             }
235 
236             break;
237         }
238 
239         case OnNameBegin:
240         {
241             if(node.type() == xml::Node::Characters) // member-name
242             {
243                 const xml::Characters& chars = static_cast<const xml::Characters&>(node);
244                 const std::string& name = chars.content().narrow();
245 
246                 _deserializer->beginMember(name, std::string(), SerializationInfo::Object);
247 
248                 _state = OnName;
249             }
250             else
251             {
252                 throwSerializationError();
253             }
254 
255             break;
256         }
257 
258         case OnName:
259         {
260             if(node.type() == xml::Node::EndElement) // </name>
261             {
262                 const xml::EndElement& ee = static_cast<const xml::EndElement&>(node);
263 
264                 if(ee.name() != L"name")
265                     throwSerializationError();
266 
267                 _state = OnNameEnd;
268             }
269             else if(node.type() == xml::Node::StartElement)
270             {
271                 throwSerializationError();
272             }
273 
274             break;
275         }
276 
277         case OnNameEnd:
278         {
279             if(node.type() == xml::Node::StartElement) // <value>
280             {
281                 const xml::StartElement& se = static_cast<const xml::StartElement&>(node);
282 
283                 if(se.name() != L"value")
284                     throwSerializationError();
285 
286                 _state = OnValueBegin;
287             }
288             else if(node.type() == xml::Node::EndElement)
289             {
290                 throwSerializationError();
291             }
292 
293             break;
294         }
295 
296         case OnScalarBegin:
297         {
298             if(node.type() == xml::Node::Characters)
299             {
300                 const xml::Characters& chars = static_cast<const xml::Characters&>(node);
301                 _state = OnScalar;
302 
303                 _deserializer->setValue( chars.content() );
304             }
305             else if(node.type() == xml::Node::EndElement) // no content, for example empty strings
306             {
307 
308                 _deserializer->setValue( cxxtools::String() );
309                 _state = OnScalarEnd;
310             }
311             else
312             {
313                 throwSerializationError();
314             }
315 
316             break;
317         }
318 
319         case OnScalar:
320         {
321             if(node.type() == xml::Node::EndElement) // </int>, boolean ...
322             {
323                 _state = OnScalarEnd;
324             }
325             else if(node.type() == xml::Node::StartElement)
326             {
327                 throwSerializationError();
328             }
329 
330             break;
331         }
332 
333         case OnScalarEnd:
334         {
335             if(node.type() == xml::Node::EndElement) // </value>
336             {
337                 const xml::EndElement& ee = static_cast<const xml::EndElement&>(node);
338 
339                 if(ee.name() != L"value")
340                     throwSerializationError();
341 
342                 _state = OnValueEnd;
343             }
344             else if(node.type() == xml::Node::StartElement)
345             {
346                 throwSerializationError();
347             }
348 
349             break;
350         }
351 
352         case OnArrayBegin:
353         {
354             if(node.type() == xml::Node::StartElement) // <data>
355             {
356                 const xml::StartElement& se = static_cast<const xml::StartElement&>(node);
357 
358                 if(se.name() != L"data")
359                     throwSerializationError();
360 
361                 _state = OnDataBegin;
362             }
363             else if(node.type() == xml::Node::EndElement)
364             {
365                 throwSerializationError();
366             }
367 
368             break;
369         }
370 
371         case OnDataBegin:
372         {
373             if(node.type() == xml::Node::StartElement) // value
374             {
375                 _deserializer->beginMember(std::string(), std::string(), SerializationInfo::Array);
376                 _state = OnValueBegin;
377             }
378             else if(node.type() == xml::Node::EndElement) // empty array
379             {
380                 const xml::EndElement& ee = static_cast<const xml::EndElement&>(node);
381                 if(ee.name() != L"data")
382                     throwSerializationError();
383 
384                 _state = OnDataEnd;
385             }
386 
387             break;
388         }
389 
390         case OnDataEnd:
391         {
392             if(node.type() == xml::Node::EndElement) // </array>
393             {
394                 const xml::EndElement& ee = static_cast<const xml::EndElement&>(node);
395 
396                 if(ee.name() != L"array")
397                     throwSerializationError();
398 
399                 _state = OnArrayEnd;
400             }
401             else if(node.type() == xml::Node::StartElement)
402             {
403                 throwSerializationError();
404             }
405 
406             break;
407         }
408 
409         case OnArrayEnd:
410         {
411             if(node.type() == xml::Node::EndElement) // </value>
412             {
413                 const xml::EndElement& ee = static_cast<const xml::EndElement&>(node);
414 
415                 if(ee.name() != L"value")
416                     throwSerializationError();
417 
418                 _state = OnValueEnd;
419             }
420             else if(node.type() == xml::Node::StartElement)
421             {
422                 throwSerializationError();
423             }
424 
425             break;
426         }
427     }
428 
429     return false;
430 }
431 
432 }
433 
434 }
435