initial load of upstream version 1.06.32
[xmlrpc-c] / src / cpp / value.cpp
1 /*****************************************************************************
2                                 value.cpp
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.
7
8   Everything is based on the C services in libxmlrpc.
9
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.
13
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.
17
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<>.
22
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
27   those members.
28
29 *****************************************************************************/
30
31 #include <cstdlib>
32 #include <string>
33 #include <vector>
34 #include <time.h>
35
36 #include "xmlrpc-c/girerr.hpp"
37 using girerr::error;
38 #include "xmlrpc-c/base.h"
39 #include "xmlrpc-c/base_int.h"
40 #include "env_wrap.hpp"
41
42 #include "xmlrpc-c/base.hpp"
43
44 using namespace std;
45 using namespace xmlrpc_c;
46
47 namespace {
48
49 void
50 throwIfError(env_wrap const& env) {
51
52     if (env.env_c.fault_occurred)
53         throw(error(env.env_c.fault_string));
54 }
55
56
57
58 class cDatetimeValueWrapper {
59 public:
60     xmlrpc_value * valueP;
61     
62     cDatetimeValueWrapper(time_t const cppvalue) {
63         env_wrap env;
64         
65         this->valueP = xmlrpc_datetime_new_sec(&env.env_c, cppvalue);
66         throwIfError(env);
67     }
68     ~cDatetimeValueWrapper() {
69         xmlrpc_DECREF(this->valueP);
70     }
71 };
72
73
74 class cStringWrapper {
75 public:
76     const char * str;
77     size_t length;
78     cStringWrapper(xmlrpc_value * valueP) {
79         env_wrap env;
80
81         xmlrpc_read_string_lp(&env.env_c, valueP, &length, &str);
82         throwIfError(env);
83     }
84     ~cStringWrapper() {
85         free((char*)str);
86     }
87 };
88
89
90
91 } // namespace
92
93
94
95 namespace xmlrpc_c {
96
97 value::value() {
98     this->cValueP = NULL;
99 }
100
101
102
103 value::value(xmlrpc_value * const valueP) {  // default constructor
104
105     this->instantiate(valueP);
106 }
107
108
109
110 value::value(xmlrpc_c::value const& value) {  // copy constructor
111     this->cValueP = value.cValue();
112 }
113
114
115
116 xmlrpc_c::value&
117 value::operator=(xmlrpc_c::value const& value) {
118
119     if (this->cValueP != NULL)
120         throw(error("Assigning to already instantiated xmlrpc_c::value"));
121
122     this->cValueP = value.cValue();
123     return *this;  // The result of the (a = b) expression
124 }
125
126
127
128 value::~value() {
129     if (this->cValueP) {
130         xmlrpc_DECREF(this->cValueP);
131     }
132 }
133
134
135
136 void
137 value::instantiate(xmlrpc_value * const valueP) {
138
139     xmlrpc_INCREF(valueP);
140     this->cValueP = valueP;
141 }
142
143
144
145 xmlrpc_value *
146 value::cValue() const {
147
148     if (this->cValueP) {
149         xmlrpc_INCREF(this->cValueP);  // For Caller
150     }
151     return this->cValueP;
152 }
153
154
155
156 void
157 value::appendToCArray(xmlrpc_value * const arrayP) const {
158 /*----------------------------------------------------------------------------
159   Append this value to the C array 'arrayP'.
160 ----------------------------------------------------------------------------*/
161     env_wrap env;
162
163     xmlrpc_array_append_item(&env.env_c, arrayP, this->cValueP);
164
165     throwIfError(env);
166 }
167
168
169
170 void
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 ----------------------------------------------------------------------------*/
176     env_wrap env;
177
178     xmlrpc_struct_set_value_n(&env.env_c, structP,
179                               key.c_str(), key.length(),
180                               this->cValueP);
181
182     throwIfError(env);
183 }
184
185
186
187 value::type_t 
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.
192     */
193     union {
194         xmlrpc_type   x;
195         value::type_t y;
196     } u;
197
198     u.x = xmlrpc_value_type(this->cValueP);
199
200     return u.y;
201 }
202
203
204
205 value_int::value_int(int const cppvalue) {
206
207     class cWrapper {
208     public:
209         xmlrpc_value * valueP;
210         
211         cWrapper(int const cppvalue) {
212             env_wrap env;
213             
214             this->valueP = xmlrpc_int_new(&env.env_c, cppvalue);
215             throwIfError(env);
216         }
217         ~cWrapper() {
218             xmlrpc_DECREF(this->valueP);
219         }
220     };
221     
222     cWrapper wrapper(cppvalue);
223     
224     this->instantiate(wrapper.valueP);
225 }
226
227
228
229 value_int::value_int(xmlrpc_c::value const baseValue) {
230
231     if (baseValue.type() != xmlrpc_c::value::TYPE_INT)
232         throw(error("Not integer type.  See type() method"));
233     else {
234         this->instantiate(baseValue.cValueP);
235     }
236 }
237
238
239
240 value_int::operator int() const {
241
242     int retval;
243     env_wrap env;
244
245     xmlrpc_read_int(&env.env_c, this->cValueP, &retval);
246     throwIfError(env);
247
248     return retval;
249 }
250
251
252
253 value_double::value_double(double const cppvalue) {
254
255     class cWrapper {
256     public:
257         xmlrpc_value * valueP;
258         
259         cWrapper(double const cppvalue) {
260             env_wrap env;
261             
262             this->valueP = xmlrpc_double_new(&env.env_c, cppvalue);
263             throwIfError(env);
264         }
265         ~cWrapper() {
266             xmlrpc_DECREF(this->valueP);
267         }
268     };
269     
270     this->instantiate(cWrapper(cppvalue).valueP);
271 }
272
273
274
275 value_double::value_double(xmlrpc_c::value const baseValue) {
276
277     if (baseValue.type() != xmlrpc_c::value::TYPE_DOUBLE)
278         throw(error("Not double type.  See type() method"));
279     else {
280         this->instantiate(baseValue.cValueP);
281     }
282 }
283
284
285
286 value_double::operator double() const {
287
288     double retval;
289
290     env_wrap env;
291
292     xmlrpc_read_double(&env.env_c, this->cValueP, &retval);
293     throwIfError(env);
294
295     return retval;
296 }
297
298
299
300 value_boolean::value_boolean(bool const cppvalue) {
301
302     class cWrapper {
303     public:
304         xmlrpc_value * valueP;
305         
306         cWrapper(xmlrpc_bool const cppvalue) {
307             env_wrap env;
308             
309             this->valueP = xmlrpc_bool_new(&env.env_c, cppvalue);
310             throwIfError(env);
311         }
312         ~cWrapper() {
313             xmlrpc_DECREF(this->valueP);
314         }
315     };
316     
317     cWrapper wrapper(cppvalue);
318     
319     this->instantiate(wrapper.valueP);
320 }
321
322
323
324 value_boolean::operator bool() const {
325
326     xmlrpc_bool retval;
327
328     env_wrap env;
329
330     xmlrpc_read_bool(&env.env_c, this->cValueP, &retval);
331     throwIfError(env);
332
333     return (bool)retval;
334 }
335
336
337
338 value_boolean::value_boolean(xmlrpc_c::value const baseValue) {
339
340     if (baseValue.type() != xmlrpc_c::value::TYPE_BOOLEAN)
341         throw(error("Not boolean type.  See type() method"));
342     else {
343         this->instantiate(baseValue.cValueP);
344     }
345 }
346
347
348
349 value_datetime::value_datetime(string const cppvalue) {
350
351     class cWrapper {
352     public:
353         xmlrpc_value * valueP;
354         
355         cWrapper(string const cppvalue) {
356             env_wrap env;
357             
358             this->valueP = xmlrpc_datetime_new_str(&env.env_c,
359                                                    cppvalue.c_str());
360             throwIfError(env);
361         }
362         ~cWrapper() {
363             xmlrpc_DECREF(this->valueP);
364         }
365     };
366     
367     cWrapper wrapper(cppvalue);
368     
369     this->instantiate(wrapper.valueP);
370 }
371
372
373
374 value_datetime::value_datetime(time_t const cppvalue) {
375
376     cDatetimeValueWrapper wrapper(cppvalue);
377     
378     this->instantiate(wrapper.valueP);
379 }
380
381
382
383 value_datetime::value_datetime(struct timeval const& cppvalue) {
384
385     cDatetimeValueWrapper wrapper(cppvalue.tv_sec);
386
387     this->instantiate(wrapper.valueP);
388 }
389
390
391
392 value_datetime::value_datetime(struct timespec const& cppvalue) {
393
394     cDatetimeValueWrapper wrapper(cppvalue.tv_sec);
395
396     this->instantiate(wrapper.valueP);
397 }
398
399
400
401 value_datetime::value_datetime(xmlrpc_c::value const baseValue) {
402
403     if (baseValue.type() != xmlrpc_c::value::TYPE_DATETIME)
404         throw(error("Not datetime type.  See type() method"));
405     else {
406         this->instantiate(baseValue.cValueP);
407     }
408 }
409
410
411
412 value_datetime::operator time_t() const {
413
414     time_t retval;
415     env_wrap env;
416
417     xmlrpc_read_datetime_sec(&env.env_c, this->cValueP, &retval);
418     throwIfError(env);
419
420     return retval;
421 }
422
423
424
425 value_string::value_string(string const& cppvalue) {
426     
427     class cWrapper {
428     public:
429         xmlrpc_value * valueP;
430         
431         cWrapper(string const cppvalue) {
432             env_wrap env;
433             
434             this->valueP = xmlrpc_string_new(&env.env_c, cppvalue.c_str());
435             throwIfError(env);
436         }
437         ~cWrapper() {
438             xmlrpc_DECREF(this->valueP);
439         }
440     };
441     
442     cWrapper wrapper(cppvalue);
443     
444     this->instantiate(wrapper.valueP);
445 }
446
447
448
449 value_string::value_string(xmlrpc_c::value const baseValue) {
450
451     if (baseValue.type() != xmlrpc_c::value::TYPE_STRING)
452         throw(error("Not string type.  See type() method"));
453     else {
454         this->instantiate(baseValue.cValueP);
455     }
456 }
457
458
459
460 value_string::operator string() const {
461
462     env_wrap env;
463
464     cStringWrapper adapter(this->cValueP);
465
466     return string(adapter.str, adapter.length);
467 }
468
469
470
471 value_bytestring::value_bytestring(
472     vector<unsigned char> const& cppvalue) {
473
474     class cWrapper {
475     public:
476         xmlrpc_value * valueP;
477         
478         cWrapper(vector<unsigned char> const& cppvalue) {
479             env_wrap env;
480             
481             this->valueP = 
482                 xmlrpc_base64_new(&env.env_c, cppvalue.size(), &cppvalue[0]);
483             throwIfError(env);
484         }
485         ~cWrapper() {
486             xmlrpc_DECREF(this->valueP);
487         }
488     };
489     
490     cWrapper wrapper(cppvalue);
491     
492     this->instantiate(wrapper.valueP);
493 }
494
495
496
497 vector<unsigned char>
498 value_bytestring::vectorUcharValue() const {
499
500     class cWrapper {
501     public:
502         const unsigned char * contents;
503         size_t length;
504
505         cWrapper(xmlrpc_value * const valueP) {
506             env_wrap env;
507
508             xmlrpc_read_base64(&env.env_c, valueP, &length, &contents);
509             throwIfError(env);
510         }
511         ~cWrapper() {
512             free((void*)contents);
513         }
514     };
515     
516     cWrapper wrapper(this->cValueP);
517
518     return vector<unsigned char>(&wrapper.contents[0], 
519                                  &wrapper.contents[wrapper.length]);
520 }
521
522
523
524 size_t
525 value_bytestring::length() const {
526
527     env_wrap env;
528     size_t length;
529
530     xmlrpc_read_base64_size(&env.env_c, this->cValueP, &length);
531     throwIfError(env);
532
533     return length;
534 }
535
536
537
538 value_bytestring::value_bytestring(xmlrpc_c::value const baseValue) {
539
540     if (baseValue.type() != xmlrpc_c::value::TYPE_BYTESTRING)
541         throw(error("Not byte string type.  See type() method"));
542     else {
543         this->instantiate(baseValue.cValueP);
544     }
545 }
546
547
548
549 value_array::value_array(vector<xmlrpc_c::value> const& cppvalue) {
550     
551     class cWrapper {
552     public:
553         xmlrpc_value * valueP;
554         
555         cWrapper() {
556             env_wrap env;
557             
558             this->valueP = xmlrpc_array_new(&env.env_c);
559             throwIfError(env);
560         }
561         ~cWrapper() {
562             xmlrpc_DECREF(this->valueP);
563         }
564     };
565     
566     cWrapper wrapper;
567     
568     vector<xmlrpc_c::value>::const_iterator i;
569     for (i = cppvalue.begin(); i != cppvalue.end(); ++i)
570         i->appendToCArray(wrapper.valueP);
571
572     this->instantiate(wrapper.valueP);
573 }
574
575
576
577 value_array::value_array(xmlrpc_c::value const baseValue) {
578
579     if (baseValue.type() != xmlrpc_c::value::TYPE_ARRAY)
580         throw(error("Not array type.  See type() method"));
581     else {
582         this->instantiate(baseValue.cValueP);
583     }
584 }
585
586
587
588 vector<xmlrpc_c::value>
589 value_array::vectorValueValue() const {
590
591     env_wrap env;
592
593     unsigned int arraySize;
594
595     arraySize = xmlrpc_array_size(&env.env_c, this->cValueP);
596     throwIfError(env);
597     
598     vector<xmlrpc_c::value> retval(arraySize);
599     
600     for (unsigned int i = 0; i < arraySize; ++i) {
601
602         class cWrapper {
603         public:
604             xmlrpc_value * valueP;
605
606             cWrapper(xmlrpc_value * const arrayP,
607                      unsigned int   const index) {
608                 env_wrap env;
609
610                 xmlrpc_array_read_item(&env.env_c, arrayP, index, &valueP);
611                 
612                 throwIfError(env);
613             }
614             ~cWrapper() {
615                 xmlrpc_DECREF(valueP);
616             }
617         };
618
619         cWrapper wrapper(this->cValueP, i);
620
621         retval[i].instantiate(wrapper.valueP);
622     }
623
624     return retval;
625 }
626
627
628
629 size_t
630 value_array::size() const {
631
632     env_wrap env;
633     unsigned int arraySize;
634
635     arraySize = xmlrpc_array_size(&env.env_c, this->cValueP);
636     throwIfError(env);
637     
638     return arraySize;
639 }
640
641
642
643 value_struct::value_struct(
644     map<string, xmlrpc_c::value> const &cppvalue) {
645
646     class cWrapper {
647     public:
648         xmlrpc_value * valueP;
649         
650         cWrapper() {
651             env_wrap env;
652             
653             this->valueP = xmlrpc_struct_new(&env.env_c);
654             throwIfError(env);
655         }
656         ~cWrapper() {
657             xmlrpc_DECREF(this->valueP);
658         }
659     };
660     
661     cWrapper wrapper;
662
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);
668     }
669     
670     this->instantiate(wrapper.valueP);
671 }
672
673
674
675 value_struct::value_struct(xmlrpc_c::value const baseValue) {
676
677     if (baseValue.type() != xmlrpc_c::value::TYPE_STRUCT)
678         throw(error("Not struct type.  See type() method"));
679     else {
680         this->instantiate(baseValue.cValueP);
681     }
682 }
683
684
685
686 value_struct::operator map<string, xmlrpc_c::value>() const {
687
688     env_wrap env;
689     unsigned int structSize;
690
691     structSize = xmlrpc_struct_size(&env.env_c, this->cValueP);
692     throwIfError(env);
693     
694     map<string, xmlrpc_c::value> retval;
695     
696     for (unsigned int i = 0; i < structSize; ++i) {
697         class cMemberWrapper {
698         public:
699             xmlrpc_value * keyP;
700             xmlrpc_value * valueP;
701
702             cMemberWrapper(xmlrpc_value * const structP,
703                            unsigned int   const index) {
704
705                 env_wrap env;
706             
707                 xmlrpc_struct_read_member(&env.env_c, structP, index, 
708                                           &keyP, &valueP);
709                 
710                 throwIfError(env);
711             }
712             ~cMemberWrapper() {
713                 xmlrpc_DECREF(keyP);
714                 xmlrpc_DECREF(valueP);
715             }
716         };
717
718         cMemberWrapper memberWrapper(this->cValueP, i);
719
720         cStringWrapper keyWrapper(memberWrapper.keyP);
721
722         string const key(keyWrapper.str, keyWrapper.length);
723
724         retval[key] = xmlrpc_c::value(memberWrapper.valueP);
725     }
726
727     return retval;
728 }
729
730
731
732 value_nil::value_nil() {
733     
734     class cWrapper {
735     public:
736         xmlrpc_value * valueP;
737         
738         cWrapper() {
739             env_wrap env;
740             
741             this->valueP = xmlrpc_nil_new(&env.env_c);
742             throwIfError(env);
743         }
744         ~cWrapper() {
745             xmlrpc_DECREF(this->valueP);
746         }
747     };
748     
749     cWrapper wrapper;
750     
751     this->instantiate(wrapper.valueP);
752 }
753     
754
755
756 value_nil::value_nil(xmlrpc_c::value const baseValue) {
757
758     if (baseValue.type() != xmlrpc_c::value::TYPE_NIL)
759         throw(error("Not nil type.  See type() method"));
760     else {
761         this->instantiate(baseValue.cValueP);
762     }
763 }
764
765
766
767 } // namespace
768