git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@8545 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris
2008-05-23 20:56:24 +00:00
parent d2290cfa3a
commit 00654d880e
338 changed files with 55725 additions and 19400 deletions

View File

@@ -1,37 +1,18 @@
/* 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. */
/* Copyright information is at end of file */
#include "xmlrpc_config.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <xmlparse.h>
#include <xmlparse.h> /* Expat */
#include "bool.h"
#include "xmlrpc-c/base.h"
#include "xmlrpc-c/base_int.h"
#include "xmlrpc-c/string_int.h"
#include "xmlrpc-c/xmlparser.h"
/* Define the contents of our internal structure. */
@@ -64,8 +45,10 @@ struct _xml_element {
** arguments are implementation-dependent.
*/
static xml_element *xml_element_new (xmlrpc_env *env, char *name)
{
static xml_element *
xml_element_new (xmlrpc_env * const env,
const char * const name) {
xml_element *retval;
int name_valid, cdata_valid, children_valid;
@@ -79,7 +62,7 @@ static xml_element *xml_element_new (xmlrpc_env *env, char *name)
/* Allocate our xml_element structure. */
retval = (xml_element*) malloc(sizeof(xml_element));
XMLRPC_FAIL_IF_NULL(retval, env, XMLRPC_INTERNAL_ERROR,
"Couldn't allocate memory for XML element");
"Couldn't allocate memory for XML element");
/* Set our parent field to NULL. */
retval->_parent = NULL;
@@ -87,7 +70,7 @@ static xml_element *xml_element_new (xmlrpc_env *env, char *name)
/* Copy over the element name. */
retval->_name = (char*) malloc(strlen(name) + 1);
XMLRPC_FAIL_IF_NULL(retval->_name, env, XMLRPC_INTERNAL_ERROR,
"Couldn't allocate memory for XML element");
"Couldn't allocate memory for XML element");
name_valid = 1;
strcpy(retval->_name, name);
@@ -103,18 +86,18 @@ static xml_element *xml_element_new (xmlrpc_env *env, char *name)
cleanup:
if (env->fault_occurred) {
if (retval) {
if (name_valid)
free(retval->_name);
if (cdata_valid)
xmlrpc_mem_block_clean(&retval->_cdata);
if (children_valid)
xmlrpc_mem_block_clean(&retval->_children);
free(retval);
}
return NULL;
if (retval) {
if (name_valid)
free(retval->_name);
if (cdata_valid)
xmlrpc_mem_block_clean(&retval->_cdata);
if (children_valid)
xmlrpc_mem_block_clean(&retval->_children);
free(retval);
}
return NULL;
} else {
return retval;
return retval;
}
}
@@ -124,9 +107,9 @@ static xml_element *xml_element_new (xmlrpc_env *env, char *name)
**=========================================================================
** Blow away an existing element & all of its child elements.
*/
void
xml_element_free(xml_element * const elem) {
void xml_element_free (xml_element *elem)
{
xmlrpc_mem_block *children;
int size, i;
xml_element **contents;
@@ -142,7 +125,7 @@ void xml_element_free (xml_element *elem)
contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element*, children);
size = XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element*, children);
for (i = 0; i < size; i++)
xml_element_free(contents[i]);
xml_element_free(contents[i]);
xmlrpc_mem_block_clean(&elem->_children);
free(elem);
@@ -156,12 +139,17 @@ void xml_element_free (xml_element *elem)
** documentation on each function works.
*/
char *xml_element_name (xml_element *elem)
{
XMLRPC_ASSERT_ELEM_OK(elem);
return elem->_name;
const char *
xml_element_name(const xml_element * const elemP) {
XMLRPC_ASSERT_ELEM_OK(elemP);
return elemP->_name;
}
/* The result of this function is NOT VALID until the end_element handler
** has been called! */
size_t xml_element_cdata_size (xml_element *elem)
@@ -176,28 +164,33 @@ char *xml_element_cdata (xml_element *elem)
return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &elem->_cdata);
}
size_t xml_element_children_size (xml_element *elem)
{
XMLRPC_ASSERT_ELEM_OK(elem);
return XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element*, &elem->_children);
size_t
xml_element_children_size(const xml_element * const elemP) {
XMLRPC_ASSERT_ELEM_OK(elemP);
return XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element *, &elemP->_children);
}
xml_element **xml_element_children (xml_element *elem)
{
XMLRPC_ASSERT_ELEM_OK(elem);
return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element*, &elem->_children);
xml_element **
xml_element_children(const xml_element * const elemP) {
XMLRPC_ASSERT_ELEM_OK(elemP);
return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element *, &elemP->_children);
}
/*=========================================================================
** Internal xml_element Utility Functions
**=========================================================================
*/
static void xml_element_append_cdata (xmlrpc_env *env,
xml_element *elem,
char *cdata,
size_t size)
xml_element *elem,
char *cdata,
size_t size)
{
XMLRPC_ASSERT_ENV_OK(env);
XMLRPC_ASSERT_ELEM_OK(elem);
@@ -210,8 +203,8 @@ static void xml_element_append_cdata (xmlrpc_env *env,
** WARNING - This is the exact opposite of the usual memory ownership
** rules for xmlrpc_value! So please pay attention. */
static void xml_element_append_child (xmlrpc_env *env,
xml_element *elem,
xml_element *child)
xml_element *elem,
xml_element *child)
{
XMLRPC_ASSERT_ENV_OK(env);
XMLRPC_ASSERT_ELEM_OK(elem);
@@ -221,7 +214,7 @@ static void xml_element_append_child (xmlrpc_env *env,
XMLRPC_TYPED_MEM_BLOCK_APPEND(xml_element*, env, &elem->_children,
&child, 1);
if (!env->fault_occurred)
child->_parent = elem;
child->_parent = elem;
else
xml_element_free(child);
}
@@ -233,10 +226,10 @@ static void xml_element_append_child (xmlrpc_env *env,
*/
typedef struct {
xmlrpc_env *env;
xml_element *root;
xml_element *current;
} parse_context;
xmlrpc_env env;
xml_element * rootP;
xml_element * currentP;
} parseContext;
/*=========================================================================
@@ -245,151 +238,250 @@ typedef struct {
*/
static void
start_element (void *user_data, XML_Char *name, XML_Char **atts ATTR_UNUSED)
{
parse_context *context;
xml_element *elem, *new_current;
startElement(void * const userData,
XML_Char * const name,
XML_Char ** const atts ATTR_UNUSED) {
XMLRPC_ASSERT(user_data != NULL && name != NULL);
parseContext * const contextP = userData;
/* Get our context and see if an error has already occured. */
context = (parse_context*) user_data;
if (!context->env->fault_occurred) {
XMLRPC_ASSERT(contextP != NULL);
XMLRPC_ASSERT(name != NULL);
/* Set up our error-handling preconditions. */
elem = NULL;
if (!contextP->env.fault_occurred) {
xml_element * elemP;
/* Build a new element. */
elem = xml_element_new(context->env, name);
XMLRPC_FAIL_IF_FAULT(context->env);
elemP = xml_element_new(&contextP->env, name);
if (!contextP->env.fault_occurred) {
XMLRPC_ASSERT(elemP != NULL);
/* Insert it in the appropriate place. */
if (!context->root) {
context->root = elem;
context->current = elem;
elem = NULL;
} else {
XMLRPC_ASSERT(context->current != NULL);
/* Insert the new element in the appropriate place. */
if (!contextP->rootP) {
/* No root yet, so this element must be the root. */
contextP->rootP = elemP;
contextP->currentP = elemP;
} else {
XMLRPC_ASSERT(contextP->currentP != NULL);
/* (We need to watch our error handling invariants very carefully
** here. Read the docs for xml_element_append_child. */
new_current = elem;
xml_element_append_child(context->env, context->current, elem);
elem = NULL;
XMLRPC_FAIL_IF_FAULT(context->env);
context->current = new_current;
}
cleanup:
if (elem)
xml_element_free(elem);
}
}
static void end_element (void *user_data, XML_Char *name)
{
parse_context *context;
XMLRPC_ASSERT(user_data != NULL && name != NULL);
/* Get our context and see if an error has already occured. */
context = (parse_context*) user_data;
if (!context->env->fault_occurred) {
/* XXX - I think expat enforces these facts, but I want to be sure.
** If one of these assertion ever fails, it should be replaced by a
** non-assertion runtime error check. */
XMLRPC_ASSERT(strcmp(name, context->current->_name) == 0);
XMLRPC_ASSERT(context->current->_parent != NULL ||
context->current == context->root);
/* Add a trailing '\0' to our cdata. */
xml_element_append_cdata(context->env, context->current, "\0", 1);
XMLRPC_FAIL_IF_FAULT(context->env);
/* Pop our "stack" of elements. */
context->current = context->current->_parent;
cleanup:
return;
}
}
static void character_data (void *user_data, XML_Char *s, int len)
{
parse_context *context;
XMLRPC_ASSERT(user_data != NULL && s != NULL && len >= 0);
/* Get our context and see if an error has already occured. */
context = (parse_context*) user_data;
if (!context->env->fault_occurred) {
XMLRPC_ASSERT(context->current != NULL);
xml_element_append_cdata(context->env, context->current, s, len);
XMLRPC_FAIL_IF_FAULT(context->env);
cleanup:
return;
/* (We need to watch our error handling invariants
very carefully here. Read the docs for
xml_element_append_child.
*/
xml_element_append_child(&contextP->env, contextP->currentP,
elemP);
if (!contextP->env.fault_occurred)
contextP->currentP = elemP;
}
if (contextP->env.fault_occurred)
xml_element_free(elemP);
}
if (contextP->env.fault_occurred) {
/* Having changed *contextP to reflect failure, we are responsible
for undoing everything that has been done so far in this
context.
*/
if (contextP->rootP)
xml_element_free(contextP->rootP);
}
}
}
/*=========================================================================
** Expat Driver
**=========================================================================
** XXX - We should allow the user to specify the encoding of our xml_data.
*/
xml_element *xml_parse (xmlrpc_env *env, const char *xml_data, int xml_len)
{
parse_context context;
XML_Parser parser;
int ok;
static void
endElement(void * const userData,
XML_Char * const name ATTR_UNUSED) {
XMLRPC_ASSERT_ENV_OK(env);
XMLRPC_ASSERT(xml_data != NULL && xml_len >= 0);
parseContext * const contextP = userData;
/* Set up our error-handling preconditions. */
parser = NULL;
context.root = NULL;
XMLRPC_ASSERT(contextP != NULL);
XMLRPC_ASSERT(name != NULL);
if (!contextP->env.fault_occurred) {
/* I think Expat enforces these facts: */
XMLRPC_ASSERT(xmlrpc_streq(name, contextP->currentP->_name));
XMLRPC_ASSERT(contextP->currentP->_parent != NULL ||
contextP->currentP == contextP->rootP);
/* Add a trailing NUL to our cdata. */
xml_element_append_cdata(&contextP->env, contextP->currentP, "\0", 1);
if (!contextP->env.fault_occurred)
/* Pop our "stack" of elements. */
contextP->currentP = contextP->currentP->_parent;
if (contextP->env.fault_occurred) {
/* Having changed *contextP to reflect failure, we are responsible
for undoing everything that has been done so far in this
context.
*/
if (contextP->rootP)
xml_element_free(contextP->rootP);
}
}
}
static void
characterData(void * const userData,
XML_Char * const s,
int const len) {
/*----------------------------------------------------------------------------
This is an Expat character data (cdata) handler. When an Expat
parser comes across cdata, he calls one of these with the cdata as
argument. He can call it multiple times for consecutive cdata.
We simply append the cdata to the cdata buffer for whatever XML
element the parser is presently parsing.
-----------------------------------------------------------------------------*/
parseContext * const contextP = userData;
XMLRPC_ASSERT(contextP != NULL);
XMLRPC_ASSERT(s != NULL);
XMLRPC_ASSERT(len >= 0);
if (!contextP->env.fault_occurred) {
XMLRPC_ASSERT(contextP->currentP != NULL);
/* Set up the rest of our parse context. */
context.env = env;
context.current = NULL;
/* Set up our XML parser. */
parser = XML_ParserCreate(NULL);
XMLRPC_FAIL_IF_NULL(parser, env, XMLRPC_INTERNAL_ERROR,
"Could not create expat parser");
XML_SetUserData(parser, &context);
XML_SetElementHandler(parser,
(XML_StartElementHandler) start_element,
(XML_EndElementHandler) end_element);
XML_SetCharacterDataHandler(parser,
(XML_CharacterDataHandler) character_data);
/* Parse our data. */
ok = XML_Parse(parser, xml_data, xml_len, 1);
if (!ok)
XMLRPC_FAIL(env, XMLRPC_PARSE_ERROR,
(char*) XML_ErrorString(XML_GetErrorCode(parser)));
XMLRPC_FAIL_IF_FAULT(env);
/* Perform some sanity checks. */
XMLRPC_ASSERT(context.root != NULL);
XMLRPC_ASSERT(context.current == NULL);
cleanup:
if (parser)
XML_ParserFree(parser);
if (env->fault_occurred) {
if (context.root)
xml_element_free(context.root);
return NULL;
} else {
return context.root;
xml_element_append_cdata(&contextP->env, contextP->currentP, s, len);
}
}
static void
createParser(xmlrpc_env * const envP,
parseContext * const contextP,
XML_Parser * const parserP) {
/*----------------------------------------------------------------------------
Create an Expat parser to parse our XML.
-----------------------------------------------------------------------------*/
XML_Parser parser;
parser = xmlrpc_XML_ParserCreate(NULL);
if (parser == NULL)
xmlrpc_faultf(envP, "Could not create expat parser");
else {
/* Initialize our parse context. */
xmlrpc_env_init(&contextP->env);
contextP->rootP = NULL;
contextP->currentP = NULL;
xmlrpc_XML_SetUserData(parser, contextP);
xmlrpc_XML_SetElementHandler(
parser,
(XML_StartElementHandler) startElement,
(XML_EndElementHandler) endElement);
xmlrpc_XML_SetCharacterDataHandler(
parser,
(XML_CharacterDataHandler) characterData);
*parserP = parser;
}
}
static void
destroyParser(XML_Parser const parser,
parseContext * const contextP) {
xmlrpc_env_clean(&contextP->env);
xmlrpc_XML_ParserFree(parser);
}
void
xml_parse(xmlrpc_env * const envP,
const char * const xmlData,
size_t const xmlDataLen,
xml_element ** const resultPP) {
/*----------------------------------------------------------------------------
Parse the XML text 'xmlData', of length 'xmlDataLen'. Return the
description of the element that the XML text contains as *resultPP.
-----------------------------------------------------------------------------*/
/*
This is an Expat driver.
We set up event-based parser handlers for Expat and set Expat loose
on the XML. Expat walks through the XML, calling our handlers along
the way. Our handlers build up the element description in our
'context' variable, so that when Expat is finished, our results are
in 'context' and we just have to pluck them out.
We should allow the user to specify the encoding in 'xmlData', but
we don't.
*/
XML_Parser parser;
parseContext context;
XMLRPC_ASSERT_ENV_OK(envP);
XMLRPC_ASSERT(xmlData != NULL);
createParser(envP, &context, &parser);
if (!envP->fault_occurred) {
bool ok;
ok = xmlrpc_XML_Parse(parser, xmlData, xmlDataLen, 1);
/* sets 'context', *envP */
if (!ok) {
/* Expat failed on its own to parse it -- this is not an error
that our handlers detected.
*/
xmlrpc_env_set_fault(
envP, XMLRPC_PARSE_ERROR,
xmlrpc_XML_GetErrorString(parser));
if (!context.env.fault_occurred) {
/* Have to clean up what our handlers built before Expat
barfed.
*/
if (context.rootP)
xml_element_free(context.rootP);
}
} else {
/* Expat got through the XML OK, but when it called our handlers,
they might have detected a problem. They would have noted
such a problem in *contextP.
*/
if (context.env.fault_occurred)
xmlrpc_env_set_fault_formatted(
envP, context.env.fault_code,
"XML doesn't parse. %s", context.env.fault_string);
else {
XMLRPC_ASSERT(context.rootP != NULL);
XMLRPC_ASSERT(context.currentP == NULL);
*resultPP = context.rootP;
}
}
destroyParser(parser, &context);
}
}
/* 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. */