00001
00002 #include "XmlRpcValue.h"
00003 #include "XmlRpcException.h"
00004 #include "XmlRpcUtil.h"
00005 #include "base64.h"
00006
00007 #ifndef MAKEDEPEND
00008 # include <iostream>
00009 # include <ostream>
00010 # include <stdlib.h>
00011 # include <stdio.h>
00012 #endif
00013
00014 #include <sstream>
00015
00016 namespace XmlRpc {
00017
00018
00019 static const char VALUE_TAG[] = "<value>";
00020 static const char VALUE_ETAG[] = "</value>";
00021
00022 static const char BOOLEAN_TAG[] = "<boolean>";
00023 static const char BOOLEAN_ETAG[] = "</boolean>";
00024 static const char DOUBLE_TAG[] = "<double>";
00025 static const char DOUBLE_ETAG[] = "</double>";
00026 static const char INT_TAG[] = "<int>";
00027 static const char I4_TAG[] = "<i4>";
00028 static const char I4_ETAG[] = "</i4>";
00029 static const char STRING_TAG[] = "<string>";
00030 static const char DATETIME_TAG[] = "<dateTime.iso8601>";
00031 static const char DATETIME_ETAG[] = "</dateTime.iso8601>";
00032 static const char BASE64_TAG[] = "<base64>";
00033 static const char BASE64_ETAG[] = "</base64>";
00034
00035 static const char ARRAY_TAG[] = "<array>";
00036 static const char DATA_TAG[] = "<data>";
00037 static const char DATA_ETAG[] = "</data>";
00038 static const char ARRAY_ETAG[] = "</array>";
00039
00040 static const char STRUCT_TAG[] = "<struct>";
00041 static const char MEMBER_TAG[] = "<member>";
00042 static const char NAME_TAG[] = "<name>";
00043 static const char NAME_ETAG[] = "</name>";
00044 static const char MEMBER_ETAG[] = "</member>";
00045 static const char STRUCT_ETAG[] = "</struct>";
00046
00047
00048
00049
00050 std::string XmlRpcValue::_doubleFormat("%.16g");
00051
00052
00053
00054
00055 void XmlRpcValue::invalidate()
00056 {
00057 switch (_type) {
00058 case TypeString: delete _value.asString; break;
00059 case TypeDateTime: delete _value.asTime; break;
00060 case TypeBase64: delete _value.asBinary; break;
00061 case TypeArray: delete _value.asArray; break;
00062 case TypeStruct: delete _value.asStruct; break;
00063 default: break;
00064 }
00065 _type = TypeInvalid;
00066 _value.asBinary = 0;
00067 }
00068
00069
00070
00071 void XmlRpcValue::assertTypeOrInvalid(Type t)
00072 {
00073 if (_type == TypeInvalid)
00074 {
00075 _type = t;
00076 switch (_type) {
00077 case TypeString: _value.asString = new std::string(); break;
00078 case TypeDateTime: _value.asTime = new struct tm(); break;
00079 case TypeBase64: _value.asBinary = new BinaryData(); break;
00080 case TypeArray: _value.asArray = new ValueArray(); break;
00081 case TypeStruct: _value.asStruct = new ValueStruct(); break;
00082 default: _value.asBinary = 0; break;
00083 }
00084 }
00085 else if (_type != t)
00086 throw XmlRpcException("type error");
00087 }
00088
00089 void XmlRpcValue::assertArray(int size) const
00090 {
00091 if (_type != TypeArray)
00092 throw XmlRpcException("type error: expected an array");
00093 else if (int(_value.asArray->size()) < size)
00094 throw XmlRpcException("range error: array index too large");
00095 }
00096
00097
00098 void XmlRpcValue::assertArray(int size)
00099 {
00100 if (_type == TypeInvalid) {
00101 _type = TypeArray;
00102 _value.asArray = new ValueArray(size);
00103 } else if (_type == TypeArray) {
00104 if (int(_value.asArray->size()) < size)
00105 _value.asArray->resize(size);
00106 } else
00107 throw XmlRpcException("type error: expected an array");
00108 }
00109
00110 void XmlRpcValue::assertStruct()
00111 {
00112 if (_type == TypeInvalid) {
00113 _type = TypeStruct;
00114 _value.asStruct = new ValueStruct();
00115 } else if (_type != TypeStruct)
00116 throw XmlRpcException("type error: expected a struct");
00117 }
00118
00119
00120
00121 XmlRpcValue& XmlRpcValue::operator=(XmlRpcValue const& rhs)
00122 {
00123 if (this != &rhs)
00124 {
00125 invalidate();
00126 _type = rhs._type;
00127 switch (_type) {
00128 case TypeBoolean: _value.asBool = rhs._value.asBool; break;
00129 case TypeInt: _value.asInt = rhs._value.asInt; break;
00130 case TypeDouble: _value.asDouble = rhs._value.asDouble; break;
00131 case TypeDateTime: _value.asTime = new struct tm(*rhs._value.asTime); break;
00132 case TypeString: _value.asString = new std::string(*rhs._value.asString); break;
00133 case TypeBase64: _value.asBinary = new BinaryData(*rhs._value.asBinary); break;
00134 case TypeArray: _value.asArray = new ValueArray(*rhs._value.asArray); break;
00135 case TypeStruct: _value.asStruct = new ValueStruct(*rhs._value.asStruct); break;
00136 default: _value.asBinary = 0; break;
00137 }
00138 }
00139 return *this;
00140 }
00141
00142
00143
00144 static bool tmEq(struct tm const& t1, struct tm const& t2) {
00145 return t1.tm_sec == t2.tm_sec && t1.tm_min == t2.tm_min &&
00146 t1.tm_hour == t2.tm_hour && t1.tm_mday == t1.tm_mday &&
00147 t1.tm_mon == t2.tm_mon && t1.tm_year == t2.tm_year;
00148 }
00149
00150 bool XmlRpcValue::operator==(XmlRpcValue const& other) const
00151 {
00152 if (_type != other._type)
00153 return false;
00154
00155 switch (_type) {
00156 case TypeBoolean: return ( !_value.asBool && !other._value.asBool) ||
00157 ( _value.asBool && other._value.asBool);
00158 case TypeInt: return _value.asInt == other._value.asInt;
00159 case TypeDouble: return _value.asDouble == other._value.asDouble;
00160 case TypeDateTime: return tmEq(*_value.asTime, *other._value.asTime);
00161 case TypeString: return *_value.asString == *other._value.asString;
00162 case TypeBase64: return *_value.asBinary == *other._value.asBinary;
00163 case TypeArray: return *_value.asArray == *other._value.asArray;
00164
00165
00166 case TypeStruct:
00167 {
00168 if (_value.asStruct->size() != other._value.asStruct->size())
00169 return false;
00170
00171 ValueStruct::const_iterator it1=_value.asStruct->begin();
00172 ValueStruct::const_iterator it2=other._value.asStruct->begin();
00173 while (it1 != _value.asStruct->end()) {
00174 const XmlRpcValue& v1 = it1->second;
00175 const XmlRpcValue& v2 = it2->second;
00176 if ( ! (v1 == v2))
00177 return false;
00178 it1++;
00179 it2++;
00180 }
00181 return true;
00182 }
00183 default: break;
00184 }
00185 return true;
00186 }
00187
00188 bool XmlRpcValue::operator!=(XmlRpcValue const& other) const
00189 {
00190 return !(*this == other);
00191 }
00192
00193
00194
00195 int XmlRpcValue::size() const
00196 {
00197 switch (_type) {
00198 case TypeString: return int(_value.asString->size());
00199 case TypeBase64: return int(_value.asBinary->size());
00200 case TypeArray: return int(_value.asArray->size());
00201 case TypeStruct: return int(_value.asStruct->size());
00202 default: break;
00203 }
00204
00205 throw XmlRpcException("type error");
00206 }
00207
00208
00209 bool XmlRpcValue::hasMember(const std::string& name) const
00210 {
00211 return _type == TypeStruct && _value.asStruct->find(name) != _value.asStruct->end();
00212 }
00213
00214
00215
00216 bool XmlRpcValue::fromXml(std::string const& valueXml, int* offset)
00217 {
00218 int savedOffset = *offset;
00219
00220 invalidate();
00221 if ( ! XmlRpcUtil::nextTagIs(VALUE_TAG, valueXml, offset))
00222 return false;
00223
00224 int afterValueOffset = *offset;
00225 std::string typeTag = XmlRpcUtil::getNextTag(valueXml, offset);
00226 bool result = false;
00227 if (typeTag == BOOLEAN_TAG)
00228 result = boolFromXml(valueXml, offset);
00229 else if (typeTag == I4_TAG || typeTag == INT_TAG)
00230 result = intFromXml(valueXml, offset);
00231 else if (typeTag == DOUBLE_TAG)
00232 result = doubleFromXml(valueXml, offset);
00233 else if (typeTag.empty() || typeTag == STRING_TAG)
00234 result = stringFromXml(valueXml, offset);
00235 else if (typeTag == DATETIME_TAG)
00236 result = timeFromXml(valueXml, offset);
00237 else if (typeTag == BASE64_TAG)
00238 result = binaryFromXml(valueXml, offset);
00239 else if (typeTag == ARRAY_TAG)
00240 result = arrayFromXml(valueXml, offset);
00241 else if (typeTag == STRUCT_TAG)
00242 result = structFromXml(valueXml, offset);
00243
00244 else if (typeTag == VALUE_ETAG)
00245 {
00246 *offset = afterValueOffset;
00247 result = stringFromXml(valueXml, offset);
00248 }
00249
00250 if (result)
00251 XmlRpcUtil::findTag(VALUE_ETAG, valueXml, offset);
00252 else
00253 *offset = savedOffset;
00254
00255 return result;
00256 }
00257
00258
00259 std::string XmlRpcValue::toXml() const
00260 {
00261 switch (_type) {
00262 case TypeBoolean: return boolToXml();
00263 case TypeInt: return intToXml();
00264 case TypeDouble: return doubleToXml();
00265 case TypeString: return stringToXml();
00266 case TypeDateTime: return timeToXml();
00267 case TypeBase64: return binaryToXml();
00268 case TypeArray: return arrayToXml();
00269 case TypeStruct: return structToXml();
00270 default: break;
00271 }
00272 return std::string();
00273 }
00274
00275
00276
00277 bool XmlRpcValue::boolFromXml(std::string const& valueXml, int* offset)
00278 {
00279 const char* valueStart = valueXml.c_str() + *offset;
00280 char* valueEnd;
00281 long ivalue = strtol(valueStart, &valueEnd, 10);
00282 if (valueEnd == valueStart || (ivalue != 0 && ivalue != 1))
00283 return false;
00284
00285 _type = TypeBoolean;
00286 _value.asBool = (ivalue == 1);
00287 *offset += int(valueEnd - valueStart);
00288 return true;
00289 }
00290
00291 std::string XmlRpcValue::boolToXml() const
00292 {
00293 std::string xml = VALUE_TAG;
00294 xml += BOOLEAN_TAG;
00295 xml += (_value.asBool ? "1" : "0");
00296 xml += BOOLEAN_ETAG;
00297 xml += VALUE_ETAG;
00298 return xml;
00299 }
00300
00301
00302 bool XmlRpcValue::intFromXml(std::string const& valueXml, int* offset)
00303 {
00304 const char* valueStart = valueXml.c_str() + *offset;
00305 char* valueEnd;
00306 long ivalue = strtol(valueStart, &valueEnd, 10);
00307 if (valueEnd == valueStart)
00308 return false;
00309
00310 _type = TypeInt;
00311 _value.asInt = int(ivalue);
00312 *offset += int(valueEnd - valueStart);
00313 return true;
00314 }
00315
00316 std::string XmlRpcValue::intToXml() const
00317 {
00318 char buf[256];
00319 snprintf(buf, sizeof(buf)-1, "%d", _value.asInt);
00320 buf[sizeof(buf)-1] = 0;
00321 std::string xml = VALUE_TAG;
00322 xml += I4_TAG;
00323 xml += buf;
00324 xml += I4_ETAG;
00325 xml += VALUE_ETAG;
00326 return xml;
00327 }
00328
00329
00330 bool XmlRpcValue::doubleFromXml(std::string const& valueXml, int* offset)
00331 {
00332 const char* valueStart = valueXml.c_str() + *offset;
00333 char* valueEnd;
00334
00335
00336
00337
00338
00339 std::string tmplocale;
00340 char* locale_cstr = setlocale(LC_NUMERIC, 0);
00341 if (locale_cstr)
00342 {
00343 tmplocale = locale_cstr;
00344 setlocale(LC_NUMERIC, "POSIX");
00345 }
00346
00347 double dvalue = strtod(valueStart, &valueEnd);
00348
00349 if (tmplocale.size() > 0) {
00350 setlocale(LC_NUMERIC, tmplocale.c_str());
00351 }
00352
00353 if (valueEnd == valueStart)
00354 return false;
00355
00356 _type = TypeDouble;
00357 _value.asDouble = dvalue;
00358 *offset += int(valueEnd - valueStart);
00359 return true;
00360 }
00361
00362 std::string XmlRpcValue::doubleToXml() const
00363 {
00364
00365 std::stringstream ss;
00366 ss.imbue(std::locale::classic());
00367 ss.precision(17);
00368 ss << _value.asDouble;
00369
00370 std::string xml = VALUE_TAG;
00371 xml += DOUBLE_TAG;
00372 xml += ss.str();
00373 xml += DOUBLE_ETAG;
00374 xml += VALUE_ETAG;
00375 return xml;
00376 }
00377
00378
00379 bool XmlRpcValue::stringFromXml(std::string const& valueXml, int* offset)
00380 {
00381 size_t valueEnd = valueXml.find('<', *offset);
00382 if (valueEnd == std::string::npos)
00383 return false;
00384
00385 _type = TypeString;
00386 _value.asString = new std::string(XmlRpcUtil::xmlDecode(valueXml.substr(*offset, valueEnd-*offset)));
00387 *offset += int(_value.asString->length());
00388 return true;
00389 }
00390
00391 std::string XmlRpcValue::stringToXml() const
00392 {
00393 std::string xml = VALUE_TAG;
00394
00395 xml += XmlRpcUtil::xmlEncode(*_value.asString);
00396
00397 xml += VALUE_ETAG;
00398 return xml;
00399 }
00400
00401
00402 bool XmlRpcValue::timeFromXml(std::string const& valueXml, int* offset)
00403 {
00404 size_t valueEnd = valueXml.find('<', *offset);
00405 if (valueEnd == std::string::npos)
00406 return false;
00407
00408 std::string stime = valueXml.substr(*offset, valueEnd-*offset);
00409
00410 struct tm t;
00411 #ifdef _MSC_VER
00412 if (sscanf_s(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)
00413 #else
00414 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)
00415 #endif
00416 return false;
00417
00418 t.tm_isdst = -1;
00419 _type = TypeDateTime;
00420 _value.asTime = new struct tm(t);
00421 *offset += int(stime.length());
00422 return true;
00423 }
00424
00425 std::string XmlRpcValue::timeToXml() const
00426 {
00427 struct tm* t = _value.asTime;
00428 char buf[20];
00429 snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d",
00430 t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
00431 buf[sizeof(buf)-1] = 0;
00432
00433 std::string xml = VALUE_TAG;
00434 xml += DATETIME_TAG;
00435 xml += buf;
00436 xml += DATETIME_ETAG;
00437 xml += VALUE_ETAG;
00438 return xml;
00439 }
00440
00441
00442
00443 bool XmlRpcValue::binaryFromXml(std::string const& valueXml, int* offset)
00444 {
00445 size_t valueEnd = valueXml.find('<', *offset);
00446 if (valueEnd == std::string::npos)
00447 return false;
00448
00449 _type = TypeBase64;
00450 std::string asString = valueXml.substr(*offset, valueEnd-*offset);
00451 _value.asBinary = new BinaryData();
00452
00453
00454
00455 int iostatus = 0;
00456 base64<char> decoder;
00457 std::back_insert_iterator<BinaryData> ins = std::back_inserter(*(_value.asBinary));
00458 decoder.get(asString.begin(), asString.end(), ins, iostatus);
00459
00460 *offset += int(asString.length());
00461 return true;
00462 }
00463
00464
00465 std::string XmlRpcValue::binaryToXml() const
00466 {
00467
00468 std::vector<char> base64data;
00469 int iostatus = 0;
00470 base64<char> encoder;
00471 std::back_insert_iterator<std::vector<char> > ins = std::back_inserter(base64data);
00472 encoder.put(_value.asBinary->begin(), _value.asBinary->end(), ins, iostatus, base64<>::crlf());
00473
00474
00475 std::string xml = VALUE_TAG;
00476 xml += BASE64_TAG;
00477 xml.append(base64data.begin(), base64data.end());
00478 xml += BASE64_ETAG;
00479 xml += VALUE_ETAG;
00480 return xml;
00481 }
00482
00483
00484
00485 bool XmlRpcValue::arrayFromXml(std::string const& valueXml, int* offset)
00486 {
00487 if ( ! XmlRpcUtil::nextTagIs(DATA_TAG, valueXml, offset))
00488 return false;
00489
00490 _type = TypeArray;
00491 _value.asArray = new ValueArray;
00492 XmlRpcValue v;
00493 while (v.fromXml(valueXml, offset))
00494 _value.asArray->push_back(v);
00495
00496
00497 (void) XmlRpcUtil::nextTagIs(DATA_ETAG, valueXml, offset);
00498 return true;
00499 }
00500
00501
00502
00503
00504 std::string XmlRpcValue::arrayToXml() const
00505 {
00506 std::string xml = VALUE_TAG;
00507 xml += ARRAY_TAG;
00508 xml += DATA_TAG;
00509
00510 int s = int(_value.asArray->size());
00511 for (int i=0; i<s; ++i)
00512 xml += _value.asArray->at(i).toXml();
00513
00514 xml += DATA_ETAG;
00515 xml += ARRAY_ETAG;
00516 xml += VALUE_ETAG;
00517 return xml;
00518 }
00519
00520
00521
00522 bool XmlRpcValue::structFromXml(std::string const& valueXml, int* offset)
00523 {
00524 _type = TypeStruct;
00525 _value.asStruct = new ValueStruct;
00526
00527 while (XmlRpcUtil::nextTagIs(MEMBER_TAG, valueXml, offset)) {
00528
00529 const std::string name = XmlRpcUtil::parseTag(NAME_TAG, valueXml, offset);
00530
00531 XmlRpcValue val(valueXml, offset);
00532 if ( ! val.valid()) {
00533 invalidate();
00534 return false;
00535 }
00536 const std::pair<const std::string, XmlRpcValue> p(name, val);
00537 _value.asStruct->insert(p);
00538
00539 (void) XmlRpcUtil::nextTagIs(MEMBER_ETAG, valueXml, offset);
00540 }
00541 return true;
00542 }
00543
00544
00545
00546
00547 std::string XmlRpcValue::structToXml() const
00548 {
00549 std::string xml = VALUE_TAG;
00550 xml += STRUCT_TAG;
00551
00552 ValueStruct::const_iterator it;
00553 for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it) {
00554 xml += MEMBER_TAG;
00555 xml += NAME_TAG;
00556 xml += XmlRpcUtil::xmlEncode(it->first);
00557 xml += NAME_ETAG;
00558 xml += it->second.toXml();
00559 xml += MEMBER_ETAG;
00560 }
00561
00562 xml += STRUCT_ETAG;
00563 xml += VALUE_ETAG;
00564 return xml;
00565 }
00566
00567
00568
00569
00570 std::ostream& XmlRpcValue::write(std::ostream& os) const {
00571 switch (_type) {
00572 default: break;
00573 case TypeBoolean: os << _value.asBool; break;
00574 case TypeInt: os << _value.asInt; break;
00575 case TypeDouble: os << _value.asDouble; break;
00576 case TypeString: os << *_value.asString; break;
00577 case TypeDateTime:
00578 {
00579 struct tm* t = _value.asTime;
00580 char buf[20];
00581 snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d",
00582 t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
00583 buf[sizeof(buf)-1] = 0;
00584 os << buf;
00585 break;
00586 }
00587 case TypeBase64:
00588 {
00589 int iostatus = 0;
00590 std::ostreambuf_iterator<char> out(os);
00591 base64<char> encoder;
00592 encoder.put(_value.asBinary->begin(), _value.asBinary->end(), out, iostatus, base64<>::crlf());
00593 break;
00594 }
00595 case TypeArray:
00596 {
00597 int s = int(_value.asArray->size());
00598 os << '{';
00599 for (int i=0; i<s; ++i)
00600 {
00601 if (i > 0) os << ',';
00602 _value.asArray->at(i).write(os);
00603 }
00604 os << '}';
00605 break;
00606 }
00607 case TypeStruct:
00608 {
00609 os << '[';
00610 ValueStruct::const_iterator it;
00611 for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it)
00612 {
00613 if (it!=_value.asStruct->begin()) os << ',';
00614 os << it->first << ':';
00615 it->second.write(os);
00616 }
00617 os << ']';
00618 break;
00619 }
00620
00621 }
00622
00623 return os;
00624 }
00625
00626 }
00627
00628
00629
00630 std::ostream& operator<<(std::ostream& os, XmlRpc::XmlRpcValue& v)
00631 {
00632
00633
00634 return v.write(os);
00635 }
00636