initial load of upstream version 1.06.32
[xmlrpc-c] / src / cpp / XmlRpcCpp.cpp
1 // Copyright (C) 2001 by Eric Kidd. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions
5 // are met:
6 // 1. Redistributions of source code must retain the above copyright
7 //    notice, this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright
9 //    notice, this list of conditions and the following disclaimer in the
10 //    documentation and/or other materials provided with the distribution.
11 // 3. The name of the author may not be used to endorse or promote products
12 //    derived from this software without specific prior written permission. 
13 //  
14 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 // SUCH DAMAGE.
25
26
27 #include <string>
28 #include <cstring>
29
30 #include "xmlrpc-c/oldcppwrapper.hpp"
31
32 using std::string;
33
34 //=========================================================================
35 //  XmlRpcFault Methods
36 //=========================================================================
37
38 XmlRpcFault::XmlRpcFault (const XmlRpcFault &fault) {
39     xmlrpc_env_init(&mFault);
40     xmlrpc_env_set_fault(&mFault,
41                          fault.mFault.fault_code,
42                          fault.mFault.fault_string);
43 }
44
45 XmlRpcFault::XmlRpcFault (const int faultCode, const string faultString) {
46     xmlrpc_env_init(&mFault);
47     xmlrpc_env_set_fault(&mFault, faultCode,
48                          const_cast<char*>(faultString.c_str()));
49 }
50  
51 XmlRpcFault::XmlRpcFault (const xmlrpc_env *env) {
52     if (!env->fault_string)
53         throw XmlRpcFault(XMLRPC_INTERNAL_ERROR,
54                           "Tried to create empty fault");
55     xmlrpc_env_init(&mFault);
56     xmlrpc_env_set_fault(&mFault, env->fault_code,
57                          const_cast<char*>(env->fault_string));
58 }
59
60 XmlRpcFault::~XmlRpcFault (void) {
61     xmlrpc_env_clean(&mFault);
62 }
63
64 string XmlRpcFault::getFaultString (void) const {
65     XMLRPC_ASSERT(mFault.fault_occurred);
66     return string(mFault.fault_string);
67 }
68
69
70 //=========================================================================
71 //  XmlRpcEnv Methods
72 //=========================================================================
73
74 XmlRpcEnv::XmlRpcEnv (const XmlRpcEnv &env) {
75     xmlrpc_env_init(&mEnv);
76     if (env.hasFaultOccurred())
77         xmlrpc_env_set_fault(&mEnv,
78                              env.mEnv.fault_code,
79                              env.mEnv.fault_string);
80 }
81
82 XmlRpcFault XmlRpcEnv::getFault (void) const {
83     return XmlRpcFault(&mEnv);
84 }
85
86 void XmlRpcEnv::throwMe (void) const {
87     throw XmlRpcFault(&mEnv);
88 }
89
90
91 //=========================================================================
92 //  XmlRpcValue Methods
93 //=========================================================================
94
95 // If the user doesn't tell us what kind of value to create, use
96 // a false boolean value as the default.
97 XmlRpcValue::XmlRpcValue (void) {
98     XmlRpcEnv env;
99     mValue = xmlrpc_build_value(env, "b", (xmlrpc_bool) 0);
100     env.throwIfFaultOccurred();
101 }
102
103 XmlRpcValue XmlRpcValue::makeInt (const XmlRpcValue::int32 i) {
104     XmlRpcEnv env;
105     xmlrpc_value *value = xmlrpc_build_value(env, "i", i);
106     env.throwIfFaultOccurred();
107     return XmlRpcValue(value, CONSUME_REFERENCE);
108 }
109
110 XmlRpcValue XmlRpcValue::makeBool (const bool b) {
111     XmlRpcEnv env;
112     xmlrpc_value *value = xmlrpc_build_value(env, "b", (xmlrpc_bool) b);
113     env.throwIfFaultOccurred();
114     return XmlRpcValue(value, CONSUME_REFERENCE);
115 }
116
117 XmlRpcValue XmlRpcValue::makeDouble (const double d) {
118     XmlRpcEnv env;
119     xmlrpc_value *value = xmlrpc_build_value(env, "d", d);
120     env.throwIfFaultOccurred();
121     return XmlRpcValue(value, CONSUME_REFERENCE);
122 }
123
124 XmlRpcValue XmlRpcValue::makeDateTime (const string& dateTime) {
125     XmlRpcEnv env;
126     xmlrpc_value *value;
127     const char *data = dateTime.c_str(); // Make sure we're not using wchar_t.
128     value = xmlrpc_build_value(env, "8", data);
129     env.throwIfFaultOccurred();
130     return XmlRpcValue(value, CONSUME_REFERENCE);    
131 }
132
133 XmlRpcValue XmlRpcValue::makeString (const string& str) {
134     XmlRpcEnv env;
135     const char *data = str.data();      // Make sure we're not using wchar_t.
136     size_t size = str.size();
137     xmlrpc_value *value = xmlrpc_build_value(env, "s#", data, size);
138     env.throwIfFaultOccurred();
139     return XmlRpcValue(value, CONSUME_REFERENCE);    
140 }
141
142 XmlRpcValue XmlRpcValue::makeString (const char *const str) {
143     XmlRpcEnv env;
144     xmlrpc_value *value = xmlrpc_build_value(env, "s", str);
145     env.throwIfFaultOccurred();
146     return XmlRpcValue(value, CONSUME_REFERENCE);    
147 }
148
149 XmlRpcValue XmlRpcValue::makeString (const char *const str, size_t len) {
150     XmlRpcEnv env;
151     xmlrpc_value *value = xmlrpc_build_value(env, "s#", str, len);
152     env.throwIfFaultOccurred();
153     return XmlRpcValue(value, CONSUME_REFERENCE);    
154 }
155
156 XmlRpcValue XmlRpcValue::makeArray (void) {
157     XmlRpcEnv env;
158     xmlrpc_value *value = xmlrpc_build_value(env, "()");
159     env.throwIfFaultOccurred();
160     return XmlRpcValue(value, CONSUME_REFERENCE);    
161 }
162
163 XmlRpcValue XmlRpcValue::makeStruct (void) {
164     XmlRpcEnv env;
165     xmlrpc_value *value = xmlrpc_struct_new(env);
166     env.throwIfFaultOccurred();
167     return XmlRpcValue(value, CONSUME_REFERENCE);
168 }
169
170 XmlRpcValue XmlRpcValue::makeBase64 (const unsigned char *const data,
171                                      size_t len)
172 {
173     XmlRpcEnv env;
174     xmlrpc_value *value = xmlrpc_build_value(env, "6", data, len);
175     env.throwIfFaultOccurred();
176     return XmlRpcValue(value, CONSUME_REFERENCE);
177 }
178
179 XmlRpcValue::int32 XmlRpcValue::getInt (void) const {
180     XmlRpcEnv env;
181     XmlRpcValue::int32 result;
182     xmlrpc_parse_value(env, mValue, "i", &result);
183     env.throwIfFaultOccurred();
184     return result;
185 }
186
187 bool XmlRpcValue::getBool (void) const {
188     XmlRpcEnv env;
189     xmlrpc_bool result;
190     xmlrpc_parse_value(env, mValue, "b", &result);
191     env.throwIfFaultOccurred();
192     return result;
193 }
194
195 double XmlRpcValue::getDouble (void) const {
196     XmlRpcEnv env;
197     double result;
198     xmlrpc_parse_value(env, mValue, "d", &result);
199     env.throwIfFaultOccurred();
200     return result;
201 }
202
203 string XmlRpcValue::getRawDateTime (void) const {
204     XmlRpcEnv env;
205     char *result;
206     xmlrpc_parse_value(env, mValue, "8", &result);
207     env.throwIfFaultOccurred();
208     return string(result);
209 }
210
211 string XmlRpcValue::getString (void) const {
212     XmlRpcEnv env;
213     char *result;
214     size_t result_len;
215     xmlrpc_parse_value(env, mValue, "s#", &result, &result_len);
216     env.throwIfFaultOccurred();
217     return string(result, result_len);
218     
219 }
220
221 XmlRpcValue XmlRpcValue::getArray (void) const {
222     XmlRpcEnv env;
223     xmlrpc_value *result;
224     xmlrpc_parse_value(env, mValue, "A", &result);
225     env.throwIfFaultOccurred();
226     return XmlRpcValue(result);
227 }
228
229 XmlRpcValue XmlRpcValue::getStruct (void) const {
230     XmlRpcEnv env;
231     xmlrpc_value *result;
232     xmlrpc_parse_value(env, mValue, "S", &result);
233     env.throwIfFaultOccurred();
234     return XmlRpcValue(result);
235 }
236
237 void XmlRpcValue::getBase64 (const unsigned char *& out_data,
238                              size_t& out_len) const
239 {
240     XmlRpcEnv env;
241     xmlrpc_parse_value(env, mValue, "6", &out_data, &out_len);
242     env.throwIfFaultOccurred();
243 }
244
245 size_t XmlRpcValue::arraySize (void) const {
246     XmlRpcEnv env;
247     size_t result = xmlrpc_array_size(env, mValue);
248     env.throwIfFaultOccurred();
249     return result;
250 }
251
252 void XmlRpcValue::arrayAppendItem (const XmlRpcValue& value) {
253     XmlRpcEnv env;
254     xmlrpc_array_append_item(env, mValue, value.borrowReference());
255     env.throwIfFaultOccurred();
256 }
257
258 XmlRpcValue XmlRpcValue::arrayGetItem (int index) const {
259     XmlRpcEnv env;
260     xmlrpc_value *result = xmlrpc_array_get_item(env, mValue, index);
261     env.throwIfFaultOccurred();
262     return XmlRpcValue(result);
263 }
264
265 size_t XmlRpcValue::structSize (void) const {
266     XmlRpcEnv env;
267     size_t result = xmlrpc_struct_size(env, mValue);
268     env.throwIfFaultOccurred();
269     return result;
270 }
271
272 bool XmlRpcValue::structHasKey (const string& key) const {
273     XmlRpcEnv env;
274     const char *keystr = key.data();
275     size_t keylen = key.size();
276     bool result = xmlrpc_struct_has_key_n(env, mValue,
277                                           const_cast<char*>(keystr), keylen);
278     env.throwIfFaultOccurred();
279     return result;
280 }
281
282 XmlRpcValue XmlRpcValue::structGetValue (const string& key) const {
283     XmlRpcEnv env;
284     const char *keystr = key.data();
285     size_t keylen = key.size();
286     xmlrpc_value *result =
287         xmlrpc_struct_get_value_n(env, mValue,
288                                   const_cast<char*>(keystr), keylen);
289     env.throwIfFaultOccurred();
290     return XmlRpcValue(result);
291 }
292
293 void XmlRpcValue::structSetValue (const string& key, const XmlRpcValue& value)
294 {
295     XmlRpcEnv env;
296     const char *keystr = key.data();
297     size_t keylen = key.size();
298     xmlrpc_struct_set_value_n(env, mValue, (char*) keystr, keylen,
299                               value.borrowReference());
300     env.throwIfFaultOccurred();
301 }
302
303 void XmlRpcValue::structGetKeyAndValue (const int index,
304                                         string& out_key,
305                                         XmlRpcValue& out_value) const
306 {
307     XmlRpcEnv env;
308
309     xmlrpc_value *key, *value;
310     xmlrpc_struct_get_key_and_value(env, mValue, index, &key, &value);
311     env.throwIfFaultOccurred();
312
313     out_key = XmlRpcValue(key).getString();
314     out_value = XmlRpcValue(value);
315 }
316
317 XmlRpcGenSrv& XmlRpcGenSrv::addMethod (const string& name,
318                                        xmlrpc_method method,
319                                        void *data)
320 {
321     XmlRpcEnv env;
322
323     xmlrpc_registry_add_method (env, mRegistry, NULL,
324                                 name.c_str (),
325                                 method, data);
326
327     env.throwIfFaultOccurred ();
328     return (*this);
329 }
330
331 XmlRpcGenSrv& XmlRpcGenSrv::addMethod (const string& name,
332                                        xmlrpc_method method,
333                                        void* data,
334                                        const string& signature,
335                                        const string& help)
336 {
337     XmlRpcEnv env;
338
339     xmlrpc_registry_add_method_w_doc (env, mRegistry, NULL,
340                                       name.c_str (),
341                                       method, data,
342                                       signature.c_str (),
343                                       help.c_str ());
344
345     env.throwIfFaultOccurred ();
346     return (*this);
347 }
348
349 xmlrpc_mem_block* XmlRpcGenSrv::alloc (XmlRpcEnv& env, const string& body) const
350 {
351     xmlrpc_mem_block*   result = NULL;
352     char*               contents;
353
354     result      = xmlrpc_mem_block_new (env, body.length ());
355     env.throwIfFaultOccurred ();
356
357     contents    = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, result);
358
359     memcpy (contents, body.c_str (), body.length ());
360     return result;
361 }
362
363 string XmlRpcGenSrv::handle (const string& body) const
364 {
365     XmlRpcEnv env;
366     string result;
367     xmlrpc_mem_block*   input = NULL, * output = NULL; 
368     char* input_data, * output_data;
369     size_t input_size, output_size;
370
371     if (body.length () > xmlrpc_limit_get (XMLRPC_XML_SIZE_LIMIT_ID))
372         throw XmlRpcFault (XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC request too large");
373
374     input   = alloc (env, body);
375     input_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, input);
376     input_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, input);
377
378     output  = xmlrpc_registry_process_call (env, mRegistry, NULL,
379                                             input_data, input_size);
380
381     if (output)
382     {
383         output_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output);
384         output_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output);
385
386         result.assign (output_data, output_size);
387         xmlrpc_mem_block_free (output);
388     }
389
390     xmlrpc_mem_block_free (input);
391     if (!result.length ())
392         throw XmlRpcFault (env);
393
394     return result;
395 }