├── .gitignore ├── README.md ├── tool_archive_xmlrpc_c.py ├── LICENSE ├── Archive_xmlrpc_c.cpp ├── testSerialization.cpp └── Archive_xmlrpc_c.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.o 3 | testSerialization 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Archive_xmlrpc_c 2 | This tool provides C++ classes `Iarchive_xmlrpc_c` and `Oarchive_xmlrpc_c`, which are Boost input and output archive classes which support serialization to and from [xmlrpc-c](http://xmlrpc-c.sourceforge.net/) `xmlrpc_c::value_struct` dictionaries. 3 | -------------------------------------------------------------------------------- /tool_archive_xmlrpc_c.py: -------------------------------------------------------------------------------- 1 | # 2 | # Rules to build libarchive_xmlrpc_c.a and export it as a SCons tool 3 | # 4 | import os 5 | 6 | tools = Split(''' 7 | boost_serialization 8 | xmlrpc_client++ 9 | ''') 10 | env = Environment(tools=['default'] + tools) 11 | 12 | tooldir = env.Dir('.').srcnode().abspath # this directory 13 | 14 | # The library and header files will live in this directory. 15 | libDir = tooldir 16 | includeDir = tooldir 17 | 18 | sources = Split(''' 19 | Archive_xmlrpc_c.cpp 20 | ''') 21 | 22 | lib = env.Library('archive_xmlrpc_c', sources) 23 | Default(lib) 24 | 25 | testSerialization = env.Program('testSerialization', ['testSerialization.cpp']) 26 | Default(testSerialization) 27 | 28 | def archive_xmlrpc_c(env): 29 | env.Require(tools) 30 | env.AppendUnique(CPPPATH = [includeDir]) 31 | env.Append(LIBS = [lib]) 32 | 33 | Export('archive_xmlrpc_c') 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | LICENSE 2 | ======= 3 | 4 | Copyright (c) 1990 - 2016, University Corporation for Atmospheric 5 | Research (UCAR), Boulder, Colorado, USA. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | 1) If the software is modified to produce derivative works, such 12 | modified software should be clearly marked, so as not to confuse it 13 | with the copyright holder's original. 14 | 15 | 2) Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 18 | 3) Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | 22 | 4) Neither the name of the copyright holder nor the names of its 23 | contributors, if any, may be used to endorse or promote products 24 | derived from this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | -------------------------------------------------------------------------------- /Archive_xmlrpc_c.cpp: -------------------------------------------------------------------------------- 1 | // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* 2 | // ** Copyright UCAR (c) 1990 - 2016 3 | // ** University Corporation for Atmospheric Research (UCAR) 4 | // ** National Center for Atmospheric Research (NCAR) 5 | // ** Boulder, Colorado, USA 6 | // ** BSD licence applies - redistribution and use in source and binary 7 | // ** forms, with or without modification, are permitted provided that 8 | // ** the following conditions are met: 9 | // ** 1) If the software is modified to produce derivative works, 10 | // ** such modified software should be clearly marked, so as not 11 | // ** to confuse it with the version available from UCAR. 12 | // ** 2) Redistributions of source code must retain the above copyright 13 | // ** notice, this list of conditions and the following disclaimer. 14 | // ** 3) Redistributions in binary form must reproduce the above copyright 15 | // ** notice, this list of conditions and the following disclaimer in the 16 | // ** documentation and/or other materials provided with the distribution. 17 | // ** 4) Neither the name of UCAR nor the names of its contributors, 18 | // ** if any, may be used to endorse or promote products derived from 19 | // ** this software without specific prior written permission. 20 | // ** DISCLAIMER: THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS 21 | // ** OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 22 | // ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 23 | // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* 24 | /* 25 | * Archive_xmlrpc_c.cpp 26 | * 27 | * Created on: Jun 27, 2013 28 | * Author: burghart 29 | */ 30 | #define BOOST_ARCHIVE_SOURCE 31 | 32 | #include 33 | #include "Archive_xmlrpc_c.h" 34 | 35 | #if (BOOST_VERSION == 104100) 36 | // For Boost 1.41, we must explicitly instantiate some implementation for 37 | // this type of stream 38 | # include 39 | template class boost::archive::detail::common_oarchive; 40 | template class boost::archive::detail::common_iarchive; 41 | template class boost::archive::detail::archive_serializer_map; 42 | #endif 43 | -------------------------------------------------------------------------------- /testSerialization.cpp: -------------------------------------------------------------------------------- 1 | // testSerialization.cpp 2 | // Created on: Jan 31, 2019 3 | // Author: Chris Burghart 4 | 5 | /// Test Archive_xmlrpc_c serialization 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "Archive_xmlrpc_c.h" 12 | 13 | class TestClass { 14 | public: 15 | TestClass() : 16 | _i8Bit(INT8_MIN), 17 | _ui8Bit(UINT8_MAX), 18 | _i16Bit(INT16_MIN), 19 | _ui16Bit(UINT16_MAX), 20 | _i32Bit(INT32_MIN), 21 | _ui32Bit(UINT32_MAX), 22 | _i64Bit(INT64_MIN), 23 | _ui64Bit(UINT64_MAX) {} 24 | 25 | virtual ~TestClass() {} 26 | 27 | /// @brief Serialize our members to a boost save (output) archive or populate 28 | /// our members from a boost load (input) archive. 29 | /// @param ar the archive to load from or save to. 30 | /// @param version the version 31 | friend class boost::serialization::access; 32 | 33 | template 34 | void serialize(Archive & ar, const unsigned int version) { 35 | // Map named entries to our member variables using serialization's 36 | // name/value pairs (nvp). If anything is changed in this section, be 37 | // sure to increment the version number in STATUS_VERSION above. 38 | ar & BOOST_SERIALIZATION_NVP(_i8Bit); 39 | ar & BOOST_SERIALIZATION_NVP(_ui8Bit); 40 | ar & BOOST_SERIALIZATION_NVP(_i16Bit); 41 | ar & BOOST_SERIALIZATION_NVP(_ui16Bit); 42 | ar & BOOST_SERIALIZATION_NVP(_i32Bit); 43 | ar & BOOST_SERIALIZATION_NVP(_ui32Bit); 44 | ar & BOOST_SERIALIZATION_NVP(_i64Bit); 45 | ar & BOOST_SERIALIZATION_NVP(_ui64Bit); 46 | } 47 | 48 | int8_t _i8Bit; 49 | uint8_t _ui8Bit; 50 | int16_t _i16Bit; 51 | uint16_t _ui16Bit; 52 | int32_t _i32Bit; 53 | uint32_t _ui32Bit; 54 | int64_t _i64Bit; 55 | uint64_t _ui64Bit; 56 | }; 57 | 58 | //xmlrpc_c::value_struct 59 | //TestClass::toXmlRpcValue() const { 60 | // std::map statusDict; 61 | // // Clone ourself to a non-const instance 62 | // TestClass clone(*this); 63 | // // Stuff our content into the statusDict, i.e., _serialize() to an 64 | // // output archiver wrapped around the statusDict. 65 | // Oarchive_xmlrpc_c oar(statusDict); 66 | // oar << clone; 67 | // // Finally, return the statusDict 68 | // return(xmlrpc_c::value_struct(statusDict)); 69 | //} 70 | 71 | int 72 | main(int argc, char *argv[]) { 73 | TestClass tc; 74 | 75 | xmlrpc_c::cstruct outMap; 76 | Oarchive_xmlrpc_c oa(outMap); 77 | oa << tc; 78 | 79 | xmlrpc_c::value_struct xmlStruct(outMap); 80 | Iarchive_xmlrpc_c ia(xmlStruct); 81 | XmlrpcSerializable newTc(xmlStruct); 82 | 83 | bool fail = false; 84 | bool ok; 85 | ok = (newTc._i8Bit == INT8_MIN); 86 | std::cout << "int8_t " << (ok ? "GOOD" : "BAD") << std::endl; 87 | fail |= !ok; 88 | 89 | ok = (newTc._ui8Bit == UINT8_MAX); 90 | std::cout << "uint8_t " << (ok ? "GOOD" : "BAD") << std::endl; 91 | fail |= !ok; 92 | 93 | ok = (newTc._i16Bit == INT16_MIN); 94 | std::cout << "int16_t " << (ok ? "GOOD" : "BAD") << std::endl; 95 | fail |= !ok; 96 | 97 | ok = (newTc._ui16Bit == UINT16_MAX); 98 | std::cout << "uint32_t " << (ok ? "GOOD" : "BAD") << std::endl; 99 | fail |= !ok; 100 | 101 | ok = (newTc._i32Bit == INT32_MIN); 102 | std::cout << "int32_t " << (ok ? "GOOD" : "BAD") << std::endl; 103 | fail |= !ok; 104 | 105 | ok = (newTc._ui32Bit == UINT32_MAX); 106 | std::cout << "uint32_t " << (ok ? "GOOD" : "BAD") << std::endl; 107 | fail |= !ok; 108 | 109 | ok = (newTc._i64Bit == INT64_MIN); 110 | std::cout << "int64_t " << (ok ? "GOOD" : "BAD") << std::endl; 111 | fail |= !ok; 112 | 113 | ok = (newTc._ui64Bit == UINT64_MAX); 114 | std::cout << "uint64_t " << (ok ? "GOOD" : "BAD") << std::endl; 115 | fail |= !ok; 116 | 117 | } 118 | -------------------------------------------------------------------------------- /Archive_xmlrpc_c.h: -------------------------------------------------------------------------------- 1 | // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* 2 | // ** Copyright UCAR (c) 1990 - 2016 3 | // ** University Corporation for Atmospheric Research (UCAR) 4 | // ** National Center for Atmospheric Research (NCAR) 5 | // ** Boulder, Colorado, USA 6 | // ** BSD licence applies - redistribution and use in source and binary 7 | // ** forms, with or without modification, are permitted provided that 8 | // ** the following conditions are met: 9 | // ** 1) If the software is modified to produce derivative works, 10 | // ** such modified software should be clearly marked, so as not 11 | // ** to confuse it with the version available from UCAR. 12 | // ** 2) Redistributions of source code must retain the above copyright 13 | // ** notice, this list of conditions and the following disclaimer. 14 | // ** 3) Redistributions in binary form must reproduce the above copyright 15 | // ** notice, this list of conditions and the following disclaimer in the 16 | // ** documentation and/or other materials provided with the distribution. 17 | // ** 4) Neither the name of UCAR nor the names of its contributors, 18 | // ** if any, may be used to endorse or promote products derived from 19 | // ** this software without specific prior written permission. 20 | // ** DISCLAIMER: THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS 21 | // ** OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 22 | // ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 23 | // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* 24 | 25 | #ifndef _ARCHIVE_XMLRPC_C_H_ 26 | #define _ARCHIVE_XMLRPC_C_H_ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | using namespace xmlrpc_c; 38 | 39 | // Template forward reference 40 | template class XmlrpcSerializable; 41 | 42 | /// @brief Boost output archive class to populate an xmlrpc_c::value_struct 43 | /// dictionary 44 | /// 45 | /// Here's a simple class with a templated serialize() method: 46 | /// 47 | /// class foo { 48 | /// public: 49 | /// foo() { _a = -1; _b = -1.0; _c = true } 50 | /// foo(const xmlrpc_c::value_struct & dict) { serialize(Iarchive_xmlrpc_c(dict); } 51 | /// foo(const xmlrpc_c::value_struct & statusDict) { 52 | /// // Create an input archiver wrapper around the xmlrpc_c::value_struct 53 | /// // dictionary, and use serialize() to populate our members from its 54 | /// // content. 55 | /// Iarchive_xmlrpc_c iar(statusDict); 56 | /// iar >> *this; 57 | /// } 58 | /// 59 | /// xmlrpc_c::value_struct 60 | /// to_value_struct() { 61 | /// xmlrpc_c::value_struct * vsPtr = 0; 62 | /// Oarchive_xmlrpc_c oar(vsPtr); 63 | /// oar << *this; 64 | /// xmlrpc_c::value_struct retval(*vsPtr); 65 | /// delete(vsPtr); 66 | /// return(retval); 67 | /// } 68 | /// 69 | /// template 70 | /// void serialize(Archive & ar, const int version) { 71 | /// ar & BOOST_SERIALIZATION_NVP(_a); 72 | /// ar & BOOST_SERIALIZATION_NVP(_b); 73 | /// ar & BOOST_SERIALIZATION_NVP(_c); 74 | /// } 75 | /// private: 76 | /// int _a; 77 | /// double _b; 78 | /// bool _c; 79 | /// }; 80 | /// 81 | 82 | class Oarchive_xmlrpc_c : 83 | public boost::archive::detail::common_oarchive { 84 | public: 85 | /// @brief Archive to the given dictionary mapping string keys to 86 | /// xmlrpc_c::value objects. 87 | Oarchive_xmlrpc_c(std::map & dict) : 88 | _dict(dict) {} 89 | 90 | #ifdef BOOST_PFTO 91 | // default processing - kick back to our superclass 92 | template 93 | void save_override(const T & t, BOOST_PFTO int) { 94 | boost::archive::detail::common_oarchive::save_override(t, 0); 95 | } 96 | 97 | // Add special key "class_version" in the dictionary to hold the version 98 | // number of the class we're archiving. 99 | void save_override(const boost::archive::version_type & t, BOOST_PFTO int) { 100 | _dict["class_version"] = xmlrpc_c::value_int(static_cast(t)); 101 | } 102 | 103 | // Don't bother archiving tracking_type, class_id_optional_type Boost special values 104 | void save_override(const boost::archive::tracking_type & t, BOOST_PFTO int) { 105 | // std::cerr << "Oarchive_xmlrpc_c dropping tracking_type" << std::endl; 106 | } 107 | void save_override(const boost::archive::class_id_optional_type & t, BOOST_PFTO int) { 108 | // std::cerr << "Oarchive_xmlrpc_c dropping class_id_optional_type" << std::endl; 109 | } 110 | 111 | // Template save_override implementation for boost::serialization:nvp 112 | // when T is an enumerated type 113 | template 114 | void nvp_save_override(const boost::serialization::nvp & pair, 115 | std::true_type is_enum, 116 | std::false_type is_class, 117 | std::false_type is_integral 118 | ) { 119 | const char * key = pair.name(); 120 | _dict[key] = xmlrpc_c::value_int(int(pair.value())); 121 | } 122 | 123 | // Template save_override implementation for boost::serialization:nvp 124 | // when T is a class with a serialize() method 125 | template 126 | void nvp_save_override(const boost::serialization::nvp & pair, 127 | std::false_type is_enum, 128 | std::true_type is_class, 129 | std::false_type is_integral 130 | ) { 131 | const char * key = pair.name(); 132 | XmlrpcSerializable sValue(pair.value()); 133 | _dict[key] = sValue; 134 | } 135 | 136 | // Template save_override implementation for boost::serialization:nvp 137 | // when T is an integral type 138 | template 139 | void nvp_save_override(const boost::serialization::nvp & pair, 140 | std::false_type is_enum, 141 | std::false_type is_class, 142 | std::true_type is_integral 143 | ) { 144 | const char * key = pair.name(); 145 | xmlrpc_c::value xmlrpcval; 146 | // Split handling. 32-bit and smaller integers are saved as 32-bit 147 | // values. Bigger integers are saved as 64-bit values. 148 | if (sizeof(T) <= 4) { 149 | // For signed integer values, save as xmlrpc_c::value_int (32 bit) 150 | // 151 | // For unsigned values, save as their bitwise-equivalent 32-bit 152 | // signed int. They will be reinterpreted the other way when 153 | // loaded again. 154 | if (std::is_signed::value) { 155 | xmlrpcval = xmlrpc_c::value_int(pair.value()); 156 | } else { 157 | uint32_t unsignedVal = pair.value(); 158 | int32_t signedBitwiseEquiv(*reinterpret_cast(&unsignedVal)); 159 | xmlrpcval = xmlrpc_c::value_int(signedBitwiseEquiv); 160 | } 161 | } else { 162 | // Similar to above, but we save as 8-byte (64-bit) type 163 | // xmlrpc_c::value_i8 164 | if (std::is_signed::value) { 165 | xmlrpcval = xmlrpc_c::value_i8(pair.value()); 166 | } else { 167 | uint64_t unsignedVal = pair.value(); 168 | int64_t signedBitwiseEquiv(*reinterpret_cast(&unsignedVal)); 169 | xmlrpcval = xmlrpc_c::value_i8(signedBitwiseEquiv); 170 | } 171 | } 172 | _dict[key] = xmlrpcval; 173 | } 174 | 175 | // Template save_override for boost::serialization::nvp 176 | // (name/value pairs) 177 | // 178 | // This template uses one of the nvp_save_override specializations above, 179 | // selected at compile time based on T's type traits 180 | template 181 | void save_override(const boost::serialization::nvp & pair, 182 | BOOST_PFTO int) { 183 | // Select implementation at compile time depending on whether T is an 184 | // enumerated type or a class 185 | nvp_save_override(pair, std::is_enum{}, std::is_class{}, std::is_integral{}); 186 | } 187 | 188 | // name-value pair handling for bool values 189 | void save_override(const boost::serialization::nvp & pair, BOOST_PFTO int) { 190 | _dict[pair.name()] = xmlrpc_c::value_boolean(pair.value()); 191 | } 192 | 193 | // name-value pair handling for double values 194 | void save_override(const boost::serialization::nvp & pair, BOOST_PFTO int) { 195 | _dict[pair.name()] = xmlrpc_c::value_double(pair.value()); 196 | } 197 | 198 | // name-value pair handling for float values 199 | void save_override(const boost::serialization::nvp & pair, BOOST_PFTO int) { 200 | _dict[pair.name()] = xmlrpc_c::value_double(pair.value()); 201 | } 202 | 203 | // name-value pair handling for std::string values 204 | void save_override(const boost::serialization::nvp & pair, BOOST_PFTO int) { 205 | _dict[pair.name()] = xmlrpc_c::value_string(pair.value()); 206 | } 207 | #else 208 | // default processing - kick back to our superclass 209 | template 210 | void save_override(const T & t) { 211 | boost::archive::detail::common_oarchive::save_override(t); 212 | } 213 | 214 | // Add special key "class_version" in the dictionary to hold the version 215 | // number of the class we're archiving. 216 | void save_override(const boost::archive::version_type & t) { 217 | _dict["class_version"] = xmlrpc_c::value_int(static_cast(t)); 218 | } 219 | 220 | // Don't bother archiving tracking_type, class_id_optional_type Boost special values 221 | void save_override(const boost::archive::tracking_type & t) { 222 | // std::cerr << "Oarchive_xmlrpc_c dropping tracking_type" << std::endl; 223 | } 224 | void save_override(const boost::archive::class_id_optional_type & t) { 225 | // std::cerr << "Oarchive_xmlrpc_c dropping class_id_optional_type" << std::endl; 226 | } 227 | 228 | // Template save_override implementation for boost::serialization:nvp 229 | // when T is an enumerated type 230 | template 231 | void nvp_save_override(const boost::serialization::nvp & pair, 232 | std::true_type is_enum, 233 | std::false_type is_class, 234 | std::false_type is_integral 235 | ) { 236 | const char * key = pair.name(); 237 | _dict[key] = xmlrpc_c::value_int(int(pair.value())); 238 | } 239 | 240 | // Template save_override implementation for boost::serialization:nvp 241 | // when T is a class with a serialize() method 242 | template 243 | void nvp_save_override(const boost::serialization::nvp & pair, 244 | std::false_type is_enum, 245 | std::true_type is_class, 246 | std::false_type is_integral 247 | ) { 248 | const char * key = pair.name(); 249 | XmlrpcSerializable sValue(pair.value()); 250 | _dict[key] = sValue; 251 | } 252 | 253 | // Template save_override implementation for boost::serialization:nvp 254 | // when T is an integral type 255 | template 256 | void nvp_save_override(const boost::serialization::nvp & pair, 257 | std::false_type is_enum, 258 | std::false_type is_class, 259 | std::true_type is_integral 260 | ) { 261 | const char * key = pair.name(); 262 | xmlrpc_c::value xmlrpcval; 263 | // Split handling. 32-bit and smaller integers are saved as 32-bit 264 | // values. Bigger integers are saved as 64-bit values. 265 | if (sizeof(T) <= 4) { 266 | // For signed integer values, save as xmlrpc_c::value_int (32 bit) 267 | // 268 | // For unsigned values, save as their bitwise-equivalent 32-bit 269 | // signed int. They will be reinterpreted the other way when 270 | // loaded again. 271 | if (std::is_signed::value) { 272 | xmlrpcval = xmlrpc_c::value_int(pair.value()); 273 | } else { 274 | uint32_t unsignedVal = pair.value(); 275 | int32_t signedBitwiseEquiv(*reinterpret_cast(&unsignedVal)); 276 | xmlrpcval = xmlrpc_c::value_int(signedBitwiseEquiv); 277 | } 278 | } else { 279 | // Similar to above, but we save as 8-byte (64-bit) type 280 | // xmlrpc_c::value_i8 281 | if (std::is_signed::value) { 282 | xmlrpcval = xmlrpc_c::value_i8(pair.value()); 283 | } else { 284 | uint64_t unsignedVal = pair.value(); 285 | int64_t signedBitwiseEquiv(*reinterpret_cast(&unsignedVal)); 286 | xmlrpcval = xmlrpc_c::value_i8(signedBitwiseEquiv); 287 | } 288 | } 289 | _dict[key] = xmlrpcval; 290 | } 291 | 292 | // Template save_override for boost::serialization::nvp 293 | // (name/value pairs) 294 | // 295 | // This template uses one of the nvp_save_override specializations above, 296 | // selected at compile time based on T's type traits 297 | template 298 | void save_override(const boost::serialization::nvp & pair) { 299 | // Select implementation at compile time depending on whether T is an 300 | // enumerated type or a class 301 | nvp_save_override(pair, std::is_enum{}, std::is_class{}, std::is_integral{}); 302 | } 303 | 304 | // name-value pair handling for bool values 305 | void save_override(const boost::serialization::nvp & pair) { 306 | _dict[pair.name()] = xmlrpc_c::value_boolean(pair.value()); 307 | } 308 | 309 | // name-value pair handling for double values 310 | void save_override(const boost::serialization::nvp & pair) { 311 | _dict[pair.name()] = xmlrpc_c::value_double(pair.value()); 312 | } 313 | 314 | // name-value pair handling for float values 315 | void save_override(const boost::serialization::nvp & pair) { 316 | _dict[pair.name()] = xmlrpc_c::value_double(pair.value()); 317 | } 318 | 319 | // name-value pair handling for std::string values 320 | void save_override(const boost::serialization::nvp & pair) { 321 | _dict[pair.name()] = xmlrpc_c::value_string(pair.value()); 322 | } 323 | #endif // ifdef BOOST_PFTO 324 | 325 | // Not sure why we need this, but things won't compile without it... 326 | template 327 | void save(T & t) { 328 | std::ostringstream ss; 329 | ss << "Oarchive_xmlrpc_c only deals with name-value pairs, \n" << 330 | "failed to save from (mangled) type: " << 331 | typeid(T).name() << "\n" << 332 | "\n(Try 'c++filt -t ' to demangle the type name.)"; 333 | throw(std::runtime_error(ss.str())); 334 | } 335 | private: 336 | friend class boost::archive::detail::common_oarchive; 337 | std::map & _dict; 338 | }; 339 | 340 | /// @brief Boost input archive class to unpack from an xmlrpc_c::value_struct 341 | /// or std::map. 342 | class Iarchive_xmlrpc_c : 343 | public boost::archive::detail::common_iarchive { 344 | public: 345 | Iarchive_xmlrpc_c(const std::map & map) : 346 | _archiveMap(map) {} 347 | Iarchive_xmlrpc_c(const xmlrpc_c::value_struct & archive) : 348 | _archiveMap(static_cast>(archive)) {} 349 | 350 | #ifdef BOOST_PFTO 351 | // default processing - kick back to our superclass 352 | template 353 | void load_override(T & t, BOOST_PFTO int) { 354 | boost::archive::detail::common_iarchive::load_override(t, 0); 355 | } 356 | 357 | // Get class version number from special key "class_version" in the 358 | // xmlrpc_c::value_struct dictionary. 359 | void load_override(boost::archive::version_type & t, BOOST_PFTO int) { 360 | const std::string key("class_version"); 361 | if (_archiveMap.find(key) == _archiveMap.end()) { 362 | std::ostringstream ss; 363 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 364 | key << "'"; 365 | throw(std::runtime_error(ss.str())); 366 | } 367 | xmlrpc_c::value_int ival(_archiveMap.find(key)->second); 368 | t = boost::archive::version_type(static_cast(ival)); 369 | } 370 | 371 | // Don't bother loading tracking_type and class_id_optional_type Boost 372 | // special values 373 | void load_override(boost::archive::tracking_type & t, BOOST_PFTO int) { 374 | // std::cerr << "Iarchive_xmlrpc_c not loading tracking_type" << std::endl; 375 | } 376 | void load_override(boost::archive::class_id_optional_type & t, BOOST_PFTO int) { 377 | // std::cerr << "Iarchive_xmlrpc_c not loading class_id_optional_type" << std::endl; 378 | } 379 | 380 | // Template load_override implementation for boost::serialization:nvp 381 | // when T is an enumerated type 382 | template 383 | void nvp_load_override(const boost::serialization::nvp & pair, 384 | std::true_type is_enum, 385 | std::false_type is_class, 386 | std::false_type is_integral 387 | ) { 388 | const char * key = pair.name(); 389 | auto archiveIter = _archiveMap.find(key); 390 | if (archiveIter == _archiveMap.end()) { 391 | std::ostringstream ss; 392 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 393 | key << "'"; 394 | throw(std::runtime_error(ss.str())); 395 | } 396 | // The returned value should be of type xmlrpc_c::value_int. If it 397 | // isn't, the value_int cast below will throw an exception 398 | int intVal(xmlrpc_c::value_int(archiveIter->second)); 399 | // Cast the integer value to the enumerated type 400 | pair.value() = static_cast(intVal); 401 | } 402 | 403 | // Template load_override implementation for boost::serialization:nvp 404 | // when T is a class with a serialize() method 405 | template 406 | void nvp_load_override(const boost::serialization::nvp & pair, 407 | std::false_type is_enum, 408 | std::true_type is_class, 409 | std::false_type is_integral 410 | ) { 411 | const char * key = pair.name(); 412 | auto archiveIter = _archiveMap.find(key); 413 | if (archiveIter == _archiveMap.end()) { 414 | std::ostringstream ss; 415 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 416 | key << "'"; 417 | throw(std::runtime_error(ss.str())); 418 | } 419 | xmlrpc_c::value xmlrpcVal = archiveIter->second; 420 | pair.value() = XmlrpcSerializable(xmlrpcVal); 421 | } 422 | 423 | // Template load_override implementation for boost::serialization:nvp 424 | // when T is an integral type 425 | template 426 | void nvp_load_override(const boost::serialization::nvp & pair, 427 | std::false_type is_enum, 428 | std::false_type is_class, 429 | std::true_type is_integral 430 | ) { 431 | const std::string key = pair.name(); 432 | if (_archiveMap.find(key) == _archiveMap.end()) { 433 | std::ostringstream ss; 434 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 435 | key << "'"; 436 | throw(std::runtime_error(ss.str())); 437 | } 438 | 439 | // Split handling. 32-bit and smaller integers are loaded from 32-bit 440 | // values. Bigger integers are loaded from 64-bit values. 441 | if (sizeof(T) <= 4) { 442 | // For signed integer values, save as xmlrpc_c::value_int (32 bit) 443 | // 444 | // For unsigned values, save as their bitwise-equivalent 32-bit 445 | // signed int. They will be reinterpreted the other way when 446 | // loaded again. 447 | xmlrpc_c::value_int xml_ival(_archiveMap.find(key)->second); 448 | if (std::is_signed::value) { 449 | pair.value() = xml_ival.cvalue(); 450 | } else { 451 | // We get the value as a signed int (from the matching save_override() 452 | // above), and reinterpret to unsigned int. 453 | int32_t signedBitwiseEquiv(xml_ival.cvalue()); 454 | uint32_t uval = *reinterpret_cast(&signedBitwiseEquiv); 455 | pair.value() = uval; 456 | } 457 | } else { 458 | // Similar to above, but we load from 8-byte (64-bit) type 459 | // xmlrpc_c::value_i8 460 | xmlrpc_c::value_i8 xml_ival(_archiveMap.find(key)->second); 461 | if (std::is_signed::value) { 462 | pair.value() = xml_ival.cvalue(); 463 | } else { 464 | // We get the value as a signed int (from the matching save_override() 465 | // above), and reinterpret to unsigned int. 466 | int64_t signedBitwiseEquiv(xml_ival.cvalue()); 467 | uint64_t uval = *reinterpret_cast(&signedBitwiseEquiv); 468 | pair.value() = uval; 469 | } 470 | } 471 | } 472 | 473 | // Template load_override for boost::serialization::nvp 474 | // (name/value pairs) 475 | // 476 | // This template uses one of the nvp_load_override specializations above, 477 | // selected at compile time based on T's type traits 478 | template 479 | void load_override( 480 | #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING 481 | const 482 | #endif 483 | boost::serialization::nvp & pair, 484 | BOOST_PFTO int) 485 | { 486 | // Select implementation at compile time depending on whether T is an 487 | // enumerated type or a class 488 | nvp_load_override(pair, std::is_enum{}, std::is_class{}, std::is_integral{}); 489 | } 490 | 491 | // Loader for name-value pair with bool value 492 | void load_override(const boost::serialization::nvp & pair, BOOST_PFTO int) { 493 | const char * key = pair.name(); 494 | if (_archiveMap.find(key) == _archiveMap.end()) { 495 | std::ostringstream ss; 496 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 497 | key << "'"; 498 | throw(std::runtime_error(ss.str())); 499 | } 500 | xmlrpc_c::value_boolean bval(_archiveMap.find(key)->second); 501 | pair.value() = static_cast(bval); 502 | } 503 | 504 | // Loader for name-value pair with double value 505 | void load_override(const boost::serialization::nvp & pair, BOOST_PFTO int) { 506 | const char * key = pair.name(); 507 | if (_archiveMap.find(key) == _archiveMap.end()) { 508 | std::ostringstream ss; 509 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 510 | key << "'"; 511 | throw(std::runtime_error(ss.str())); 512 | } 513 | xmlrpc_c::value_double dval(_archiveMap.find(key)->second); 514 | pair.value() = static_cast(dval); 515 | } 516 | 517 | // Loader for name-value pair with float value 518 | void load_override(const boost::serialization::nvp & pair, BOOST_PFTO int) { 519 | const char * key = pair.name(); 520 | if (_archiveMap.find(key) == _archiveMap.end()) { 521 | std::ostringstream ss; 522 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 523 | key << "'"; 524 | throw(std::runtime_error(ss.str())); 525 | } 526 | xmlrpc_c::value_double dval(_archiveMap.find(key)->second); 527 | pair.value() = static_cast(dval); 528 | } 529 | 530 | // Loader for name-value pair with std::string value 531 | void load_override(const boost::serialization::nvp & pair, BOOST_PFTO int) { 532 | const char * key = pair.name(); 533 | if (_archiveMap.find(key) == _archiveMap.end()) { 534 | std::ostringstream ss; 535 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 536 | key << "'"; 537 | throw(std::runtime_error(ss.str())); 538 | } 539 | xmlrpc_c::value_string sval(_archiveMap.find(key)->second); 540 | pair.value() = static_cast(sval); 541 | } 542 | 543 | #else 544 | // default processing - kick back to our superclass 545 | template 546 | void load_override(T & t) { 547 | boost::archive::detail::common_iarchive::load_override(t); 548 | } 549 | 550 | // Get class version number from special key "class_version" in the 551 | // xmlrpc_c::value_struct dictionary. 552 | void load_override(boost::archive::version_type & t) { 553 | const std::string key("class_version"); 554 | if (_archiveMap.find(key) == _archiveMap.end()) { 555 | std::ostringstream ss; 556 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 557 | key << "'"; 558 | throw(std::runtime_error(ss.str())); 559 | } 560 | xmlrpc_c::value_int ival(_archiveMap.find(key)->second); 561 | t = boost::archive::version_type(static_cast(ival)); 562 | } 563 | 564 | // Don't bother loading tracking_type and class_id_optional_type Boost 565 | // special values 566 | void load_override(boost::archive::tracking_type & t) { 567 | // std::cerr << "Iarchive_xmlrpc_c not loading tracking_type" << std::endl; 568 | } 569 | void load_override(boost::archive::class_id_optional_type & t) { 570 | // std::cerr << "Iarchive_xmlrpc_c not loading class_id_optional_type" << std::endl; 571 | } 572 | 573 | // Template load_override implementation for boost::serialization:nvp 574 | // when T is an enumerated type 575 | template 576 | void nvp_load_override(const boost::serialization::nvp & pair, 577 | std::true_type is_enum, 578 | std::false_type is_class, 579 | std::false_type is_integral 580 | ) { 581 | const char * key = pair.name(); 582 | auto archiveIter = _archiveMap.find(key); 583 | if (archiveIter == _archiveMap.end()) { 584 | std::ostringstream ss; 585 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 586 | key << "'"; 587 | throw(std::runtime_error(ss.str())); 588 | } 589 | // The returned value should be of type xmlrpc_c::value_int. If it 590 | // isn't, the value_int cast below will throw an exception 591 | int intVal(xmlrpc_c::value_int(archiveIter->second)); 592 | // Cast the integer value to the enumerated type 593 | pair.value() = static_cast(intVal); 594 | } 595 | 596 | // Template load_override implementation for boost::serialization:nvp 597 | // when T is a class with a serialize() method 598 | template 599 | void nvp_load_override(const boost::serialization::nvp & pair, 600 | std::false_type is_enum, 601 | std::true_type is_class, 602 | std::false_type is_integral 603 | ) { 604 | const char * key = pair.name(); 605 | auto archiveIter = _archiveMap.find(key); 606 | if (archiveIter == _archiveMap.end()) { 607 | std::ostringstream ss; 608 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 609 | key << "'"; 610 | throw(std::runtime_error(ss.str())); 611 | } 612 | xmlrpc_c::value xmlrpcVal = archiveIter->second; 613 | pair.value() = XmlrpcSerializable(xmlrpcVal); 614 | } 615 | 616 | // Template load_override implementation for boost::serialization:nvp 617 | // when T is an integral type 618 | template 619 | void nvp_load_override(const boost::serialization::nvp & pair, 620 | std::false_type is_enum, 621 | std::false_type is_class, 622 | std::true_type is_integral 623 | ) { 624 | const std::string key = pair.name(); 625 | if (_archiveMap.find(key) == _archiveMap.end()) { 626 | std::ostringstream ss; 627 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 628 | key << "'"; 629 | throw(std::runtime_error(ss.str())); 630 | } 631 | 632 | // Split handling. 32-bit and smaller integers are loaded from 32-bit 633 | // values. Bigger integers are loaded from 64-bit values. 634 | if (sizeof(T) <= 4) { 635 | // For signed integer values, save as xmlrpc_c::value_int (32 bit) 636 | // 637 | // For unsigned values, save as their bitwise-equivalent 32-bit 638 | // signed int. They will be reinterpreted the other way when 639 | // loaded again. 640 | xmlrpc_c::value_int xml_ival(_archiveMap.find(key)->second); 641 | if (std::is_signed::value) { 642 | pair.value() = xml_ival.cvalue(); 643 | } else { 644 | // We get the value as a signed int (from the matching save_override() 645 | // above), and reinterpret to unsigned int. 646 | int32_t signedBitwiseEquiv(xml_ival.cvalue()); 647 | uint32_t uval = *reinterpret_cast(&signedBitwiseEquiv); 648 | pair.value() = uval; 649 | } 650 | } else { 651 | // Similar to above, but we load from 8-byte (64-bit) type 652 | // xmlrpc_c::value_i8 653 | xmlrpc_c::value_i8 xml_ival(_archiveMap.find(key)->second); 654 | if (std::is_signed::value) { 655 | pair.value() = xml_ival.cvalue(); 656 | } else { 657 | // We get the value as a signed int (from the matching save_override() 658 | // above), and reinterpret to unsigned int. 659 | int64_t signedBitwiseEquiv(xml_ival.cvalue()); 660 | uint64_t uval = *reinterpret_cast(&signedBitwiseEquiv); 661 | pair.value() = uval; 662 | } 663 | } 664 | } 665 | 666 | // Template load_override for boost::serialization::nvp 667 | // (name/value pairs) 668 | // 669 | // This template uses one of the nvp_load_override specializations above, 670 | // selected at compile time based on T's type traits 671 | template 672 | void load_override(const boost::serialization::nvp & pair) 673 | { 674 | // Select implementation at compile time depending on whether T is an 675 | // enumerated type or a class 676 | nvp_load_override(pair, std::is_enum{}, std::is_class{}, std::is_integral{}); 677 | } 678 | 679 | // Loader for name-value pair with bool value 680 | void load_override(const boost::serialization::nvp & pair) { 681 | const char * key = pair.name(); 682 | if (_archiveMap.find(key) == _archiveMap.end()) { 683 | std::ostringstream ss; 684 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 685 | key << "'"; 686 | throw(std::runtime_error(ss.str())); 687 | } 688 | xmlrpc_c::value_boolean bval(_archiveMap.find(key)->second); 689 | pair.value() = static_cast(bval); 690 | } 691 | 692 | // Loader for name-value pair with double value 693 | void load_override(const boost::serialization::nvp & pair) { 694 | const char * key = pair.name(); 695 | if (_archiveMap.find(key) == _archiveMap.end()) { 696 | std::ostringstream ss; 697 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 698 | key << "'"; 699 | throw(std::runtime_error(ss.str())); 700 | } 701 | xmlrpc_c::value_double dval(_archiveMap.find(key)->second); 702 | pair.value() = static_cast(dval); 703 | } 704 | 705 | // Loader for name-value pair with float value 706 | void load_override(const boost::serialization::nvp & pair) { 707 | const char * key = pair.name(); 708 | if (_archiveMap.find(key) == _archiveMap.end()) { 709 | std::ostringstream ss; 710 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 711 | key << "'"; 712 | throw(std::runtime_error(ss.str())); 713 | } 714 | xmlrpc_c::value_double dval(_archiveMap.find(key)->second); 715 | pair.value() = static_cast(dval); 716 | } 717 | 718 | // Loader for name-value pair with std::string value 719 | void load_override(const boost::serialization::nvp & pair) { 720 | const char * key = pair.name(); 721 | if (_archiveMap.find(key) == _archiveMap.end()) { 722 | std::ostringstream ss; 723 | ss << "xmlrpc_c::value_struct dictionary does not contain requested key '" << 724 | key << "'"; 725 | throw(std::runtime_error(ss.str())); 726 | } 727 | xmlrpc_c::value_string sval(_archiveMap.find(key)->second); 728 | pair.value() = static_cast(sval); 729 | } 730 | #endif // ifdef BOOST_PFTO 731 | // Not sure why we need this, but things won't compile without it... 732 | template 733 | void load(T & t) { 734 | std::ostringstream ss; 735 | ss << "Iarchive_xmlrpc_c only deals with name-value pairs, \n" << 736 | "failed to load from (mangled) type: " << 737 | typeid(T).name() << "\n" << 738 | "\n(Try 'c++filt -t ' to demangle the type name.)"; 739 | throw(std::runtime_error(ss.str())); 740 | } 741 | 742 | private: 743 | // For boost::serialization, we must make our superclass our friend! 744 | friend class boost::archive::detail::common_iarchive; 745 | const std::map _archiveMap; 746 | }; 747 | 748 | BOOST_SERIALIZATION_REGISTER_ARCHIVE(Oarchive_xmlrpc_c) 749 | BOOST_SERIALIZATION_REGISTER_ARCHIVE(Iarchive_xmlrpc_c) 750 | 751 | /// Mix-in class which allows objects of its class to be serialized to/from 752 | /// Oarchive_xmlrpc_c/Iarchive_xmlrpc_c archives as composite members 753 | /// of other classes. 754 | /// 755 | /// Members of this class must provide a boost::serialization serialize() 756 | /// template method which serializes to/from boost::serialization::nvp 757 | /// name-value pair representation. 758 | template 759 | class XmlrpcSerializable : public T { 760 | public: 761 | /// @brief Default constructor 762 | XmlrpcSerializable() : T() {} 763 | 764 | /// @brief Constructor which copies from an instance of T 765 | /// @param t the instance of type T to copy 766 | XmlrpcSerializable(const T & t) : T(t) {} 767 | 768 | /// @brief Construct from an xmlrpc_c::value (which must be 769 | /// xmlrpc_c::value_struct) 770 | /// @param xmlrpcVal the xmlrpc_c::value holding the content from which 771 | /// to construct 772 | XmlrpcSerializable(const xmlrpc_c::value & xmlrpcVal) : T() { 773 | // Cast the xmlrpc_c::value to xmlrpc_c::value_struct, then from that 774 | // to std::map. 775 | xmlrpc_c::value_struct statusStruct(xmlrpcVal); 776 | std::map statusMap(statusStruct); 777 | 778 | // Create an input archiver wrapper around the map and use serialize() 779 | // to populate our members from its content. 780 | Iarchive_xmlrpc_c iar(statusMap); 781 | iar >> *this; 782 | } 783 | 784 | virtual ~XmlrpcSerializable() {}; 785 | 786 | /// @brief Cast to xmlrpc_c::value 787 | operator xmlrpc_c::value() const { return(_toXmlRpcValueStruct()); } 788 | 789 | private: 790 | /// @brief Return an xmlrpc_c::value containing a struct (dictionary) with 791 | /// the object's serialized representation 792 | xmlrpc_c::value_struct _toXmlRpcValueStruct() const { 793 | std::map statusMap; 794 | // Stuff our content into the statusMap, i.e., _serialize() to an 795 | // output archiver wrapped around the statusMap. 796 | Oarchive_xmlrpc_c oar(statusMap); 797 | oar << *this; 798 | // Finally, return a value_struct constructed from the map 799 | return(xmlrpc_c::value_struct(statusMap)); 800 | } 801 | 802 | }; 803 | 804 | 805 | #endif // ifndef _ARCHIVE_XMLRPC_C_H_ 806 | --------------------------------------------------------------------------------