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