mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-31 15:44:21 +00:00
FS-2746 --resolve large xmlrpc update thanks garmt
This commit is contained in:
1 parent
37ecad9903
commit
6b6c83a718
397 files changed
+41821
-33840
No files matched your search
+441
-208
@@ -1,34 +1,30 @@
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#define _XOPEN_SOURCE 600 /* Make sure strdup() is in <string.h> */
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#if MSVCRT
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "bool.h"
|
||||
#include "mallocvar.h"
|
||||
|
||||
#include "xmlrpc-c/c_util.h"
|
||||
#include "xmlrpc-c/base.h"
|
||||
#include "xmlrpc-c/base_int.h"
|
||||
#include "xmlrpc-c/string_int.h"
|
||||
#include "xmlrpc-c/time_int.h"
|
||||
|
||||
|
||||
/* Future work: the XMLRPC_TYPE_DATETIME xmlrpc_value should store the
|
||||
datetime as something computation-friendly, not as a string. The
|
||||
XML-RPC XML parser should parse the string value and reject the XML if
|
||||
it isn't valid.
|
||||
|
||||
But this file should remain the authority on datetimes, so the XML
|
||||
parser and builder should call on routines in here to do that.
|
||||
|
||||
time_t won't work because it can't represent times before 1970 or
|
||||
after 2038. We need to figure out something better.
|
||||
*/
|
||||
|
||||
#if HAVE_REGEX
|
||||
#include <regex.h>
|
||||
#endif
|
||||
|
||||
#if MSVCRT
|
||||
|
||||
@@ -111,20 +107,66 @@ validateDatetimeType(xmlrpc_env * const envP,
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_read_datetime(xmlrpc_env * const envP,
|
||||
const xmlrpc_value * const valueP,
|
||||
xmlrpc_datetime * const dtP) {
|
||||
|
||||
validateDatetimeType(envP, valueP);
|
||||
if (!envP->fault_occurred) {
|
||||
*dtP = valueP->_value.dt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_read_datetime_str(xmlrpc_env * const envP,
|
||||
const xmlrpc_value * const valueP,
|
||||
const char ** const stringValueP) {
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
This exists for backward compatibility. No normal modern program would
|
||||
want to see a datetime value in this format. Note that the format isn't
|
||||
even ISO 8601 -- it's a bizarre hybrid of two ISO 8601 formats.
|
||||
|
||||
Do not extend this.
|
||||
|
||||
This exists because Xmlrpc-c was at one time lazy and this was the only way
|
||||
to extract the value. An xmlrpc_value in those days represented a datetime
|
||||
with the actual XML-RPC wire format of a datetime, and this function simply
|
||||
returned a copy of it.
|
||||
-----------------------------------------------------------------------------*/
|
||||
validateDatetimeType(envP, valueP);
|
||||
if (!envP->fault_occurred) {
|
||||
const char * const contents =
|
||||
XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
|
||||
*stringValueP = strdup(contents);
|
||||
if (*stringValueP == NULL)
|
||||
xmlrpc_env_set_fault_formatted(
|
||||
envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate space "
|
||||
"for datetime string");
|
||||
time_t secs;
|
||||
unsigned int usecs;
|
||||
|
||||
xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs);
|
||||
|
||||
if (!envP->fault_occurred) {
|
||||
struct tm brokenTime;
|
||||
char dtString[64];
|
||||
|
||||
xmlrpc_gmtime(secs, &brokenTime);
|
||||
|
||||
/* Note that this format is NOT ISO 8601 -- it's a bizarre
|
||||
hybrid of two ISO 8601 formats.
|
||||
*/
|
||||
strftime(dtString, sizeof(dtString), "%Y%m%dT%H:%M:%S",
|
||||
&brokenTime);
|
||||
|
||||
if (usecs != 0) {
|
||||
char usecString[64];
|
||||
assert(usecs < 1000000);
|
||||
snprintf(usecString, sizeof(usecString), ".%06u", usecs);
|
||||
STRSCAT(dtString, usecString);
|
||||
}
|
||||
|
||||
*stringValueP = strdup(dtString);
|
||||
if (*stringValueP == NULL)
|
||||
xmlrpc_faultf(envP,
|
||||
"Unable to allocate memory for datetime string");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,160 +176,69 @@ void
|
||||
xmlrpc_read_datetime_str_old(xmlrpc_env * const envP,
|
||||
const xmlrpc_value * const valueP,
|
||||
const char ** const stringValueP) {
|
||||
|
||||
assert(valueP->_cache);
|
||||
|
||||
validateDatetimeType(envP, valueP);
|
||||
if (!envP->fault_occurred) {
|
||||
*stringValueP = XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block);
|
||||
const char ** const readBufferP = valueP->_cache;
|
||||
|
||||
if (!*readBufferP)
|
||||
/* Nobody's asked for the internal buffer before. Set it up. */
|
||||
xmlrpc_read_datetime_str(envP, valueP, readBufferP);
|
||||
|
||||
*stringValueP = *readBufferP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseDateNumbers(const char * const t,
|
||||
unsigned int * const YP,
|
||||
unsigned int * const MP,
|
||||
unsigned int * const DP,
|
||||
unsigned int * const hP,
|
||||
unsigned int * const mP,
|
||||
unsigned int * const sP) {
|
||||
|
||||
char year[4+1];
|
||||
char month[2+1];
|
||||
char day[2+1];
|
||||
char hour[2+1];
|
||||
char minute[2+1];
|
||||
char second[2+1];
|
||||
|
||||
assert(strlen(t) == 17);
|
||||
|
||||
year[0] = t[ 0];
|
||||
year[1] = t[ 1];
|
||||
year[2] = t[ 2];
|
||||
year[3] = t[ 3];
|
||||
year[4] = '\0';
|
||||
|
||||
month[0] = t[ 4];
|
||||
month[1] = t[ 5];
|
||||
month[2] = '\0';
|
||||
|
||||
day[0] = t[ 6];
|
||||
day[1] = t[ 7];
|
||||
day[2] = '\0';
|
||||
|
||||
assert(t[ 8] == 'T');
|
||||
|
||||
hour[0] = t[ 9];
|
||||
hour[1] = t[10];
|
||||
hour[2] = '\0';
|
||||
|
||||
assert(t[11] == ':');
|
||||
|
||||
minute[0] = t[12];
|
||||
minute[1] = t[13];
|
||||
minute[2] = '\0';
|
||||
|
||||
assert(t[14] == ':');
|
||||
|
||||
second[0] = t[15];
|
||||
second[1] = t[16];
|
||||
second[2] = '\0';
|
||||
|
||||
*YP = atoi(year);
|
||||
*MP = atoi(month);
|
||||
*DP = atoi(day);
|
||||
*hP = atoi(hour);
|
||||
*mP = atoi(minute);
|
||||
*sP = atoi(second);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
validateFormat(xmlrpc_env * const envP,
|
||||
const char * const t) {
|
||||
|
||||
if (strlen(t) != 17)
|
||||
xmlrpc_faultf(envP, "%u characters instead of 15.", strlen(t));
|
||||
else if (t[8] != 'T')
|
||||
xmlrpc_faultf(envP, "9th character is '%c', not 'T'", t[8]);
|
||||
else {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 8 && !envP->fault_occurred; ++i)
|
||||
if (!isdigit(t[i]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", t[i]);
|
||||
|
||||
if (!isdigit(t[9]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", t[9]);
|
||||
if (!isdigit(t[10]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", t[10]);
|
||||
if (t[11] != ':')
|
||||
xmlrpc_faultf(envP, "Not a colon: '%c'", t[11]);
|
||||
if (!isdigit(t[12]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", t[12]);
|
||||
if (!isdigit(t[13]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", t[13]);
|
||||
if (t[14] != ':')
|
||||
xmlrpc_faultf(envP, "Not a colon: '%c'", t[14]);
|
||||
if (!isdigit(t[15]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", t[15]);
|
||||
if (!isdigit(t[16]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", t[16]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseDatetime(xmlrpc_env * const envP,
|
||||
const char * const t,
|
||||
time_t * const timeValueP) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Parse a time in the format stored in an xmlrpc_value and return the
|
||||
time that it represents.
|
||||
|
||||
t[] is the input time string. We return the result as *timeValueP.
|
||||
|
||||
Example of the format we parse: "19980717T14:08:55"
|
||||
Note that this is not quite ISO 8601. It's a bizarre combination of
|
||||
two ISO 8601 formats.
|
||||
|
||||
The input is capable of representing datetimes that cannot be expressed
|
||||
as a time_t. In that case, we fail, with fault code
|
||||
XMLRPC_INTERNAL_ERROR.
|
||||
|
||||
And of course the input may not validly represent a datetime at all.
|
||||
In that case too, we fail with fault code XMLRPC_PARSE_ERROR.
|
||||
-----------------------------------------------------------------------------*/
|
||||
validateFormat(envP, t);
|
||||
void
|
||||
xmlrpc_read_datetime_usec(xmlrpc_env * const envP,
|
||||
const xmlrpc_value * const valueP,
|
||||
time_t * const secsP,
|
||||
unsigned int * const usecsP) {
|
||||
|
||||
validateDatetimeType(envP, valueP);
|
||||
|
||||
if (!envP->fault_occurred) {
|
||||
unsigned int Y, M, D, h, m, s;
|
||||
|
||||
parseDateNumbers(t, &Y, &M, &D, &h, &m, &s);
|
||||
|
||||
if (Y < 1970)
|
||||
xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
|
||||
"Year is too early to represent as "
|
||||
"a standard Unix time");
|
||||
if (valueP->_value.dt.Y < 1970)
|
||||
xmlrpc_faultf(envP, "Year (%u) is too early to represent as "
|
||||
"a standard Unix time",
|
||||
valueP->_value.dt.Y);
|
||||
else {
|
||||
struct tm brokenTime;
|
||||
const char * error;
|
||||
|
||||
brokenTime.tm_sec = s;
|
||||
brokenTime.tm_min = m;
|
||||
brokenTime.tm_hour = h;
|
||||
brokenTime.tm_mday = D;
|
||||
brokenTime.tm_mon = M - 1;
|
||||
brokenTime.tm_year = Y - 1900;
|
||||
|
||||
xmlrpc_timegm(&brokenTime, timeValueP, &error);
|
||||
|
||||
brokenTime.tm_sec = valueP->_value.dt.s;
|
||||
brokenTime.tm_min = valueP->_value.dt.m;
|
||||
brokenTime.tm_hour = valueP->_value.dt.h;
|
||||
brokenTime.tm_mday = valueP->_value.dt.D;
|
||||
brokenTime.tm_mon = valueP->_value.dt.M - 1;
|
||||
brokenTime.tm_year = valueP->_value.dt.Y - 1900;
|
||||
|
||||
xmlrpc_timegm(&brokenTime, secsP, &error);
|
||||
|
||||
if (error) {
|
||||
xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR, error);
|
||||
/* Ideally, this wouldn't be possible - it wouldn't be
|
||||
possible to create an xmlrpc_value that doesn't actually
|
||||
represent a real datetime. But today, we're lazy and
|
||||
don't fully validate incoming XML-RPC <dateTime.iso8601>
|
||||
elements, and we also have the legacy
|
||||
xmlrpc_datetime_new_str() constructor to which the user
|
||||
may feed garbage.
|
||||
|
||||
We should tighten that up and then simply assert here that
|
||||
xmlrpc_timegm() succeeded.
|
||||
*/
|
||||
xmlrpc_env_set_fault_formatted(envP, XMLRPC_PARSE_ERROR,
|
||||
"A datetime received in an XML-RPC message "
|
||||
"or generated with legacy Xmlrpc-c facilities "
|
||||
"does not validly describe a datetime. %s",
|
||||
error);
|
||||
xmlrpc_strfree(error);
|
||||
}
|
||||
} else
|
||||
*usecsP = valueP->_value.dt.u;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,37 +250,311 @@ xmlrpc_read_datetime_sec(xmlrpc_env * const envP,
|
||||
const xmlrpc_value * const valueP,
|
||||
time_t * const timeValueP) {
|
||||
|
||||
validateDatetimeType(envP, valueP);
|
||||
if (!envP->fault_occurred)
|
||||
parseDatetime(envP,
|
||||
XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block),
|
||||
timeValueP);
|
||||
unsigned int usecs;
|
||||
|
||||
xmlrpc_read_datetime_usec(envP, valueP, timeValueP, &usecs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if XMLRPC_HAVE_TIMEVAL
|
||||
|
||||
void
|
||||
xmlrpc_read_datetime_timeval(xmlrpc_env * const envP,
|
||||
const xmlrpc_value * const valueP,
|
||||
struct timeval * const timeValueP) {
|
||||
|
||||
time_t secs;
|
||||
unsigned int usecs;
|
||||
|
||||
xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs);
|
||||
|
||||
timeValueP->tv_sec = secs;
|
||||
timeValueP->tv_usec = usecs;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if XMLRPC_HAVE_TIMESPEC
|
||||
|
||||
void
|
||||
xmlrpc_read_datetime_timespec(xmlrpc_env * const envP,
|
||||
const xmlrpc_value * const valueP,
|
||||
struct timespec * const timeValueP) {
|
||||
|
||||
time_t secs;
|
||||
unsigned int usecs;
|
||||
|
||||
xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs);
|
||||
|
||||
timeValueP->tv_sec = secs;
|
||||
timeValueP->tv_nsec = usecs * 1000;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
xmlrpc_value *
|
||||
xmlrpc_datetime_new(xmlrpc_env * const envP,
|
||||
xmlrpc_datetime const dt) {
|
||||
|
||||
xmlrpc_value * valP;
|
||||
|
||||
const char ** readBufferP;
|
||||
|
||||
MALLOCVAR(readBufferP);
|
||||
|
||||
if (!readBufferP)
|
||||
xmlrpc_faultf(envP, "Couldn't get memory for the cache part of the "
|
||||
"XML-RPC datetime value object");
|
||||
|
||||
else {
|
||||
*readBufferP = NULL;
|
||||
|
||||
xmlrpc_createXmlrpcValue(envP, &valP);
|
||||
|
||||
if (!envP->fault_occurred) {
|
||||
valP->_type = XMLRPC_TYPE_DATETIME;
|
||||
|
||||
valP->_value.dt = dt;
|
||||
|
||||
valP->_cache = readBufferP;
|
||||
}
|
||||
if (envP->fault_occurred)
|
||||
free(readBufferP);
|
||||
}
|
||||
return valP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parseDatetimeString(const char * const datetimeString,
|
||||
xmlrpc_datetime * const dtP) {
|
||||
|
||||
size_t const dtStrlen = strlen(datetimeString);
|
||||
|
||||
char year[4+1];
|
||||
char month[2+1];
|
||||
char day[2+1];
|
||||
char hour[2+1];
|
||||
char minute[2+1];
|
||||
char second[2+1];
|
||||
|
||||
/* Because we require input to be valid: */
|
||||
assert(dtStrlen >= 17 && dtStrlen != 18 && dtStrlen <= 24);
|
||||
|
||||
year[0] = datetimeString[ 0];
|
||||
year[1] = datetimeString[ 1];
|
||||
year[2] = datetimeString[ 2];
|
||||
year[3] = datetimeString[ 3];
|
||||
year[4] = '\0';
|
||||
|
||||
month[0] = datetimeString[ 4];
|
||||
month[1] = datetimeString[ 5];
|
||||
month[2] = '\0';
|
||||
|
||||
day[0] = datetimeString[ 6];
|
||||
day[1] = datetimeString[ 7];
|
||||
day[2] = '\0';
|
||||
|
||||
assert(datetimeString[ 8] == 'T');
|
||||
|
||||
hour[0] = datetimeString[ 9];
|
||||
hour[1] = datetimeString[10];
|
||||
hour[2] = '\0';
|
||||
|
||||
assert(datetimeString[11] == ':');
|
||||
|
||||
minute[0] = datetimeString[12];
|
||||
minute[1] = datetimeString[13];
|
||||
minute[2] = '\0';
|
||||
|
||||
assert(datetimeString[14] == ':');
|
||||
|
||||
second[0] = datetimeString[15];
|
||||
second[1] = datetimeString[16];
|
||||
second[2] = '\0';
|
||||
|
||||
if (dtStrlen > 17) {
|
||||
size_t const pad = 24 - dtStrlen;
|
||||
size_t i;
|
||||
|
||||
dtP->u = atoi(&datetimeString[18]);
|
||||
for (i = 0; i < pad; ++i)
|
||||
dtP->u *= 10;
|
||||
} else
|
||||
dtP->u = 0;
|
||||
|
||||
dtP->Y = atoi(year);
|
||||
dtP->M = atoi(month);
|
||||
dtP->D = atoi(day);
|
||||
dtP->h = atoi(hour);
|
||||
dtP->m = atoi(minute);
|
||||
dtP->s = atoi(second);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
validateFirst17(xmlrpc_env * const envP,
|
||||
const char * const dt) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Assuming 'dt' is at least 17 characters long, validate that the first
|
||||
17 characters are a valid XML-RPC datetime, e.g.
|
||||
"20080628T16:35:02"
|
||||
-----------------------------------------------------------------------------*/
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 8 && !envP->fault_occurred; ++i)
|
||||
if (!isdigit(dt[i]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", dt[i]);
|
||||
|
||||
if (dt[8] != 'T')
|
||||
xmlrpc_faultf(envP, "9th character is '%c', not 'T'", dt[8]);
|
||||
if (!isdigit(dt[9]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", dt[9]);
|
||||
if (!isdigit(dt[10]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", dt[10]);
|
||||
if (dt[11] != ':')
|
||||
xmlrpc_faultf(envP, "Not a colon: '%c'", dt[11]);
|
||||
if (!isdigit(dt[12]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", dt[12]);
|
||||
if (!isdigit(dt[13]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", dt[13]);
|
||||
if (dt[14] != ':')
|
||||
xmlrpc_faultf(envP, "Not a colon: '%c'", dt[14]);
|
||||
if (!isdigit(dt[15]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", dt[15]);
|
||||
if (!isdigit(dt[16]))
|
||||
xmlrpc_faultf(envP, "Not a digit: '%c'", dt[16]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
validateFractionalSeconds(xmlrpc_env * const envP,
|
||||
const char * const dt) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Validate the fractional seconds part of the XML-RPC datetime string
|
||||
'dt', if any. That's the decimal point and everything following
|
||||
it.
|
||||
-----------------------------------------------------------------------------*/
|
||||
if (strlen(dt) > 17) {
|
||||
if (dt[17] != '.') {
|
||||
xmlrpc_faultf(envP, "'%c' where only a period is valid", dt[17]);
|
||||
} else {
|
||||
if (dt[18] == '\0')
|
||||
xmlrpc_faultf(envP, "Nothing after decimal point");
|
||||
else {
|
||||
unsigned int i;
|
||||
for (i = 18; dt[i] != '\0' && !envP->fault_occurred; ++i) {
|
||||
if (!isdigit(dt[i]))
|
||||
xmlrpc_faultf(envP,
|
||||
"Non-digit in fractional seconds: '%c'",
|
||||
dt[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
validateFormat(xmlrpc_env * const envP,
|
||||
const char * const dt) {
|
||||
|
||||
if (strlen(dt) < 17)
|
||||
xmlrpc_faultf(envP,
|
||||
"Invalid length of %u of datetime string. "
|
||||
"Must be at least 17 characters",
|
||||
(unsigned)strlen(dt));
|
||||
else {
|
||||
validateFirst17(envP, dt);
|
||||
|
||||
if (!envP->fault_occurred)
|
||||
validateFractionalSeconds(envP, dt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Microsoft Visual C in debug mode produces code that complains about
|
||||
returning an undefined value from xmlrpc_datetime_new_str(). It's a bogus
|
||||
complaint, because this function is defined to return nothing meaningful
|
||||
those cases. So we disable the check.
|
||||
*/
|
||||
#pragma runtime_checks("u", off)
|
||||
|
||||
|
||||
|
||||
xmlrpc_value *
|
||||
xmlrpc_datetime_new_str(xmlrpc_env * const envP,
|
||||
const char * const value) {
|
||||
const char * const datetimeString) {
|
||||
/*----------------------------------------------------------------------------
|
||||
This exists only for backward compatibility. Originally, this was the
|
||||
only way to create a datetime XML-RPC value, because we had a really
|
||||
lazy implementation of XML-RPC serialization and parsing (basically, the
|
||||
user did it!).
|
||||
|
||||
xmlrpc_value * valP;
|
||||
|
||||
xmlrpc_createXmlrpcValue(envP, &valP);
|
||||
Do not extend this. The user should use more normal C representations
|
||||
of datetimes.
|
||||
-----------------------------------------------------------------------------*/
|
||||
xmlrpc_value * retval;
|
||||
|
||||
validateFormat(envP, datetimeString);
|
||||
if (!envP->fault_occurred) {
|
||||
valP->_type = XMLRPC_TYPE_DATETIME;
|
||||
xmlrpc_datetime dt;
|
||||
|
||||
XMLRPC_TYPED_MEM_BLOCK_INIT(
|
||||
char, envP, &valP->_block, strlen(value) + 1);
|
||||
if (!envP->fault_occurred) {
|
||||
char * const contents =
|
||||
XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block);
|
||||
strcpy(contents, value);
|
||||
}
|
||||
if (envP->fault_occurred)
|
||||
free(valP);
|
||||
parseDatetimeString(datetimeString, &dt);
|
||||
|
||||
/* Note that parseDatetimeString() can generate an invalid datetime
|
||||
value, e.g. Hour 25 or February 30. Ideally, we would catch that
|
||||
here, but due to laziness, we simply accept the possibility of
|
||||
invalid xmlrpc_datetime in xmlrpc_value and whoever uses the the
|
||||
xmlrpc_value has to deal with it.
|
||||
*/
|
||||
retval = xmlrpc_datetime_new(envP, dt);
|
||||
}
|
||||
return valP;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma runtime_checks("u", restore)
|
||||
|
||||
|
||||
|
||||
xmlrpc_value *
|
||||
xmlrpc_datetime_new_usec(xmlrpc_env * const envP,
|
||||
time_t const secs,
|
||||
unsigned int const usecs) {
|
||||
|
||||
xmlrpc_value * valueP;
|
||||
|
||||
if (usecs >= 1000000)
|
||||
xmlrpc_faultf(envP, "Number of fractional microseconds must be less "
|
||||
"than one million. You specified %u", usecs);
|
||||
else {
|
||||
struct tm brokenTime;
|
||||
xmlrpc_datetime dt;
|
||||
|
||||
xmlrpc_gmtime(secs, &brokenTime);
|
||||
|
||||
dt.s = brokenTime.tm_sec;
|
||||
dt.m = brokenTime.tm_min;
|
||||
dt.h = brokenTime.tm_hour;
|
||||
dt.D = brokenTime.tm_mday;
|
||||
dt.M = brokenTime.tm_mon + 1;
|
||||
dt.Y = 1900 + brokenTime.tm_year;
|
||||
dt.u = usecs;
|
||||
|
||||
valueP = xmlrpc_datetime_new(envP, dt);
|
||||
}
|
||||
return valueP;
|
||||
}
|
||||
|
||||
|
||||
@@ -338,34 +563,42 @@ xmlrpc_value *
|
||||
xmlrpc_datetime_new_sec(xmlrpc_env * const envP,
|
||||
time_t const value) {
|
||||
|
||||
xmlrpc_value * valP;
|
||||
|
||||
xmlrpc_createXmlrpcValue(envP, &valP);
|
||||
|
||||
if (!envP->fault_occurred) {
|
||||
struct tm brokenTime;
|
||||
char timeString[64];
|
||||
|
||||
valP->_type = XMLRPC_TYPE_DATETIME;
|
||||
|
||||
xmlrpc_gmtime(value, &brokenTime);
|
||||
|
||||
/* Note that this format is NOT ISO 8601 -- it's a bizarre
|
||||
hybrid of two ISO 8601 formats.
|
||||
*/
|
||||
strftime(timeString, sizeof(timeString), "%Y%m%dT%H:%M:%S",
|
||||
&brokenTime);
|
||||
|
||||
XMLRPC_TYPED_MEM_BLOCK_INIT(
|
||||
char, envP, &valP->_block, strlen(timeString) + 1);
|
||||
if (!envP->fault_occurred) {
|
||||
char * const contents =
|
||||
XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block);
|
||||
|
||||
strcpy(contents, timeString);
|
||||
}
|
||||
if (envP->fault_occurred)
|
||||
free(valP);
|
||||
}
|
||||
return valP;
|
||||
return xmlrpc_datetime_new_usec(envP, value, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if XMLRPC_HAVE_TIMEVAL
|
||||
|
||||
xmlrpc_value *
|
||||
xmlrpc_datetime_new_timeval(xmlrpc_env * const envP,
|
||||
struct timeval const value) {
|
||||
|
||||
return xmlrpc_datetime_new_usec(envP, value.tv_sec, value.tv_usec);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if XMLRPC_HAVE_TIMESPEC
|
||||
|
||||
xmlrpc_value *
|
||||
xmlrpc_datetime_new_timespec(xmlrpc_env * const envP,
|
||||
struct timespec const value) {
|
||||
|
||||
return xmlrpc_datetime_new_usec(envP, value.tv_sec, value.tv_nsec/1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void
|
||||
xmlrpc_destroyDatetime(xmlrpc_value * const datetimeP) {
|
||||
|
||||
const char ** const readBufferP = datetimeP->_cache;
|
||||
|
||||
if (*readBufferP)
|
||||
xmlrpc_strfree(*readBufferP);
|
||||
|
||||
free(datetimeP->_cache);
|
||||
}
|
||||
Reference in new issue
Block a user