| File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c |
| Location: | line 162, column 17 |
| Description: | Potential buffer overflow. Replace with 'sizeof(dtString) - strlen(dtString) - 1' or use a safer 'strlcat' API |
| 1 | #include "xmlrpc_config.h" |
| 2 | |
| 3 | #define _XOPEN_SOURCE700 600 /* Make sure strdup() is in <string.h> */ |
| 4 | |
| 5 | #include <time.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <string.h> |
| 8 | #include <ctype.h> |
| 9 | #include <assert.h> |
| 10 | #include <stdio.h> |
| 11 | #if MSVCRT0 |
| 12 | #include <windows.h> |
| 13 | #endif |
| 14 | |
| 15 | #include "bool.h" |
| 16 | #include "mallocvar.h" |
| 17 | |
| 18 | #include "xmlrpc-c/c_util.h" |
| 19 | #include "xmlrpc-c/base.h" |
| 20 | #include "xmlrpc-c/base_int.h" |
| 21 | #include "xmlrpc-c/string_int.h" |
| 22 | #include "xmlrpc-c/time_int.h" |
| 23 | |
| 24 | |
| 25 | #if HAVE_REGEX1 |
| 26 | #include <regex.h> |
| 27 | #endif |
| 28 | |
| 29 | #if MSVCRT0 |
| 30 | |
| 31 | static const __int64 SECS_BETWEEN_EPOCHS = 11644473600; |
| 32 | static const __int64 SECS_TO_100NS = 10000000; /* 10^7 */ |
| 33 | |
| 34 | |
| 35 | void |
| 36 | UnixTimeToFileTime(time_t const t, |
| 37 | LPFILETIME const pft) { |
| 38 | |
| 39 | int64_t const ll = |
| 40 | Int32x32To64(t, SECS_TO_100NS) + SECS_BETWEEN_EPOCHS * SECS_TO_100NS; |
| 41 | |
| 42 | pft->dwLowDateTime = (DWORD)ll; |
| 43 | pft->dwHighDateTime = (DWORD)(ll >> 32); |
| 44 | } |
| 45 | |
| 46 | |
| 47 | |
| 48 | void |
| 49 | UnixTimeToSystemTime(time_t const t, |
| 50 | LPSYSTEMTIME const pst) { |
| 51 | FILETIME ft; |
| 52 | |
| 53 | UnixTimeToFileTime(t, &ft); |
| 54 | FileTimeToSystemTime(&ft, pst); |
| 55 | } |
| 56 | |
| 57 | |
| 58 | |
| 59 | static void |
| 60 | UnixTimeFromFileTime(xmlrpc_env * const envP, |
| 61 | LPFILETIME const pft, |
| 62 | time_t * const timeValueP) { |
| 63 | |
| 64 | int64_t const WinEpoch100Ns = |
| 65 | ((int64_t)pft->dwHighDateTime << 32) + pft->dwLowDateTime; |
| 66 | int64_t const unixEpoch100Ns = |
| 67 | WinEpoch100Ns - (SECS_BETWEEN_EPOCHS * SECS_TO_100NS); |
| 68 | int64_t const unixEpochSeconds = |
| 69 | unixEpoch100Ns / SECS_TO_100NS; |
| 70 | |
| 71 | if ((time_t)unixEpochSeconds != unixEpochSeconds) { |
| 72 | /* Value is too big for a time_t; fail. */ |
| 73 | xmlrpc_faultf(envP, "Does not indicate a valid date"); |
| 74 | *timeValueP = (time_t)(-1); |
| 75 | } else |
| 76 | *timeValueP = (time_t)unixEpochSeconds; |
| 77 | } |
| 78 | |
| 79 | |
| 80 | |
| 81 | static void |
| 82 | UnixTimeFromSystemTime(xmlrpc_env * const envP, |
| 83 | LPSYSTEMTIME const pst, |
| 84 | time_t * const timeValueP) { |
| 85 | FILETIME filetime; |
| 86 | |
| 87 | SystemTimeToFileTime(pst, &filetime); |
| 88 | UnixTimeFromFileTime(envP, &filetime, timeValueP); |
| 89 | } |
| 90 | |
| 91 | #endif /* MSVCRT */ |
| 92 | |
| 93 | |
| 94 | |
| 95 | static void |
| 96 | validateDatetimeType(xmlrpc_env * const envP, |
| 97 | const xmlrpc_value * const valueP) { |
| 98 | |
| 99 | if (valueP->_type != XMLRPC_TYPE_DATETIME) { |
| 100 | xmlrpc_env_set_fault_formatted( |
| 101 | envP, XMLRPC_TYPE_ERROR(-501), "Value of type %s supplied where " |
| 102 | "type %s was expected.", |
| 103 | xmlrpc_type_name(valueP->_type), |
| 104 | xmlrpc_type_name(XMLRPC_TYPE_DATETIME)); |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | |
| 109 | |
| 110 | void |
| 111 | xmlrpc_read_datetime(xmlrpc_env * const envP, |
| 112 | const xmlrpc_value * const valueP, |
| 113 | xmlrpc_datetime * const dtP) { |
| 114 | |
| 115 | validateDatetimeType(envP, valueP); |
| 116 | if (!envP->fault_occurred) { |
| 117 | *dtP = valueP->_value.dt; |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | |
| 122 | |
| 123 | void |
| 124 | xmlrpc_read_datetime_str(xmlrpc_env * const envP, |
| 125 | const xmlrpc_value * const valueP, |
| 126 | const char ** const stringValueP) { |
| 127 | /*---------------------------------------------------------------------------- |
| 128 | This exists for backward compatibility. No normal modern program would |
| 129 | want to see a datetime value in this format. Note that the format isn't |
| 130 | even ISO 8601 -- it's a bizarre hybrid of two ISO 8601 formats. |
| 131 | |
| 132 | Do not extend this. |
| 133 | |
| 134 | This exists because Xmlrpc-c was at one time lazy and this was the only way |
| 135 | to extract the value. An xmlrpc_value in those days represented a datetime |
| 136 | with the actual XML-RPC wire format of a datetime, and this function simply |
| 137 | returned a copy of it. |
| 138 | -----------------------------------------------------------------------------*/ |
| 139 | validateDatetimeType(envP, valueP); |
| 140 | if (!envP->fault_occurred) { |
| 141 | time_t secs; |
| 142 | unsigned int usecs; |
| 143 | |
| 144 | xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs); |
| 145 | |
| 146 | if (!envP->fault_occurred) { |
| 147 | struct tm brokenTime; |
| 148 | char dtString[64]; |
| 149 | |
| 150 | xmlrpc_gmtime(secs, &brokenTime); |
| 151 | |
| 152 | /* Note that this format is NOT ISO 8601 -- it's a bizarre |
| 153 | hybrid of two ISO 8601 formats. |
| 154 | */ |
| 155 | strftime(dtString, sizeof(dtString), "%Y%m%dT%H:%M:%S", |
| 156 | &brokenTime); |
| 157 | |
| 158 | if (usecs != 0) { |
| 159 | char usecString[64]; |
| 160 | assert(usecs < 1000000)((usecs < 1000000) ? (void) (0) : __assert_fail ("usecs < 1000000" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 160, __PRETTY_FUNCTION__ )); |
| 161 | snprintf(usecString, sizeof(usecString), ".%06u", usecs); |
| 162 | STRSCAT(dtString, usecString)(__builtin_strncat ((dtString), (usecString), sizeof(dtString )-strlen(dtString)), *((dtString)+sizeof(dtString)-1) = '\0'); |
Potential buffer overflow. Replace with 'sizeof(dtString) - strlen(dtString) - 1' or use a safer 'strlcat' API | |
| 163 | } |
| 164 | |
| 165 | *stringValueP = strdup(dtString)(__extension__ (__builtin_constant_p (dtString) && (( size_t)(const void *)((dtString) + 1) - (size_t)(const void * )(dtString) == 1) ? (((const char *) (dtString))[0] == '\0' ? (char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen (dtString) + 1; char *__retval = (char *) malloc (__len ); if (__retval != ((void*)0)) __retval = (char *) memcpy (__retval , dtString, __len); __retval; })) : __strdup (dtString))); |
| 166 | if (*stringValueP == NULL((void*)0)) |
| 167 | xmlrpc_faultf(envP, |
| 168 | "Unable to allocate memory for datetime string"); |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | |
| 174 | |
| 175 | void |
| 176 | xmlrpc_read_datetime_str_old(xmlrpc_env * const envP, |
| 177 | const xmlrpc_value * const valueP, |
| 178 | const char ** const stringValueP) { |
| 179 | |
| 180 | assert(valueP->_cache)((valueP->_cache) ? (void) (0) : __assert_fail ("valueP->_cache" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 180, __PRETTY_FUNCTION__ )); |
| 181 | |
| 182 | validateDatetimeType(envP, valueP); |
| 183 | if (!envP->fault_occurred) { |
| 184 | const char ** const readBufferP = valueP->_cache; |
| 185 | |
| 186 | if (!*readBufferP) |
| 187 | /* Nobody's asked for the internal buffer before. Set it up. */ |
| 188 | xmlrpc_read_datetime_str(envP, valueP, readBufferP); |
| 189 | |
| 190 | *stringValueP = *readBufferP; |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | |
| 195 | |
| 196 | void |
| 197 | xmlrpc_read_datetime_usec(xmlrpc_env * const envP, |
| 198 | const xmlrpc_value * const valueP, |
| 199 | time_t * const secsP, |
| 200 | unsigned int * const usecsP) { |
| 201 | |
| 202 | validateDatetimeType(envP, valueP); |
| 203 | |
| 204 | if (!envP->fault_occurred) { |
| 205 | if (valueP->_value.dt.Y < 1970) |
| 206 | xmlrpc_faultf(envP, "Year (%u) is too early to represent as " |
| 207 | "a standard Unix time", |
| 208 | valueP->_value.dt.Y); |
| 209 | else { |
| 210 | struct tm brokenTime; |
| 211 | const char * error; |
| 212 | |
| 213 | brokenTime.tm_sec = valueP->_value.dt.s; |
| 214 | brokenTime.tm_min = valueP->_value.dt.m; |
| 215 | brokenTime.tm_hour = valueP->_value.dt.h; |
| 216 | brokenTime.tm_mday = valueP->_value.dt.D; |
| 217 | brokenTime.tm_mon = valueP->_value.dt.M - 1; |
| 218 | brokenTime.tm_year = valueP->_value.dt.Y - 1900; |
| 219 | |
| 220 | xmlrpc_timegm(&brokenTime, secsP, &error); |
| 221 | |
| 222 | if (error) { |
| 223 | /* Ideally, this wouldn't be possible - it wouldn't be |
| 224 | possible to create an xmlrpc_value that doesn't actually |
| 225 | represent a real datetime. But today, we're lazy and |
| 226 | don't fully validate incoming XML-RPC <dateTime.iso8601> |
| 227 | elements, and we also have the legacy |
| 228 | xmlrpc_datetime_new_str() constructor to which the user |
| 229 | may feed garbage. |
| 230 | |
| 231 | We should tighten that up and then simply assert here that |
| 232 | xmlrpc_timegm() succeeded. |
| 233 | */ |
| 234 | xmlrpc_env_set_fault_formatted(envP, XMLRPC_PARSE_ERROR(-503), |
| 235 | "A datetime received in an XML-RPC message " |
| 236 | "or generated with legacy Xmlrpc-c facilities " |
| 237 | "does not validly describe a datetime. %s", |
| 238 | error); |
| 239 | xmlrpc_strfree(error); |
| 240 | } else |
| 241 | *usecsP = valueP->_value.dt.u; |
| 242 | } |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | |
| 247 | |
| 248 | void |
| 249 | xmlrpc_read_datetime_sec(xmlrpc_env * const envP, |
| 250 | const xmlrpc_value * const valueP, |
| 251 | time_t * const timeValueP) { |
| 252 | |
| 253 | unsigned int usecs; |
| 254 | |
| 255 | xmlrpc_read_datetime_usec(envP, valueP, timeValueP, &usecs); |
| 256 | } |
| 257 | |
| 258 | |
| 259 | |
| 260 | #if XMLRPC_HAVE_TIMEVAL1 |
| 261 | |
| 262 | void |
| 263 | xmlrpc_read_datetime_timeval(xmlrpc_env * const envP, |
| 264 | const xmlrpc_value * const valueP, |
| 265 | struct timeval * const timeValueP) { |
| 266 | |
| 267 | time_t secs; |
| 268 | unsigned int usecs; |
| 269 | |
| 270 | xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs); |
| 271 | |
| 272 | timeValueP->tv_sec = secs; |
| 273 | timeValueP->tv_usec = usecs; |
| 274 | } |
| 275 | #endif |
| 276 | |
| 277 | |
| 278 | |
| 279 | #if XMLRPC_HAVE_TIMESPEC1 |
| 280 | |
| 281 | void |
| 282 | xmlrpc_read_datetime_timespec(xmlrpc_env * const envP, |
| 283 | const xmlrpc_value * const valueP, |
| 284 | struct timespec * const timeValueP) { |
| 285 | |
| 286 | time_t secs; |
| 287 | unsigned int usecs; |
| 288 | |
| 289 | xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs); |
| 290 | |
| 291 | timeValueP->tv_sec = secs; |
| 292 | timeValueP->tv_nsec = usecs * 1000; |
| 293 | } |
| 294 | #endif |
| 295 | |
| 296 | |
| 297 | |
| 298 | xmlrpc_value * |
| 299 | xmlrpc_datetime_new(xmlrpc_env * const envP, |
| 300 | xmlrpc_datetime const dt) { |
| 301 | |
| 302 | xmlrpc_value * valP; |
| 303 | |
| 304 | const char ** readBufferP; |
| 305 | |
| 306 | MALLOCVAR(readBufferP)readBufferP = malloc(sizeof(*readBufferP)); |
| 307 | |
| 308 | if (!readBufferP) |
| 309 | xmlrpc_faultf(envP, "Couldn't get memory for the cache part of the " |
| 310 | "XML-RPC datetime value object"); |
| 311 | |
| 312 | else { |
| 313 | *readBufferP = NULL((void*)0); |
| 314 | |
| 315 | xmlrpc_createXmlrpcValue(envP, &valP); |
| 316 | |
| 317 | if (!envP->fault_occurred) { |
| 318 | valP->_type = XMLRPC_TYPE_DATETIME; |
| 319 | |
| 320 | valP->_value.dt = dt; |
| 321 | |
| 322 | valP->_cache = readBufferP; |
| 323 | } |
| 324 | if (envP->fault_occurred) |
| 325 | free(readBufferP); |
| 326 | } |
| 327 | return valP; |
| 328 | } |
| 329 | |
| 330 | |
| 331 | |
| 332 | static void |
| 333 | parseDatetimeString(const char * const datetimeString, |
| 334 | xmlrpc_datetime * const dtP) { |
| 335 | |
| 336 | size_t const dtStrlen = strlen(datetimeString); |
| 337 | |
| 338 | char year[4+1]; |
| 339 | char month[2+1]; |
| 340 | char day[2+1]; |
| 341 | char hour[2+1]; |
| 342 | char minute[2+1]; |
| 343 | char second[2+1]; |
| 344 | |
| 345 | /* Because we require input to be valid: */ |
| 346 | assert(dtStrlen >= 17 && dtStrlen != 18 && dtStrlen <= 24)((dtStrlen >= 17 && dtStrlen != 18 && dtStrlen <= 24) ? (void) (0) : __assert_fail ("dtStrlen >= 17 && dtStrlen != 18 && dtStrlen <= 24" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 346, __PRETTY_FUNCTION__ )); |
| 347 | |
| 348 | year[0] = datetimeString[ 0]; |
| 349 | year[1] = datetimeString[ 1]; |
| 350 | year[2] = datetimeString[ 2]; |
| 351 | year[3] = datetimeString[ 3]; |
| 352 | year[4] = '\0'; |
| 353 | |
| 354 | month[0] = datetimeString[ 4]; |
| 355 | month[1] = datetimeString[ 5]; |
| 356 | month[2] = '\0'; |
| 357 | |
| 358 | day[0] = datetimeString[ 6]; |
| 359 | day[1] = datetimeString[ 7]; |
| 360 | day[2] = '\0'; |
| 361 | |
| 362 | assert(datetimeString[ 8] == 'T')((datetimeString[ 8] == 'T') ? (void) (0) : __assert_fail ("datetimeString[ 8] == 'T'" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 362, __PRETTY_FUNCTION__ )); |
| 363 | |
| 364 | hour[0] = datetimeString[ 9]; |
| 365 | hour[1] = datetimeString[10]; |
| 366 | hour[2] = '\0'; |
| 367 | |
| 368 | assert(datetimeString[11] == ':')((datetimeString[11] == ':') ? (void) (0) : __assert_fail ("datetimeString[11] == ':'" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 368, __PRETTY_FUNCTION__ )); |
| 369 | |
| 370 | minute[0] = datetimeString[12]; |
| 371 | minute[1] = datetimeString[13]; |
| 372 | minute[2] = '\0'; |
| 373 | |
| 374 | assert(datetimeString[14] == ':')((datetimeString[14] == ':') ? (void) (0) : __assert_fail ("datetimeString[14] == ':'" , "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 374, __PRETTY_FUNCTION__ )); |
| 375 | |
| 376 | second[0] = datetimeString[15]; |
| 377 | second[1] = datetimeString[16]; |
| 378 | second[2] = '\0'; |
| 379 | |
| 380 | if (dtStrlen > 17) { |
| 381 | size_t const pad = 24 - dtStrlen; |
| 382 | size_t i; |
| 383 | |
| 384 | dtP->u = atoi(&datetimeString[18]); |
| 385 | for (i = 0; i < pad; ++i) |
| 386 | dtP->u *= 10; |
| 387 | } else |
| 388 | dtP->u = 0; |
| 389 | |
| 390 | dtP->Y = atoi(year); |
| 391 | dtP->M = atoi(month); |
| 392 | dtP->D = atoi(day); |
| 393 | dtP->h = atoi(hour); |
| 394 | dtP->m = atoi(minute); |
| 395 | dtP->s = atoi(second); |
| 396 | } |
| 397 | |
| 398 | |
| 399 | |
| 400 | static void |
| 401 | validateFirst17(xmlrpc_env * const envP, |
| 402 | const char * const dt) { |
| 403 | /*---------------------------------------------------------------------------- |
| 404 | Assuming 'dt' is at least 17 characters long, validate that the first |
| 405 | 17 characters are a valid XML-RPC datetime, e.g. |
| 406 | "20080628T16:35:02" |
| 407 | -----------------------------------------------------------------------------*/ |
| 408 | unsigned int i; |
| 409 | |
| 410 | for (i = 0; i < 8 && !envP->fault_occurred; ++i) |
| 411 | if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int ) _ISdigit)) |
| 412 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[i]); |
| 413 | |
| 414 | if (dt[8] != 'T') |
| 415 | xmlrpc_faultf(envP, "9th character is '%c', not 'T'", dt[8]); |
| 416 | if (!isdigit(dt[9])((*__ctype_b_loc ())[(int) ((dt[9]))] & (unsigned short int ) _ISdigit)) |
| 417 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[9]); |
| 418 | if (!isdigit(dt[10])((*__ctype_b_loc ())[(int) ((dt[10]))] & (unsigned short int ) _ISdigit)) |
| 419 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[10]); |
| 420 | if (dt[11] != ':') |
| 421 | xmlrpc_faultf(envP, "Not a colon: '%c'", dt[11]); |
| 422 | if (!isdigit(dt[12])((*__ctype_b_loc ())[(int) ((dt[12]))] & (unsigned short int ) _ISdigit)) |
| 423 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[12]); |
| 424 | if (!isdigit(dt[13])((*__ctype_b_loc ())[(int) ((dt[13]))] & (unsigned short int ) _ISdigit)) |
| 425 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[13]); |
| 426 | if (dt[14] != ':') |
| 427 | xmlrpc_faultf(envP, "Not a colon: '%c'", dt[14]); |
| 428 | if (!isdigit(dt[15])((*__ctype_b_loc ())[(int) ((dt[15]))] & (unsigned short int ) _ISdigit)) |
| 429 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[15]); |
| 430 | if (!isdigit(dt[16])((*__ctype_b_loc ())[(int) ((dt[16]))] & (unsigned short int ) _ISdigit)) |
| 431 | xmlrpc_faultf(envP, "Not a digit: '%c'", dt[16]); |
| 432 | } |
| 433 | |
| 434 | |
| 435 | |
| 436 | static void |
| 437 | validateFractionalSeconds(xmlrpc_env * const envP, |
| 438 | const char * const dt) { |
| 439 | /*---------------------------------------------------------------------------- |
| 440 | Validate the fractional seconds part of the XML-RPC datetime string |
| 441 | 'dt', if any. That's the decimal point and everything following |
| 442 | it. |
| 443 | -----------------------------------------------------------------------------*/ |
| 444 | if (strlen(dt) > 17) { |
| 445 | if (dt[17] != '.') { |
| 446 | xmlrpc_faultf(envP, "'%c' where only a period is valid", dt[17]); |
| 447 | } else { |
| 448 | if (dt[18] == '\0') |
| 449 | xmlrpc_faultf(envP, "Nothing after decimal point"); |
| 450 | else { |
| 451 | unsigned int i; |
| 452 | for (i = 18; dt[i] != '\0' && !envP->fault_occurred; ++i) { |
| 453 | if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int ) _ISdigit)) |
| 454 | xmlrpc_faultf(envP, |
| 455 | "Non-digit in fractional seconds: '%c'", |
| 456 | dt[i]); |
| 457 | } |
| 458 | } |
| 459 | } |
| 460 | } |
| 461 | } |
| 462 | |
| 463 | |
| 464 | |
| 465 | static void |
| 466 | validateFormat(xmlrpc_env * const envP, |
| 467 | const char * const dt) { |
| 468 | |
| 469 | if (strlen(dt) < 17) |
| 470 | xmlrpc_faultf(envP, |
| 471 | "Invalid length of %u of datetime string. " |
| 472 | "Must be at least 17 characters", |
| 473 | (unsigned)strlen(dt)); |
| 474 | else { |
| 475 | validateFirst17(envP, dt); |
| 476 | |
| 477 | if (!envP->fault_occurred) |
| 478 | validateFractionalSeconds(envP, dt); |
| 479 | } |
| 480 | } |
| 481 | |
| 482 | |
| 483 | |
| 484 | /* Microsoft Visual C in debug mode produces code that complains about |
| 485 | returning an undefined value from xmlrpc_datetime_new_str(). It's a bogus |
| 486 | complaint, because this function is defined to return nothing meaningful |
| 487 | those cases. So we disable the check. |
| 488 | */ |
| 489 | #pragma runtime_checks("u", off) |
| 490 | |
| 491 | |
| 492 | |
| 493 | xmlrpc_value * |
| 494 | xmlrpc_datetime_new_str(xmlrpc_env * const envP, |
| 495 | const char * const datetimeString) { |
| 496 | /*---------------------------------------------------------------------------- |
| 497 | This exists only for backward compatibility. Originally, this was the |
| 498 | only way to create a datetime XML-RPC value, because we had a really |
| 499 | lazy implementation of XML-RPC serialization and parsing (basically, the |
| 500 | user did it!). |
| 501 | |
| 502 | Do not extend this. The user should use more normal C representations |
| 503 | of datetimes. |
| 504 | -----------------------------------------------------------------------------*/ |
| 505 | xmlrpc_value * retval; |
| 506 | |
| 507 | validateFormat(envP, datetimeString); |
| 508 | if (!envP->fault_occurred) { |
| 509 | xmlrpc_datetime dt; |
| 510 | |
| 511 | parseDatetimeString(datetimeString, &dt); |
| 512 | |
| 513 | /* Note that parseDatetimeString() can generate an invalid datetime |
| 514 | value, e.g. Hour 25 or February 30. Ideally, we would catch that |
| 515 | here, but due to laziness, we simply accept the possibility of |
| 516 | invalid xmlrpc_datetime in xmlrpc_value and whoever uses the the |
| 517 | xmlrpc_value has to deal with it. |
| 518 | */ |
| 519 | retval = xmlrpc_datetime_new(envP, dt); |
| 520 | } |
| 521 | |
| 522 | return retval; |
| 523 | } |
| 524 | |
| 525 | |
| 526 | |
| 527 | #pragma runtime_checks("u", restore) |
| 528 | |
| 529 | |
| 530 | |
| 531 | xmlrpc_value * |
| 532 | xmlrpc_datetime_new_usec(xmlrpc_env * const envP, |
| 533 | time_t const secs, |
| 534 | unsigned int const usecs) { |
| 535 | |
| 536 | xmlrpc_value * valueP; |
| 537 | |
| 538 | if (usecs >= 1000000) |
| 539 | xmlrpc_faultf(envP, "Number of fractional microseconds must be less " |
| 540 | "than one million. You specified %u", usecs); |
| 541 | else { |
| 542 | struct tm brokenTime; |
| 543 | xmlrpc_datetime dt; |
| 544 | |
| 545 | xmlrpc_gmtime(secs, &brokenTime); |
| 546 | |
| 547 | dt.s = brokenTime.tm_sec; |
| 548 | dt.m = brokenTime.tm_min; |
| 549 | dt.h = brokenTime.tm_hour; |
| 550 | dt.D = brokenTime.tm_mday; |
| 551 | dt.M = brokenTime.tm_mon + 1; |
| 552 | dt.Y = 1900 + brokenTime.tm_year; |
| 553 | dt.u = usecs; |
| 554 | |
| 555 | valueP = xmlrpc_datetime_new(envP, dt); |
| 556 | } |
| 557 | return valueP; |
| 558 | } |
| 559 | |
| 560 | |
| 561 | |
| 562 | xmlrpc_value * |
| 563 | xmlrpc_datetime_new_sec(xmlrpc_env * const envP, |
| 564 | time_t const value) { |
| 565 | |
| 566 | return xmlrpc_datetime_new_usec(envP, value, 0); |
| 567 | } |
| 568 | |
| 569 | |
| 570 | |
| 571 | #if XMLRPC_HAVE_TIMEVAL1 |
| 572 | |
| 573 | xmlrpc_value * |
| 574 | xmlrpc_datetime_new_timeval(xmlrpc_env * const envP, |
| 575 | struct timeval const value) { |
| 576 | |
| 577 | return xmlrpc_datetime_new_usec(envP, value.tv_sec, value.tv_usec); |
| 578 | } |
| 579 | #endif |
| 580 | |
| 581 | |
| 582 | |
| 583 | #if XMLRPC_HAVE_TIMESPEC1 |
| 584 | |
| 585 | xmlrpc_value * |
| 586 | xmlrpc_datetime_new_timespec(xmlrpc_env * const envP, |
| 587 | struct timespec const value) { |
| 588 | |
| 589 | return xmlrpc_datetime_new_usec(envP, value.tv_sec, value.tv_nsec/1000); |
| 590 | } |
| 591 | #endif |
| 592 | |
| 593 | |
| 594 | |
| 595 | void |
| 596 | xmlrpc_destroyDatetime(xmlrpc_value * const datetimeP) { |
| 597 | |
| 598 | const char ** const readBufferP = datetimeP->_cache; |
| 599 | |
| 600 | if (*readBufferP) |
| 601 | xmlrpc_strfree(*readBufferP); |
| 602 | |
| 603 | free(datetimeP->_cache); |
| 604 | } |