mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-08-13 01:26:58 +00:00
merged new xmlrpc-c revision 1472 from https://xmlrpc-c.svn.sourceforge.net/svnroot/xmlrpc-c/trunk
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@8545 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
95
libs/xmlrpc-c/lib/libutil/Makefile
Normal file
95
libs/xmlrpc-c/lib/libutil/Makefile
Normal file
@@ -0,0 +1,95 @@
|
||||
###############################################################################
|
||||
# This directory builds libxmlrpc_util, which contains utility
|
||||
# functions that are used by the Xmlprc-c # libraries, and also
|
||||
# directly by Xmlrpc-c programs.
|
||||
#
|
||||
# The functions in this library are characterized by being general purpose
|
||||
# programming functions, such as one might wish were in the standard C
|
||||
# library, which have nothing in particular to do with XML-RPC.
|
||||
###############################################################################
|
||||
|
||||
ifeq ($(SRCDIR),)
|
||||
updir = $(shell echo $(dir $(1)) | sed 's/.$$//')
|
||||
LIBDIR := $(call updir,$(CURDIR))
|
||||
SRCDIR := $(call updir,$(LIBDIR))
|
||||
BLDDIR := $(SRCDIR)
|
||||
endif
|
||||
SUBDIR := lib/libutil
|
||||
|
||||
include $(BLDDIR)/config.mk
|
||||
|
||||
default: all
|
||||
|
||||
TARGET_LIBRARY_NAMES := libxmlrpc_util
|
||||
|
||||
STATIC_LIBRARIES_TO_INSTALL = libxmlrpc_util.a
|
||||
|
||||
SHARED_LIBS_TO_BUILD := libxmlrpc_util
|
||||
SHARED_LIBS_TO_INSTALL := libxmlrpc_util
|
||||
|
||||
TARGET_MODS = \
|
||||
asprintf \
|
||||
error \
|
||||
make_printable \
|
||||
memblock \
|
||||
select \
|
||||
sleep \
|
||||
time \
|
||||
utf8 \
|
||||
|
||||
OMIT_LIBXMLRPC_UTIL_RULE=Y
|
||||
MAJ=3
|
||||
# Major number of shared libraries in this directory
|
||||
|
||||
include $(SRCDIR)/common.mk
|
||||
|
||||
CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD)
|
||||
|
||||
INCLUDES = -I$(BLDDIR) -Isrcdir \
|
||||
-I$(BLDDIR)/include -Isrcdir/include -Isrcdir/lib/util/include
|
||||
|
||||
UTIL_SHLIB = $(call shlibfn,libxmlrpc_util)
|
||||
#UTIL_SHLIB is e.g. libxmlrpc_util.so.3.1
|
||||
UTIL_SHLIBLE = $(call shliblefn,libxmlrpc_util)
|
||||
#UTIL_SHLIBLE is e.g. libxmlrpc_util.so
|
||||
|
||||
ifneq ($(SHARED_LIB_TYPE),NONE)
|
||||
TARGET_SHARED_LIBS := $(UTIL_SHLIB) $(UTIL_SHLIBLE)
|
||||
endif
|
||||
|
||||
# This 'common.mk' dependency makes sure the symlinks get built before
|
||||
# this make file is used for anything.
|
||||
|
||||
$(SRCDIR)/common.mk: srcdir blddir
|
||||
|
||||
.PHONY: all
|
||||
all: libxmlrpc_util.a $(TARGET_SHARED_LIBS) $(TARGET_SHARED_LE_LIBS)
|
||||
|
||||
# Rule for this is in common.mk, courtesy of TARGET_LIBRARY_NAMES:
|
||||
$(UTIL_SHLIB): $(TARGET_MODS:%=%.osh)
|
||||
$(UTIL_SHLIB): LIBOBJECTS = $(TARGET_MODS:%=%.osh)
|
||||
|
||||
# Rule for this is in common.mk, courtesy of TARGET_LIBRARY_NAMES:
|
||||
|
||||
libxmlrpc_util.a: $(TARGET_MODS:%=%.o)
|
||||
libxmlrpc_util.a: LIBOBJECTS = $(TARGET_MODS:%=%.o)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# RULES TO COMPILE OBJECT MODULES FOR LIBRARIES
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Rules to compile object modules from which to build the static and shared
|
||||
# library are in common.mk, courtesy of TARGET_MODS.
|
||||
|
||||
.PHONY: install
|
||||
install: install-common
|
||||
|
||||
.PHONY: clean distclean
|
||||
clean: clean-common
|
||||
|
||||
distclean: clean distclean-common
|
||||
|
||||
.PHONY: dep
|
||||
dep: dep-common
|
||||
|
||||
include Makefile.depend
|
116
libs/xmlrpc-c/lib/libutil/asprintf.c
Normal file
116
libs/xmlrpc-c/lib/libutil/asprintf.c
Normal file
@@ -0,0 +1,116 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "xmlrpc_config.h" /* For HAVE_ASPRINTF, __inline__ */
|
||||
#include "xmlrpc-c/string_int.h"
|
||||
|
||||
|
||||
|
||||
static __inline__ void
|
||||
simpleVasprintf(char ** const retvalP,
|
||||
const char * const fmt,
|
||||
va_list varargs) {
|
||||
/*----------------------------------------------------------------------------
|
||||
This is a poor man's implementation of vasprintf(), of GNU fame.
|
||||
-----------------------------------------------------------------------------*/
|
||||
size_t const initialSize = 4096;
|
||||
char * result;
|
||||
|
||||
result = malloc(initialSize);
|
||||
if (result != NULL) {
|
||||
size_t bytesNeeded;
|
||||
bytesNeeded = XMLRPC_VSNPRINTF(result, initialSize, fmt, varargs);
|
||||
if (bytesNeeded > initialSize) {
|
||||
free(result);
|
||||
result = malloc(bytesNeeded);
|
||||
if (result != NULL)
|
||||
XMLRPC_VSNPRINTF(result, bytesNeeded, fmt, varargs);
|
||||
} else if (bytesNeeded == initialSize) {
|
||||
if (result[initialSize-1] != '\0') {
|
||||
/* This is one of those old systems where vsnprintf()
|
||||
returns the number of bytes it used, instead of the
|
||||
number that it needed, and it in fact needed more than
|
||||
we gave it. Rather than mess with this highly unlikely
|
||||
case (old system and string > 4095 characters), we just
|
||||
treat this like an out of memory failure.
|
||||
*/
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
*retvalP = result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char * const xmlrpc_strsol = "[insufficient memory to build string]";
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_vasprintf(const char ** const retvalP,
|
||||
const char * const fmt,
|
||||
va_list varargs) {
|
||||
|
||||
char * string;
|
||||
|
||||
#if HAVE_ASPRINTF
|
||||
vasprintf(&string, fmt, varargs);
|
||||
#else
|
||||
simpleVasprintf(&string, fmt, varargs);
|
||||
#endif
|
||||
|
||||
if (string == NULL)
|
||||
*retvalP = xmlrpc_strsol;
|
||||
else
|
||||
*retvalP = string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GNU_PRINTF_ATTR(2,3)
|
||||
xmlrpc_asprintf(const char ** const retvalP, const char * const fmt, ...) {
|
||||
|
||||
va_list varargs; /* mysterious structure used by variable arg facility */
|
||||
|
||||
va_start(varargs, fmt); /* start up the mysterious variable arg facility */
|
||||
|
||||
xmlrpc_vasprintf(retvalP, fmt, varargs);
|
||||
|
||||
va_end(varargs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *
|
||||
xmlrpc_strdupnull(const char * const string) {
|
||||
|
||||
if (string)
|
||||
return strdup(string);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_strfree(const char * const string) {
|
||||
|
||||
if (string != xmlrpc_strsol)
|
||||
free((void *)string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_strfreenull(const char * const string) {
|
||||
|
||||
if (string)
|
||||
xmlrpc_strfree(string);
|
||||
}
|
||||
|
||||
|
||||
|
163
libs/xmlrpc-c/lib/libutil/error.c
Normal file
163
libs/xmlrpc-c/lib/libutil/error.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/* Copyright information is at end of file */
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "xmlrpc-c/util_int.h"
|
||||
#include "xmlrpc-c/string_int.h"
|
||||
#include "xmlrpc-c/util.h"
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_assertion_failed(const char * const fileName,
|
||||
int const lineNumber) {
|
||||
|
||||
fprintf(stderr, "%s:%d: assertion failed\n", fileName, lineNumber);
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char * const default_fault_string =
|
||||
"Not enough memory for error message";
|
||||
|
||||
void xmlrpc_env_init (xmlrpc_env* env)
|
||||
{
|
||||
XMLRPC_ASSERT(env != NULL);
|
||||
|
||||
env->fault_occurred = 0;
|
||||
env->fault_code = 0;
|
||||
env->fault_string = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
xmlrpc_env_clean(xmlrpc_env * const envP) {
|
||||
|
||||
XMLRPC_ASSERT(envP != NULL);
|
||||
XMLRPC_ASSERT(envP->fault_string != XMLRPC_BAD_POINTER);
|
||||
|
||||
/* env->fault_string may be one of three things:
|
||||
** 1) a NULL pointer
|
||||
** 2) a pointer to the default_fault_string
|
||||
** 3) a pointer to a malloc'd fault string
|
||||
** If we have case (3), we'll need to free it. */
|
||||
if (envP->fault_string && envP->fault_string != default_fault_string)
|
||||
free(envP->fault_string);
|
||||
envP->fault_string = XMLRPC_BAD_POINTER;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_env_set_fault(xmlrpc_env * const envP,
|
||||
int const faultCode,
|
||||
const char * const faultDescription) {
|
||||
|
||||
char * buffer;
|
||||
|
||||
XMLRPC_ASSERT(envP != NULL);
|
||||
XMLRPC_ASSERT(faultDescription != NULL);
|
||||
|
||||
/* Clean up any leftover pointers. */
|
||||
xmlrpc_env_clean(envP);
|
||||
|
||||
envP->fault_occurred = 1;
|
||||
envP->fault_code = faultCode;
|
||||
|
||||
/* Try to copy the fault string. If this fails, use a default. */
|
||||
buffer = strdup(faultDescription);
|
||||
if (buffer == NULL)
|
||||
envP->fault_string = (char *)default_fault_string;
|
||||
else {
|
||||
xmlrpc_force_to_utf8(buffer);
|
||||
xmlrpc_force_to_xml_chars(buffer);
|
||||
envP->fault_string = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_set_fault_formatted_v(xmlrpc_env * const envP,
|
||||
int const code,
|
||||
const char * const format,
|
||||
va_list const args) {
|
||||
|
||||
const char * faultDescription;
|
||||
|
||||
xmlrpc_vasprintf(&faultDescription, format, args);
|
||||
|
||||
xmlrpc_env_set_fault(envP, code, faultDescription);
|
||||
|
||||
xmlrpc_strfree(faultDescription);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_env_set_fault_formatted(xmlrpc_env * const envP,
|
||||
int const code,
|
||||
const char * const format,
|
||||
...) {
|
||||
va_list args;
|
||||
|
||||
XMLRPC_ASSERT(envP != NULL);
|
||||
XMLRPC_ASSERT(format != NULL);
|
||||
|
||||
/* Print our error message to the buffer. */
|
||||
va_start(args, format);
|
||||
xmlrpc_set_fault_formatted_v(envP, code, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_faultf(xmlrpc_env * const envP,
|
||||
const char * const format,
|
||||
...) {
|
||||
|
||||
va_list args;
|
||||
|
||||
XMLRPC_ASSERT(envP != NULL);
|
||||
XMLRPC_ASSERT(format != NULL);
|
||||
|
||||
/* Print our error message to the buffer. */
|
||||
va_start(args, format);
|
||||
xmlrpc_set_fault_formatted_v(envP, XMLRPC_INTERNAL_ERROR, format, args);
|
||||
va_end(args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 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. */
|
||||
|
101
libs/xmlrpc-c/lib/libutil/make_printable.c
Normal file
101
libs/xmlrpc-c/lib/libutil/make_printable.c
Normal file
@@ -0,0 +1,101 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
#include "xmlrpc-c/string_int.h"
|
||||
|
||||
|
||||
|
||||
const char *
|
||||
xmlrpc_makePrintable_lp(const char * const input,
|
||||
size_t const inputLength) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Convert an arbitrary string of characters in length-pointer form to
|
||||
printable ASCII. E.g. convert newlines to "\n".
|
||||
|
||||
Return the result in newly malloc'ed storage. Return NULL if we can't
|
||||
get the storage.
|
||||
-----------------------------------------------------------------------------*/
|
||||
char * output;
|
||||
|
||||
output = malloc(inputLength*4+1);
|
||||
/* Worst case, we render a character like \x01 -- 4 characters */
|
||||
|
||||
if (output != NULL) {
|
||||
unsigned int inputCursor, outputCursor;
|
||||
|
||||
for (inputCursor = 0, outputCursor = 0;
|
||||
inputCursor < inputLength;
|
||||
++inputCursor) {
|
||||
|
||||
if (0) {
|
||||
} else if (input[inputCursor] == '\\') {
|
||||
output[outputCursor++] = '\\';
|
||||
output[outputCursor++] = '\\';
|
||||
} else if (input[inputCursor] == '\n') {
|
||||
output[outputCursor++] = '\\';
|
||||
output[outputCursor++] = 'n';
|
||||
} else if (input[inputCursor] == '\t') {
|
||||
output[outputCursor++] = '\\';
|
||||
output[outputCursor++] = 't';
|
||||
} else if (input[inputCursor] == '\a') {
|
||||
output[outputCursor++] = '\\';
|
||||
output[outputCursor++] = 'a';
|
||||
} else if (input[inputCursor] == '\r') {
|
||||
output[outputCursor++] = '\\';
|
||||
output[outputCursor++] = 'r';
|
||||
} else if (isprint(input[inputCursor])) {
|
||||
output[outputCursor++] = input[inputCursor];
|
||||
} else {
|
||||
snprintf(&output[outputCursor], 5, "\\x%02x",
|
||||
input[inputCursor]);
|
||||
outputCursor += 4;
|
||||
}
|
||||
}
|
||||
output[outputCursor++] = '\0';
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *
|
||||
xmlrpc_makePrintable(const char * const input) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Convert an arbitrary string of characters (NUL-terminated, though) to
|
||||
printable ASCII. E.g. convert newlines to "\n".
|
||||
|
||||
Return the result in newly malloc'ed storage. Return NULL if we can't
|
||||
get the storage.
|
||||
-----------------------------------------------------------------------------*/
|
||||
return xmlrpc_makePrintable_lp(input, strlen(input));
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *
|
||||
xmlrpc_makePrintableChar(char const input) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Return an ASCIIZ string consisting of the character 'input',
|
||||
properly escaped so as to be printable. E.g., in C notation, '\n'
|
||||
turns into "\\n"
|
||||
-----------------------------------------------------------------------------*/
|
||||
const char * retval;
|
||||
|
||||
if (input == '\0')
|
||||
retval = strdup("\\0");
|
||||
else {
|
||||
char buffer[2];
|
||||
|
||||
buffer[0] = input;
|
||||
buffer[1] = '\0';
|
||||
|
||||
retval = xmlrpc_makePrintable(buffer);
|
||||
}
|
||||
return retval;
|
||||
}
|
214
libs/xmlrpc-c/lib/libutil/memblock.c
Normal file
214
libs/xmlrpc-c/lib/libutil/memblock.c
Normal file
@@ -0,0 +1,214 @@
|
||||
/* Copyright information is at end of file */
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "xmlrpc-c/util_int.h"
|
||||
#include "xmlrpc-c/util.h"
|
||||
|
||||
#ifdef EFENCE
|
||||
/* when looking for corruption don't allocate extra slop */
|
||||
#define BLOCK_ALLOC_MIN (1)
|
||||
#else
|
||||
#define BLOCK_ALLOC_MIN (16)
|
||||
#endif
|
||||
#define BLOCK_ALLOC_MAX (128 * 1024 * 1024)
|
||||
|
||||
|
||||
xmlrpc_mem_block *
|
||||
xmlrpc_mem_block_new(xmlrpc_env * const env,
|
||||
size_t const size) {
|
||||
|
||||
xmlrpc_mem_block* block;
|
||||
|
||||
XMLRPC_ASSERT_ENV_OK(env);
|
||||
|
||||
block = (xmlrpc_mem_block*) malloc(sizeof(xmlrpc_mem_block));
|
||||
XMLRPC_FAIL_IF_NULL(block, env, XMLRPC_INTERNAL_ERROR,
|
||||
"Can't allocate memory block");
|
||||
|
||||
xmlrpc_mem_block_init(env, block, size);
|
||||
XMLRPC_FAIL_IF_FAULT(env);
|
||||
|
||||
cleanup:
|
||||
if (env->fault_occurred) {
|
||||
if (block)
|
||||
free(block);
|
||||
return NULL;
|
||||
} else {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
/* Destroy an existing xmlrpc_mem_block, and everything it contains. */
|
||||
void
|
||||
xmlrpc_mem_block_free(xmlrpc_mem_block * const blockP) {
|
||||
|
||||
XMLRPC_ASSERT(blockP != NULL);
|
||||
XMLRPC_ASSERT(blockP->_block != NULL);
|
||||
|
||||
xmlrpc_mem_block_clean(blockP);
|
||||
free(blockP);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Initialize the contents of the provided xmlrpc_mem_block. */
|
||||
void
|
||||
xmlrpc_mem_block_init(xmlrpc_env * const envP,
|
||||
xmlrpc_mem_block * const blockP,
|
||||
size_t const size) {
|
||||
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT(blockP != NULL);
|
||||
|
||||
blockP->_size = size;
|
||||
if (size < BLOCK_ALLOC_MIN)
|
||||
blockP->_allocated = BLOCK_ALLOC_MIN;
|
||||
else
|
||||
blockP->_allocated = size;
|
||||
|
||||
blockP->_block = (void*) malloc(blockP->_allocated);
|
||||
if (!blockP->_block)
|
||||
xmlrpc_faultf(envP, "Can't allocate %u-byte memory block",
|
||||
blockP->_allocated);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Deallocate the contents of the provided xmlrpc_mem_block, but not
|
||||
the block itself.
|
||||
*/
|
||||
void
|
||||
xmlrpc_mem_block_clean(xmlrpc_mem_block * const blockP) {
|
||||
|
||||
XMLRPC_ASSERT(blockP != NULL);
|
||||
XMLRPC_ASSERT(blockP->_block != NULL);
|
||||
|
||||
free(blockP->_block);
|
||||
blockP->_block = XMLRPC_BAD_POINTER;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Get the size of the xmlrpc_mem_block. */
|
||||
size_t
|
||||
xmlrpc_mem_block_size(const xmlrpc_mem_block * const blockP) {
|
||||
|
||||
XMLRPC_ASSERT(blockP != NULL);
|
||||
return blockP->_size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Get the contents of the xmlrpc_mem_block. */
|
||||
void *
|
||||
xmlrpc_mem_block_contents(const xmlrpc_mem_block * const blockP) {
|
||||
|
||||
XMLRPC_ASSERT(blockP != NULL);
|
||||
return blockP->_block;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Resize an xmlrpc_mem_block, preserving as much of the contents as
|
||||
possible.
|
||||
*/
|
||||
void
|
||||
xmlrpc_mem_block_resize (xmlrpc_env * const envP,
|
||||
xmlrpc_mem_block * const blockP,
|
||||
size_t const size) {
|
||||
|
||||
size_t proposed_alloc;
|
||||
void* new_block;
|
||||
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT(blockP != NULL);
|
||||
|
||||
/* Check to see if we already have enough space. Maybe we'll get lucky. */
|
||||
if (size <= blockP->_allocated) {
|
||||
blockP->_size = size;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate a new allocation size. */
|
||||
#ifdef EFENCE
|
||||
proposed_alloc = size;
|
||||
#else
|
||||
proposed_alloc = blockP->_allocated;
|
||||
while (proposed_alloc < size && proposed_alloc <= BLOCK_ALLOC_MAX)
|
||||
proposed_alloc *= 2;
|
||||
#endif /* DEBUG_MEM_ERRORS */
|
||||
|
||||
if (proposed_alloc > BLOCK_ALLOC_MAX)
|
||||
XMLRPC_FAIL(envP, XMLRPC_INTERNAL_ERROR, "Memory block too large");
|
||||
|
||||
/* Allocate our new memory block. */
|
||||
new_block = (void*) malloc(proposed_alloc);
|
||||
XMLRPC_FAIL_IF_NULL(new_block, envP, XMLRPC_INTERNAL_ERROR,
|
||||
"Can't resize memory block");
|
||||
|
||||
/* Copy over our data and update the xmlrpc_mem_block struct. */
|
||||
memcpy(new_block, blockP->_block, blockP->_size);
|
||||
free(blockP->_block);
|
||||
blockP->_block = new_block;
|
||||
blockP->_size = size;
|
||||
blockP->_allocated = proposed_alloc;
|
||||
|
||||
cleanup:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_mem_block_append(xmlrpc_env * const envP,
|
||||
xmlrpc_mem_block * const blockP,
|
||||
const void * const data,
|
||||
size_t const len) {
|
||||
|
||||
int size;
|
||||
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT(blockP != NULL);
|
||||
|
||||
size = blockP->_size;
|
||||
xmlrpc_mem_block_resize(envP, blockP, size + len);
|
||||
XMLRPC_FAIL_IF_FAULT(envP);
|
||||
|
||||
memcpy(((unsigned char*) blockP->_block) + size, data, len);
|
||||
|
||||
cleanup:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 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.
|
||||
*/
|
59
libs/xmlrpc-c/lib/libutil/select.c
Normal file
59
libs/xmlrpc-c/lib/libutil/select.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#define _XOPEN_SOURCE 600 /* Get pselect() in <sys/select.h> */
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock.h>
|
||||
#else
|
||||
/* In some systems (SUS), the select() interface comes from <sys/time.h>;
|
||||
in others, from <sys/select.h>, and other from both. Including both
|
||||
in this order appears to work on all.
|
||||
*/
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include "xmlrpc-c/select_int.h"
|
||||
|
||||
|
||||
/* xmlrpc_pselect() is just for use with sockets. In a POSIX system,
|
||||
it technically works for any file descriptor, but in Windows, select()
|
||||
is part of the socket facility.
|
||||
*/
|
||||
|
||||
int
|
||||
xmlrpc_pselect(int const n,
|
||||
fd_set * const readfdsP,
|
||||
fd_set * const writefdsP,
|
||||
fd_set * const exceptfdsP,
|
||||
const xmlrpc_timespec * const timeoutP,
|
||||
sigset_t * const sigmaskP) {
|
||||
|
||||
int retval;
|
||||
|
||||
#if HAVE_PSELECT
|
||||
#if !HAVE_TIMESPEC
|
||||
#error "Impossible configuration -- has pselect(), but not struct timespec"
|
||||
#else
|
||||
retval = pselect(n, readfdsP, writefdsP, exceptfdsP, timeoutP, sigmaskP);
|
||||
#endif
|
||||
#else /* HAVE_PSELECT */
|
||||
struct timeval timeout;
|
||||
|
||||
timeout.tv_sec = timeoutP->tv_sec;
|
||||
timeout.tv_usec = timeoutP->tv_nsec/1000;
|
||||
#ifdef WIN32
|
||||
retval = select(n, readfdsP, writefdsP, exceptfdsP, &timeout);
|
||||
#else
|
||||
{
|
||||
sigset_t origmask;
|
||||
sigprocmask(SIG_SETMASK, sigmaskP, &origmask);
|
||||
retval = select(n, readfdsP, writefdsP, exceptfdsP, &timeout);
|
||||
sigprocmask(SIG_SETMASK, &origmask, NULL);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
21
libs/xmlrpc-c/lib/libutil/sleep.c
Normal file
21
libs/xmlrpc-c/lib/libutil/sleep.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "bool.h"
|
||||
|
||||
#include "xmlrpc-c/sleep_int.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_millisecond_sleep(unsigned int const milliseconds) {
|
||||
|
||||
#ifdef WIN32
|
||||
SleepEx(milliseconds, true);
|
||||
#else
|
||||
usleep(milliseconds * 1000);
|
||||
#endif
|
||||
}
|
173
libs/xmlrpc-c/lib/libutil/time.c
Normal file
173
libs/xmlrpc-c/lib/libutil/time.c
Normal file
@@ -0,0 +1,173 @@
|
||||
#include "xmlrpc_config.h"
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
#if !MSVCRT
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#if MSVCRT
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "xmlrpc-c/string_int.h"
|
||||
#include "xmlrpc-c/time_int.h"
|
||||
|
||||
|
||||
/* A note about struct timeval and Windows: There is a 'struct
|
||||
timeval' type in Windows, but it is just an argument to select(),
|
||||
which is just part of the sockets interface. It's defined
|
||||
identically to the POSIX type of the same name, but not meant for
|
||||
general timekeeping as the POSIX type is.
|
||||
*/
|
||||
|
||||
#if HAVE_GETTIMEOFDAY
|
||||
static void
|
||||
gettimeofdayPosix(xmlrpc_timespec * const todP) {
|
||||
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
todP->tv_sec = tv.tv_sec;
|
||||
todP->tv_nsec = tv.tv_usec * 1000;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MSVCRT
|
||||
static void
|
||||
gettimeofdayWindows(xmlrpc_timespec * const todP) {
|
||||
|
||||
__int64 const epochOffset = 116444736000000000i64;
|
||||
/* Number of 100-nanosecond units between the beginning of the
|
||||
Windows epoch (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970).
|
||||
*/
|
||||
FILETIME ft;
|
||||
LARGE_INTEGER li;
|
||||
__int64 t;
|
||||
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
li.LowPart = ft.dwLowDateTime;
|
||||
li.HighPart = ft.dwHighDateTime;
|
||||
t = (li.QuadPart - epochOffset) * 100; /* nanoseconds */
|
||||
todP->tv_sec = (long)(t / 1E9);
|
||||
todP->tv_nsec = (long)(t - (__int64)todP->tv_sec * 1E9);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_gettimeofday(xmlrpc_timespec * const todP) {
|
||||
|
||||
assert(todP);
|
||||
|
||||
#if HAVE_GETTIMEOFDAY
|
||||
gettimeofdayPosix(todP);
|
||||
#else
|
||||
#if MSVCRT
|
||||
gettimeofdayWindows(todP);
|
||||
#else
|
||||
#error "We don't know how to get the time of day on this system"
|
||||
#endif
|
||||
#endif /* HAVE_GETTIMEOFDAY */
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool
|
||||
isLeapYear(unsigned int const yearOfAd) {
|
||||
|
||||
return
|
||||
(yearOfAd % 4) == 0 &&
|
||||
((yearOfAd % 100) != 0 || (yearOfAd % 400) == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_timegm(const struct tm * const tmP,
|
||||
time_t * const timeValueP,
|
||||
const char ** const errorP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
This does what GNU libc's timegm() does.
|
||||
-----------------------------------------------------------------------------*/
|
||||
if (tmP->tm_year < 70 ||
|
||||
tmP->tm_mon > 11 ||
|
||||
tmP->tm_mon < 0 ||
|
||||
tmP->tm_mday > 31 ||
|
||||
tmP->tm_min > 60 ||
|
||||
tmP->tm_sec > 60 ||
|
||||
tmP->tm_hour > 24) {
|
||||
|
||||
xmlrpc_asprintf(errorP, "Invalid time specification; a member "
|
||||
"of struct tm is out of range");
|
||||
} else {
|
||||
static unsigned int const monthDaysNonLeap[12] =
|
||||
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
unsigned int totalDays;
|
||||
unsigned int year;
|
||||
unsigned int month;
|
||||
|
||||
totalDays = 0; /* initial value */
|
||||
|
||||
for (year = 70; year < (unsigned int)tmP->tm_year; ++year)
|
||||
totalDays += isLeapYear(1900 + year) ? 366 : 365;
|
||||
|
||||
for (month = 0; month < (unsigned int)tmP->tm_mon; ++month)
|
||||
totalDays += monthDaysNonLeap[month];
|
||||
|
||||
if (tmP->tm_mon > 1 && isLeapYear(1900 + tmP->tm_year))
|
||||
totalDays += 1;
|
||||
|
||||
totalDays += tmP->tm_mday - 1;
|
||||
|
||||
*errorP = NULL;
|
||||
|
||||
*timeValueP = ((totalDays * 24 +
|
||||
tmP->tm_hour) * 60 +
|
||||
tmP->tm_min) * 60 +
|
||||
tmP->tm_sec;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_localtime(time_t const datetime,
|
||||
struct tm * const tmP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Convert datetime from standard to broken-down format in the local
|
||||
time zone.
|
||||
|
||||
For Windows, this is not thread-safe. If you run a version of Abyss
|
||||
with multiple threads, you can get arbitrary results here.
|
||||
-----------------------------------------------------------------------------*/
|
||||
#if HAVE_LOCALTIME_R
|
||||
localtime_r(&datetime, tmP);
|
||||
#else
|
||||
*tmP = *localtime(&datetime);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_gmtime(time_t const datetime,
|
||||
struct tm * const resultP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Convert datetime from standard to broken-down UTC format.
|
||||
|
||||
For Windows, this is not thread-safe. If you run a version of Abyss
|
||||
with multiple threads, you can get arbitrary results here.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
#if HAVE_GMTIME_R
|
||||
gmtime_r(&datetime, resultP);
|
||||
#else
|
||||
*resultP = *gmtime(&datetime);
|
||||
#endif
|
||||
}
|
511
libs/xmlrpc-c/lib/libutil/utf8.c
Normal file
511
libs/xmlrpc-c/lib/libutil/utf8.c
Normal file
@@ -0,0 +1,511 @@
|
||||
/* Copyright (C) 2001 by Eric Kidd. 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. */
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
** XML-RPC UTF-8 Utilities
|
||||
**=========================================================================
|
||||
** Routines for validating, encoding and decoding UTF-8 data. We try to
|
||||
** be very, very strict about invalid UTF-8 data.
|
||||
**
|
||||
** All of the code in this file assumes that your machine represents
|
||||
** wchar_t as a 16-bit (or wider) character containing UCS-2 data. If this
|
||||
** assumption is incorrect, you may need to replace this file.
|
||||
**
|
||||
** For lots of information on Unicode and UTF-8 decoding, see:
|
||||
** http://www.cl.cam.ac.uk/~mgk25/unicode.html
|
||||
*/
|
||||
|
||||
#include "int.h"
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
#include "bool.h"
|
||||
#include "xmlrpc-c/base.h"
|
||||
|
||||
/*=========================================================================
|
||||
** Tables and Constants
|
||||
**=========================================================================
|
||||
** We use a variety of tables and constants to help decode and validate
|
||||
** UTF-8 data.
|
||||
*/
|
||||
|
||||
/* The number of bytes in a UTF-8 sequence starting with the character used
|
||||
** as the array index. A zero entry indicates an illegal initial byte.
|
||||
** This table was generated using a Perl script and information from the
|
||||
** UTF-8 standard.
|
||||
**
|
||||
** Fredrik Lundh's UTF-8 decoder Python 2.0 uses a similar table. But
|
||||
** since Python 2.0 has the icky CNRI license, I regenerated this
|
||||
** table from scratch and wrote my own decoder. */
|
||||
static unsigned char utf8_seq_length[256] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0
|
||||
};
|
||||
|
||||
/* The minimum legal character value for a UTF-8 sequence of the given
|
||||
** length. We have to check this to avoid accepting "overlong" UTF-8
|
||||
** sequences, which use more bytes than necessary to encode a given
|
||||
** character. Such sequences are commonly used by evil people to bypass
|
||||
** filters and security checks. This table is based on the UTF-8-test.txt
|
||||
** file by Markus Kuhn <mkuhn@acm.org>. */
|
||||
static uint32_t const utf8_min_char_for_length[] = {
|
||||
0, /* Length 0: Not used (meaningless) */
|
||||
0x0000, /* Length 1: Not used (special-cased) */
|
||||
0x0080, /* Length 2 */
|
||||
0x0800, /* Length 3 */
|
||||
0x00010000, /* Length 4 */
|
||||
0x00200000, /* Length 5 */
|
||||
0x04000000 /* Length 6 */
|
||||
};
|
||||
|
||||
/* This is the maximum legal 16-byte (UCS-2) character. Again, this
|
||||
** information is based on UTF-8-test.txt. */
|
||||
#define UCS2_MAX_LEGAL_CHARACTER (0xFFFD)
|
||||
|
||||
/* First and last UTF-16 surrogate characters. These are *not* legal UCS-2
|
||||
** characters--they're used to code for UCS-4 characters when using
|
||||
** UTF-16. They should never appear in decoded UTF-8 data! Again, these
|
||||
** could hypothetically be used to bypass security measures on some machines.
|
||||
** Based on UTF-8-test.txt. */
|
||||
#define UTF16_FIRST_SURROGATE (0xD800)
|
||||
#define UTF16_LAST_SURROGATE (0xDFFF)
|
||||
|
||||
/* Is the character 'c' a UTF-8 continuation character? */
|
||||
#define IS_CONTINUATION(c) (((c) & 0xC0) == 0x80)
|
||||
|
||||
#define MAX_ENCODED_BYTES (3)
|
||||
/* Maximum number of bytes needed to encode in UTF-8 a character
|
||||
in the Basic Multilingual Plane.
|
||||
*/
|
||||
|
||||
|
||||
#if HAVE_UNICODE_WCHAR
|
||||
|
||||
|
||||
static void
|
||||
decode_utf8(xmlrpc_env * const envP,
|
||||
const char * const utf8_data,
|
||||
size_t const utf8_len,
|
||||
wchar_t * const ioBuff,
|
||||
size_t * const outBuffLenP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Decode to UCS-2 (or validates as UTF-8 that can be decoded to UCS-2)
|
||||
a UTF-8 string. To validate, set ioBuff and outBuffLenP to NULL.
|
||||
To decode, allocate a sufficiently large buffer, pass it as ioBuff,
|
||||
and pass a pointer as as outBuffLenP. The data will be written to
|
||||
the buffer, and the length to outBuffLenP.
|
||||
|
||||
We assume that wchar_t holds a single UCS-2 character in native-endian
|
||||
byte ordering.
|
||||
-----------------------------------------------------------------------------*/
|
||||
size_t i, length, out_pos;
|
||||
char init, con1, con2;
|
||||
wchar_t wc;
|
||||
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT_PTR_OK(utf8_data);
|
||||
XMLRPC_ASSERT((!ioBuff && !outBuffLenP) ||
|
||||
(ioBuff && outBuffLenP));
|
||||
|
||||
/* Suppress GCC warning about possibly undefined variable. */
|
||||
wc = 0;
|
||||
|
||||
i = 0;
|
||||
out_pos = 0;
|
||||
while (i < utf8_len) {
|
||||
init = utf8_data[i];
|
||||
if ((init & 0x80) == 0x00) {
|
||||
/* Convert ASCII character to wide character. */
|
||||
wc = init;
|
||||
i++;
|
||||
} else {
|
||||
/* Look up the length of this UTF-8 sequence. */
|
||||
length = utf8_seq_length[(unsigned char) init];
|
||||
|
||||
/* Check to make sure we have enough bytes to convert. */
|
||||
if (i + length > utf8_len)
|
||||
XMLRPC_FAIL(envP, XMLRPC_INVALID_UTF8_ERROR,
|
||||
"Truncated UTF-8 sequence");
|
||||
|
||||
/* Decode a multibyte UTF-8 sequence. */
|
||||
switch (length) {
|
||||
case 0:
|
||||
XMLRPC_FAIL(envP, XMLRPC_INVALID_UTF8_ERROR,
|
||||
"Invalid UTF-8 initial byte");
|
||||
|
||||
case 2:
|
||||
/* 110xxxxx 10xxxxxx */
|
||||
con1 = utf8_data[i+1];
|
||||
if (!IS_CONTINUATION(con1))
|
||||
XMLRPC_FAIL(envP, XMLRPC_INVALID_UTF8_ERROR,
|
||||
"UTF-8 sequence too short");
|
||||
wc = ((((wchar_t) (init & 0x1F)) << 6) |
|
||||
(((wchar_t) (con1 & 0x3F))));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
/* 1110xxxx 10xxxxxx 10xxxxxx */
|
||||
con1 = utf8_data[i+1];
|
||||
con2 = utf8_data[i+2];
|
||||
if (!IS_CONTINUATION(con1) || !IS_CONTINUATION(con2))
|
||||
XMLRPC_FAIL(envP, XMLRPC_INVALID_UTF8_ERROR,
|
||||
"UTF-8 sequence too short");
|
||||
wc = ((((wchar_t) (init & 0x0F)) << 12) |
|
||||
(((wchar_t) (con1 & 0x3F)) << 6) |
|
||||
(((wchar_t) (con2 & 0x3F))));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
case 5:
|
||||
/* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
case 6:
|
||||
/* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
/* This would require more than 16 bits in UTF-16, so
|
||||
it can't be represented in UCS-2, so it's beyond
|
||||
our capability. Characters in the BMP fit in 16
|
||||
bits.
|
||||
*/
|
||||
xmlrpc_env_set_fault_formatted(
|
||||
envP, XMLRPC_INVALID_UTF8_ERROR,
|
||||
"UTF-8 string contains a character not in the "
|
||||
"Basic Multilingual Plane (first byte %08x)",
|
||||
init);
|
||||
goto cleanup;
|
||||
|
||||
default:
|
||||
XMLRPC_ASSERT("Error in UTF-8 decoder tables");
|
||||
}
|
||||
|
||||
/* Advance to the end of the sequence. */
|
||||
i += length;
|
||||
|
||||
/* Check for illegal UCS-2 characters. */
|
||||
if (wc > UCS2_MAX_LEGAL_CHARACTER)
|
||||
XMLRPC_FAIL(envP, XMLRPC_INVALID_UTF8_ERROR,
|
||||
"UCS-2 characters > U+FFFD are illegal");
|
||||
|
||||
/* Check for UTF-16 surrogates. */
|
||||
if (UTF16_FIRST_SURROGATE <= wc && wc <= UTF16_LAST_SURROGATE)
|
||||
XMLRPC_FAIL(envP, XMLRPC_INVALID_UTF8_ERROR,
|
||||
"UTF-16 surrogates may not appear in UTF-8 data");
|
||||
|
||||
/* Check for overlong sequences. */
|
||||
if ((uint32_t)wc < utf8_min_char_for_length[length])
|
||||
XMLRPC_FAIL(envP, XMLRPC_INVALID_UTF8_ERROR,
|
||||
"Overlong UTF-8 sequence not allowed");
|
||||
}
|
||||
|
||||
/* If we have a buffer, write our character to it. */
|
||||
if (ioBuff) {
|
||||
ioBuff[out_pos++] = wc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Record the number of characters we found. */
|
||||
if (outBuffLenP)
|
||||
*outBuffLenP = out_pos;
|
||||
|
||||
cleanup:
|
||||
if (envP->fault_occurred) {
|
||||
if (outBuffLenP)
|
||||
*outBuffLenP = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_validate_utf8(xmlrpc_env * const env,
|
||||
const char * const utf8_data,
|
||||
size_t const utf8_len) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Validate that a string is valid UTF-8.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
decode_utf8(env, utf8_data, utf8_len, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
xmlrpc_mem_block *
|
||||
xmlrpc_utf8_to_wcs(xmlrpc_env * const envP,
|
||||
const char * const utf8_data,
|
||||
size_t const utf8_len) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Decode UTF-8 string to a "wide character string". This function
|
||||
returns an xmlrpc_mem_block with an element type of wchar_t. Don't
|
||||
try to intepret the block in a bytewise fashion--it won't work in
|
||||
any useful or portable fashion.
|
||||
|
||||
For backward compatibility, we return a meaningful value even when we
|
||||
fail. We return NULL when we fail.
|
||||
-----------------------------------------------------------------------------*/
|
||||
xmlrpc_mem_block * wcsP;
|
||||
size_t wcs_length;
|
||||
|
||||
/* Allocate a memory block large enough to hold any possible output.
|
||||
We assume that each byte of the input may decode to a whcar_t.
|
||||
*/
|
||||
wcsP = XMLRPC_MEMBLOCK_NEW(wchar_t, envP, utf8_len);
|
||||
if (!envP->fault_occurred) {
|
||||
/* Decode the UTF-8 data. */
|
||||
decode_utf8(envP, utf8_data, utf8_len,
|
||||
XMLRPC_MEMBLOCK_CONTENTS(wchar_t, wcsP),
|
||||
&wcs_length);
|
||||
if (!envP->fault_occurred) {
|
||||
/* We can't have overrun our buffer. */
|
||||
XMLRPC_ASSERT(wcs_length <= utf8_len);
|
||||
|
||||
/* Correct the length of the memory block. */
|
||||
XMLRPC_MEMBLOCK_RESIZE(wchar_t, envP, wcsP, wcs_length);
|
||||
}
|
||||
if (envP->fault_occurred)
|
||||
XMLRPC_MEMBLOCK_FREE(wchar_t, wcsP);
|
||||
}
|
||||
if (envP->fault_occurred)
|
||||
return NULL;
|
||||
else
|
||||
return wcsP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
xmlrpc_mem_block *
|
||||
xmlrpc_wcs_to_utf8(xmlrpc_env * const envP,
|
||||
const wchar_t * const wcs_data,
|
||||
size_t const wcs_len) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Encode a "wide character string" as UTF-8.
|
||||
|
||||
For backward compatibility, we return a meaningful value even when we
|
||||
fail. We return NULL when we fail.
|
||||
-----------------------------------------------------------------------------*/
|
||||
size_t const estimate = wcs_len * MAX_ENCODED_BYTES;
|
||||
/* Our conservative estimate of how big the output will be;
|
||||
i.e. we know it won't be larger than this. For the estimate,
|
||||
we assume that every wchar might encode to the maximum length.
|
||||
*/
|
||||
xmlrpc_mem_block * utf8P;
|
||||
|
||||
XMLRPC_ASSERT_ENV_OK(envP);
|
||||
XMLRPC_ASSERT_PTR_OK(wcs_data);
|
||||
|
||||
utf8P = XMLRPC_MEMBLOCK_NEW(char, envP, estimate);
|
||||
if (!envP->fault_occurred) {
|
||||
unsigned char * const buffer = XMLRPC_MEMBLOCK_CONTENTS(char, utf8P);
|
||||
size_t bytesUsed;
|
||||
size_t i;
|
||||
|
||||
bytesUsed = 0;
|
||||
for (i = 0; i < wcs_len && !envP->fault_occurred; ++i) {
|
||||
wchar_t const wc = wcs_data[i];
|
||||
if (wc <= 0x007F)
|
||||
buffer[bytesUsed++] = wc & 0x7F;
|
||||
else if (wc <= 0x07FF) {
|
||||
/* 110xxxxx 10xxxxxx */
|
||||
buffer[bytesUsed++] = 0xC0 | (wc >> 6);
|
||||
buffer[bytesUsed++] = 0x80 | (wc & 0x3F);
|
||||
} else if (wc <= 0xFFFF) {
|
||||
/* 1110xxxx 10xxxxxx 10xxxxxx */
|
||||
buffer[bytesUsed++] = 0xE0 | (wc >> 12);
|
||||
buffer[bytesUsed++] = 0x80 | ((wc >> 6) & 0x3F);
|
||||
buffer[bytesUsed++] = 0x80 | (wc & 0x3F);
|
||||
} else
|
||||
xmlrpc_faultf(envP,
|
||||
"Don't know how to encode UCS-4 characters yet");
|
||||
}
|
||||
if (!envP->fault_occurred) {
|
||||
XMLRPC_ASSERT(bytesUsed <= estimate);
|
||||
|
||||
XMLRPC_MEMBLOCK_RESIZE(char, envP, utf8P, bytesUsed);
|
||||
}
|
||||
if (envP->fault_occurred)
|
||||
XMLRPC_MEMBLOCK_FREE(char, utf8P);
|
||||
}
|
||||
|
||||
if (envP->fault_occurred)
|
||||
return NULL;
|
||||
else
|
||||
return utf8P;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else /* HAVE_UNICODE_WCHAR */
|
||||
|
||||
xmlrpc_mem_block *
|
||||
xmlrpc_utf8_to_wcs(xmlrpc_env * const envP,
|
||||
const char * const utf8_data ATTR_UNUSED,
|
||||
size_t const utf8_len ATTR_UNUSED) {
|
||||
|
||||
xmlrpc_faultf(envP, "INTERNAL ERROR: xmlrpc_utf8_to_wcs() called "
|
||||
"on a system that doesn't do Unicode!");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif /* HAVE_UNICODE_WCHAR */
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_force_to_utf8(char * const buffer) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Force the contents of 'buffer' to be valid UTF-8, any way possible.
|
||||
The buffer ends with a NUL character, and the mutation does not make
|
||||
it longer.
|
||||
|
||||
The most common reason for a string that's supposed to be UTF-8 not
|
||||
to be UTF-8 is that it was supposed to be ASCII but instead
|
||||
includes garbage with the high bit on (ASCII characters always have
|
||||
the high bit off), or maybe a primitive 8-bit ASCII extension.
|
||||
Therefore, we force it to UTF-8 by replacing some bytes that have
|
||||
the high bit set with DEL (0x7F). That would leave the other
|
||||
characters meaningful.
|
||||
-----------------------------------------------------------------------------*/
|
||||
char * p;
|
||||
|
||||
for (p = &buffer[0]; *p;) {
|
||||
uint const length = utf8_seq_length[(unsigned char) *p];
|
||||
|
||||
bool forceDel;
|
||||
uint32_t decoded;
|
||||
|
||||
forceDel = false;
|
||||
decoded = 0; /* suppress compiler warning; valid when !forceDel */
|
||||
|
||||
switch (length) {
|
||||
case 1:
|
||||
/* One-byte UTF-8 characters are easy. */
|
||||
decoded = *p;
|
||||
break;
|
||||
case 2:
|
||||
/* 110xxxxx 10xxxxxx */
|
||||
if (!*(p+1) || !(*p+2))
|
||||
forceDel = true;
|
||||
else if (!IS_CONTINUATION(*(p+1)))
|
||||
forceDel = true;
|
||||
else
|
||||
decoded =
|
||||
((uint32_t)(*(p+0) & 0x1F) << 6) |
|
||||
((uint32_t)(*(p+1) & 0x3F) << 0);
|
||||
break;
|
||||
case 3:
|
||||
/* 1110xxxx 10xxxxxx 10xxxxxx */
|
||||
if (!*(p+1) || !(*p+2) || !(*p+3))
|
||||
forceDel = true;
|
||||
else if (!IS_CONTINUATION(*(p+1)) || !IS_CONTINUATION(*(p+2)))
|
||||
forceDel = true;
|
||||
else
|
||||
decoded =
|
||||
((uint32_t)(*(p+0) & 0x0F) << 12) |
|
||||
((uint32_t)(*(p+1) & 0x3F) << 6) |
|
||||
((uint32_t)(*(p+2) & 0x3F) << 0);
|
||||
break;
|
||||
default:
|
||||
forceDel = true;
|
||||
}
|
||||
|
||||
if (!forceDel) {
|
||||
if (decoded > UCS2_MAX_LEGAL_CHARACTER)
|
||||
forceDel = true;
|
||||
else if (UTF16_FIRST_SURROGATE <= decoded &&
|
||||
decoded <= UTF16_LAST_SURROGATE)
|
||||
forceDel = true;
|
||||
else if (decoded < utf8_min_char_for_length[length])
|
||||
forceDel = true;
|
||||
}
|
||||
|
||||
if (forceDel) {
|
||||
/* Not a valid UTF-8 character, so replace the first byte
|
||||
with a nice simple ASCII DEL.
|
||||
*/
|
||||
*p = 0x7F;
|
||||
p += 1;
|
||||
} else
|
||||
p += length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_force_to_xml_chars(char * const buffer) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Modify 'buffer' so that it contains nothing but valid XML
|
||||
characters. The buffer ends with a NUL character, and the mutation
|
||||
does not make it longer.
|
||||
|
||||
Note that the valid characters in an XML document are all Unicode
|
||||
codepoints except the ASCII control characters, plus CR, LF, and
|
||||
Tab.
|
||||
|
||||
We change all non-XML characters to DEL (0x7F).
|
||||
|
||||
Assume input is valid UTF-8.
|
||||
-----------------------------------------------------------------------------*/
|
||||
char * p;
|
||||
|
||||
for (p = &buffer[0]; *p;) {
|
||||
uint const length = utf8_seq_length[(unsigned char) *p];
|
||||
|
||||
if (length == 1) {
|
||||
if (*p < 0x20 && *p != '\r' && *p != '\n' && *p != '\t')
|
||||
/* Not valid XML. Force to DEL */
|
||||
*p = 0x7f;
|
||||
} else {
|
||||
/* We assume here that all other UTF-8 characters are
|
||||
valid XML, but it's apparently not actually true.
|
||||
*/
|
||||
}
|
||||
|
||||
{
|
||||
unsigned int i;
|
||||
/* Advance to next UTF-8 character */
|
||||
for (i = 0; i < length && *p; ++i)
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user