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

@@ -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

View 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);
}

View 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. */

View 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;
}

View 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.
*/

View 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;
}

View 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
}

View 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
}

View 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;
}
}
}