• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 #include "XmlRpcValue.h"
3 #include "XmlRpcException.h"
4 #include "XmlRpcUtil.h"
5 #include "base64.h"
6 
7 #ifndef MAKEDEPEND
8 # include <iostream>
9 # include <ostream>
10 # include <stdlib.h>
11 # include <stdio.h>
12 #endif
13 
14 namespace XmlRpc {
15 
16 
17   static const char VALUE_TAG[]     = "<value>";
18   static const char VALUE_ETAG[]    = "</value>";
19 
20   static const char BOOLEAN_TAG[]   = "<boolean>";
21   static const char BOOLEAN_ETAG[]  = "</boolean>";
22   static const char DOUBLE_TAG[]    = "<double>";
23   static const char DOUBLE_ETAG[]   = "</double>";
24   static const char INT_TAG[]       = "<int>";
25   static const char I4_TAG[]        = "<i4>";
26   static const char I4_ETAG[]       = "</i4>";
27   static const char STRING_TAG[]    = "<string>";
28   static const char DATETIME_TAG[]  = "<dateTime.iso8601>";
29   static const char DATETIME_ETAG[] = "</dateTime.iso8601>";
30   static const char BASE64_TAG[]    = "<base64>";
31   static const char BASE64_ETAG[]   = "</base64>";
32   static const char NIL_TAG[]        = "<nil/>";
33 
34   static const char ARRAY_TAG[]     = "<array>";
35   static const char DATA_TAG[]      = "<data>";
36   static const char DATA_ETAG[]     = "</data>";
37   static const char ARRAY_ETAG[]    = "</array>";
38 
39   static const char STRUCT_TAG[]    = "<struct>";
40   static const char MEMBER_TAG[]    = "<member>";
41   static const char NAME_TAG[]      = "<name>";
42   static const char NAME_ETAG[]     = "</name>";
43   static const char MEMBER_ETAG[]   = "</member>";
44   static const char STRUCT_ETAG[]   = "</struct>";
45 
46 
47 
48   // Format strings
49   std::string XmlRpcValue::_doubleFormat("%f");
50 
51 
52 
53   // Clean up
invalidate()54   void XmlRpcValue::invalidate()
55   {
56     switch (_type) {
57       case TypeString:    delete _value.asString; break;
58       case TypeDateTime:  delete _value.asTime;   break;
59       case TypeBase64:    delete _value.asBinary; break;
60       case TypeArray:     delete _value.asArray;  break;
61       case TypeStruct:    delete _value.asStruct; break;
62       default: break;
63     }
64     _type = TypeInvalid;
65     _value.asBinary = 0;
66   }
67 
68 
69   // Type checking
assertTypeOrInvalid(Type t)70   void XmlRpcValue::assertTypeOrInvalid(Type t)
71   {
72     if (_type == TypeInvalid)
73     {
74       _type = t;
75       switch (_type) {    // Ensure there is a valid value for the type
76         case TypeString:   _value.asString = new std::string(); break;
77         case TypeDateTime: _value.asTime = new struct tm();     break;
78         case TypeBase64:   _value.asBinary = new BinaryData();  break;
79         case TypeArray:    _value.asArray = new ValueArray();   break;
80         case TypeStruct:   _value.asStruct = new ValueStruct(); break;
81         default:           _value.asBinary = 0; break;
82       }
83     }
84     else if (_type != t)
85       throw XmlRpcException("type error");
86   }
87 
assertArray(int size) const88   void XmlRpcValue::assertArray(int size) const
89   {
90     if (_type != TypeArray)
91       throw XmlRpcException("type error: expected an array");
92     else if (int(_value.asArray->size()) < size)
93       throw XmlRpcException("range error: array index too large");
94   }
95 
96 
assertArray(int size)97   void XmlRpcValue::assertArray(int size)
98   {
99     if (_type == TypeInvalid) {
100       _type = TypeArray;
101       _value.asArray = new ValueArray(size);
102     } else if (_type == TypeArray) {
103       if (int(_value.asArray->size()) < size)
104         _value.asArray->resize(size);
105     } else
106       throw XmlRpcException("type error: expected an array");
107   }
108 
assertStruct()109   void XmlRpcValue::assertStruct()
110   {
111     if (_type == TypeInvalid) {
112       _type = TypeStruct;
113       _value.asStruct = new ValueStruct();
114     } else if (_type != TypeStruct)
115       throw XmlRpcException("type error: expected a struct");
116   }
117 
118 
119   // Operators
operator =(XmlRpcValue const & rhs)120   XmlRpcValue& XmlRpcValue::operator=(XmlRpcValue const& rhs)
121   {
122     if (this != &rhs)
123     {
124       invalidate();
125       _type = rhs._type;
126       switch (_type) {
127         case TypeBoolean:  _value.asBool = rhs._value.asBool; break;
128         case TypeInt:      _value.asInt = rhs._value.asInt; break;
129         case TypeDouble:   _value.asDouble = rhs._value.asDouble; break;
130         case TypeDateTime: _value.asTime = new struct tm(*rhs._value.asTime); break;
131         case TypeString:   _value.asString = new std::string(*rhs._value.asString); break;
132         case TypeBase64:   _value.asBinary = new BinaryData(*rhs._value.asBinary); break;
133         case TypeArray:    _value.asArray = new ValueArray(*rhs._value.asArray); break;
134         case TypeStruct:   _value.asStruct = new ValueStruct(*rhs._value.asStruct); break;
135         default:           _value.asBinary = 0; break;
136       }
137     }
138     return *this;
139   }
140 
141 
142   // Predicate for tm equality
tmEq(struct tm const & t1,struct tm const & t2)143   static bool tmEq(struct tm const& t1, struct tm const& t2) {
144     return t1.tm_sec == t2.tm_sec && t1.tm_min == t2.tm_min &&
145             t1.tm_hour == t2.tm_hour && t1.tm_mday == t1.tm_mday &&
146             t1.tm_mon == t2.tm_mon && t1.tm_year == t2.tm_year;
147   }
148 
operator ==(XmlRpcValue const & other) const149   bool XmlRpcValue::operator==(XmlRpcValue const& other) const
150   {
151     if (_type != other._type)
152       return false;
153 
154     switch (_type) {
155       case TypeBoolean:  return ( !_value.asBool && !other._value.asBool) ||
156                                 ( _value.asBool && other._value.asBool);
157       case TypeInt:      return _value.asInt == other._value.asInt;
158       case TypeDouble:   return _value.asDouble == other._value.asDouble;
159       case TypeDateTime: return tmEq(*_value.asTime, *other._value.asTime);
160       case TypeString:   return *_value.asString == *other._value.asString;
161       case TypeBase64:   return *_value.asBinary == *other._value.asBinary;
162       case TypeArray:    return *_value.asArray == *other._value.asArray;
163 
164       // The map<>::operator== requires the definition of value< for kcc
165       case TypeStruct:   //return *_value.asStruct == *other._value.asStruct;
166         {
167           if (_value.asStruct->size() != other._value.asStruct->size())
168             return false;
169 
170           ValueStruct::const_iterator it1=_value.asStruct->begin();
171           ValueStruct::const_iterator it2=other._value.asStruct->begin();
172           while (it1 != _value.asStruct->end()) {
173             const XmlRpcValue& v1 = it1->second;
174             const XmlRpcValue& v2 = it2->second;
175             if ( ! (v1 == v2))
176               return false;
177             it1++;
178             it2++;
179           }
180           return true;
181         }
182       default: break;
183     }
184     return true;    // Both invalid values ...
185   }
186 
operator !=(XmlRpcValue const & other) const187   bool XmlRpcValue::operator!=(XmlRpcValue const& other) const
188   {
189     return !(*this == other);
190   }
191 
192 
193   // Works for strings, binary data, arrays, and structs.
size() const194   int XmlRpcValue::size() const
195   {
196     switch (_type) {
197       case TypeString: return int(_value.asString->size());
198       case TypeBase64: return int(_value.asBinary->size());
199       case TypeArray:  return int(_value.asArray->size());
200       case TypeStruct: return int(_value.asStruct->size());
201       default: break;
202     }
203 
204     throw XmlRpcException("type error");
205   }
206 
207   // Checks for existence of struct member
hasMember(const std::string & name) const208   bool XmlRpcValue::hasMember(const std::string& name) const
209   {
210     return _type == TypeStruct && _value.asStruct->find(name) != _value.asStruct->end();
211   }
212 
213   // Set the value from xml. The chars at *offset into valueXml
214   // should be the start of a <value> tag. Destroys any existing value.
fromXml(std::string const & valueXml,int * offset)215   bool XmlRpcValue::fromXml(std::string const& valueXml, int* offset)
216   {
217     int savedOffset = *offset;
218 
219     invalidate();
220     if ( ! XmlRpcUtil::nextTagIs(VALUE_TAG, valueXml, offset))
221       return false;       // Not a value, offset not updated
222 
223 	int afterValueOffset = *offset;
224     std::string typeTag = XmlRpcUtil::getNextTag(valueXml, offset);
225     bool result = false;
226     if (typeTag == NIL_TAG)
227       result = nilFromXml(valueXml, offset);
228     else if (typeTag == BOOLEAN_TAG)
229       result = boolFromXml(valueXml, offset);
230     else if (typeTag == I4_TAG || typeTag == INT_TAG)
231       result = intFromXml(valueXml, offset);
232     else if (typeTag == DOUBLE_TAG)
233       result = doubleFromXml(valueXml, offset);
234     else if (typeTag.empty() || typeTag == STRING_TAG)
235       result = stringFromXml(valueXml, offset);
236     else if (typeTag == DATETIME_TAG)
237       result = timeFromXml(valueXml, offset);
238     else if (typeTag == BASE64_TAG)
239       result = binaryFromXml(valueXml, offset);
240     else if (typeTag == ARRAY_TAG)
241       result = arrayFromXml(valueXml, offset);
242     else if (typeTag == STRUCT_TAG)
243       result = structFromXml(valueXml, offset);
244     // Watch for empty/blank strings with no <string>tag
245     else if (typeTag == VALUE_ETAG)
246     {
247       *offset = afterValueOffset;   // back up & try again
248       result = stringFromXml(valueXml, offset);
249     }
250 
251     if (result)  // Skip over the </value> tag
252       XmlRpcUtil::findTag(VALUE_ETAG, valueXml, offset);
253     else        // Unrecognized tag after <value>
254       *offset = savedOffset;
255 
256     return result;
257   }
258 
259   // Encode the Value in xml
toXml() const260   std::string XmlRpcValue::toXml() const
261   {
262     switch (_type) {
263       case TypeNil:      return nilToXml();
264       case TypeBoolean:  return boolToXml();
265       case TypeInt:      return intToXml();
266       case TypeDouble:   return doubleToXml();
267       case TypeString:   return stringToXml();
268       case TypeDateTime: return timeToXml();
269       case TypeBase64:   return binaryToXml();
270       case TypeArray:    return arrayToXml();
271       case TypeStruct:   return structToXml();
272       default: break;
273     }
274     return std::string();   // Invalid value
275   }
276 
277   // Nil
nilFromXml(std::string const &,int *)278   bool XmlRpcValue::nilFromXml(std::string const& /* valueXml */, int* /* offset */)
279   {
280     _type = TypeNil;
281     _value.asBinary = 0;
282     return true;
283   }
284 
nilToXml() const285   std::string XmlRpcValue::nilToXml() const
286   {
287     std::string xml = VALUE_TAG;
288     xml += NIL_TAG;
289     xml += VALUE_ETAG;
290     return xml;
291   }
292 
293   // Boolean
boolFromXml(std::string const & valueXml,int * offset)294   bool XmlRpcValue::boolFromXml(std::string const& valueXml, int* offset)
295   {
296     const char* valueStart = valueXml.c_str() + *offset;
297     char* valueEnd;
298     long ivalue = strtol(valueStart, &valueEnd, 10);
299     if (valueEnd == valueStart || (ivalue != 0 && ivalue != 1))
300       return false;
301 
302     _type = TypeBoolean;
303     _value.asBool = (ivalue == 1);
304     *offset += int(valueEnd - valueStart);
305     return true;
306   }
307 
boolToXml() const308   std::string XmlRpcValue::boolToXml() const
309   {
310     std::string xml = VALUE_TAG;
311     xml += BOOLEAN_TAG;
312     xml += (_value.asBool ? "1" : "0");
313     xml += BOOLEAN_ETAG;
314     xml += VALUE_ETAG;
315     return xml;
316   }
317 
318   // Int
intFromXml(std::string const & valueXml,int * offset)319   bool XmlRpcValue::intFromXml(std::string const& valueXml, int* offset)
320   {
321     const char* valueStart = valueXml.c_str() + *offset;
322     char* valueEnd;
323     long ivalue = strtol(valueStart, &valueEnd, 10);
324     if (valueEnd == valueStart)
325       return false;
326 
327     _type = TypeInt;
328     _value.asInt = int(ivalue);
329     *offset += int(valueEnd - valueStart);
330     return true;
331   }
332 
intToXml() const333   std::string XmlRpcValue::intToXml() const
334   {
335     char buf[256];
336     snprintf(buf, sizeof(buf)-1, "%d", _value.asInt);
337     buf[sizeof(buf)-1] = 0;
338     std::string xml = VALUE_TAG;
339     xml += I4_TAG;
340     xml += buf;
341     xml += I4_ETAG;
342     xml += VALUE_ETAG;
343     return xml;
344   }
345 
346   // Double
doubleFromXml(std::string const & valueXml,int * offset)347   bool XmlRpcValue::doubleFromXml(std::string const& valueXml, int* offset)
348   {
349     const char* valueStart = valueXml.c_str() + *offset;
350     char* valueEnd;
351     double dvalue = strtod(valueStart, &valueEnd);
352     if (valueEnd == valueStart)
353       return false;
354 
355     _type = TypeDouble;
356     _value.asDouble = dvalue;
357     *offset += int(valueEnd - valueStart);
358     return true;
359   }
360 
doubleToXml() const361   std::string XmlRpcValue::doubleToXml() const
362   {
363     char buf[256];
364     snprintf(buf, sizeof(buf)-1, getDoubleFormat().c_str(), _value.asDouble);
365     buf[sizeof(buf)-1] = 0;
366 
367     std::string xml = VALUE_TAG;
368     xml += DOUBLE_TAG;
369     xml += buf;
370     xml += DOUBLE_ETAG;
371     xml += VALUE_ETAG;
372     return xml;
373   }
374 
375   // String
stringFromXml(std::string const & valueXml,int * offset)376   bool XmlRpcValue::stringFromXml(std::string const& valueXml, int* offset)
377   {
378     size_t valueEnd = valueXml.find('<', *offset);
379     if (valueEnd == std::string::npos)
380       return false;     // No end tag;
381 
382     _type = TypeString;
383     _value.asString = new std::string(XmlRpcUtil::xmlDecode(valueXml.substr(*offset, valueEnd-*offset)));
384     *offset += int(_value.asString->length());
385     return true;
386   }
387 
stringToXml() const388   std::string XmlRpcValue::stringToXml() const
389   {
390     std::string xml = VALUE_TAG;
391     //xml += STRING_TAG; optional
392     xml += XmlRpcUtil::xmlEncode(*_value.asString);
393     //xml += STRING_ETAG;
394     xml += VALUE_ETAG;
395     return xml;
396   }
397 
398   // DateTime (stored as a struct tm)
timeFromXml(std::string const & valueXml,int * offset)399   bool XmlRpcValue::timeFromXml(std::string const& valueXml, int* offset)
400   {
401     size_t valueEnd = valueXml.find('<', *offset);
402     if (valueEnd == std::string::npos)
403       return false;     // No end tag;
404 
405     std::string stime = valueXml.substr(*offset, valueEnd-*offset);
406 
407     struct tm t;
408     if (sscanf(stime.c_str(),"%4d%2d%2dT%2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec) != 6)
409       return false;
410 
411     t.tm_isdst = -1;
412     _type = TypeDateTime;
413     _value.asTime = new struct tm(t);
414     *offset += int(stime.length());
415     return true;
416   }
417 
timeToXml() const418   std::string XmlRpcValue::timeToXml() const
419   {
420     struct tm* t = _value.asTime;
421     char buf[20];
422     snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d",
423       t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
424     buf[sizeof(buf)-1] = 0;
425 
426     std::string xml = VALUE_TAG;
427     xml += DATETIME_TAG;
428     xml += buf;
429     xml += DATETIME_ETAG;
430     xml += VALUE_ETAG;
431     return xml;
432   }
433 
434 
435   // Base64
binaryFromXml(std::string const & valueXml,int * offset)436   bool XmlRpcValue::binaryFromXml(std::string const& valueXml, int* offset)
437   {
438     size_t valueEnd = valueXml.find('<', *offset);
439     if (valueEnd == std::string::npos)
440       return false;     // No end tag;
441 
442     _type = TypeBase64;
443     std::string asString = valueXml.substr(*offset, valueEnd-*offset);
444     _value.asBinary = new BinaryData();
445     // check whether base64 encodings can contain chars xml encodes...
446 
447     // convert from base64 to binary
448     int iostatus = 0;
449 	  base64<char> decoder;
450     std::back_insert_iterator<BinaryData> ins = std::back_inserter(*(_value.asBinary));
451 		decoder.get(asString.begin(), asString.end(), ins, iostatus);
452 
453     *offset += int(asString.length());
454     return true;
455   }
456 
457 
binaryToXml() const458   std::string XmlRpcValue::binaryToXml() const
459   {
460     // convert to base64
461     std::vector<char> base64data;
462     int iostatus = 0;
463 	  base64<char> encoder;
464     std::back_insert_iterator<std::vector<char> > ins = std::back_inserter(base64data);
465 		encoder.put(_value.asBinary->begin(), _value.asBinary->end(), ins, iostatus, base64<>::crlf());
466 
467     // Wrap with xml
468     std::string xml = VALUE_TAG;
469     xml += BASE64_TAG;
470     xml.append(base64data.begin(), base64data.end());
471     xml += BASE64_ETAG;
472     xml += VALUE_ETAG;
473     return xml;
474   }
475 
476 
477   // Array
arrayFromXml(std::string const & valueXml,int * offset)478   bool XmlRpcValue::arrayFromXml(std::string const& valueXml, int* offset)
479   {
480     if ( ! XmlRpcUtil::nextTagIs(DATA_TAG, valueXml, offset))
481       return false;
482 
483     _type = TypeArray;
484     _value.asArray = new ValueArray;
485     XmlRpcValue v;
486     while (v.fromXml(valueXml, offset))
487       _value.asArray->push_back(v);       // copy...
488 
489     // Skip the trailing </data>
490     (void) XmlRpcUtil::nextTagIs(DATA_ETAG, valueXml, offset);
491     return true;
492   }
493 
494 
495   // In general, its preferable to generate the xml of each element of the
496   // array as it is needed rather than glomming up one big string.
arrayToXml() const497   std::string XmlRpcValue::arrayToXml() const
498   {
499     std::string xml = VALUE_TAG;
500     xml += ARRAY_TAG;
501     xml += DATA_TAG;
502 
503     int s = int(_value.asArray->size());
504     for (int i=0; i<s; ++i)
505        xml += _value.asArray->at(i).toXml();
506 
507     xml += DATA_ETAG;
508     xml += ARRAY_ETAG;
509     xml += VALUE_ETAG;
510     return xml;
511   }
512 
513 
514   // Struct
structFromXml(std::string const & valueXml,int * offset)515   bool XmlRpcValue::structFromXml(std::string const& valueXml, int* offset)
516   {
517     _type = TypeStruct;
518     _value.asStruct = new ValueStruct;
519 
520     while (XmlRpcUtil::nextTagIs(MEMBER_TAG, valueXml, offset)) {
521       // name
522       const std::string name = XmlRpcUtil::parseTag(NAME_TAG, valueXml, offset);
523       // value
524       XmlRpcValue val(valueXml, offset);
525       if ( ! val.valid()) {
526         invalidate();
527         return false;
528       }
529       const std::pair<const std::string, XmlRpcValue> p(name, val);
530       _value.asStruct->insert(p);
531 
532       (void) XmlRpcUtil::nextTagIs(MEMBER_ETAG, valueXml, offset);
533     }
534     return true;
535   }
536 
537 
538   // In general, its preferable to generate the xml of each element
539   // as it is needed rather than glomming up one big string.
structToXml() const540   std::string XmlRpcValue::structToXml() const
541   {
542     std::string xml = VALUE_TAG;
543     xml += STRUCT_TAG;
544 
545     ValueStruct::const_iterator it;
546     for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it) {
547       xml += MEMBER_TAG;
548       xml += NAME_TAG;
549       xml += XmlRpcUtil::xmlEncode(it->first);
550       xml += NAME_ETAG;
551       xml += it->second.toXml();
552       xml += MEMBER_ETAG;
553     }
554 
555     xml += STRUCT_ETAG;
556     xml += VALUE_ETAG;
557     return xml;
558   }
559 
560 
561 
562   // Write the value without xml encoding it
write(std::ostream & os) const563   std::ostream& XmlRpcValue::write(std::ostream& os) const {
564     switch (_type) {
565       default:           break;
566       case TypeBoolean:  os << _value.asBool; break;
567       case TypeInt:      os << _value.asInt; break;
568       case TypeDouble:   os << _value.asDouble; break;
569       case TypeString:   os << *_value.asString; break;
570       case TypeDateTime:
571         {
572           struct tm* t = _value.asTime;
573           char buf[20];
574           snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d",
575             t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
576           buf[sizeof(buf)-1] = 0;
577           os << buf;
578           break;
579         }
580       case TypeBase64:
581         {
582           int iostatus = 0;
583           std::ostreambuf_iterator<char> out(os);
584           base64<char> encoder;
585           encoder.put(_value.asBinary->begin(), _value.asBinary->end(), out, iostatus, base64<>::crlf());
586           break;
587         }
588       case TypeArray:
589         {
590           int s = int(_value.asArray->size());
591           os << '{';
592           for (int i=0; i<s; ++i)
593           {
594             if (i > 0) os << ',';
595             _value.asArray->at(i).write(os);
596           }
597           os << '}';
598           break;
599         }
600       case TypeStruct:
601         {
602           os << '[';
603           ValueStruct::const_iterator it;
604           for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it)
605           {
606             if (it!=_value.asStruct->begin()) os << ',';
607             os << it->first << ':';
608             it->second.write(os);
609           }
610           os << ']';
611           break;
612         }
613 
614     }
615 
616     return os;
617   }
618 
619 } // namespace XmlRpc
620 
621 
622 // ostream
operator <<(std::ostream & os,XmlRpc::XmlRpcValue & v)623 std::ostream& operator<<(std::ostream& os, XmlRpc::XmlRpcValue& v)
624 {
625   // If you want to output in xml format:
626   //return os << v.toXml();
627   return v.write(os);
628 }
629 
630