1 /*****************************************************************************
3 ******************************************************************************
4 This module provides services for dealing with XML-RPC values. Each
5 type of XML-RPC value is a C++ class. An object represents a
6 particular XML-RPC value.
8 Everything is based on the C services in libxmlrpc.
10 We could make things more efficient by using the internal interfaces
11 via xmlrpc_int.h. We could make them even more efficient by dumping
12 libxmlrpc altogether for some or all of these services.
14 An xmlrpc_c::value object is really just a handle for a C xmlrpc_value
15 object. You're not supposed to make a pointer to an xmlrpc_c::value
16 object, but rather copy the object around.
18 Because the C xmlrpc_value object does reference counting, it
19 disappears automatically when the last handle does. To go pure C++,
20 we'd have to have a C++ object for the value itself and a separate
21 handle object, like Boost's shared_ptr<>.
23 The C++ is designed so that the user never sees the C interface at
24 all. Unfortunately, the user can see it if he wants because some
25 class members had to be declared public so that other components of
26 the library could see them, but the user is not supposed to access
29 *****************************************************************************/
36 #include "xmlrpc-c/girerr.hpp"
38 #include "xmlrpc-c/base.h"
39 #include "xmlrpc-c/base_int.h"
40 #include "env_wrap.hpp"
42 #include "xmlrpc-c/base.hpp"
45 using namespace xmlrpc_c;
50 throwIfError(env_wrap const& env) {
52 if (env.env_c.fault_occurred)
53 throw(error(env.env_c.fault_string));
58 class cDatetimeValueWrapper {
60 xmlrpc_value * valueP;
62 cDatetimeValueWrapper(time_t const cppvalue) {
65 this->valueP = xmlrpc_datetime_new_sec(&env.env_c, cppvalue);
68 ~cDatetimeValueWrapper() {
69 xmlrpc_DECREF(this->valueP);
74 class cStringWrapper {
78 cStringWrapper(xmlrpc_value * valueP) {
81 xmlrpc_read_string_lp(&env.env_c, valueP, &length, &str);
103 value::value(xmlrpc_value * const valueP) { // default constructor
105 this->instantiate(valueP);
110 value::value(xmlrpc_c::value const& value) { // copy constructor
111 this->cValueP = value.cValue();
117 value::operator=(xmlrpc_c::value const& value) {
119 if (this->cValueP != NULL)
120 throw(error("Assigning to already instantiated xmlrpc_c::value"));
122 this->cValueP = value.cValue();
123 return *this; // The result of the (a = b) expression
130 xmlrpc_DECREF(this->cValueP);
137 value::instantiate(xmlrpc_value * const valueP) {
139 xmlrpc_INCREF(valueP);
140 this->cValueP = valueP;
146 value::cValue() const {
149 xmlrpc_INCREF(this->cValueP); // For Caller
151 return this->cValueP;
157 value::appendToCArray(xmlrpc_value * const arrayP) const {
158 /*----------------------------------------------------------------------------
159 Append this value to the C array 'arrayP'.
160 ----------------------------------------------------------------------------*/
163 xmlrpc_array_append_item(&env.env_c, arrayP, this->cValueP);
171 value::addToCStruct(xmlrpc_value * const structP,
172 string const key) const {
173 /*----------------------------------------------------------------------------
174 Add this value to the C array 'arrayP' with key 'key'.
175 ----------------------------------------------------------------------------*/
178 xmlrpc_struct_set_value_n(&env.env_c, structP,
179 key.c_str(), key.length(),
188 value::type() const {
189 /* You'd think we could just cast from xmlrpc_type to
190 value:type_t, but Gcc warns if we do that. So we have to do this
191 even messier union nonsense.
198 u.x = xmlrpc_value_type(this->cValueP);
205 value_int::value_int(int const cppvalue) {
209 xmlrpc_value * valueP;
211 cWrapper(int const cppvalue) {
214 this->valueP = xmlrpc_int_new(&env.env_c, cppvalue);
218 xmlrpc_DECREF(this->valueP);
222 cWrapper wrapper(cppvalue);
224 this->instantiate(wrapper.valueP);
229 value_int::value_int(xmlrpc_c::value const baseValue) {
231 if (baseValue.type() != xmlrpc_c::value::TYPE_INT)
232 throw(error("Not integer type. See type() method"));
234 this->instantiate(baseValue.cValueP);
240 value_int::operator int() const {
245 xmlrpc_read_int(&env.env_c, this->cValueP, &retval);
253 value_double::value_double(double const cppvalue) {
257 xmlrpc_value * valueP;
259 cWrapper(double const cppvalue) {
262 this->valueP = xmlrpc_double_new(&env.env_c, cppvalue);
266 xmlrpc_DECREF(this->valueP);
270 this->instantiate(cWrapper(cppvalue).valueP);
275 value_double::value_double(xmlrpc_c::value const baseValue) {
277 if (baseValue.type() != xmlrpc_c::value::TYPE_DOUBLE)
278 throw(error("Not double type. See type() method"));
280 this->instantiate(baseValue.cValueP);
286 value_double::operator double() const {
292 xmlrpc_read_double(&env.env_c, this->cValueP, &retval);
300 value_boolean::value_boolean(bool const cppvalue) {
304 xmlrpc_value * valueP;
306 cWrapper(xmlrpc_bool const cppvalue) {
309 this->valueP = xmlrpc_bool_new(&env.env_c, cppvalue);
313 xmlrpc_DECREF(this->valueP);
317 cWrapper wrapper(cppvalue);
319 this->instantiate(wrapper.valueP);
324 value_boolean::operator bool() const {
330 xmlrpc_read_bool(&env.env_c, this->cValueP, &retval);
338 value_boolean::value_boolean(xmlrpc_c::value const baseValue) {
340 if (baseValue.type() != xmlrpc_c::value::TYPE_BOOLEAN)
341 throw(error("Not boolean type. See type() method"));
343 this->instantiate(baseValue.cValueP);
349 value_datetime::value_datetime(string const cppvalue) {
353 xmlrpc_value * valueP;
355 cWrapper(string const cppvalue) {
358 this->valueP = xmlrpc_datetime_new_str(&env.env_c,
363 xmlrpc_DECREF(this->valueP);
367 cWrapper wrapper(cppvalue);
369 this->instantiate(wrapper.valueP);
374 value_datetime::value_datetime(time_t const cppvalue) {
376 cDatetimeValueWrapper wrapper(cppvalue);
378 this->instantiate(wrapper.valueP);
383 value_datetime::value_datetime(struct timeval const& cppvalue) {
385 cDatetimeValueWrapper wrapper(cppvalue.tv_sec);
387 this->instantiate(wrapper.valueP);
392 value_datetime::value_datetime(struct timespec const& cppvalue) {
394 cDatetimeValueWrapper wrapper(cppvalue.tv_sec);
396 this->instantiate(wrapper.valueP);
401 value_datetime::value_datetime(xmlrpc_c::value const baseValue) {
403 if (baseValue.type() != xmlrpc_c::value::TYPE_DATETIME)
404 throw(error("Not datetime type. See type() method"));
406 this->instantiate(baseValue.cValueP);
412 value_datetime::operator time_t() const {
417 xmlrpc_read_datetime_sec(&env.env_c, this->cValueP, &retval);
425 value_string::value_string(string const& cppvalue) {
429 xmlrpc_value * valueP;
431 cWrapper(string const cppvalue) {
434 this->valueP = xmlrpc_string_new(&env.env_c, cppvalue.c_str());
438 xmlrpc_DECREF(this->valueP);
442 cWrapper wrapper(cppvalue);
444 this->instantiate(wrapper.valueP);
449 value_string::value_string(xmlrpc_c::value const baseValue) {
451 if (baseValue.type() != xmlrpc_c::value::TYPE_STRING)
452 throw(error("Not string type. See type() method"));
454 this->instantiate(baseValue.cValueP);
460 value_string::operator string() const {
464 cStringWrapper adapter(this->cValueP);
466 return string(adapter.str, adapter.length);
471 value_bytestring::value_bytestring(
472 vector<unsigned char> const& cppvalue) {
476 xmlrpc_value * valueP;
478 cWrapper(vector<unsigned char> const& cppvalue) {
482 xmlrpc_base64_new(&env.env_c, cppvalue.size(), &cppvalue[0]);
486 xmlrpc_DECREF(this->valueP);
490 cWrapper wrapper(cppvalue);
492 this->instantiate(wrapper.valueP);
497 vector<unsigned char>
498 value_bytestring::vectorUcharValue() const {
502 const unsigned char * contents;
505 cWrapper(xmlrpc_value * const valueP) {
508 xmlrpc_read_base64(&env.env_c, valueP, &length, &contents);
512 free((void*)contents);
516 cWrapper wrapper(this->cValueP);
518 return vector<unsigned char>(&wrapper.contents[0],
519 &wrapper.contents[wrapper.length]);
525 value_bytestring::length() const {
530 xmlrpc_read_base64_size(&env.env_c, this->cValueP, &length);
538 value_bytestring::value_bytestring(xmlrpc_c::value const baseValue) {
540 if (baseValue.type() != xmlrpc_c::value::TYPE_BYTESTRING)
541 throw(error("Not byte string type. See type() method"));
543 this->instantiate(baseValue.cValueP);
549 value_array::value_array(vector<xmlrpc_c::value> const& cppvalue) {
553 xmlrpc_value * valueP;
558 this->valueP = xmlrpc_array_new(&env.env_c);
562 xmlrpc_DECREF(this->valueP);
568 vector<xmlrpc_c::value>::const_iterator i;
569 for (i = cppvalue.begin(); i != cppvalue.end(); ++i)
570 i->appendToCArray(wrapper.valueP);
572 this->instantiate(wrapper.valueP);
577 value_array::value_array(xmlrpc_c::value const baseValue) {
579 if (baseValue.type() != xmlrpc_c::value::TYPE_ARRAY)
580 throw(error("Not array type. See type() method"));
582 this->instantiate(baseValue.cValueP);
588 vector<xmlrpc_c::value>
589 value_array::vectorValueValue() const {
593 unsigned int arraySize;
595 arraySize = xmlrpc_array_size(&env.env_c, this->cValueP);
598 vector<xmlrpc_c::value> retval(arraySize);
600 for (unsigned int i = 0; i < arraySize; ++i) {
604 xmlrpc_value * valueP;
606 cWrapper(xmlrpc_value * const arrayP,
607 unsigned int const index) {
610 xmlrpc_array_read_item(&env.env_c, arrayP, index, &valueP);
615 xmlrpc_DECREF(valueP);
619 cWrapper wrapper(this->cValueP, i);
621 retval[i].instantiate(wrapper.valueP);
630 value_array::size() const {
633 unsigned int arraySize;
635 arraySize = xmlrpc_array_size(&env.env_c, this->cValueP);
643 value_struct::value_struct(
644 map<string, xmlrpc_c::value> const &cppvalue) {
648 xmlrpc_value * valueP;
653 this->valueP = xmlrpc_struct_new(&env.env_c);
657 xmlrpc_DECREF(this->valueP);
663 map<string, xmlrpc_c::value>::const_iterator i;
664 for (i = cppvalue.begin(); i != cppvalue.end(); ++i) {
665 xmlrpc_c::value mapvalue(i->second);
666 string mapkey(i->first);
667 mapvalue.addToCStruct(wrapper.valueP, mapkey);
670 this->instantiate(wrapper.valueP);
675 value_struct::value_struct(xmlrpc_c::value const baseValue) {
677 if (baseValue.type() != xmlrpc_c::value::TYPE_STRUCT)
678 throw(error("Not struct type. See type() method"));
680 this->instantiate(baseValue.cValueP);
686 value_struct::operator map<string, xmlrpc_c::value>() const {
689 unsigned int structSize;
691 structSize = xmlrpc_struct_size(&env.env_c, this->cValueP);
694 map<string, xmlrpc_c::value> retval;
696 for (unsigned int i = 0; i < structSize; ++i) {
697 class cMemberWrapper {
700 xmlrpc_value * valueP;
702 cMemberWrapper(xmlrpc_value * const structP,
703 unsigned int const index) {
707 xmlrpc_struct_read_member(&env.env_c, structP, index,
714 xmlrpc_DECREF(valueP);
718 cMemberWrapper memberWrapper(this->cValueP, i);
720 cStringWrapper keyWrapper(memberWrapper.keyP);
722 string const key(keyWrapper.str, keyWrapper.length);
724 retval[key] = xmlrpc_c::value(memberWrapper.valueP);
732 value_nil::value_nil() {
736 xmlrpc_value * valueP;
741 this->valueP = xmlrpc_nil_new(&env.env_c);
745 xmlrpc_DECREF(this->valueP);
751 this->instantiate(wrapper.valueP);
756 value_nil::value_nil(xmlrpc_c::value const baseValue) {
758 if (baseValue.type() != xmlrpc_c::value::TYPE_NIL)
759 throw(error("Not nil type. See type() method"));
761 this->instantiate(baseValue.cValueP);