2
// XmlRpc++ Copyright (c) 2002-2008 by Chris Morley
5
#include "XmlRpcValue.h"
6
#include "XmlRpcException.h"
7
#include "XmlRpcUtil.h"
19
static const char VALUE_TAG[] = "value";
20
static const char NIL_TAG[] = "nil";
21
static const char BOOLEAN_TAG[] = "boolean";
22
static const char DOUBLE_TAG[] = "double";
23
static const char INT_TAG[] = "int";
24
static const char I4_TAG[] = "i4";
25
static const char STRING_TAG[] = "string";
26
static const char DATETIME_TAG[] = "dateTime.iso8601";
27
static const char BASE64_TAG[] = "base64";
29
static const char ARRAY_TAG[] = "array";
30
static const char DATA_TAG[] = "data";
32
static const char STRUCT_TAG[] = "struct";
33
static const char MEMBER_TAG[] = "member";
34
static const char NAME_TAG[] = "name";
38
std::string XmlRpcValue::_doubleFormat("%f");
43
void XmlRpcValue::invalidate()
46
case TypeString: delete _value.asString; break;
47
case TypeDateTime: delete _value.asTime; break;
48
case TypeBase64: delete _value.asBinary; break;
49
case TypeArray: delete _value.asArray; break;
50
case TypeStruct: delete _value.asStruct; break;
59
void XmlRpcValue::assertType(Type t) const
63
throw XmlRpcException("type error");
67
void XmlRpcValue::assertType(Type t)
69
if (_type == TypeInvalid)
72
switch (_type) { // Ensure there is a valid value for the type
73
case TypeString: _value.asString = new std::string(); break;
74
case TypeDateTime: _value.asTime = new struct tm(); break;
75
case TypeBase64: _value.asBinary = new BinaryData(); break;
76
case TypeArray: _value.asArray = new ValueArray(); break;
77
case TypeStruct: _value.asStruct = new ValueStruct(); break;
78
default: _value.asBinary = 0; break;
83
throw XmlRpcException("type error");
87
void XmlRpcValue::assertArray(int size) const
89
if (_type != TypeArray)
90
throw XmlRpcException("type error: expected an array");
91
else if (int(_value.asArray->size()) < size)
92
throw XmlRpcException("range error: array index too large");
96
void XmlRpcValue::assertArray(int size)
98
if (_type == TypeInvalid) {
100
_value.asArray = new ValueArray(size);
101
} else if (_type == TypeArray) {
102
if (int(_value.asArray->size()) < size)
103
_value.asArray->resize(size);
105
throw XmlRpcException("type error: expected an array");
108
void XmlRpcValue::assertStruct()
110
if (_type == TypeInvalid) {
112
_value.asStruct = new ValueStruct();
113
} else if (_type != TypeStruct)
114
throw XmlRpcException("type error: expected a struct");
119
XmlRpcValue& XmlRpcValue::operator=(XmlRpcValue const& rhs)
126
case TypeBoolean: _value.asBool = rhs._value.asBool; break;
127
case TypeInt: _value.asInt = rhs._value.asInt; break;
128
case TypeDouble: _value.asDouble = rhs._value.asDouble; break;
129
case TypeDateTime: _value.asTime = new struct tm(*rhs._value.asTime); break;
130
case TypeString: _value.asString = new std::string(*rhs._value.asString); break;
131
case TypeBase64: _value.asBinary = new BinaryData(*rhs._value.asBinary); break;
132
case TypeArray: _value.asArray = new ValueArray(*rhs._value.asArray); break;
133
case TypeStruct: _value.asStruct = new ValueStruct(*rhs._value.asStruct); break;
134
default: _value.asBinary = 0; break;
141
// Predicate for tm equality
142
static bool tmEq(struct tm const& t1, struct tm const& t2) {
143
return t1.tm_sec == t2.tm_sec && t1.tm_min == t2.tm_min &&
144
t1.tm_hour == t2.tm_hour && t1.tm_mday == t1.tm_mday &&
145
t1.tm_mon == t2.tm_mon && t1.tm_year == t2.tm_year;
148
bool XmlRpcValue::operator==(XmlRpcValue const& other) const
150
if (_type != other._type)
154
case TypeBoolean: return ( !_value.asBool && !other._value.asBool) ||
155
( _value.asBool && other._value.asBool);
156
case TypeInt: return _value.asInt == other._value.asInt;
157
case TypeDouble: return _value.asDouble == other._value.asDouble;
158
case TypeDateTime: return tmEq(*_value.asTime, *other._value.asTime);
159
case TypeString: return *_value.asString == *other._value.asString;
160
case TypeBase64: return *_value.asBinary == *other._value.asBinary;
161
case TypeArray: return *_value.asArray == *other._value.asArray;
163
// The map<>::operator== requires the definition of value< for kcc
164
case TypeStruct: //return *_value.asStruct == *other._value.asStruct;
166
if (_value.asStruct->size() != other._value.asStruct->size())
169
ValueStruct::const_iterator it1=_value.asStruct->begin();
170
ValueStruct::const_iterator it2=other._value.asStruct->begin();
171
while (it1 != _value.asStruct->end()) {
172
const XmlRpcValue& v1 = it1->second;
173
const XmlRpcValue& v2 = it2->second;
183
return true; // Both invalid values ...
186
bool XmlRpcValue::operator!=(XmlRpcValue const& other) const
188
return !(*this == other);
192
// Works for strings, binary data, arrays, and structs.
193
int XmlRpcValue::size() const
196
case TypeString: return int(_value.asString->size());
197
case TypeBase64: return int(_value.asBinary->size());
198
case TypeArray: return int(_value.asArray->size());
199
case TypeStruct: return int(_value.asStruct->size());
203
throw XmlRpcException("type error");
206
// Checks for existence of struct member
207
bool XmlRpcValue::hasMember(const std::string& name) const
209
return _type == TypeStruct && _value.asStruct->find(name) != _value.asStruct->end();
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.
215
bool XmlRpcValue::fromXml(std::string const& valueXml, int* offset)
217
int savedOffset = *offset;
221
if ( ! XmlRpcUtil::nextTagIs(VALUE_TAG, valueXml, offset, &emptyTag))
222
return false; // Not a value, offset not updated
224
// No value? Pretend its an empty string...
231
// No type tag? Assume string
233
int valueOffset = *offset;
234
if (XmlRpcUtil::nextTagIsEnd(VALUE_TAG, valueXml, offset))
236
return stringFromXml(valueXml, &valueOffset);
238
else if (XmlRpcUtil::nextTagIs(NIL_TAG, valueXml, offset, &emptyTag))
243
else if (XmlRpcUtil::nextTagIs(BOOLEAN_TAG, valueXml, offset, &emptyTag))
248
result = boolFromXml(valueXml, offset) &&
249
XmlRpcUtil::nextTagIsEnd(BOOLEAN_TAG, valueXml, offset);
251
else if (XmlRpcUtil::nextTagIs(I4_TAG, valueXml, offset, &emptyTag))
256
result = intFromXml(valueXml, offset) &&
257
XmlRpcUtil::nextTagIsEnd(I4_TAG, valueXml, offset);
259
else if (XmlRpcUtil::nextTagIs(INT_TAG, valueXml, offset, &emptyTag))
264
result = intFromXml(valueXml, offset) &&
265
XmlRpcUtil::nextTagIsEnd(INT_TAG, valueXml, offset);
267
else if (XmlRpcUtil::nextTagIs(DOUBLE_TAG, valueXml, offset, &emptyTag))
272
result = doubleFromXml(valueXml, offset) &&
273
XmlRpcUtil::nextTagIsEnd(DOUBLE_TAG, valueXml, offset);
275
else if (XmlRpcUtil::nextTagIs(STRING_TAG, valueXml, offset, &emptyTag))
280
result = stringFromXml(valueXml, offset) &&
281
XmlRpcUtil::nextTagIsEnd(STRING_TAG, valueXml, offset);
283
else if (XmlRpcUtil::nextTagIs(DATETIME_TAG, valueXml, offset, &emptyTag))
288
result = timeFromXml(valueXml, offset) &&
289
XmlRpcUtil::nextTagIsEnd(DATETIME_TAG, valueXml, offset);
291
else if (XmlRpcUtil::nextTagIs(BASE64_TAG, valueXml, offset, &emptyTag))
294
result = binaryFromXml("", 0);
296
result = binaryFromXml(valueXml, offset) &&
297
XmlRpcUtil::nextTagIsEnd(BASE64_TAG, valueXml, offset);
299
else if (XmlRpcUtil::nextTagIs(ARRAY_TAG, valueXml, offset, &emptyTag))
304
result = arrayFromXml(valueXml, offset) &&
305
XmlRpcUtil::nextTagIsEnd(ARRAY_TAG, valueXml, offset);
307
else if (XmlRpcUtil::nextTagIs(STRUCT_TAG, valueXml, offset, &emptyTag))
312
result = structFromXml(valueXml, offset) &&
313
XmlRpcUtil::nextTagIsEnd(STRUCT_TAG, valueXml, offset);
316
// Unrecognized tag after <value> or no </value>
317
if ( ! result || ! XmlRpcUtil::nextTagIsEnd(VALUE_TAG, valueXml, offset))
319
*offset = savedOffset;
326
// Encode the Value in xml
327
std::string XmlRpcValue::toXml() const
330
case TypeNil: return nilToXml();
331
case TypeBoolean: return boolToXml();
332
case TypeInt: return intToXml();
333
case TypeDouble: return doubleToXml();
334
case TypeString: return stringToXml();
335
case TypeDateTime: return timeToXml();
336
case TypeBase64: return binaryToXml();
337
case TypeArray: return arrayToXml();
338
case TypeStruct: return structToXml();
341
return std::string(); // Invalid value
346
bool XmlRpcValue::boolFromXml(std::string const& valueXml, int* offset)
348
const char* valueStart = valueXml.c_str() + *offset;
350
long ivalue = strtol(valueStart, &valueEnd, 10);
351
if (valueEnd == valueStart || (ivalue != 0 && ivalue != 1))
355
_value.asBool = (ivalue == 1);
356
*offset += int(valueEnd - valueStart);
360
std::string XmlRpcValue::nilToXml() const
362
return "<value><nil/></value>";
365
std::string XmlRpcValue::boolToXml() const
367
static std::string booleanTrueXml("<value><boolean>1</boolean></value>");
368
static std::string booleanFalseXml("<value><boolean>0</boolean></value>");
369
return _value.asBool ? booleanTrueXml : booleanFalseXml;
373
bool XmlRpcValue::intFromXml(std::string const& valueXml, int* offset)
375
const char* valueStart = valueXml.c_str() + *offset;
377
long ivalue = strtol(valueStart, &valueEnd, 10);
378
if (valueEnd == valueStart)
382
_value.asInt = int(ivalue);
383
*offset += int(valueEnd - valueStart);
387
std::string XmlRpcValue::intToXml() const
390
snprintf(buf, sizeof(buf)-1, "<value><i4>%d</i4></value>", _value.asInt);
391
buf[sizeof(buf)-1] = 0;
393
return std::string(buf);
397
bool XmlRpcValue::doubleFromXml(std::string const& valueXml, int* offset)
399
const char* valueStart = valueXml.c_str() + *offset;
401
double dvalue = strtod(valueStart, &valueEnd);
402
if (valueEnd == valueStart)
406
_value.asDouble = dvalue;
407
*offset += int(valueEnd - valueStart);
411
std::string XmlRpcValue::doubleToXml() const
413
char fmtbuf[256], buf[256];
414
snprintf(fmtbuf, sizeof(fmtbuf)-1, "<value><double>%s</double></value>", getDoubleFormat().c_str());
415
fmtbuf[sizeof(fmtbuf)-1] = 0;
416
snprintf(buf, sizeof(buf)-1, fmtbuf, _value.asDouble);
417
buf[sizeof(buf)-1] = 0;
419
return std::string(buf);
423
bool XmlRpcValue::stringFromXml(std::string const& valueXml, int* offset)
425
size_t valueEnd = valueXml.find('<', *offset);
426
if (valueEnd == std::string::npos)
427
return false; // No end tag;
430
_value.asString = new std::string(XmlRpcUtil::xmlDecode(valueXml.substr(*offset, valueEnd-*offset)));
431
*offset += int(_value.asString->length());
435
std::string XmlRpcValue::stringToXml() const
437
return std::string("<value>") + XmlRpcUtil::xmlEncode(*_value.asString) + std::string("</value>");
440
// DateTime (stored as a struct tm)
441
bool XmlRpcValue::timeFromXml(std::string const& valueXml, int* offset)
443
size_t valueEnd = valueXml.find('<', *offset);
444
if (valueEnd == std::string::npos)
445
return false; // No end tag;
447
std::string stime = valueXml.substr(*offset, valueEnd-*offset);
450
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)
453
t.tm_year -= 1900; // years since 1900
454
t.tm_mon -= 1; // months 0..11
456
_type = TypeDateTime;
457
_value.asTime = new struct tm(t);
458
*offset += int(stime.length());
462
std::string XmlRpcValue::timeToXml() const
464
struct tm* t = _value.asTime;
466
snprintf(buf, sizeof(buf)-1, "%04d%02d%02dT%02d:%02d:%02d",
467
1900+t->tm_year,1+t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
468
buf[sizeof(buf)-1] = 0;
470
return std::string("<value><dateTime.iso8601>") + buf + std::string("</dateTime.iso8601></value>");
475
bool XmlRpcValue::binaryFromXml(std::string const& valueXml, int* offset)
477
size_t valueEnd = valueXml.find('<', *offset);
478
if (valueEnd == std::string::npos)
479
return false; // No end tag;
482
std::string asString = valueXml.substr(*offset, valueEnd-*offset);
483
_value.asBinary = new BinaryData();
484
// check whether base64 encodings can contain chars xml encodes...
486
// convert from base64 to binary
488
base64<char> decoder;
489
std::back_insert_iterator<BinaryData> ins = std::back_inserter(*(_value.asBinary));
490
decoder.get(asString.begin(), asString.end(), ins, iostatus);
492
*offset += int(asString.length());
497
std::string XmlRpcValue::binaryToXml() const
500
std::vector<char> base64data;
502
base64<char> encoder;
503
std::back_insert_iterator<std::vector<char> > ins = std::back_inserter(base64data);
504
encoder.put(_value.asBinary->begin(), _value.asBinary->end(), ins, iostatus, base64<>::crlf());
507
std::string xml = "<value><base64>";
508
xml.append(base64data.begin(), base64data.end());
509
xml += "</base64></value>";
515
bool XmlRpcValue::arrayFromXml(std::string const& valueXml, int* offset)
518
if ( ! XmlRpcUtil::nextTagIs(DATA_TAG, valueXml, offset, &emptyTag))
522
_value.asArray = new ValueArray;
527
while (v.fromXml(valueXml, offset))
528
_value.asArray->push_back(v); // copy...
530
// Skip the trailing </data>
531
(void) XmlRpcUtil::nextTagIsEnd(DATA_TAG, valueXml, offset);
537
// In general, its preferable to generate the xml of each element of the
538
// array as it is needed rather than glomming up one big string.
539
std::string XmlRpcValue::arrayToXml() const
541
std::string xml = "<value><array><data>";
543
int s = int(_value.asArray->size());
544
for (int i=0; i<s; ++i)
545
xml += _value.asArray->at(i).toXml();
547
xml += "</data></array></value>";
553
bool XmlRpcValue::structFromXml(std::string const& valueXml, int* offset)
556
_value.asStruct = new ValueStruct;
560
while (XmlRpcUtil::nextTagIs(MEMBER_TAG, valueXml, offset, &emptyTag))
564
if (XmlRpcUtil::parseTag(NAME_TAG, valueXml, offset, name))
567
XmlRpcValue val(valueXml, offset);
568
if ( ! val.valid()) {
572
const std::pair<const std::string, XmlRpcValue> p(name, val);
573
_value.asStruct->insert(p);
575
(void) XmlRpcUtil::nextTagIsEnd(MEMBER_TAG, valueXml, offset);
584
// In general, its preferable to generate the xml of each element
585
// as it is needed rather than glomming up one big string.
586
std::string XmlRpcValue::structToXml() const
588
std::string xml = "<value><struct>";
590
ValueStruct::const_iterator it;
591
for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it)
593
xml += "<member><name>";
594
xml += XmlRpcUtil::xmlEncode(it->first);
596
xml += it->second.toXml();
600
xml += "</struct></value>";
606
// Write the value without xml encoding it
607
std::ostream& XmlRpcValue::write(std::ostream& os) const {
610
case TypeBoolean: os << _value.asBool; break;
611
case TypeInt: os << _value.asInt; break;
612
case TypeDouble: os << _value.asDouble; break;
613
case TypeString: os << *_value.asString; break;
616
struct tm* t = _value.asTime;
618
snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d",
619
t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
620
buf[sizeof(buf)-1] = 0;
627
std::ostreambuf_iterator<char> out(os);
628
base64<char> encoder;
629
encoder.put(_value.asBinary->begin(), _value.asBinary->end(), out, iostatus, base64<>::crlf());
634
int s = int(_value.asArray->size());
636
for (int i=0; i<s; ++i)
638
if (i > 0) os << ',';
639
_value.asArray->at(i).write(os);
647
ValueStruct::const_iterator it;
648
for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it)
650
if (it!=_value.asStruct->begin()) os << ',';
651
os << it->first << ':';
652
it->second.write(os);
663
} // namespace XmlRpc
667
std::ostream& operator<<(std::ostream& os, XmlRpc::XmlRpcValue& v)
669
// If you want to output in xml format:
670
//return os << v.toXml();