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