1 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
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.
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
26 #include "xmlrpc_config.h"
32 #include "xmlrpc-c/base.h"
33 #include "xmlrpc-c/base_int.h"
35 #define KEY_ERROR_BUFFER_SZ (32)
39 xmlrpc_destroyStruct(xmlrpc_value * const structP) {
41 _struct_member * const members =
42 XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
44 XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block);
48 for (i = 0; i < size; ++i) {
49 xmlrpc_DECREF(members[i].key);
50 xmlrpc_DECREF(members[i].value);
52 XMLRPC_MEMBLOCK_CLEAN(_struct_member, &structP->_block);
57 /*=========================================================================
59 **=========================================================================
60 ** Create a new <struct> value. The corresponding destructor code
61 ** currently lives in xmlrpc_DECREF.
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.
69 xmlrpc_struct_new(xmlrpc_env * const envP) {
73 XMLRPC_ASSERT_ENV_OK(envP);
75 xmlrpc_createXmlrpcValue(envP, &valP);
76 if (!envP->fault_occurred) {
77 valP->_type = XMLRPC_TYPE_STRUCT;
79 XMLRPC_MEMBLOCK_INIT(_struct_member, envP, &valP->_block, 0);
81 if (envP->fault_occurred)
89 /*=========================================================================
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.
97 xmlrpc_struct_size(xmlrpc_env* env, xmlrpc_value* strct)
101 /* Suppress a compiler warning about uninitialized variables. */
104 XMLRPC_ASSERT_ENV_OK(env);
105 XMLRPC_ASSERT_VALUE_OK(strct);
107 XMLRPC_TYPE_CHECK(env, strct, XMLRPC_TYPE_STRUCT);
108 retval = XMLRPC_MEMBLOCK_SIZE(_struct_member, &strct->_block);
111 if (env->fault_occurred)
118 /*=========================================================================
120 **=========================================================================
121 ** A mindlessly simple hash function. Please feel free to write something
122 ** more clever if this produces bad results.
126 get_hash(const char * const key,
127 size_t const key_len) {
129 unsigned char retval;
132 XMLRPC_ASSERT(key != NULL);
135 for (i = 0; i < key_len; i++)
142 /*=========================================================================
144 **=========================================================================
145 ** Get the index of the member with the specified key, or -1 if no such
150 find_member(xmlrpc_value * const strctP,
151 const char * const key,
152 size_t const key_len) {
156 _struct_member *contents;
157 xmlrpc_value *keyval;
161 XMLRPC_ASSERT_VALUE_OK(strctP);
162 XMLRPC_ASSERT(key != NULL);
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)
182 /*=========================================================================
183 ** xmlrpc_struct_has_key
184 **=========================================================================
188 xmlrpc_struct_has_key(xmlrpc_env * const envP,
189 xmlrpc_value * const strctP,
190 const char * const key) {
192 XMLRPC_ASSERT(key != NULL);
193 return xmlrpc_struct_has_key_n(envP, strctP, key, strlen(key));
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) {
205 /* Suppress a compiler warning about uninitialized variables. */
208 XMLRPC_ASSERT_ENV_OK(envP);
209 XMLRPC_ASSERT_VALUE_OK(strctP);
210 XMLRPC_ASSERT(key != NULL);
212 XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT);
213 index = find_member(strctP, key, key_len);
216 if (envP->fault_occurred)
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.
231 /* It would be a nice extension to be able to look up a key that is
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);
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",
255 /* Get our member index. */
256 index = find_member(structP, key, strlen(key));
260 _struct_member * const members =
261 XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
262 *valuePP = members[index].value;
264 XMLRPC_ASSERT_VALUE_OK(*valuePP);
266 xmlrpc_INCREF(*valuePP);
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);
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",
291 if (keyP->_type != XMLRPC_TYPE_STRING)
292 xmlrpc_env_set_fault_formatted(
293 envP, XMLRPC_TYPE_ERROR, "Key value is not a string. "
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);
306 _struct_member * const members =
307 XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
308 *valuePP = members[index].value;
310 XMLRPC_ASSERT_VALUE_OK(*valuePP);
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);
329 if (!envP->fault_occurred && *valuePP)
330 xmlrpc_INCREF(*valuePP);
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...
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) {
348 xmlrpc_struct_find_value_v(envP, structP, keyP, valuePP);
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));
363 xmlrpc_struct_read_value(xmlrpc_env * const envP,
364 xmlrpc_value * const structP,
365 const char * const key,
366 xmlrpc_value ** const valuePP) {
368 xmlrpc_struct_find_value(envP, structP, key, valuePP);
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'",
375 /* We should fix the error message to format the key for display */
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.
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) {
396 xmlrpc_value * retval;
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.
406 findValueVNoRef(envP, structP, keyP, &retval);
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'",
414 /* We should fix the error message to format the key
426 xmlrpc_struct_get_value(xmlrpc_env * const envP,
427 xmlrpc_value * const strctP,
428 const char * const key) {
430 XMLRPC_ASSERT(key != NULL);
431 return xmlrpc_struct_get_value_n(envP, strctP, key, strlen(key));
436 /*=========================================================================
437 ** xmlrpc_struct_set_value
438 **=========================================================================
442 xmlrpc_struct_set_value(xmlrpc_env * const envP,
443 xmlrpc_value * const strctP,
444 const char * const key,
445 xmlrpc_value * const valueP) {
447 XMLRPC_ASSERT(key != NULL);
448 xmlrpc_struct_set_value_n(envP, strctP, key, strlen(key), valueP);
454 xmlrpc_struct_set_value_n(xmlrpc_env * const envP,
455 xmlrpc_value * const strctP,
456 const char * const key,
458 xmlrpc_value * const valueP) {
460 XMLRPC_ASSERT_ENV_OK(envP);
461 XMLRPC_ASSERT(key != NULL);
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);
470 xmlrpc_value * keyvalP;
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);
477 xmlrpc_DECREF(keyvalP);
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) {
492 _struct_member *members, *member, new_member;
493 xmlrpc_value *old_value;
495 XMLRPC_ASSERT_ENV_OK(envP);
496 XMLRPC_ASSERT_VALUE_OK(strctP);
497 XMLRPC_ASSERT_VALUE_OK(keyvalP);
498 XMLRPC_ASSERT_VALUE_OK(valueP);
500 XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT);
501 XMLRPC_TYPE_CHECK(envP, keyvalP, XMLRPC_TYPE_STRING);
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);
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];
514 /* Juggle our references. */
515 old_value = member->value;
516 member->value = valueP;
517 xmlrpc_INCREF(member->value);
518 xmlrpc_DECREF(old_value);
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,
526 XMLRPC_FAIL_IF_FAULT(envP);
527 xmlrpc_INCREF(keyvalP);
528 xmlrpc_INCREF(valueP);
537 /* Note that the order of keys and values is undefined, and may change
538 when you modify the struct.
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) {
548 XMLRPC_ASSERT_ENV_OK(envP);
549 XMLRPC_ASSERT_VALUE_OK(structP);
550 XMLRPC_ASSERT_PTR_OK(keyvalP);
551 XMLRPC_ASSERT_PTR_OK(valueP);
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");
558 _struct_member * const members =
559 XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
561 XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block);
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);
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);
580 xmlrpc_struct_get_key_and_value(xmlrpc_env * const envP,
581 xmlrpc_value * const structP,
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.
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);
597 xmlrpc_env_set_fault_formatted(
598 envP, XMLRPC_INDEX_ERROR, "Index %d is negative.", index);
600 xmlrpc_struct_read_member(envP, structP, index, keyvalP, valueP);
601 if (!envP->fault_occurred) {
602 xmlrpc_DECREF(*keyvalP);
603 xmlrpc_DECREF(*valueP);
606 if (envP->fault_occurred) {