| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608 |
- /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
- **
- ** Redistribution and use in source and binary forms, with or without
- ** modification, are permitted provided that the following conditions
- ** are met:
- ** 1. Redistributions of source code must retain the above copyright
- ** notice, this list of conditions and the following disclaimer.
- ** 2. Redistributions in binary form must reproduce the above copyright
- ** notice, this list of conditions and the following disclaimer in the
- ** documentation and/or other materials provided with the distribution.
- ** 3. The name of the author may not be used to endorse or promote products
- ** derived from this software without specific prior written permission.
- **
- ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- ** SUCH DAMAGE. */
- #include "xmlrpc_config.h"
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include "xmlrpc.h"
- #include "xmlrpc_int.h"
- #define KEY_ERROR_BUFFER_SZ (32)
- void
- xmlrpc_destroyStruct(xmlrpc_value * const structP) {
- _struct_member * const members =
- XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
- size_t const size =
- XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block);
- unsigned int i;
- for (i = 0; i < size; ++i) {
- xmlrpc_DECREF(members[i].key);
- xmlrpc_DECREF(members[i].value);
- }
- XMLRPC_MEMBLOCK_CLEAN(_struct_member, &structP->_block);
- }
- /*=========================================================================
- ** xmlrpc_struct_new
- **=========================================================================
- ** Create a new <struct> value. The corresponding destructor code
- ** currently lives in xmlrpc_DECREF.
- **
- ** We store the individual members in an array of _struct_member. This
- ** contains a key, a hash code, and a value. We look up keys by doing
- ** a linear search of the hash codes.
- */
- xmlrpc_value *
- xmlrpc_struct_new(xmlrpc_env* env)
- {
- xmlrpc_value *strct;
- int strct_valid;
- XMLRPC_ASSERT_ENV_OK(env);
- /* Set up error handling preconditions. */
- strct_valid = 0;
- /* Allocate and fill out an empty structure. */
- strct = (xmlrpc_value*) malloc(sizeof(xmlrpc_value));
- XMLRPC_FAIL_IF_NULL(strct, env, XMLRPC_INTERNAL_ERROR,
- "Could not allocate memory for struct");
- strct->_refcount = 1;
- strct->_type = XMLRPC_TYPE_STRUCT;
- XMLRPC_MEMBLOCK_INIT(_struct_member, env, &strct->_block, 0);
- XMLRPC_FAIL_IF_FAULT(env);
- strct_valid = 1;
- cleanup:
- if (env->fault_occurred) {
- if (strct) {
- if (strct_valid)
- xmlrpc_DECREF(strct);
- else
- free(strct);
- }
- return NULL;
- }
- return strct;
- }
- /*=========================================================================
- ** xmlrpc_struct_size
- **=========================================================================
- ** Return the number of key-value pairs contained in the struct. If the
- ** value is not a struct, return -1 and set a fault.
- */
- int
- xmlrpc_struct_size(xmlrpc_env* env, xmlrpc_value* strct)
- {
- int retval;
- /* Suppress a compiler warning about uninitialized variables. */
- retval = 0;
- XMLRPC_ASSERT_ENV_OK(env);
- XMLRPC_ASSERT_VALUE_OK(strct);
- XMLRPC_TYPE_CHECK(env, strct, XMLRPC_TYPE_STRUCT);
- retval = XMLRPC_MEMBLOCK_SIZE(_struct_member, &strct->_block);
- cleanup:
- if (env->fault_occurred)
- return -1;
- return retval;
- }
- /*=========================================================================
- ** get_hash
- **=========================================================================
- ** A mindlessly simple hash function. Please feel free to write something
- ** more clever if this produces bad results.
- */
- static unsigned char
- get_hash(const char * const key,
- size_t const key_len) {
- unsigned char retval;
- size_t i;
- XMLRPC_ASSERT(key != NULL);
-
- retval = 0;
- for (i = 0; i < key_len; i++)
- retval += key[i];
- return retval;
- }
- /*=========================================================================
- ** find_member
- **=========================================================================
- ** Get the index of the member with the specified key, or -1 if no such
- ** member exists.
- */
- static int
- find_member(xmlrpc_value * const strctP,
- const char * const key,
- size_t const key_len) {
- size_t size, i;
- unsigned char hash;
- _struct_member *contents;
- xmlrpc_value *keyval;
- char *keystr;
- size_t keystr_size;
- XMLRPC_ASSERT_VALUE_OK(strctP);
- XMLRPC_ASSERT(key != NULL);
- /* Look for our key. */
- hash = get_hash(key, key_len);
- size = XMLRPC_MEMBLOCK_SIZE(_struct_member, &strctP->_block);
- contents = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &strctP->_block);
- for (i = 0; i < size; i++) {
- if (contents[i].key_hash == hash) {
- keyval = contents[i].key;
- keystr = XMLRPC_MEMBLOCK_CONTENTS(char, &keyval->_block);
- keystr_size = XMLRPC_MEMBLOCK_SIZE(char, &keyval->_block)-1;
- if (key_len == keystr_size && memcmp(key, keystr, key_len) == 0)
- return i;
- }
- }
- return -1;
- }
- /*=========================================================================
- ** xmlrpc_struct_has_key
- **=========================================================================
- */
- int
- xmlrpc_struct_has_key(xmlrpc_env * const envP,
- xmlrpc_value * const strctP,
- const char * const key) {
- XMLRPC_ASSERT(key != NULL);
- return xmlrpc_struct_has_key_n(envP, strctP, key, strlen(key));
- }
- int
- xmlrpc_struct_has_key_n(xmlrpc_env * const envP,
- xmlrpc_value * const strctP,
- const char * const key,
- size_t const key_len) {
- int xmIndex;
- /* Suppress a compiler warning about uninitialized variables. */
- xmIndex = 0;
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT_VALUE_OK(strctP);
- XMLRPC_ASSERT(key != NULL);
-
- XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT);
- xmIndex = find_member(strctP, key, key_len);
- cleanup:
- if (envP->fault_occurred)
- return 0;
- return (xmIndex >= 0);
- }
- /*=========================================================================
- ** xmlrpc_struct_find_value...
- **=========================================================================
- ** These functions look up a specified key value in a specified struct.
- ** If it exists, they return the value of the struct member. If not,
- ** they return a NULL to indicate such.
- */
- /* It would be a nice extension to be able to look up a key that is
- not a text string.
- */
- void
- xmlrpc_struct_find_value(xmlrpc_env * const envP,
- xmlrpc_value * const structP,
- const char * const key,
- xmlrpc_value ** const valuePP) {
- /*----------------------------------------------------------------------------
- Given a key, retrieve a value from the struct. If the key is not
- present, return NULL as *valuePP.
- -----------------------------------------------------------------------------*/
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT_VALUE_OK(structP);
- XMLRPC_ASSERT_PTR_OK(key);
-
- if (structP->_type != XMLRPC_TYPE_STRUCT)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_TYPE_ERROR, "Value is not a struct. It is type #%d",
- structP->_type);
- else {
- int xmIndex;
- /* Get our member index. */
- xmIndex = find_member(structP, key, strlen(key));
- if (xmIndex < 0)
- *valuePP = NULL;
- else {
- _struct_member * const members =
- XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
- *valuePP = members[xmIndex].value;
-
- XMLRPC_ASSERT_VALUE_OK(*valuePP);
-
- xmlrpc_INCREF(*valuePP);
- }
- }
- }
- void
- xmlrpc_struct_find_value_v(xmlrpc_env * const envP,
- xmlrpc_value * const structP,
- xmlrpc_value * const keyP,
- xmlrpc_value ** const valuePP) {
- /*----------------------------------------------------------------------------
- Given a key, retrieve a value from the struct. If the key is not
- present, return NULL as *valuePP.
- -----------------------------------------------------------------------------*/
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT_VALUE_OK(structP);
- XMLRPC_ASSERT_VALUE_OK(keyP);
-
- if (structP->_type != XMLRPC_TYPE_STRUCT)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_TYPE_ERROR, "Value is not a struct. It is type #%d",
- structP->_type);
- else {
- if (keyP->_type != XMLRPC_TYPE_STRING)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_TYPE_ERROR, "Key value is not a string. "
- "It is type #%d",
- keyP->_type);
- else {
- int xmIndex;
- /* Get our member index. */
- xmIndex = find_member(structP,
- XMLRPC_MEMBLOCK_CONTENTS(char, &keyP->_block),
- XMLRPC_MEMBLOCK_SIZE(char, &keyP->_block)-1);
- if (xmIndex < 0)
- *valuePP = NULL;
- else {
- _struct_member * const members =
- XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
- *valuePP = members[xmIndex].value;
-
- XMLRPC_ASSERT_VALUE_OK(*valuePP);
-
- xmlrpc_INCREF(*valuePP);
- }
- }
- }
- }
- /*=========================================================================
- ** xmlrpc_struct_read_value...
- **=========================================================================
- ** These fail if no member with the specified key exists.
- ** Otherwise, they are the same as xmlrpc_struct_find_value...
- */
- void
- xmlrpc_struct_read_value_v(xmlrpc_env * const envP,
- xmlrpc_value * const structP,
- xmlrpc_value * const keyP,
- xmlrpc_value ** const valuePP) {
- xmlrpc_struct_find_value_v(envP, structP, keyP, valuePP);
- if (!envP->fault_occurred) {
- if (*valuePP == NULL) {
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%.*s'",
- XMLRPC_MEMBLOCK_SIZE(char, &keyP->_block),
- XMLRPC_MEMBLOCK_CONTENTS(char, &keyP->_block));
- }
- }
- }
- void
- xmlrpc_struct_read_value(xmlrpc_env * const envP,
- xmlrpc_value * const structP,
- const char * const key,
- xmlrpc_value ** const valuePP) {
- xmlrpc_struct_find_value(envP, structP, key, valuePP);
-
- if (!envP->fault_occurred) {
- if (*valuePP == NULL) {
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%s'",
- key);
- /* We should fix the error message to format the key for display */
- }
- }
- }
- /*=========================================================================
- ** xmlrpc_struct_get_value...
- **=========================================================================
- ** These are for backward compatibility. They used to be the only ones.
- ** They're deprecated because they don't acquire a reference to the
- ** value they return.
- */
- xmlrpc_value *
- xmlrpc_struct_get_value_n(xmlrpc_env * const envP,
- xmlrpc_value * const structP,
- const char * const key,
- size_t const keyLen) {
- xmlrpc_value * retval;
- xmlrpc_value * keyP;
-
- keyP = xmlrpc_build_value(envP, "s#", key, keyLen);
- if (!envP->fault_occurred) {
- xmlrpc_struct_find_value_v(envP, structP, keyP, &retval);
- if (!envP->fault_occurred) {
- if (retval == NULL) {
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INDEX_ERROR,
- "No member of struct has key '%.*s'",
- keyLen, key);
- /* We should fix the error message to format the key
- for display */
- } else
- /* For backward compatibility. */
- xmlrpc_DECREF(retval);
- }
- xmlrpc_DECREF(keyP);
- }
- return retval;
- }
- xmlrpc_value *
- xmlrpc_struct_get_value(xmlrpc_env * const envP,
- xmlrpc_value * const strctP,
- const char * const key) {
- XMLRPC_ASSERT(key != NULL);
- return xmlrpc_struct_get_value_n(envP, strctP, key, strlen(key));
- }
- /*=========================================================================
- ** xmlrpc_struct_set_value
- **=========================================================================
- */
- void
- xmlrpc_struct_set_value(xmlrpc_env * const envP,
- xmlrpc_value * const strctP,
- const char * const key,
- xmlrpc_value * const valueP) {
- XMLRPC_ASSERT(key != NULL);
- xmlrpc_struct_set_value_n(envP, strctP, key, strlen(key), valueP);
- }
- void
- xmlrpc_struct_set_value_n(xmlrpc_env * const envP,
- xmlrpc_value * const strctP,
- const char * const key,
- size_t const key_len,
- xmlrpc_value * const valueP) {
- xmlrpc_value *keyval;
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT(key != NULL);
- /* Set up error handling preconditions. */
- keyval = NULL;
- XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT);
- /* Build an xmlrpc_value from our string. */
- keyval = xmlrpc_build_value(envP, "s#", key, key_len);
- XMLRPC_FAIL_IF_FAULT(envP);
- /* Do the actual work. */
- xmlrpc_struct_set_value_v(envP, strctP, keyval, valueP);
- cleanup:
- if (keyval)
- xmlrpc_DECREF(keyval);
- }
- void
- xmlrpc_struct_set_value_v(xmlrpc_env * const envP,
- xmlrpc_value * const strctP,
- xmlrpc_value * const keyvalP,
- xmlrpc_value * const valueP) {
- char *key;
- size_t key_len;
- int xmIndex;
- _struct_member *members, *member, new_member;
- xmlrpc_value *old_value;
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT_VALUE_OK(strctP);
- XMLRPC_ASSERT_VALUE_OK(keyvalP);
- XMLRPC_ASSERT_VALUE_OK(valueP);
- XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT);
- XMLRPC_TYPE_CHECK(envP, keyvalP, XMLRPC_TYPE_STRING);
- key = XMLRPC_MEMBLOCK_CONTENTS(char, &keyvalP->_block);
- key_len = XMLRPC_MEMBLOCK_SIZE(char, &keyvalP->_block) - 1;
- xmIndex = find_member(strctP, key, key_len);
- if (xmIndex >= 0) {
- /* Change the value of an existing member. (But be careful--the
- ** original and new values might be the same object, so watch
- ** the order of INCREF and DECREF calls!) */
- members = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &strctP->_block);
- member = &members[xmIndex];
- /* Juggle our references. */
- old_value = member->value;
- member->value = valueP;
- xmlrpc_INCREF(member->value);
- xmlrpc_DECREF(old_value);
- } else {
- /* Add a new member. */
- new_member.key_hash = get_hash(key, key_len);
- new_member.key = keyvalP;
- new_member.value = valueP;
- XMLRPC_MEMBLOCK_APPEND(_struct_member, envP, &strctP->_block,
- &new_member, 1);
- XMLRPC_FAIL_IF_FAULT(envP);
- xmlrpc_INCREF(keyvalP);
- xmlrpc_INCREF(valueP);
- }
- cleanup:
- return;
- }
- /* Note that the order of keys and values is undefined, and may change
- when you modify the struct.
- */
- void
- xmlrpc_struct_read_member(xmlrpc_env * const envP,
- xmlrpc_value * const structP,
- unsigned int const xmIndex,
- xmlrpc_value ** const keyvalP,
- xmlrpc_value ** const valueP) {
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT_VALUE_OK(structP);
- XMLRPC_ASSERT_PTR_OK(keyvalP);
- XMLRPC_ASSERT_PTR_OK(valueP);
- if (structP->_type != XMLRPC_TYPE_STRUCT)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_TYPE_ERROR, "Attempt to read a struct member "
- "of something that is not a struct");
- else {
- _struct_member * const members =
- XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block);
- size_t const size =
- XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block);
- if (xmIndex >= size)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INDEX_ERROR, "Index %u is beyond the end of "
- "the %u-member structure", xmIndex, (unsigned int)size);
- else {
- _struct_member * const memberP = &members[xmIndex];
- *keyvalP = memberP->key;
- xmlrpc_INCREF(memberP->key);
- *valueP = memberP->value;
- xmlrpc_INCREF(memberP->value);
- }
- }
- }
- void
- xmlrpc_struct_get_key_and_value(xmlrpc_env * const envP,
- xmlrpc_value * const structP,
- int const xmIndex,
- xmlrpc_value ** const keyvalP,
- xmlrpc_value ** const valueP) {
- /*----------------------------------------------------------------------------
- Same as xmlrpc_struct_read_member(), except doesn't take a reference
- to the returned value.
- This is obsolete.
- -----------------------------------------------------------------------------*/
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT_VALUE_OK(structP);
- XMLRPC_ASSERT_PTR_OK(keyvalP);
- XMLRPC_ASSERT_PTR_OK(valueP);
- if (xmIndex < 0)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INDEX_ERROR, "Index %d is negative.");
- else {
- xmlrpc_struct_read_member(envP, structP, xmIndex, keyvalP, valueP);
- if (!envP->fault_occurred) {
- xmlrpc_DECREF(*keyvalP);
- xmlrpc_DECREF(*valueP);
- }
- }
- if (envP->fault_occurred) {
- *keyvalP = NULL;
- *valueP = NULL;
- }
- }
|