From 1f8d5cc30098001ea7587b86348677d86bc4d831 Mon Sep 17 00:00:00 2001 From: HiepLM Date: Tue, 24 Mar 2026 15:25:48 +0700 Subject: [PATCH] update --- include/robot_xmlrpcpp/XmlRpcValue.h | 380 ++++---- src/XmlRpcValue.cpp | 1234 +++++++++++++------------- 2 files changed, 807 insertions(+), 807 deletions(-) diff --git a/include/robot_xmlrpcpp/XmlRpcValue.h b/include/robot_xmlrpcpp/XmlRpcValue.h index 0e5027b..f0488a9 100644 --- a/include/robot_xmlrpcpp/XmlRpcValue.h +++ b/include/robot_xmlrpcpp/XmlRpcValue.h @@ -1,190 +1,190 @@ -#ifndef _ROBOT_XMLRPCVALUE_H_ -#define _ROBOT_XMLRPCVALUE_H_ -// -// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley -// -#if defined(_MSC_VER) -# pragma warning(disable:4786) // identifier was truncated in debug info -#endif - -#ifndef MAKEDEPEND -# include -# include -# include -# include -#endif - -namespace robot_xmlrpcpp { - - //! RPC method arguments and results are represented by Values - // should probably refcount them... - class XmlRpcValue { - public: - - - enum Type { - TypeInvalid, - TypeBoolean, - TypeInt, - TypeDouble, - TypeString, - TypeDateTime, - TypeBase64, - TypeArray, - TypeStruct - }; - - // Non-primitive types - typedef std::vector BinaryData; - typedef std::vector ValueArray; - typedef std::map ValueStruct; - - - //! Constructors - XmlRpcValue() : _type(TypeInvalid) { _value.asBinary = 0; } - XmlRpcValue(bool value) : _type(TypeBoolean) { _value.asBool = value; } - XmlRpcValue(int value) : _type(TypeInt) { _value.asInt = value; } - XmlRpcValue(double value) : _type(TypeDouble) { _value.asDouble = value; } - - XmlRpcValue(std::string const& value) : _type(TypeString) - { _value.asString = new std::string(value); } - - XmlRpcValue(const char* value) : _type(TypeString) - { _value.asString = new std::string(value); } - - XmlRpcValue(struct tm* value) : _type(TypeDateTime) - { _value.asTime = new struct tm(*value); } - - - XmlRpcValue(void* value, int nBytes) : _type(TypeBase64) - { - _value.asBinary = new BinaryData((char*)value, ((char*)value)+nBytes); - } - - //! Construct from xml, beginning at *offset chars into the string, updates offset - XmlRpcValue(std::string const& xml, int* offset) : _type(TypeInvalid) - { if ( ! fromXml(xml,offset)) _type = TypeInvalid; } - - //! Copy - XmlRpcValue(XmlRpcValue const& rhs) : _type(TypeInvalid) { *this = rhs; } - - //! Destructor (make virtual if you want to subclass) - /*virtual*/ ~XmlRpcValue() { invalidate(); } - - //! Erase the current value - void clear() { invalidate(); } - - // Operators - XmlRpcValue& operator=(XmlRpcValue const& rhs); - XmlRpcValue& operator=(int const& rhs) { return operator=(XmlRpcValue(rhs)); } - XmlRpcValue& operator=(double const& rhs) { return operator=(XmlRpcValue(rhs)); } - XmlRpcValue& operator=(const char* rhs) { return operator=(XmlRpcValue(std::string(rhs))); } - - bool operator==(XmlRpcValue const& other) const; - bool operator!=(XmlRpcValue const& other) const; - - operator bool&() { assertTypeOrInvalid(TypeBoolean); return _value.asBool; } - operator int&() { assertTypeOrInvalid(TypeInt); return _value.asInt; } - operator double&() { assertTypeOrInvalid(TypeDouble); return _value.asDouble; } - operator std::string&() { assertTypeOrInvalid(TypeString); return *_value.asString; } - operator BinaryData&() { assertTypeOrInvalid(TypeBase64); return *_value.asBinary; } - operator struct tm&() { assertTypeOrInvalid(TypeDateTime); return *_value.asTime; } - - XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); } - XmlRpcValue& operator[](int i) { assertArray(i+1); return _value.asArray->at(i); } - - XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; } - XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; } - - // Accessors - //! Return true if the value has been set to something. - bool valid() const { return _type != TypeInvalid; } - - //! Return the type of the value stored. \see Type. - Type const &getType() const { return _type; } - - //! Return the size for string, base64, array, and struct values. - int size() const; - - //! Specify the size for array values. Array values will grow beyond this size if needed. - void setSize(int size) { assertArray(size); } - - //! Check for the existence of a struct member by name. - bool hasMember(const std::string& name) const; - - //! If this value is a struct, returns pointer to its members; otherwise nullptr. - const ValueStruct *getStructMembers() const; - - //! Decode xml. Destroys any existing value. - bool fromXml(std::string const& valueXml, int* offset); - - //! Encode the Value in xml - std::string toXml() const; - - //! Write the value (no xml encoding) - std::ostream& write(std::ostream& os) const; - - // Formatting - //! Return the format used to write double values. - static std::string const& getDoubleFormat() { return _doubleFormat; } - - //! Specify the format used to write double values. - static void setDoubleFormat(const char* f) { _doubleFormat = f; } - - - protected: - // Clean up - void invalidate(); - - // Type checking - void assertTypeOrInvalid(Type t); - void assertArray(int size) const; - void assertArray(int size); - void assertStruct(); - - // XML decoding - bool boolFromXml(std::string const& valueXml, int* offset); - bool intFromXml(std::string const& valueXml, int* offset); - bool doubleFromXml(std::string const& valueXml, int* offset); - bool stringFromXml(std::string const& valueXml, int* offset); - bool timeFromXml(std::string const& valueXml, int* offset); - bool binaryFromXml(std::string const& valueXml, int* offset); - bool arrayFromXml(std::string const& valueXml, int* offset); - bool structFromXml(std::string const& valueXml, int* offset); - - // XML encoding - std::string boolToXml() const; - std::string intToXml() const; - std::string doubleToXml() const; - std::string stringToXml() const; - std::string timeToXml() const; - std::string binaryToXml() const; - std::string arrayToXml() const; - std::string structToXml() const; - - // Format strings - static std::string _doubleFormat; - - // Type tag and values - Type _type; - - // At some point I will split off Arrays and Structs into - // separate ref-counted objects for more efficient copying. - union { - bool asBool; - int asInt; - double asDouble; - struct tm* asTime; - std::string* asString; - BinaryData* asBinary; - ValueArray* asArray; - ValueStruct* asStruct; - } _value; - - }; -} // namespace robot_xmlrpcpp - - -std::ostream& operator<<(std::ostream& os, robot_xmlrpcpp::XmlRpcValue& v); - -#endif // _ROBOT_XMLRPCVALUE_H_ +#ifndef _ROBOT_XMLRPCVALUE_H_ +#define _ROBOT_XMLRPCVALUE_H_ +// +// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley +// +#if defined(_MSC_VER) +# pragma warning(disable:4786) // identifier was truncated in debug info +#endif + +#ifndef MAKEDEPEND +# include +# include +# include +# include +#endif + +namespace robot_xmlrpcpp { + + //! RPC method arguments and results are represented by Values + // should probably refcount them... + class XmlRpcValue { + public: + + + enum Type { + TypeInvalid, + TypeBoolean, + TypeInt, + TypeDouble, + TypeString, + TypeDateTime, + TypeBase64, + TypeArray, + TypeStruct + }; + + // Non-primitive types + typedef std::vector BinaryData; + typedef std::vector ValueArray; + typedef std::map ValueStruct; + + + //! Constructors + XmlRpcValue() : _type(TypeInvalid) { _value.asBinary = 0; } + XmlRpcValue(bool value) : _type(TypeBoolean) { _value.asBool = value; } + XmlRpcValue(int value) : _type(TypeInt) { _value.asInt = value; } + XmlRpcValue(double value) : _type(TypeDouble) { _value.asDouble = value; } + + XmlRpcValue(std::string const& value) : _type(TypeString) + { _value.asString = new std::string(value); } + + XmlRpcValue(const char* value) : _type(TypeString) + { _value.asString = new std::string(value); } + + XmlRpcValue(struct tm* value) : _type(TypeDateTime) + { _value.asTime = new struct tm(*value); } + + + XmlRpcValue(void* value, int nBytes) : _type(TypeBase64) + { + _value.asBinary = new BinaryData((char*)value, ((char*)value)+nBytes); + } + + //! Construct from xml, beginning at *offset chars into the string, updates offset + XmlRpcValue(std::string const& xml, int* offset) : _type(TypeInvalid) + { if ( ! fromXml(xml,offset)) _type = TypeInvalid; } + + //! Copy + XmlRpcValue(XmlRpcValue const& rhs) : _type(TypeInvalid) { *this = rhs; } + + //! Destructor (make virtual if you want to subclass) + /*virtual*/ ~XmlRpcValue() { invalidate(); } + + //! Erase the current value + void clear() { invalidate(); } + + // Operators + XmlRpcValue& operator=(XmlRpcValue const& rhs); + XmlRpcValue& operator=(int const& rhs) { return operator=(XmlRpcValue(rhs)); } + XmlRpcValue& operator=(double const& rhs) { return operator=(XmlRpcValue(rhs)); } + XmlRpcValue& operator=(const char* rhs) { return operator=(XmlRpcValue(std::string(rhs))); } + + bool operator==(XmlRpcValue const& other) const; + bool operator!=(XmlRpcValue const& other) const; + + operator bool&() { assertTypeOrInvalid(TypeBoolean); return _value.asBool; } + operator int&() { assertTypeOrInvalid(TypeInt); return _value.asInt; } + operator double&() { assertTypeOrInvalid(TypeDouble); return _value.asDouble; } + operator std::string&() { assertTypeOrInvalid(TypeString); return *_value.asString; } + operator BinaryData&() { assertTypeOrInvalid(TypeBase64); return *_value.asBinary; } + operator struct tm&() { assertTypeOrInvalid(TypeDateTime); return *_value.asTime; } + + XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); } + XmlRpcValue& operator[](int i) { assertArray(i+1); return _value.asArray->at(i); } + + XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; } + XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; } + + // Accessors + //! Return true if the value has been set to something. + bool valid() const { return _type != TypeInvalid; } + + //! Return the type of the value stored. \see Type. + Type const &getType() const { return _type; } + + //! Return the size for string, base64, array, and struct values. + int size() const; + + //! Specify the size for array values. Array values will grow beyond this size if needed. + void setSize(int size) { assertArray(size); } + + //! Check for the existence of a struct member by name. + bool hasMember(const std::string& name) const; + + //! If this value is a struct, returns pointer to its members; otherwise nullptr. + const ValueStruct *getStructMembers() const; + + //! Decode xml. Destroys any existing value. + bool fromXml(std::string const& valueXml, int* offset); + + //! Encode the Value in xml + std::string toXml() const; + + //! Write the value (no xml encoding) + std::ostream& write(std::ostream& os) const; + + // Formatting + //! Return the format used to write double values. + static std::string const& getDoubleFormat() { return _doubleFormat; } + + //! Specify the format used to write double values. + static void setDoubleFormat(const char* f) { _doubleFormat = f; } + + + protected: + // Clean up + void invalidate(); + + // Type checking + void assertTypeOrInvalid(Type t); + void assertArray(int size) const; + void assertArray(int size); + void assertStruct(); + + // XML decoding + bool boolFromXml(std::string const& valueXml, int* offset); + bool intFromXml(std::string const& valueXml, int* offset); + bool doubleFromXml(std::string const& valueXml, int* offset); + bool stringFromXml(std::string const& valueXml, int* offset); + bool timeFromXml(std::string const& valueXml, int* offset); + bool binaryFromXml(std::string const& valueXml, int* offset); + bool arrayFromXml(std::string const& valueXml, int* offset); + bool structFromXml(std::string const& valueXml, int* offset); + + // XML encoding + std::string boolToXml() const; + std::string intToXml() const; + std::string doubleToXml() const; + std::string stringToXml() const; + std::string timeToXml() const; + std::string binaryToXml() const; + std::string arrayToXml() const; + std::string structToXml() const; + + // Format strings + static std::string _doubleFormat; + + // Type tag and values + Type _type; + + // At some point I will split off Arrays and Structs into + // separate ref-counted objects for more efficient copying. + union { + bool asBool; + int asInt; + double asDouble; + struct tm* asTime; + std::string* asString; + BinaryData* asBinary; + ValueArray* asArray; + ValueStruct* asStruct; + } _value; + + }; +} // namespace robot_xmlrpcpp + + +std::ostream& operator<<(std::ostream& os, robot_xmlrpcpp::XmlRpcValue& v); + +#endif // _ROBOT_XMLRPCVALUE_H_ diff --git a/src/XmlRpcValue.cpp b/src/XmlRpcValue.cpp index 883fb9b..15c277f 100644 --- a/src/XmlRpcValue.cpp +++ b/src/XmlRpcValue.cpp @@ -1,617 +1,617 @@ - -#include "robot_xmlrpcpp/XmlRpcValue.h" -#include "robot_xmlrpcpp/XmlRpcException.h" -#include "robot_xmlrpcpp/XmlRpcUtil.h" -#include "robot_xmlrpcpp/base64.h" - -#ifndef MAKEDEPEND -# include -# include -# include -# include -#endif - -namespace robot_xmlrpcpp { - - - static const char VALUE_TAG[] = ""; - static const char VALUE_ETAG[] = ""; - - static const char BOOLEAN_TAG[] = ""; - static const char BOOLEAN_ETAG[] = ""; - static const char DOUBLE_TAG[] = ""; - static const char DOUBLE_ETAG[] = ""; - static const char INT_TAG[] = ""; - static const char I4_TAG[] = ""; - static const char I4_ETAG[] = ""; - static const char STRING_TAG[] = ""; - static const char DATETIME_TAG[] = ""; - static const char DATETIME_ETAG[] = ""; - static const char BASE64_TAG[] = ""; - static const char BASE64_ETAG[] = ""; - - static const char ARRAY_TAG[] = ""; - static const char DATA_TAG[] = ""; - static const char DATA_ETAG[] = ""; - static const char ARRAY_ETAG[] = ""; - - static const char STRUCT_TAG[] = ""; - static const char MEMBER_TAG[] = ""; - static const char NAME_TAG[] = ""; - static const char NAME_ETAG[] = ""; - static const char MEMBER_ETAG[] = ""; - static const char STRUCT_ETAG[] = ""; - - - - // Format strings - std::string XmlRpcValue::_doubleFormat("%f"); - - - - // Clean up - void XmlRpcValue::invalidate() - { - switch (_type) { - case TypeString: delete _value.asString; break; - case TypeDateTime: delete _value.asTime; break; - case TypeBase64: delete _value.asBinary; break; - case TypeArray: delete _value.asArray; break; - case TypeStruct: delete _value.asStruct; break; - default: break; - } - _type = TypeInvalid; - _value.asBinary = 0; - } - - - // Type checking - void XmlRpcValue::assertTypeOrInvalid(Type t) - { - if (_type == TypeInvalid) - { - _type = t; - switch (_type) { // Ensure there is a valid value for the type - case TypeString: _value.asString = new std::string(); break; - case TypeDateTime: _value.asTime = new struct tm(); break; - case TypeBase64: _value.asBinary = new BinaryData(); break; - case TypeArray: _value.asArray = new ValueArray(); break; - case TypeStruct: _value.asStruct = new ValueStruct(); break; - default: _value.asBinary = 0; break; - } - } - else if (_type != t) - throw XmlRpcException("type error"); - } - - void XmlRpcValue::assertArray(int size) const - { - if (_type != TypeArray) - throw XmlRpcException("type error: expected an array"); - else if (int(_value.asArray->size()) < size) - throw XmlRpcException("range error: array index too large"); - } - - - void XmlRpcValue::assertArray(int size) - { - if (_type == TypeInvalid) { - _type = TypeArray; - _value.asArray = new ValueArray(size); - } else if (_type == TypeArray) { - if (int(_value.asArray->size()) < size) - _value.asArray->resize(size); - } else - throw XmlRpcException("type error: expected an array"); - } - - void XmlRpcValue::assertStruct() - { - if (_type == TypeInvalid) { - _type = TypeStruct; - _value.asStruct = new ValueStruct(); - } else if (_type != TypeStruct) - throw XmlRpcException("type error: expected a struct"); - } - - - // Operators - XmlRpcValue& XmlRpcValue::operator=(XmlRpcValue const& rhs) - { - if (this != &rhs) - { - invalidate(); - _type = rhs._type; - switch (_type) { - case TypeBoolean: _value.asBool = rhs._value.asBool; break; - case TypeInt: _value.asInt = rhs._value.asInt; break; - case TypeDouble: _value.asDouble = rhs._value.asDouble; break; - case TypeDateTime: _value.asTime = new struct tm(*rhs._value.asTime); break; - case TypeString: _value.asString = new std::string(*rhs._value.asString); break; - case TypeBase64: _value.asBinary = new BinaryData(*rhs._value.asBinary); break; - case TypeArray: _value.asArray = new ValueArray(*rhs._value.asArray); break; - case TypeStruct: _value.asStruct = new ValueStruct(*rhs._value.asStruct); break; - default: _value.asBinary = 0; break; - } - } - return *this; - } - - - // Predicate for tm equality - static bool tmEq(struct tm const& t1, struct tm const& t2) { - return t1.tm_sec == t2.tm_sec && t1.tm_min == t2.tm_min && - t1.tm_hour == t2.tm_hour && t1.tm_mday == t2.tm_mday && - t1.tm_mon == t2.tm_mon && t1.tm_year == t2.tm_year; - } - - bool XmlRpcValue::operator==(XmlRpcValue const& other) const - { - if (_type != other._type) - return false; - - switch (_type) { - case TypeBoolean: return ( !_value.asBool && !other._value.asBool) || - ( _value.asBool && other._value.asBool); - case TypeInt: return _value.asInt == other._value.asInt; - case TypeDouble: return _value.asDouble == other._value.asDouble; - case TypeDateTime: return tmEq(*_value.asTime, *other._value.asTime); - case TypeString: return *_value.asString == *other._value.asString; - case TypeBase64: return *_value.asBinary == *other._value.asBinary; - case TypeArray: return *_value.asArray == *other._value.asArray; - - // The map<>::operator== requires the definition of value< for kcc - case TypeStruct: //return *_value.asStruct == *other._value.asStruct; - { - if (_value.asStruct->size() != other._value.asStruct->size()) - return false; - - ValueStruct::const_iterator it1=_value.asStruct->begin(); - ValueStruct::const_iterator it2=other._value.asStruct->begin(); - while (it1 != _value.asStruct->end()) { - const XmlRpcValue& v1 = it1->second; - const XmlRpcValue& v2 = it2->second; - if ( ! (v1 == v2)) - return false; - it1++; - it2++; - } - return true; - } - default: break; - } - return true; // Both invalid values ... - } - - bool XmlRpcValue::operator!=(XmlRpcValue const& other) const - { - return !(*this == other); - } - - - // Works for strings, binary data, arrays, and structs. - int XmlRpcValue::size() const - { - switch (_type) { - case TypeString: return int(_value.asString->size()); - case TypeBase64: return int(_value.asBinary->size()); - case TypeArray: return int(_value.asArray->size()); - case TypeStruct: return int(_value.asStruct->size()); - default: break; - } - - throw XmlRpcException("type error"); - } - - // Checks for existence of struct member - bool XmlRpcValue::hasMember(const std::string& name) const - { - return _type == TypeStruct && _value.asStruct->find(name) != _value.asStruct->end(); - } - - const XmlRpcValue::ValueStruct *XmlRpcValue::getStructMembers() const - { - if (_type != TypeStruct) - return nullptr; - return _value.asStruct; - } - - // Set the value from xml. The chars at *offset into valueXml - // should be the start of a tag. Destroys any existing value. - bool XmlRpcValue::fromXml(std::string const& valueXml, int* offset) - { - int savedOffset = *offset; - - invalidate(); - if ( ! XmlRpcUtil::nextTagIs(VALUE_TAG, valueXml, offset)) - return false; // Not a value, offset not updated - - int afterValueOffset = *offset; - std::string typeTag = XmlRpcUtil::getNextTag(valueXml, offset); - bool result = false; - if (typeTag == BOOLEAN_TAG) - result = boolFromXml(valueXml, offset); - else if (typeTag == I4_TAG || typeTag == INT_TAG) - result = intFromXml(valueXml, offset); - else if (typeTag == DOUBLE_TAG) - result = doubleFromXml(valueXml, offset); - else if (typeTag.empty() || typeTag == STRING_TAG) - result = stringFromXml(valueXml, offset); - else if (typeTag == DATETIME_TAG) - result = timeFromXml(valueXml, offset); - else if (typeTag == BASE64_TAG) - result = binaryFromXml(valueXml, offset); - else if (typeTag == ARRAY_TAG) - result = arrayFromXml(valueXml, offset); - else if (typeTag == STRUCT_TAG) - result = structFromXml(valueXml, offset); - // Watch for empty/blank strings with no tag - else if (typeTag == VALUE_ETAG) - { - *offset = afterValueOffset; // back up & try again - result = stringFromXml(valueXml, offset); - } - - if (result) // Skip over the tag - XmlRpcUtil::findTag(VALUE_ETAG, valueXml, offset); - else // Unrecognized tag after - *offset = savedOffset; - - return result; - } - - // Encode the Value in xml - std::string XmlRpcValue::toXml() const - { - switch (_type) { - case TypeBoolean: return boolToXml(); - case TypeInt: return intToXml(); - case TypeDouble: return doubleToXml(); - case TypeString: return stringToXml(); - case TypeDateTime: return timeToXml(); - case TypeBase64: return binaryToXml(); - case TypeArray: return arrayToXml(); - case TypeStruct: return structToXml(); - default: break; - } - return std::string(); // Invalid value - } - - - // Boolean - bool XmlRpcValue::boolFromXml(std::string const& valueXml, int* offset) - { - const char* valueStart = valueXml.c_str() + *offset; - char* valueEnd; - long ivalue = strtol(valueStart, &valueEnd, 10); - if (valueEnd == valueStart || (ivalue != 0 && ivalue != 1)) - return false; - - _type = TypeBoolean; - _value.asBool = (ivalue == 1); - *offset += int(valueEnd - valueStart); - return true; - } - - std::string XmlRpcValue::boolToXml() const - { - std::string xml = VALUE_TAG; - xml += BOOLEAN_TAG; - xml += (_value.asBool ? "1" : "0"); - xml += BOOLEAN_ETAG; - xml += VALUE_ETAG; - return xml; - } - - // Int - bool XmlRpcValue::intFromXml(std::string const& valueXml, int* offset) - { - const char* valueStart = valueXml.c_str() + *offset; - char* valueEnd; - long ivalue = strtol(valueStart, &valueEnd, 10); - if (valueEnd == valueStart) - return false; - - _type = TypeInt; - _value.asInt = int(ivalue); - *offset += int(valueEnd - valueStart); - return true; - } - - std::string XmlRpcValue::intToXml() const - { - char buf[256]; - snprintf(buf, sizeof(buf)-1, "%d", _value.asInt); - buf[sizeof(buf)-1] = 0; - std::string xml = VALUE_TAG; - xml += I4_TAG; - xml += buf; - xml += I4_ETAG; - xml += VALUE_ETAG; - return xml; - } - - // Double - bool XmlRpcValue::doubleFromXml(std::string const& valueXml, int* offset) - { - const char* valueStart = valueXml.c_str() + *offset; - char* valueEnd; - double dvalue = strtod(valueStart, &valueEnd); - if (valueEnd == valueStart) - return false; - - _type = TypeDouble; - _value.asDouble = dvalue; - *offset += int(valueEnd - valueStart); - return true; - } - - std::string XmlRpcValue::doubleToXml() const - { - char buf[256]; - snprintf(buf, sizeof(buf)-1, getDoubleFormat().c_str(), _value.asDouble); - buf[sizeof(buf)-1] = 0; - - std::string xml = VALUE_TAG; - xml += DOUBLE_TAG; - xml += buf; - xml += DOUBLE_ETAG; - xml += VALUE_ETAG; - return xml; - } - - // String - bool XmlRpcValue::stringFromXml(std::string const& valueXml, int* offset) - { - size_t valueEnd = valueXml.find('<', *offset); - if (valueEnd == std::string::npos) - return false; // No end tag; - - _type = TypeString; - _value.asString = new std::string(XmlRpcUtil::xmlDecode(valueXml.substr(*offset, valueEnd-*offset))); - *offset += int(_value.asString->length()); - return true; - } - - std::string XmlRpcValue::stringToXml() const - { - std::string xml = VALUE_TAG; - //xml += STRING_TAG; optional - xml += XmlRpcUtil::xmlEncode(*_value.asString); - //xml += STRING_ETAG; - xml += VALUE_ETAG; - return xml; - } - - // DateTime (stored as a struct tm) - bool XmlRpcValue::timeFromXml(std::string const& valueXml, int* offset) - { - size_t valueEnd = valueXml.find('<', *offset); - if (valueEnd == std::string::npos) - return false; // No end tag; - - std::string stime = valueXml.substr(*offset, valueEnd-*offset); - - struct tm t; - 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) - return false; - - t.tm_isdst = -1; - _type = TypeDateTime; - _value.asTime = new struct tm(t); - *offset += int(stime.length()); - return true; - } - - std::string XmlRpcValue::timeToXml() const - { - struct tm* t = _value.asTime; - char buf[20]; - snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d", - t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); - buf[sizeof(buf)-1] = 0; - - std::string xml = VALUE_TAG; - xml += DATETIME_TAG; - xml += buf; - xml += DATETIME_ETAG; - xml += VALUE_ETAG; - return xml; - } - - - // Base64 - bool XmlRpcValue::binaryFromXml(std::string const& valueXml, int* offset) - { - size_t valueEnd = valueXml.find('<', *offset); - if (valueEnd == std::string::npos) - return false; // No end tag; - - _type = TypeBase64; - std::string asString = valueXml.substr(*offset, valueEnd-*offset); - _value.asBinary = new BinaryData(); - // check whether base64 encodings can contain chars xml encodes... - - // convert from base64 to binary - int iostatus = 0; - base64 decoder; - std::back_insert_iterator ins = std::back_inserter(*(_value.asBinary)); - decoder.get(asString.begin(), asString.end(), ins, iostatus); - - *offset += int(asString.length()); - return true; - } - - - std::string XmlRpcValue::binaryToXml() const - { - // convert to base64 - std::vector base64data; - int iostatus = 0; - base64 encoder; - std::back_insert_iterator > ins = std::back_inserter(base64data); - encoder.put(_value.asBinary->begin(), _value.asBinary->end(), ins, iostatus, base64<>::crlf()); - - // Wrap with xml - std::string xml = VALUE_TAG; - xml += BASE64_TAG; - xml.append(base64data.begin(), base64data.end()); - xml += BASE64_ETAG; - xml += VALUE_ETAG; - return xml; - } - - - // Array - bool XmlRpcValue::arrayFromXml(std::string const& valueXml, int* offset) - { - if ( ! XmlRpcUtil::nextTagIs(DATA_TAG, valueXml, offset)) - return false; - - _type = TypeArray; - _value.asArray = new ValueArray; - XmlRpcValue v; - while (v.fromXml(valueXml, offset)) - _value.asArray->push_back(v); // copy... - - // Skip the trailing - (void) XmlRpcUtil::nextTagIs(DATA_ETAG, valueXml, offset); - return true; - } - - - // In general, its preferable to generate the xml of each element of the - // array as it is needed rather than glomming up one big string. - std::string XmlRpcValue::arrayToXml() const - { - std::string xml = VALUE_TAG; - xml += ARRAY_TAG; - xml += DATA_TAG; - - int s = int(_value.asArray->size()); - for (int i=0; iat(i).toXml(); - - xml += DATA_ETAG; - xml += ARRAY_ETAG; - xml += VALUE_ETAG; - return xml; - } - - - // Struct - bool XmlRpcValue::structFromXml(std::string const& valueXml, int* offset) - { - _type = TypeStruct; - _value.asStruct = new ValueStruct; - - while (XmlRpcUtil::nextTagIs(MEMBER_TAG, valueXml, offset)) { - // name - const std::string name = XmlRpcUtil::parseTag(NAME_TAG, valueXml, offset); - // value - XmlRpcValue val(valueXml, offset); - if ( ! val.valid()) { - invalidate(); - return false; - } - const std::pair p(name, val); - _value.asStruct->insert(p); - - (void) XmlRpcUtil::nextTagIs(MEMBER_ETAG, valueXml, offset); - } - return true; - } - - - // In general, its preferable to generate the xml of each element - // as it is needed rather than glomming up one big string. - std::string XmlRpcValue::structToXml() const - { - std::string xml = VALUE_TAG; - xml += STRUCT_TAG; - - ValueStruct::const_iterator it; - for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it) { - xml += MEMBER_TAG; - xml += NAME_TAG; - xml += XmlRpcUtil::xmlEncode(it->first); - xml += NAME_ETAG; - xml += it->second.toXml(); - xml += MEMBER_ETAG; - } - - xml += STRUCT_ETAG; - xml += VALUE_ETAG; - return xml; - } - - - - // Write the value without xml encoding it - std::ostream& XmlRpcValue::write(std::ostream& os) const { - switch (_type) { - default: break; - case TypeBoolean: os << _value.asBool; break; - case TypeInt: os << _value.asInt; break; - case TypeDouble: os << _value.asDouble; break; - case TypeString: os << *_value.asString; break; - case TypeDateTime: - { - struct tm* t = _value.asTime; - char buf[20]; - snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d", - t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); - buf[sizeof(buf)-1] = 0; - os << buf; - break; - } - case TypeBase64: - { - int iostatus = 0; - std::ostreambuf_iterator out(os); - base64 encoder; - encoder.put(_value.asBinary->begin(), _value.asBinary->end(), out, iostatus, base64<>::crlf()); - break; - } - case TypeArray: - { - int s = int(_value.asArray->size()); - os << '{'; - for (int i=0; i 0) os << ','; - _value.asArray->at(i).write(os); - } - os << '}'; - break; - } - case TypeStruct: - { - os << '['; - ValueStruct::const_iterator it; - for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it) - { - if (it!=_value.asStruct->begin()) os << ','; - os << it->first << ':'; - it->second.write(os); - } - os << ']'; - break; - } - - } - - return os; - } - -} // namespace robot_xmlrpcpp - - -// ostream -std::ostream& operator<<(std::ostream& os, robot_xmlrpcpp::XmlRpcValue& v) -{ - // If you want to output in xml format: - //return os << v.toXml(); - return v.write(os); -} - + +#include "robot_xmlrpcpp/XmlRpcValue.h" +#include "robot_xmlrpcpp/XmlRpcException.h" +#include "robot_xmlrpcpp/XmlRpcUtil.h" +#include "robot_xmlrpcpp/base64.h" + +#ifndef MAKEDEPEND +# include +# include +# include +# include +#endif + +namespace robot_xmlrpcpp { + + + static const char VALUE_TAG[] = ""; + static const char VALUE_ETAG[] = ""; + + static const char BOOLEAN_TAG[] = ""; + static const char BOOLEAN_ETAG[] = ""; + static const char DOUBLE_TAG[] = ""; + static const char DOUBLE_ETAG[] = ""; + static const char INT_TAG[] = ""; + static const char I4_TAG[] = ""; + static const char I4_ETAG[] = ""; + static const char STRING_TAG[] = ""; + static const char DATETIME_TAG[] = ""; + static const char DATETIME_ETAG[] = ""; + static const char BASE64_TAG[] = ""; + static const char BASE64_ETAG[] = ""; + + static const char ARRAY_TAG[] = ""; + static const char DATA_TAG[] = ""; + static const char DATA_ETAG[] = ""; + static const char ARRAY_ETAG[] = ""; + + static const char STRUCT_TAG[] = ""; + static const char MEMBER_TAG[] = ""; + static const char NAME_TAG[] = ""; + static const char NAME_ETAG[] = ""; + static const char MEMBER_ETAG[] = ""; + static const char STRUCT_ETAG[] = ""; + + + + // Format strings + std::string XmlRpcValue::_doubleFormat("%f"); + + + + // Clean up + void XmlRpcValue::invalidate() + { + switch (_type) { + case TypeString: delete _value.asString; break; + case TypeDateTime: delete _value.asTime; break; + case TypeBase64: delete _value.asBinary; break; + case TypeArray: delete _value.asArray; break; + case TypeStruct: delete _value.asStruct; break; + default: break; + } + _type = TypeInvalid; + _value.asBinary = 0; + } + + + // Type checking + void XmlRpcValue::assertTypeOrInvalid(Type t) + { + if (_type == TypeInvalid) + { + _type = t; + switch (_type) { // Ensure there is a valid value for the type + case TypeString: _value.asString = new std::string(); break; + case TypeDateTime: _value.asTime = new struct tm(); break; + case TypeBase64: _value.asBinary = new BinaryData(); break; + case TypeArray: _value.asArray = new ValueArray(); break; + case TypeStruct: _value.asStruct = new ValueStruct(); break; + default: _value.asBinary = 0; break; + } + } + else if (_type != t) + throw XmlRpcException("type error"); + } + + void XmlRpcValue::assertArray(int size) const + { + if (_type != TypeArray) + throw XmlRpcException("type error: expected an array"); + else if (int(_value.asArray->size()) < size) + throw XmlRpcException("range error: array index too large"); + } + + + void XmlRpcValue::assertArray(int size) + { + if (_type == TypeInvalid) { + _type = TypeArray; + _value.asArray = new ValueArray(size); + } else if (_type == TypeArray) { + if (int(_value.asArray->size()) < size) + _value.asArray->resize(size); + } else + throw XmlRpcException("type error: expected an array"); + } + + void XmlRpcValue::assertStruct() + { + if (_type == TypeInvalid) { + _type = TypeStruct; + _value.asStruct = new ValueStruct(); + } else if (_type != TypeStruct) + throw XmlRpcException("type error: expected a struct"); + } + + + // Operators + XmlRpcValue& XmlRpcValue::operator=(XmlRpcValue const& rhs) + { + if (this != &rhs) + { + invalidate(); + _type = rhs._type; + switch (_type) { + case TypeBoolean: _value.asBool = rhs._value.asBool; break; + case TypeInt: _value.asInt = rhs._value.asInt; break; + case TypeDouble: _value.asDouble = rhs._value.asDouble; break; + case TypeDateTime: _value.asTime = new struct tm(*rhs._value.asTime); break; + case TypeString: _value.asString = new std::string(*rhs._value.asString); break; + case TypeBase64: _value.asBinary = new BinaryData(*rhs._value.asBinary); break; + case TypeArray: _value.asArray = new ValueArray(*rhs._value.asArray); break; + case TypeStruct: _value.asStruct = new ValueStruct(*rhs._value.asStruct); break; + default: _value.asBinary = 0; break; + } + } + return *this; + } + + + // Predicate for tm equality + static bool tmEq(struct tm const& t1, struct tm const& t2) { + return t1.tm_sec == t2.tm_sec && t1.tm_min == t2.tm_min && + t1.tm_hour == t2.tm_hour && t1.tm_mday == t2.tm_mday && + t1.tm_mon == t2.tm_mon && t1.tm_year == t2.tm_year; + } + + bool XmlRpcValue::operator==(XmlRpcValue const& other) const + { + if (_type != other._type) + return false; + + switch (_type) { + case TypeBoolean: return ( !_value.asBool && !other._value.asBool) || + ( _value.asBool && other._value.asBool); + case TypeInt: return _value.asInt == other._value.asInt; + case TypeDouble: return _value.asDouble == other._value.asDouble; + case TypeDateTime: return tmEq(*_value.asTime, *other._value.asTime); + case TypeString: return *_value.asString == *other._value.asString; + case TypeBase64: return *_value.asBinary == *other._value.asBinary; + case TypeArray: return *_value.asArray == *other._value.asArray; + + // The map<>::operator== requires the definition of value< for kcc + case TypeStruct: //return *_value.asStruct == *other._value.asStruct; + { + if (_value.asStruct->size() != other._value.asStruct->size()) + return false; + + ValueStruct::const_iterator it1=_value.asStruct->begin(); + ValueStruct::const_iterator it2=other._value.asStruct->begin(); + while (it1 != _value.asStruct->end()) { + const XmlRpcValue& v1 = it1->second; + const XmlRpcValue& v2 = it2->second; + if ( ! (v1 == v2)) + return false; + it1++; + it2++; + } + return true; + } + default: break; + } + return true; // Both invalid values ... + } + + bool XmlRpcValue::operator!=(XmlRpcValue const& other) const + { + return !(*this == other); + } + + + // Works for strings, binary data, arrays, and structs. + int XmlRpcValue::size() const + { + switch (_type) { + case TypeString: return int(_value.asString->size()); + case TypeBase64: return int(_value.asBinary->size()); + case TypeArray: return int(_value.asArray->size()); + case TypeStruct: return int(_value.asStruct->size()); + default: break; + } + + throw XmlRpcException("type error"); + } + + // Checks for existence of struct member + bool XmlRpcValue::hasMember(const std::string& name) const + { + return _type == TypeStruct && _value.asStruct->find(name) != _value.asStruct->end(); + } + + const XmlRpcValue::ValueStruct *XmlRpcValue::getStructMembers() const + { + if (_type != TypeStruct) + return nullptr; + return _value.asStruct; + } + + // Set the value from xml. The chars at *offset into valueXml + // should be the start of a tag. Destroys any existing value. + bool XmlRpcValue::fromXml(std::string const& valueXml, int* offset) + { + int savedOffset = *offset; + + invalidate(); + if ( ! XmlRpcUtil::nextTagIs(VALUE_TAG, valueXml, offset)) + return false; // Not a value, offset not updated + + int afterValueOffset = *offset; + std::string typeTag = XmlRpcUtil::getNextTag(valueXml, offset); + bool result = false; + if (typeTag == BOOLEAN_TAG) + result = boolFromXml(valueXml, offset); + else if (typeTag == I4_TAG || typeTag == INT_TAG) + result = intFromXml(valueXml, offset); + else if (typeTag == DOUBLE_TAG) + result = doubleFromXml(valueXml, offset); + else if (typeTag.empty() || typeTag == STRING_TAG) + result = stringFromXml(valueXml, offset); + else if (typeTag == DATETIME_TAG) + result = timeFromXml(valueXml, offset); + else if (typeTag == BASE64_TAG) + result = binaryFromXml(valueXml, offset); + else if (typeTag == ARRAY_TAG) + result = arrayFromXml(valueXml, offset); + else if (typeTag == STRUCT_TAG) + result = structFromXml(valueXml, offset); + // Watch for empty/blank strings with no tag + else if (typeTag == VALUE_ETAG) + { + *offset = afterValueOffset; // back up & try again + result = stringFromXml(valueXml, offset); + } + + if (result) // Skip over the tag + XmlRpcUtil::findTag(VALUE_ETAG, valueXml, offset); + else // Unrecognized tag after + *offset = savedOffset; + + return result; + } + + // Encode the Value in xml + std::string XmlRpcValue::toXml() const + { + switch (_type) { + case TypeBoolean: return boolToXml(); + case TypeInt: return intToXml(); + case TypeDouble: return doubleToXml(); + case TypeString: return stringToXml(); + case TypeDateTime: return timeToXml(); + case TypeBase64: return binaryToXml(); + case TypeArray: return arrayToXml(); + case TypeStruct: return structToXml(); + default: break; + } + return std::string(); // Invalid value + } + + + // Boolean + bool XmlRpcValue::boolFromXml(std::string const& valueXml, int* offset) + { + const char* valueStart = valueXml.c_str() + *offset; + char* valueEnd; + long ivalue = strtol(valueStart, &valueEnd, 10); + if (valueEnd == valueStart || (ivalue != 0 && ivalue != 1)) + return false; + + _type = TypeBoolean; + _value.asBool = (ivalue == 1); + *offset += int(valueEnd - valueStart); + return true; + } + + std::string XmlRpcValue::boolToXml() const + { + std::string xml = VALUE_TAG; + xml += BOOLEAN_TAG; + xml += (_value.asBool ? "1" : "0"); + xml += BOOLEAN_ETAG; + xml += VALUE_ETAG; + return xml; + } + + // Int + bool XmlRpcValue::intFromXml(std::string const& valueXml, int* offset) + { + const char* valueStart = valueXml.c_str() + *offset; + char* valueEnd; + long ivalue = strtol(valueStart, &valueEnd, 10); + if (valueEnd == valueStart) + return false; + + _type = TypeInt; + _value.asInt = int(ivalue); + *offset += int(valueEnd - valueStart); + return true; + } + + std::string XmlRpcValue::intToXml() const + { + char buf[256]; + snprintf(buf, sizeof(buf)-1, "%d", _value.asInt); + buf[sizeof(buf)-1] = 0; + std::string xml = VALUE_TAG; + xml += I4_TAG; + xml += buf; + xml += I4_ETAG; + xml += VALUE_ETAG; + return xml; + } + + // Double + bool XmlRpcValue::doubleFromXml(std::string const& valueXml, int* offset) + { + const char* valueStart = valueXml.c_str() + *offset; + char* valueEnd; + double dvalue = strtod(valueStart, &valueEnd); + if (valueEnd == valueStart) + return false; + + _type = TypeDouble; + _value.asDouble = dvalue; + *offset += int(valueEnd - valueStart); + return true; + } + + std::string XmlRpcValue::doubleToXml() const + { + char buf[256]; + snprintf(buf, sizeof(buf)-1, getDoubleFormat().c_str(), _value.asDouble); + buf[sizeof(buf)-1] = 0; + + std::string xml = VALUE_TAG; + xml += DOUBLE_TAG; + xml += buf; + xml += DOUBLE_ETAG; + xml += VALUE_ETAG; + return xml; + } + + // String + bool XmlRpcValue::stringFromXml(std::string const& valueXml, int* offset) + { + size_t valueEnd = valueXml.find('<', *offset); + if (valueEnd == std::string::npos) + return false; // No end tag; + + _type = TypeString; + _value.asString = new std::string(XmlRpcUtil::xmlDecode(valueXml.substr(*offset, valueEnd-*offset))); + *offset += int(_value.asString->length()); + return true; + } + + std::string XmlRpcValue::stringToXml() const + { + std::string xml = VALUE_TAG; + //xml += STRING_TAG; optional + xml += XmlRpcUtil::xmlEncode(*_value.asString); + //xml += STRING_ETAG; + xml += VALUE_ETAG; + return xml; + } + + // DateTime (stored as a struct tm) + bool XmlRpcValue::timeFromXml(std::string const& valueXml, int* offset) + { + size_t valueEnd = valueXml.find('<', *offset); + if (valueEnd == std::string::npos) + return false; // No end tag; + + std::string stime = valueXml.substr(*offset, valueEnd-*offset); + + struct tm t; + 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) + return false; + + t.tm_isdst = -1; + _type = TypeDateTime; + _value.asTime = new struct tm(t); + *offset += int(stime.length()); + return true; + } + + std::string XmlRpcValue::timeToXml() const + { + struct tm* t = _value.asTime; + char buf[20]; + snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d", + t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); + buf[sizeof(buf)-1] = 0; + + std::string xml = VALUE_TAG; + xml += DATETIME_TAG; + xml += buf; + xml += DATETIME_ETAG; + xml += VALUE_ETAG; + return xml; + } + + + // Base64 + bool XmlRpcValue::binaryFromXml(std::string const& valueXml, int* offset) + { + size_t valueEnd = valueXml.find('<', *offset); + if (valueEnd == std::string::npos) + return false; // No end tag; + + _type = TypeBase64; + std::string asString = valueXml.substr(*offset, valueEnd-*offset); + _value.asBinary = new BinaryData(); + // check whether base64 encodings can contain chars xml encodes... + + // convert from base64 to binary + int iostatus = 0; + base64 decoder; + std::back_insert_iterator ins = std::back_inserter(*(_value.asBinary)); + decoder.get(asString.begin(), asString.end(), ins, iostatus); + + *offset += int(asString.length()); + return true; + } + + + std::string XmlRpcValue::binaryToXml() const + { + // convert to base64 + std::vector base64data; + int iostatus = 0; + base64 encoder; + std::back_insert_iterator > ins = std::back_inserter(base64data); + encoder.put(_value.asBinary->begin(), _value.asBinary->end(), ins, iostatus, base64<>::crlf()); + + // Wrap with xml + std::string xml = VALUE_TAG; + xml += BASE64_TAG; + xml.append(base64data.begin(), base64data.end()); + xml += BASE64_ETAG; + xml += VALUE_ETAG; + return xml; + } + + + // Array + bool XmlRpcValue::arrayFromXml(std::string const& valueXml, int* offset) + { + if ( ! XmlRpcUtil::nextTagIs(DATA_TAG, valueXml, offset)) + return false; + + _type = TypeArray; + _value.asArray = new ValueArray; + XmlRpcValue v; + while (v.fromXml(valueXml, offset)) + _value.asArray->push_back(v); // copy... + + // Skip the trailing + (void) XmlRpcUtil::nextTagIs(DATA_ETAG, valueXml, offset); + return true; + } + + + // In general, its preferable to generate the xml of each element of the + // array as it is needed rather than glomming up one big string. + std::string XmlRpcValue::arrayToXml() const + { + std::string xml = VALUE_TAG; + xml += ARRAY_TAG; + xml += DATA_TAG; + + int s = int(_value.asArray->size()); + for (int i=0; iat(i).toXml(); + + xml += DATA_ETAG; + xml += ARRAY_ETAG; + xml += VALUE_ETAG; + return xml; + } + + + // Struct + bool XmlRpcValue::structFromXml(std::string const& valueXml, int* offset) + { + _type = TypeStruct; + _value.asStruct = new ValueStruct; + + while (XmlRpcUtil::nextTagIs(MEMBER_TAG, valueXml, offset)) { + // name + const std::string name = XmlRpcUtil::parseTag(NAME_TAG, valueXml, offset); + // value + XmlRpcValue val(valueXml, offset); + if ( ! val.valid()) { + invalidate(); + return false; + } + const std::pair p(name, val); + _value.asStruct->insert(p); + + (void) XmlRpcUtil::nextTagIs(MEMBER_ETAG, valueXml, offset); + } + return true; + } + + + // In general, its preferable to generate the xml of each element + // as it is needed rather than glomming up one big string. + std::string XmlRpcValue::structToXml() const + { + std::string xml = VALUE_TAG; + xml += STRUCT_TAG; + + ValueStruct::const_iterator it; + for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it) { + xml += MEMBER_TAG; + xml += NAME_TAG; + xml += XmlRpcUtil::xmlEncode(it->first); + xml += NAME_ETAG; + xml += it->second.toXml(); + xml += MEMBER_ETAG; + } + + xml += STRUCT_ETAG; + xml += VALUE_ETAG; + return xml; + } + + + + // Write the value without xml encoding it + std::ostream& XmlRpcValue::write(std::ostream& os) const { + switch (_type) { + default: break; + case TypeBoolean: os << _value.asBool; break; + case TypeInt: os << _value.asInt; break; + case TypeDouble: os << _value.asDouble; break; + case TypeString: os << *_value.asString; break; + case TypeDateTime: + { + struct tm* t = _value.asTime; + char buf[20]; + snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d", + t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); + buf[sizeof(buf)-1] = 0; + os << buf; + break; + } + case TypeBase64: + { + int iostatus = 0; + std::ostreambuf_iterator out(os); + base64 encoder; + encoder.put(_value.asBinary->begin(), _value.asBinary->end(), out, iostatus, base64<>::crlf()); + break; + } + case TypeArray: + { + int s = int(_value.asArray->size()); + os << '{'; + for (int i=0; i 0) os << ','; + _value.asArray->at(i).write(os); + } + os << '}'; + break; + } + case TypeStruct: + { + os << '['; + ValueStruct::const_iterator it; + for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it) + { + if (it!=_value.asStruct->begin()) os << ','; + os << it->first << ':'; + it->second.write(os); + } + os << ']'; + break; + } + + } + + return os; + } + +} // namespace robot_xmlrpcpp + + +// ostream +std::ostream& operator<<(std::ostream& os, robot_xmlrpcpp::XmlRpcValue& v) +{ + // If you want to output in xml format: + //return os << v.toXml(); + return v.write(os); +} +