initial load of upstream version 1.06.32
[xmlrpc-c] / src / xmlrpc_struct.c
1 /* Copyright (C) 2001 by First Peer, Inc. 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 #include "xmlrpc_config.h"
27
28 #include <stddef.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "xmlrpc-c/base.h"
33 #include "xmlrpc-c/base_int.h"
34
35 #define KEY_ERROR_BUFFER_SZ (32)
36
37
38 void
39 xmlrpc_destroyStruct(xmlrpc_value * const structP) {
40
41     _struct_member * const members = 
42         XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
43     size_t const size = 
44         XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block);
45
46     unsigned int i;
47
48     for (i = 0; i < size; ++i) {
49         xmlrpc_DECREF(members[i].key);
50         xmlrpc_DECREF(members[i].value);
51     }
52     XMLRPC_MEMBLOCK_CLEAN(_struct_member, &structP->_block);
53 }
54
55
56
57 /*=========================================================================
58 **  xmlrpc_struct_new
59 **=========================================================================
60 **  Create a new <struct> value. The corresponding destructor code
61 **  currently lives in xmlrpc_DECREF.
62 **
63 **  We store the individual members in an array of _struct_member. This
64 **  contains a key, a hash code, and a value. We look up keys by doing
65 **  a linear search of the hash codes.
66 */
67
68 xmlrpc_value *
69 xmlrpc_struct_new(xmlrpc_env * const envP) {
70
71     xmlrpc_value * valP;
72
73     XMLRPC_ASSERT_ENV_OK(envP);
74
75     xmlrpc_createXmlrpcValue(envP, &valP);
76     if (!envP->fault_occurred) {
77         valP->_type = XMLRPC_TYPE_STRUCT;
78
79         XMLRPC_MEMBLOCK_INIT(_struct_member, envP, &valP->_block, 0);
80
81         if (envP->fault_occurred)
82             free(valP);
83     }
84     return valP;
85 }
86
87
88
89 /*=========================================================================
90 **  xmlrpc_struct_size
91 **=========================================================================
92 **  Return the number of key-value pairs contained in the struct. If the
93 **  value is not a struct, return -1 and set a fault.
94 */
95
96 int 
97 xmlrpc_struct_size(xmlrpc_env* env, xmlrpc_value* strct)
98 {
99     int retval;
100
101     /* Suppress a compiler warning about uninitialized variables. */
102     retval = 0;
103
104     XMLRPC_ASSERT_ENV_OK(env);
105     XMLRPC_ASSERT_VALUE_OK(strct);
106
107     XMLRPC_TYPE_CHECK(env, strct, XMLRPC_TYPE_STRUCT);
108     retval = XMLRPC_MEMBLOCK_SIZE(_struct_member, &strct->_block);
109
110  cleanup:
111     if (env->fault_occurred)
112         return -1;
113     return retval;
114 }
115
116
117
118 /*=========================================================================
119 **  get_hash
120 **=========================================================================
121 **  A mindlessly simple hash function. Please feel free to write something
122 **  more clever if this produces bad results.
123 */
124
125 static unsigned char 
126 get_hash(const char * const key, 
127          size_t       const key_len) {
128
129     unsigned char retval;
130     size_t i;
131
132     XMLRPC_ASSERT(key != NULL);
133     
134     retval = 0;
135     for (i = 0; i < key_len; i++)
136         retval += key[i];
137     return retval;
138 }
139
140
141
142 /*=========================================================================
143 **  find_member
144 **=========================================================================
145 **  Get the index of the member with the specified key, or -1 if no such
146 **  member exists.
147 */
148
149 static int 
150 find_member(xmlrpc_value * const strctP, 
151             const char *   const key, 
152             size_t         const key_len) {
153
154     size_t size, i;
155     unsigned char hash;
156     _struct_member *contents;
157     xmlrpc_value *keyval;
158     char *keystr;
159     size_t keystr_size;
160
161     XMLRPC_ASSERT_VALUE_OK(strctP);
162     XMLRPC_ASSERT(key != NULL);
163
164     /* Look for our key. */
165     hash = get_hash(key, key_len);
166     size = XMLRPC_MEMBLOCK_SIZE(_struct_member, &strctP->_block);
167     contents = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &strctP->_block);
168     for (i = 0; i < size; i++) {
169         if (contents[i].key_hash == hash) {
170             keyval = contents[i].key;
171             keystr = XMLRPC_MEMBLOCK_CONTENTS(char, &keyval->_block);
172             keystr_size = XMLRPC_MEMBLOCK_SIZE(char, &keyval->_block)-1;
173             if (key_len == keystr_size && memcmp(key, keystr, key_len) == 0)
174                 return i;
175         }   
176     }
177     return -1;
178 }
179
180
181
182 /*=========================================================================
183 **  xmlrpc_struct_has_key
184 **=========================================================================
185 */
186
187 int 
188 xmlrpc_struct_has_key(xmlrpc_env *   const envP,
189                       xmlrpc_value * const strctP,
190                       const char *   const key) {
191
192     XMLRPC_ASSERT(key != NULL);
193     return xmlrpc_struct_has_key_n(envP, strctP, key, strlen(key));
194 }
195
196
197
198 int 
199 xmlrpc_struct_has_key_n(xmlrpc_env   * const envP,
200                         xmlrpc_value * const strctP,
201                         const char *   const key, 
202                         size_t         const key_len) {
203     int index;
204
205     /* Suppress a compiler warning about uninitialized variables. */
206     index = 0;
207
208     XMLRPC_ASSERT_ENV_OK(envP);
209     XMLRPC_ASSERT_VALUE_OK(strctP);
210     XMLRPC_ASSERT(key != NULL);
211     
212     XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT);
213     index = find_member(strctP, key, key_len);
214
215  cleanup:
216     if (envP->fault_occurred)
217         return 0;
218     return (index >= 0);
219 }
220
221
222
223 /*=========================================================================
224 **  xmlrpc_struct_find_value...
225 **=========================================================================
226 **  These functions look up a specified key value in a specified struct.
227 **  If it exists, they return the value of the struct member.  If not,
228 **  they return a NULL to indicate such.
229 */
230
231 /* It would be a nice extension to be able to look up a key that is
232    not a text string.
233 */
234
235 void
236 xmlrpc_struct_find_value(xmlrpc_env *    const envP,
237                          xmlrpc_value *  const structP,
238                          const char *    const key,
239                          xmlrpc_value ** const valuePP) {
240 /*----------------------------------------------------------------------------
241   Given a key, retrieve a value from the struct.  If the key is not
242   present, return NULL as *valuePP.
243 -----------------------------------------------------------------------------*/
244     XMLRPC_ASSERT_ENV_OK(envP);
245     XMLRPC_ASSERT_VALUE_OK(structP);
246     XMLRPC_ASSERT_PTR_OK(key);
247     
248     if (structP->_type != XMLRPC_TYPE_STRUCT)
249         xmlrpc_env_set_fault_formatted(
250             envP, XMLRPC_TYPE_ERROR, "Value is not a struct.  It is type #%d",
251             structP->_type);
252     else {
253         int index;
254
255         /* Get our member index. */
256         index = find_member(structP, key, strlen(key));
257         if (index < 0)
258             *valuePP = NULL;
259         else {
260             _struct_member * const members =
261                 XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
262             *valuePP = members[index].value;
263             
264             XMLRPC_ASSERT_VALUE_OK(*valuePP);
265             
266             xmlrpc_INCREF(*valuePP);
267         }
268     }
269 }
270
271
272
273 static void
274 findValueVNoRef(xmlrpc_env *    const envP,
275                 xmlrpc_value *  const structP,
276                 xmlrpc_value *  const keyP,
277                 xmlrpc_value ** const valuePP) {
278 /*----------------------------------------------------------------------------
279   Same as xmlrpc_find_value_v(), except we don't increment the reference
280   count on the xmlrpc_value we return.
281 -----------------------------------------------------------------------------*/
282     XMLRPC_ASSERT_ENV_OK(envP);
283     XMLRPC_ASSERT_VALUE_OK(structP);
284     XMLRPC_ASSERT_VALUE_OK(keyP);
285     
286     if (structP->_type != XMLRPC_TYPE_STRUCT)
287         xmlrpc_env_set_fault_formatted(
288             envP, XMLRPC_TYPE_ERROR, "Value is not a struct.  It is type #%d",
289             structP->_type);
290     else {
291         if (keyP->_type != XMLRPC_TYPE_STRING)
292             xmlrpc_env_set_fault_formatted(
293                 envP, XMLRPC_TYPE_ERROR, "Key value is not a string.  "
294                 "It is type #%d",
295                 keyP->_type);
296         else {
297             int index;
298
299             /* Get our member index. */
300             index = find_member(structP, 
301                                 XMLRPC_MEMBLOCK_CONTENTS(char, &keyP->_block),
302                                 XMLRPC_MEMBLOCK_SIZE(char, &keyP->_block)-1);
303             if (index < 0)
304                 *valuePP = NULL;
305             else {
306                 _struct_member * const members =
307                     XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
308                 *valuePP = members[index].value;
309                 
310                 XMLRPC_ASSERT_VALUE_OK(*valuePP);
311             }
312         }
313     }
314 }
315
316
317
318 void
319 xmlrpc_struct_find_value_v(xmlrpc_env *    const envP,
320                            xmlrpc_value *  const structP,
321                            xmlrpc_value *  const keyP,
322                            xmlrpc_value ** const valuePP) {
323 /*----------------------------------------------------------------------------
324   Given a key, retrieve a value from the struct.  If the key is not
325   present, return NULL as *valuePP.
326 -----------------------------------------------------------------------------*/
327     findValueVNoRef(envP, structP, keyP, valuePP);
328
329     if (!envP->fault_occurred && *valuePP)
330         xmlrpc_INCREF(*valuePP);
331 }
332
333
334
335 /*=========================================================================
336 **  xmlrpc_struct_read_value...
337 **=========================================================================
338 **  These fail if no member with the specified key exists.
339 **  Otherwise, they are the same as xmlrpc_struct_find_value...
340 */
341
342 void
343 xmlrpc_struct_read_value_v(xmlrpc_env *    const envP,
344                            xmlrpc_value *  const structP,
345                            xmlrpc_value *  const keyP,
346                            xmlrpc_value ** const valuePP) {
347
348     xmlrpc_struct_find_value_v(envP, structP, keyP, valuePP);
349
350     if (!envP->fault_occurred) {
351         if (*valuePP == NULL) {
352             xmlrpc_env_set_fault_formatted(
353                 envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%.*s'",
354                 (int)XMLRPC_MEMBLOCK_SIZE(char, &keyP->_block),
355                 XMLRPC_MEMBLOCK_CONTENTS(char, &keyP->_block));
356         }
357     }
358 }
359
360
361
362 void
363 xmlrpc_struct_read_value(xmlrpc_env *    const envP,
364                          xmlrpc_value *  const structP,
365                          const char *    const key,
366                          xmlrpc_value ** const valuePP) {
367
368     xmlrpc_struct_find_value(envP, structP, key, valuePP);
369     
370     if (!envP->fault_occurred) {
371         if (*valuePP == NULL) {
372             xmlrpc_env_set_fault_formatted(
373                 envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%s'",
374                 key);
375             /* We should fix the error message to format the key for display */
376         }
377     }
378 }
379
380
381
382 /*=========================================================================
383 **  xmlrpc_struct_get_value...
384 **=========================================================================
385 **  These are for backward compatibility.  They used to be the only ones.
386 **  They're deprecated because they don't acquire a reference to the
387 **  value they return.
388 */
389
390 xmlrpc_value * 
391 xmlrpc_struct_get_value_n(xmlrpc_env *   const envP,
392                           xmlrpc_value * const structP,
393                           const char *   const key, 
394                           size_t         const keyLen) {
395
396     xmlrpc_value * retval;
397     xmlrpc_value * keyP;
398     
399     keyP = xmlrpc_build_value(envP, "s#", key, keyLen);
400     if (!envP->fault_occurred) {
401         /* We cannot use xmlrpc_find_value_v here because 
402            some legacy code uses xmlrpc_struct_get_value() from multiple
403            simultaneous threads and xmlrpc_find_value isn't thread safe
404            due to its manipulation of the reference count.
405         */
406         findValueVNoRef(envP, structP, keyP, &retval);
407
408         if (!envP->fault_occurred) {
409             if (retval == NULL) {
410                 xmlrpc_env_set_fault_formatted(
411                     envP, XMLRPC_INDEX_ERROR, 
412                     "No member of struct has key '%.*s'",
413                     (int)keyLen, key);
414                 /* We should fix the error message to format the key
415                    for display */
416             }
417         }
418         xmlrpc_DECREF(keyP);
419     }
420     return retval;
421 }
422
423
424
425 xmlrpc_value * 
426 xmlrpc_struct_get_value(xmlrpc_env *   const envP,
427                         xmlrpc_value * const strctP,
428                         const char *   const key) {
429
430     XMLRPC_ASSERT(key != NULL);
431     return xmlrpc_struct_get_value_n(envP, strctP, key, strlen(key));
432 }
433
434
435
436 /*=========================================================================
437 **  xmlrpc_struct_set_value
438 **=========================================================================
439 */
440
441 void 
442 xmlrpc_struct_set_value(xmlrpc_env *   const envP,
443                         xmlrpc_value * const strctP,
444                         const char *   const key,
445                         xmlrpc_value * const valueP) {
446
447     XMLRPC_ASSERT(key != NULL);
448     xmlrpc_struct_set_value_n(envP, strctP, key, strlen(key), valueP);
449 }
450
451
452
453 void 
454 xmlrpc_struct_set_value_n(xmlrpc_env *    const envP,
455                           xmlrpc_value *  const strctP,
456                           const char *    const key, 
457                           size_t          const keyLen,
458                           xmlrpc_value *  const valueP) {
459
460     XMLRPC_ASSERT_ENV_OK(envP);
461     XMLRPC_ASSERT(key != NULL);
462
463     if (xmlrpc_value_type(strctP) != XMLRPC_TYPE_STRUCT)
464         xmlrpc_env_set_fault_formatted(
465             envP, XMLRPC_TYPE_ERROR,
466             "Trying to set value in something not a struct.  "
467             "Type is %d; struct is %d",
468             xmlrpc_value_type(strctP), XMLRPC_TYPE_STRUCT);
469     else {
470         xmlrpc_value * keyvalP;
471
472         /* Get the key as an xmlrpc_value */
473         keyvalP = xmlrpc_build_value(envP, "s#", key, keyLen);
474         if (!envP->fault_occurred)
475             xmlrpc_struct_set_value_v(envP, strctP, keyvalP, valueP);
476
477         xmlrpc_DECREF(keyvalP);
478     }
479 }
480
481
482
483 void 
484 xmlrpc_struct_set_value_v(xmlrpc_env *   const envP,
485                           xmlrpc_value * const strctP,
486                           xmlrpc_value * const keyvalP,
487                           xmlrpc_value * const valueP) {
488
489     char *key;
490     size_t key_len;
491     int index;
492     _struct_member *members, *member, new_member;
493     xmlrpc_value *old_value;
494
495     XMLRPC_ASSERT_ENV_OK(envP);
496     XMLRPC_ASSERT_VALUE_OK(strctP);
497     XMLRPC_ASSERT_VALUE_OK(keyvalP);
498     XMLRPC_ASSERT_VALUE_OK(valueP);
499
500     XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT);
501     XMLRPC_TYPE_CHECK(envP, keyvalP, XMLRPC_TYPE_STRING);
502
503     key = XMLRPC_MEMBLOCK_CONTENTS(char, &keyvalP->_block);
504     key_len = XMLRPC_MEMBLOCK_SIZE(char, &keyvalP->_block) - 1;
505     index = find_member(strctP, key, key_len);
506
507     if (index >= 0) {
508         /* Change the value of an existing member. (But be careful--the
509         ** original and new values might be the same object, so watch
510         ** the order of INCREF and DECREF calls!) */
511         members = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &strctP->_block);
512         member = &members[index];
513
514         /* Juggle our references. */
515         old_value = member->value;
516         member->value = valueP;
517         xmlrpc_INCREF(member->value);
518         xmlrpc_DECREF(old_value);
519     } else {
520         /* Add a new member. */
521         new_member.key_hash = get_hash(key, key_len);
522         new_member.key      = keyvalP;
523         new_member.value    = valueP;
524         XMLRPC_MEMBLOCK_APPEND(_struct_member, envP, &strctP->_block,
525                                &new_member, 1);
526         XMLRPC_FAIL_IF_FAULT(envP);
527         xmlrpc_INCREF(keyvalP);
528         xmlrpc_INCREF(valueP);
529     }
530
531 cleanup:
532     return;
533 }
534
535
536
537 /* Note that the order of keys and values is undefined, and may change
538    when you modify the struct.
539 */
540
541 void 
542 xmlrpc_struct_read_member(xmlrpc_env *    const envP,
543                           xmlrpc_value *  const structP,
544                           unsigned int    const index,
545                           xmlrpc_value ** const keyvalP,
546                           xmlrpc_value ** const valueP) {
547
548     XMLRPC_ASSERT_ENV_OK(envP);
549     XMLRPC_ASSERT_VALUE_OK(structP);
550     XMLRPC_ASSERT_PTR_OK(keyvalP);
551     XMLRPC_ASSERT_PTR_OK(valueP);
552
553     if (structP->_type != XMLRPC_TYPE_STRUCT)
554         xmlrpc_env_set_fault_formatted(
555             envP, XMLRPC_TYPE_ERROR, "Attempt to read a struct member "
556             "of something that is not a struct");
557     else {
558         _struct_member * const members =
559             XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
560         size_t const size = 
561             XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block);
562
563         if (index >= size)
564             xmlrpc_env_set_fault_formatted(
565                 envP, XMLRPC_INDEX_ERROR, "Index %u is beyond the end of "
566                 "the %u-member structure", index, (unsigned int)size);
567         else {
568             _struct_member * const memberP = &members[index];
569             *keyvalP = memberP->key;
570             xmlrpc_INCREF(memberP->key);
571             *valueP = memberP->value;
572             xmlrpc_INCREF(memberP->value);
573         }
574     }
575 }
576
577
578
579 void 
580 xmlrpc_struct_get_key_and_value(xmlrpc_env *    const envP,
581                                 xmlrpc_value *  const structP,
582                                 int             const index,
583                                 xmlrpc_value ** const keyvalP,
584                                 xmlrpc_value ** const valueP) {
585 /*----------------------------------------------------------------------------
586    Same as xmlrpc_struct_read_member(), except doesn't take a reference
587    to the returned value.
588
589    This is obsolete.
590 -----------------------------------------------------------------------------*/
591     XMLRPC_ASSERT_ENV_OK(envP);
592     XMLRPC_ASSERT_VALUE_OK(structP);
593     XMLRPC_ASSERT_PTR_OK(keyvalP);
594     XMLRPC_ASSERT_PTR_OK(valueP);
595
596     if (index < 0)
597         xmlrpc_env_set_fault_formatted(
598             envP, XMLRPC_INDEX_ERROR, "Index %d is negative.", index);
599     else {
600         xmlrpc_struct_read_member(envP, structP, index, keyvalP, valueP);
601         if (!envP->fault_occurred) {
602             xmlrpc_DECREF(*keyvalP);
603             xmlrpc_DECREF(*valueP);
604         }
605     }
606     if (envP->fault_occurred) {
607         *keyvalP = NULL;
608         *valueP = NULL;
609     }
610 }