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"
33 #include "xmlrpc_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
* env
)
74 XMLRPC_ASSERT_ENV_OK(env
);
76 /* Set up error handling preconditions. */
79 /* Allocate and fill out an empty structure. */
80 strct
= (xmlrpc_value
*) malloc(sizeof(xmlrpc_value
));
81 XMLRPC_FAIL_IF_NULL(strct
, env
, XMLRPC_INTERNAL_ERROR
,
82 "Could not allocate memory for struct");
84 strct
->_type
= XMLRPC_TYPE_STRUCT
;
85 XMLRPC_MEMBLOCK_INIT(_struct_member
, env
, &strct
->_block
, 0);
86 XMLRPC_FAIL_IF_FAULT(env
);
90 if (env
->fault_occurred
) {
104 /*=========================================================================
105 ** xmlrpc_struct_size
106 **=========================================================================
107 ** Return the number of key-value pairs contained in the struct. If the
108 ** value is not a struct, return -1 and set a fault.
112 xmlrpc_struct_size(xmlrpc_env
* env
, xmlrpc_value
* strct
)
116 /* Suppress a compiler warning about uninitialized variables. */
119 XMLRPC_ASSERT_ENV_OK(env
);
120 XMLRPC_ASSERT_VALUE_OK(strct
);
122 XMLRPC_TYPE_CHECK(env
, strct
, XMLRPC_TYPE_STRUCT
);
123 retval
= (int)XMLRPC_MEMBLOCK_SIZE(_struct_member
, &strct
->_block
);
126 if (env
->fault_occurred
)
133 /*=========================================================================
135 **=========================================================================
136 ** A mindlessly simple hash function. Please feel free to write something
137 ** more clever if this produces bad results.
141 get_hash(const char * const key
,
142 size_t const key_len
) {
144 unsigned char retval
;
147 XMLRPC_ASSERT(key
!= NULL
);
150 for (i
= 0; i
< key_len
; i
++)
157 /*=========================================================================
159 **=========================================================================
160 ** Get the index of the member with the specified key, or -1 if no such
165 find_member(xmlrpc_value
* const strctP
,
166 const char * const key
,
167 size_t const key_len
) {
171 _struct_member
*contents
;
172 xmlrpc_value
*keyval
;
176 XMLRPC_ASSERT_VALUE_OK(strctP
);
177 XMLRPC_ASSERT(key
!= NULL
);
179 /* Look for our key. */
180 hash
= get_hash(key
, key_len
);
181 size
= XMLRPC_MEMBLOCK_SIZE(_struct_member
, &strctP
->_block
);
182 contents
= XMLRPC_MEMBLOCK_CONTENTS(_struct_member
, &strctP
->_block
);
183 for (i
= 0; i
< size
; i
++) {
184 if (contents
[i
].key_hash
== hash
) {
185 keyval
= contents
[i
].key
;
186 keystr
= XMLRPC_MEMBLOCK_CONTENTS(char, &keyval
->_block
);
187 keystr_size
= XMLRPC_MEMBLOCK_SIZE(char, &keyval
->_block
)-1;
188 if (key_len
== keystr_size
&& memcmp(key
, keystr
, key_len
) == 0)
197 /*=========================================================================
198 ** xmlrpc_struct_has_key
199 **=========================================================================
203 xmlrpc_struct_has_key(xmlrpc_env
* const envP
,
204 xmlrpc_value
* const strctP
,
205 const char * const key
) {
207 XMLRPC_ASSERT(key
!= NULL
);
208 return xmlrpc_struct_has_key_n(envP
, strctP
, key
, strlen(key
));
214 xmlrpc_struct_has_key_n(xmlrpc_env
* const envP
,
215 xmlrpc_value
* const strctP
,
216 const char * const key
,
217 size_t const key_len
) {
220 /* Suppress a compiler warning about uninitialized variables. */
223 XMLRPC_ASSERT_ENV_OK(envP
);
224 XMLRPC_ASSERT_VALUE_OK(strctP
);
225 XMLRPC_ASSERT(key
!= NULL
);
227 XMLRPC_TYPE_CHECK(envP
, strctP
, XMLRPC_TYPE_STRUCT
);
228 xmIndex
= find_member(strctP
, key
, key_len
);
231 if (envP
->fault_occurred
)
233 return (xmIndex
>= 0);
238 /*=========================================================================
239 ** xmlrpc_struct_find_value...
240 **=========================================================================
241 ** These functions look up a specified key value in a specified struct.
242 ** If it exists, they return the value of the struct member. If not,
243 ** they return a NULL to indicate such.
246 /* It would be a nice extension to be able to look up a key that is
251 xmlrpc_struct_find_value(xmlrpc_env
* const envP
,
252 xmlrpc_value
* const structP
,
253 const char * const key
,
254 xmlrpc_value
** const valuePP
) {
255 /*----------------------------------------------------------------------------
256 Given a key, retrieve a value from the struct. If the key is not
257 present, return NULL as *valuePP.
258 -----------------------------------------------------------------------------*/
259 XMLRPC_ASSERT_ENV_OK(envP
);
260 XMLRPC_ASSERT_VALUE_OK(structP
);
261 XMLRPC_ASSERT_PTR_OK(key
);
263 if (structP
->_type
!= XMLRPC_TYPE_STRUCT
)
264 xmlrpc_env_set_fault_formatted(
265 envP
, XMLRPC_TYPE_ERROR
, "Value is not a struct. It is type #%d",
270 /* Get our member index. */
271 xmIndex
= find_member(structP
, key
, strlen(key
));
275 _struct_member
* const members
=
276 XMLRPC_MEMBLOCK_CONTENTS(_struct_member
, &structP
->_block
);
277 *valuePP
= members
[xmIndex
].value
;
279 XMLRPC_ASSERT_VALUE_OK(*valuePP
);
281 xmlrpc_INCREF(*valuePP
);
289 xmlrpc_struct_find_value_v(xmlrpc_env
* const envP
,
290 xmlrpc_value
* const structP
,
291 xmlrpc_value
* const keyP
,
292 xmlrpc_value
** const valuePP
) {
293 /*----------------------------------------------------------------------------
294 Given a key, retrieve a value from the struct. If the key is not
295 present, return NULL as *valuePP.
296 -----------------------------------------------------------------------------*/
297 XMLRPC_ASSERT_ENV_OK(envP
);
298 XMLRPC_ASSERT_VALUE_OK(structP
);
299 XMLRPC_ASSERT_VALUE_OK(keyP
);
301 if (structP
->_type
!= XMLRPC_TYPE_STRUCT
)
302 xmlrpc_env_set_fault_formatted(
303 envP
, XMLRPC_TYPE_ERROR
, "Value is not a struct. It is type #%d",
306 if (keyP
->_type
!= XMLRPC_TYPE_STRING
)
307 xmlrpc_env_set_fault_formatted(
308 envP
, XMLRPC_TYPE_ERROR
, "Key value is not a string. "
314 /* Get our member index. */
315 xmIndex
= find_member(structP
,
316 XMLRPC_MEMBLOCK_CONTENTS(char, &keyP
->_block
),
317 XMLRPC_MEMBLOCK_SIZE(char, &keyP
->_block
)-1);
321 _struct_member
* const members
=
322 XMLRPC_MEMBLOCK_CONTENTS(_struct_member
, &structP
->_block
);
323 *valuePP
= members
[xmIndex
].value
;
325 XMLRPC_ASSERT_VALUE_OK(*valuePP
);
327 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 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 xmlrpc_struct_find_value_v(envP
, structP
, keyP
, &retval
);
403 if (!envP
->fault_occurred
) {
404 if (retval
== NULL
) {
405 xmlrpc_env_set_fault_formatted(
406 envP
, XMLRPC_INDEX_ERROR
,
407 "No member of struct has key '%.*s'",
409 /* We should fix the error message to format the key
412 /* For backward compatibility. */
413 xmlrpc_DECREF(retval
);
423 xmlrpc_struct_get_value(xmlrpc_env
* const envP
,
424 xmlrpc_value
* const strctP
,
425 const char * const key
) {
427 XMLRPC_ASSERT(key
!= NULL
);
428 return xmlrpc_struct_get_value_n(envP
, strctP
, key
, strlen(key
));
433 /*=========================================================================
434 ** xmlrpc_struct_set_value
435 **=========================================================================
439 xmlrpc_struct_set_value(xmlrpc_env
* const envP
,
440 xmlrpc_value
* const strctP
,
441 const char * const key
,
442 xmlrpc_value
* const valueP
) {
444 XMLRPC_ASSERT(key
!= NULL
);
445 xmlrpc_struct_set_value_n(envP
, strctP
, key
, strlen(key
), valueP
);
451 xmlrpc_struct_set_value_n(xmlrpc_env
* const envP
,
452 xmlrpc_value
* const strctP
,
453 const char * const key
,
454 size_t const key_len
,
455 xmlrpc_value
* const valueP
) {
457 xmlrpc_value
*keyval
;
459 XMLRPC_ASSERT_ENV_OK(envP
);
460 XMLRPC_ASSERT(key
!= NULL
);
462 /* Set up error handling preconditions. */
465 XMLRPC_TYPE_CHECK(envP
, strctP
, XMLRPC_TYPE_STRUCT
);
467 /* Build an xmlrpc_value from our string. */
468 keyval
= xmlrpc_build_value(envP
, "s#", key
, key_len
);
469 XMLRPC_FAIL_IF_FAULT(envP
);
471 /* Do the actual work. */
472 xmlrpc_struct_set_value_v(envP
, strctP
, keyval
, valueP
);
476 xmlrpc_DECREF(keyval
);
482 xmlrpc_struct_set_value_v(xmlrpc_env
* const envP
,
483 xmlrpc_value
* const strctP
,
484 xmlrpc_value
* const keyvalP
,
485 xmlrpc_value
* const valueP
) {
490 _struct_member
*members
, *member
, new_member
;
491 xmlrpc_value
*old_value
;
493 XMLRPC_ASSERT_ENV_OK(envP
);
494 XMLRPC_ASSERT_VALUE_OK(strctP
);
495 XMLRPC_ASSERT_VALUE_OK(keyvalP
);
496 XMLRPC_ASSERT_VALUE_OK(valueP
);
498 XMLRPC_TYPE_CHECK(envP
, strctP
, XMLRPC_TYPE_STRUCT
);
499 XMLRPC_TYPE_CHECK(envP
, keyvalP
, XMLRPC_TYPE_STRING
);
501 key
= XMLRPC_MEMBLOCK_CONTENTS(char, &keyvalP
->_block
);
502 key_len
= XMLRPC_MEMBLOCK_SIZE(char, &keyvalP
->_block
) - 1;
503 xmIndex
= find_member(strctP
, key
, key_len
);
506 /* Change the value of an existing member. (But be careful--the
507 ** original and new values might be the same object, so watch
508 ** the order of INCREF and DECREF calls!) */
509 members
= XMLRPC_MEMBLOCK_CONTENTS(_struct_member
, &strctP
->_block
);
510 member
= &members
[xmIndex
];
512 /* Juggle our references. */
513 old_value
= member
->value
;
514 member
->value
= valueP
;
515 xmlrpc_INCREF(member
->value
);
516 xmlrpc_DECREF(old_value
);
518 /* Add a new member. */
519 new_member
.key_hash
= get_hash(key
, key_len
);
520 new_member
.key
= keyvalP
;
521 new_member
.value
= valueP
;
522 XMLRPC_MEMBLOCK_APPEND(_struct_member
, envP
, &strctP
->_block
,
524 XMLRPC_FAIL_IF_FAULT(envP
);
525 xmlrpc_INCREF(keyvalP
);
526 xmlrpc_INCREF(valueP
);
535 /* Note that the order of keys and values is undefined, and may change
536 when you modify the struct.
540 xmlrpc_struct_read_member(xmlrpc_env
* const envP
,
541 xmlrpc_value
* const structP
,
542 unsigned int const xmIndex
,
543 xmlrpc_value
** const keyvalP
,
544 xmlrpc_value
** const valueP
) {
546 XMLRPC_ASSERT_ENV_OK(envP
);
547 XMLRPC_ASSERT_VALUE_OK(structP
);
548 XMLRPC_ASSERT_PTR_OK(keyvalP
);
549 XMLRPC_ASSERT_PTR_OK(valueP
);
551 if (structP
->_type
!= XMLRPC_TYPE_STRUCT
)
552 xmlrpc_env_set_fault_formatted(
553 envP
, XMLRPC_TYPE_ERROR
, "Attempt to read a struct member "
554 "of something that is not a struct");
556 _struct_member
* const members
=
557 XMLRPC_MEMBLOCK_CONTENTS(_struct_member
, &structP
->_block
);
559 XMLRPC_MEMBLOCK_SIZE(_struct_member
, &structP
->_block
);
562 xmlrpc_env_set_fault_formatted(
563 envP
, XMLRPC_INDEX_ERROR
, "Index %u is beyond the end of "
564 "the %u-member structure", xmIndex
, (unsigned int)size
);
566 _struct_member
* const memberP
= &members
[xmIndex
];
567 *keyvalP
= memberP
->key
;
568 xmlrpc_INCREF(memberP
->key
);
569 *valueP
= memberP
->value
;
570 xmlrpc_INCREF(memberP
->value
);
578 xmlrpc_struct_get_key_and_value(xmlrpc_env
* const envP
,
579 xmlrpc_value
* const structP
,
581 xmlrpc_value
** const keyvalP
,
582 xmlrpc_value
** const valueP
) {
583 /*----------------------------------------------------------------------------
584 Same as xmlrpc_struct_read_member(), except doesn't take a reference
585 to the returned value.
588 -----------------------------------------------------------------------------*/
589 XMLRPC_ASSERT_ENV_OK(envP
);
590 XMLRPC_ASSERT_VALUE_OK(structP
);
591 XMLRPC_ASSERT_PTR_OK(keyvalP
);
592 XMLRPC_ASSERT_PTR_OK(valueP
);
595 xmlrpc_env_set_fault_formatted(
596 envP
, XMLRPC_INDEX_ERROR
, "Index %d is negative.");
598 xmlrpc_struct_read_member(envP
, structP
, xmIndex
, keyvalP
, valueP
);
599 if (!envP
->fault_occurred
) {
600 xmlrpc_DECREF(*keyvalP
);
601 xmlrpc_DECREF(*valueP
);
604 if (envP
->fault_occurred
) {