| File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/parse_datetime.c |
| Location: | line 464, column 24 |
| Description: | Passed-by-value struct argument contains uninitialized data (e.g., field: 'Y') |
| 1 | #include "xmlrpc_config.h" | |||
| 2 | ||||
| 3 | #include <stdlib.h> | |||
| 4 | #include <assert.h> | |||
| 5 | #include <ctype.h> | |||
| 6 | #include <string.h> | |||
| 7 | ||||
| 8 | #if HAVE_REGEX1 | |||
| 9 | #include <sys/types.h> /* Missing from regex.h in GNU libc */ | |||
| 10 | #include <regex.h> | |||
| 11 | #endif | |||
| 12 | ||||
| 13 | #include "bool.h" | |||
| 14 | ||||
| 15 | #include "xmlrpc-c/base.h" | |||
| 16 | #include "xmlrpc-c/base_int.h" | |||
| 17 | #include "xmlrpc-c/util.h" | |||
| 18 | ||||
| 19 | #include "parse_datetime.h" | |||
| 20 | ||||
| 21 | ||||
| 22 | ||||
| 23 | #if HAVE_REGEX1 | |||
| 24 | ||||
| 25 | static unsigned int | |||
| 26 | digitStringValue(const char * const string, | |||
| 27 | regmatch_t const match) { | |||
| 28 | /*---------------------------------------------------------------------------- | |||
| 29 | Return the numerical value of the decimal whole number substring of | |||
| 30 | 'string' identified by 'match'. E.g. if 'string' is 'abc34d' and | |||
| 31 | 'match' says start at 3 and end at 5, we return 34. | |||
| 32 | -----------------------------------------------------------------------------*/ | |||
| 33 | unsigned int i; | |||
| 34 | unsigned int accum; | |||
| 35 | ||||
| 36 | assert(match.rm_so >= 0)((match.rm_so >= 0) ? (void) (0) : __assert_fail ("match.rm_so >= 0" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 36, __PRETTY_FUNCTION__ )); | |||
| 37 | assert(match.rm_eo >= 0)((match.rm_eo >= 0) ? (void) (0) : __assert_fail ("match.rm_eo >= 0" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 37, __PRETTY_FUNCTION__ )); | |||
| 38 | ||||
| 39 | for (i = match.rm_so, accum = 0; i < (unsigned)match.rm_eo; ++i) { | |||
| 40 | accum *= 10; | |||
| 41 | assert(isdigit(string[i]))((((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short int) _ISdigit)) ? (void) (0) : __assert_fail ("((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short int) _ISdigit)" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 41, __PRETTY_FUNCTION__ )); | |||
| 42 | accum += string[i] - '0'; | |||
| 43 | } | |||
| 44 | return accum; | |||
| 45 | } | |||
| 46 | #endif /* HAVE_REGEX */ | |||
| 47 | ||||
| 48 | ||||
| 49 | ||||
| 50 | #if HAVE_REGEX1 | |||
| 51 | ||||
| 52 | static unsigned int | |||
| 53 | digitStringMillionths(const char * const string, | |||
| 54 | regmatch_t const match) { | |||
| 55 | /*---------------------------------------------------------------------------- | |||
| 56 | Return the number of millionths represented by the digits after the | |||
| 57 | decimal point in a decimal string, where thse digits are the substring | |||
| 58 | of 'string' identified by 'match'. E.g. if the substring is | |||
| 59 | 34, we return 340,000. | |||
| 60 | -----------------------------------------------------------------------------*/ | |||
| 61 | unsigned int i; | |||
| 62 | unsigned int accum; | |||
| 63 | ||||
| 64 | assert(match.rm_so >= 0)((match.rm_so >= 0) ? (void) (0) : __assert_fail ("match.rm_so >= 0" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 64, __PRETTY_FUNCTION__ )); | |||
| 65 | assert(match.rm_eo >= 0)((match.rm_eo >= 0) ? (void) (0) : __assert_fail ("match.rm_eo >= 0" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 65, __PRETTY_FUNCTION__ )); | |||
| 66 | ||||
| 67 | for (i = match.rm_so, accum = 0; i < (unsigned)match.rm_so+6; ++i) { | |||
| 68 | accum *= 10; | |||
| 69 | if (i < (unsigned)match.rm_eo) { | |||
| 70 | assert(isdigit(string[i]))((((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short int) _ISdigit)) ? (void) (0) : __assert_fail ("((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short int) _ISdigit)" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 70, __PRETTY_FUNCTION__ )); | |||
| 71 | accum += string[i] - '0'; | |||
| 72 | } | |||
| 73 | } | |||
| 74 | return accum; | |||
| 75 | } | |||
| 76 | #endif /* HAVE_REGEX */ | |||
| 77 | ||||
| 78 | ||||
| 79 | #if HAVE_REGEX1 | |||
| 80 | ||||
| 81 | static void | |||
| 82 | subParseDtRegex_standard(regmatch_t * const matches, | |||
| 83 | const char * const datetimeString, | |||
| 84 | xmlrpc_datetime * const dtP) { | |||
| 85 | ||||
| 86 | dtP->Y = digitStringValue(datetimeString, matches[1]); | |||
| 87 | dtP->M = digitStringValue(datetimeString, matches[2]); | |||
| 88 | dtP->D = digitStringValue(datetimeString, matches[3]); | |||
| 89 | dtP->h = digitStringValue(datetimeString, matches[4]); | |||
| 90 | dtP->m = digitStringValue(datetimeString, matches[5]); | |||
| 91 | dtP->s = digitStringValue(datetimeString, matches[6]); | |||
| 92 | ||||
| 93 | if (matches[7].rm_so == -1) | |||
| 94 | dtP->u = 0; | |||
| 95 | else | |||
| 96 | dtP->u = digitStringMillionths(datetimeString, matches[7]); | |||
| 97 | } | |||
| 98 | ||||
| 99 | ||||
| 100 | ||||
| 101 | static void | |||
| 102 | subParseDtRegex_standardtzd(regmatch_t * const matches, | |||
| 103 | const char * const datetimeString, | |||
| 104 | xmlrpc_datetime * const dtP) { | |||
| 105 | ||||
| 106 | dtP->Y = digitStringValue(datetimeString, matches[1]); | |||
| 107 | dtP->M = digitStringValue(datetimeString, matches[2]); | |||
| 108 | dtP->D = digitStringValue(datetimeString, matches[3]); | |||
| 109 | dtP->h = digitStringValue(datetimeString, matches[4]); | |||
| 110 | dtP->m = digitStringValue(datetimeString, matches[5]); | |||
| 111 | dtP->s = digitStringValue(datetimeString, matches[6]); | |||
| 112 | } | |||
| 113 | ||||
| 114 | #endif /* HAVE_REGEX */ | |||
| 115 | ||||
| 116 | ||||
| 117 | #if HAVE_REGEX1 | |||
| 118 | ||||
| 119 | typedef void (*regparsefunc_t)(regmatch_t * const matches, | |||
| 120 | const char * const datetimeString, | |||
| 121 | xmlrpc_datetime * const dtP); | |||
| 122 | ||||
| 123 | ||||
| 124 | struct regexParser { | |||
| 125 | const char * const regex; | |||
| 126 | regparsefunc_t func; | |||
| 127 | }; | |||
| 128 | ||||
| 129 | static const struct regexParser iso8601Regex[] | |||
| 130 | ||||
| 131 | /* Each entry of this table is instructions for recognizing and parsing | |||
| 132 | some form of a "dateTime.iso8601" XML element. | |||
| 133 | ||||
| 134 | (Note that we recognize far more than just the XML-RPC standard | |||
| 135 | dateTime.iso8601). | |||
| 136 | */ | |||
| 137 | ||||
| 138 | = { | |||
| 139 | { | |||
| 140 | /* Examples: | |||
| 141 | YYYYMMDD[T]HHMMSS | |||
| 142 | YYYY-MM-DD[T]HH:MM:SS | |||
| 143 | YYYY-MM-DD[T]HH:MM:SS.ssss | |||
| 144 | */ | |||
| 145 | ||||
| 146 | "^([0-9]{4})\\-?([0-9]{2})\\-?([0-9]{2})T" | |||
| 147 | "([0-9]{2}):?([0-9]{2}):?([0-9]{2})\\.?([0-9]+)?$", | |||
| 148 | subParseDtRegex_standard | |||
| 149 | }, | |||
| 150 | ||||
| 151 | { | |||
| 152 | /* Examples: | |||
| 153 | YYYYMMDD[T]HHMMSS[Z] | |||
| 154 | YYYYMMDD[T]HHMMSS[+-]hh | |||
| 155 | YYYYMMDD[T]HHMMSS[+-]hhmm | |||
| 156 | */ | |||
| 157 | ||||
| 158 | "^([0-9]{4})\\-?([0-9]{2})\\-?([0-9]{2})T" | |||
| 159 | "([0-9]{2}):?([0-9]{2}):?([0-9]{2})[Z\\+\\-]([0-9]{2,4})?$", | |||
| 160 | subParseDtRegex_standardtzd | |||
| 161 | }, | |||
| 162 | { NULL((void*)0), NULL((void*)0) } | |||
| 163 | }; | |||
| 164 | #endif /* HAVE_REGEX */ | |||
| 165 | ||||
| 166 | ||||
| 167 | ||||
| 168 | #if HAVE_REGEX1 | |||
| 169 | static void | |||
| 170 | parseDtRegex(xmlrpc_env * const envP, | |||
| 171 | const char * const datetimeString, | |||
| 172 | xmlrpc_datetime * const dtP) { | |||
| 173 | ||||
| 174 | unsigned int i; | |||
| 175 | const struct regexParser * parserP; | |||
| 176 | /* The parser that matches 'datetimeString'. Null if no match yet | |||
| 177 | found. | |||
| 178 | */ | |||
| 179 | regmatch_t matches[1024]; | |||
| 180 | ||||
| 181 | for (i = 0, parserP = NULL((void*)0); iso8601Regex[i].regex && !parserP; ++i) { | |||
| 182 | const struct regexParser * const thisParserP = &iso8601Regex[i]; | |||
| 183 | ||||
| 184 | regex_t re; | |||
| 185 | int status; | |||
| 186 | ||||
| 187 | status = regcomp(&re, thisParserP->regex, REG_ICASE(1 << 1) | REG_EXTENDED1); | |||
| 188 | ||||
| 189 | /* Our regex is valid, so it must have compiled: */ | |||
| 190 | assert(status == 0)((status == 0) ? (void) (0) : __assert_fail ("status == 0", "../../../../libs/xmlrpc-c/src/parse_datetime.c" , 190, __PRETTY_FUNCTION__)); | |||
| 191 | { | |||
| 192 | int status; | |||
| 193 | ||||
| 194 | status = regexec(&re, datetimeString, ARRAY_SIZE(matches)(sizeof(matches)/sizeof(matches[0])), | |||
| 195 | matches, 0); | |||
| 196 | ||||
| 197 | if (status == 0) { | |||
| 198 | assert(matches[0].rm_so != -1)((matches[0].rm_so != -1) ? (void) (0) : __assert_fail ("matches[0].rm_so != -1" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 198, __PRETTY_FUNCTION__ )); /* Match of whole regex */ | |||
| 199 | ||||
| 200 | parserP = thisParserP; | |||
| 201 | } | |||
| 202 | regfree(&re); | |||
| 203 | } | |||
| 204 | } | |||
| 205 | ||||
| 206 | if (parserP) { | |||
| 207 | parserP->func(matches, datetimeString, dtP); | |||
| 208 | } else { | |||
| 209 | xmlrpc_env_set_fault_formatted( | |||
| 210 | envP, XMLRPC_PARSE_ERROR(-503), | |||
| 211 | "value '%s' is not of any form we recognize " | |||
| 212 | "for a <dateTime.iso8601> element", | |||
| 213 | datetimeString); | |||
| 214 | } | |||
| 215 | ||||
| 216 | } | |||
| 217 | #endif /* HAVE_REGEX */ | |||
| 218 | ||||
| 219 | ||||
| 220 | ||||
| 221 | static __inline__ void | |||
| 222 | parseDtNoRegex(xmlrpc_env * const envP, | |||
| 223 | const char * const datetimeString, | |||
| 224 | xmlrpc_datetime * const dtP) { | |||
| 225 | ||||
| 226 | unsigned int const dtStrlen = strlen(datetimeString); | |||
| 227 | ||||
| 228 | char year[4+1]; | |||
| 229 | char month[2+1]; | |||
| 230 | char day[2+1]; | |||
| 231 | char hour[2+1]; | |||
| 232 | char minute[2+1]; | |||
| 233 | char second[2+1]; | |||
| 234 | ||||
| 235 | if (dtStrlen < 17 || dtStrlen == 18 || dtStrlen > 24) | |||
| 236 | xmlrpc_faultf(envP, "could not parse date, size incompatible: '%d'", | |||
| 237 | dtStrlen); | |||
| 238 | else { | |||
| 239 | year[0] = datetimeString[ 0]; | |||
| 240 | year[1] = datetimeString[ 1]; | |||
| 241 | year[2] = datetimeString[ 2]; | |||
| 242 | year[3] = datetimeString[ 3]; | |||
| 243 | year[4] = '\0'; | |||
| 244 | ||||
| 245 | month[0] = datetimeString[ 4]; | |||
| 246 | month[1] = datetimeString[ 5]; | |||
| 247 | month[2] = '\0'; | |||
| 248 | ||||
| 249 | day[0] = datetimeString[ 6]; | |||
| 250 | day[1] = datetimeString[ 7]; | |||
| 251 | day[2] = '\0'; | |||
| 252 | ||||
| 253 | assert(datetimeString[ 8] == 'T')((datetimeString[ 8] == 'T') ? (void) (0) : __assert_fail ("datetimeString[ 8] == 'T'" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 253, __PRETTY_FUNCTION__ )); | |||
| 254 | ||||
| 255 | hour[0] = datetimeString[ 9]; | |||
| 256 | hour[1] = datetimeString[10]; | |||
| 257 | hour[2] = '\0'; | |||
| 258 | ||||
| 259 | assert(datetimeString[11] == ':')((datetimeString[11] == ':') ? (void) (0) : __assert_fail ("datetimeString[11] == ':'" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 259, __PRETTY_FUNCTION__ )); | |||
| 260 | ||||
| 261 | minute[0] = datetimeString[12]; | |||
| 262 | minute[1] = datetimeString[13]; | |||
| 263 | minute[2] = '\0'; | |||
| 264 | ||||
| 265 | assert(datetimeString[14] == ':')((datetimeString[14] == ':') ? (void) (0) : __assert_fail ("datetimeString[14] == ':'" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 265, __PRETTY_FUNCTION__ )); | |||
| 266 | ||||
| 267 | second[0] = datetimeString[15]; | |||
| 268 | second[1] = datetimeString[16]; | |||
| 269 | second[2] = '\0'; | |||
| 270 | ||||
| 271 | if (dtStrlen > 17) { | |||
| 272 | unsigned int const pad = 24 - dtStrlen; | |||
| 273 | unsigned int i; | |||
| 274 | ||||
| 275 | dtP->u = atoi(&datetimeString[18]); | |||
| 276 | for (i = 0; i < pad; ++i) | |||
| 277 | dtP->u *= 10; | |||
| 278 | } else | |||
| 279 | dtP->u = 0; | |||
| 280 | ||||
| 281 | dtP->Y = atoi(year); | |||
| 282 | dtP->M = atoi(month); | |||
| 283 | dtP->D = atoi(day); | |||
| 284 | dtP->h = atoi(hour); | |||
| 285 | dtP->m = atoi(minute); | |||
| 286 | dtP->s = atoi(second); | |||
| 287 | } | |||
| 288 | } | |||
| 289 | ||||
| 290 | ||||
| 291 | ||||
| 292 | static void | |||
| 293 | validateFirst17(xmlrpc_env * const envP, | |||
| 294 | const char * const dt) { | |||
| 295 | /*---------------------------------------------------------------------------- | |||
| 296 | Assuming 'dt' is at least 17 characters long, validate that the first | |||
| 297 | 17 characters are a valid XML-RPC datetime, e.g. | |||
| 298 | "20080628T16:35:02" | |||
| 299 | -----------------------------------------------------------------------------*/ | |||
| 300 | unsigned int i; | |||
| 301 | ||||
| 302 | for (i = 0; i < 8 && !envP->fault_occurred; ++i) | |||
| 303 | if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int ) _ISdigit)) | |||
| 304 | xmlrpc_env_set_fault_formatted( | |||
| 305 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[i]); | |||
| 306 | ||||
| 307 | if (dt[8] != 'T') | |||
| 308 | xmlrpc_env_set_fault_formatted( | |||
| 309 | envP, XMLRPC_PARSE_ERROR(-503), "9th character is '%c', not 'T'", | |||
| 310 | dt[8]); | |||
| 311 | if (!isdigit(dt[9])((*__ctype_b_loc ())[(int) ((dt[9]))] & (unsigned short int ) _ISdigit)) | |||
| 312 | xmlrpc_env_set_fault_formatted( | |||
| 313 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[9]); | |||
| 314 | if (!isdigit(dt[10])((*__ctype_b_loc ())[(int) ((dt[10]))] & (unsigned short int ) _ISdigit)) | |||
| 315 | xmlrpc_env_set_fault_formatted( | |||
| 316 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[10]); | |||
| 317 | if (dt[11] != ':') | |||
| 318 | xmlrpc_env_set_fault_formatted( | |||
| 319 | envP, XMLRPC_PARSE_ERROR(-503), "Not a colon: '%c'", dt[11]); | |||
| 320 | if (!isdigit(dt[12])((*__ctype_b_loc ())[(int) ((dt[12]))] & (unsigned short int ) _ISdigit)) | |||
| 321 | xmlrpc_env_set_fault_formatted( | |||
| 322 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[12]); | |||
| 323 | if (!isdigit(dt[13])((*__ctype_b_loc ())[(int) ((dt[13]))] & (unsigned short int ) _ISdigit)) | |||
| 324 | xmlrpc_env_set_fault_formatted( | |||
| 325 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[13]); | |||
| 326 | if (dt[14] != ':') | |||
| 327 | xmlrpc_env_set_fault_formatted( | |||
| 328 | envP, XMLRPC_PARSE_ERROR(-503), "Not a colon: '%c'", dt[14]); | |||
| 329 | if (!isdigit(dt[15])((*__ctype_b_loc ())[(int) ((dt[15]))] & (unsigned short int ) _ISdigit)) | |||
| 330 | xmlrpc_env_set_fault_formatted( | |||
| 331 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[15]); | |||
| 332 | if (!isdigit(dt[16])((*__ctype_b_loc ())[(int) ((dt[16]))] & (unsigned short int ) _ISdigit)) | |||
| 333 | xmlrpc_env_set_fault_formatted( | |||
| 334 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[16]); | |||
| 335 | } | |||
| 336 | ||||
| 337 | ||||
| 338 | ||||
| 339 | static void | |||
| 340 | validateFractionalSeconds(xmlrpc_env * const envP, | |||
| 341 | const char * const dt) { | |||
| 342 | /*---------------------------------------------------------------------------- | |||
| 343 | Validate the fractional seconds part of the XML-RPC datetime string | |||
| 344 | 'dt', if any. That's the decimal point and everything following | |||
| 345 | it. | |||
| 346 | -----------------------------------------------------------------------------*/ | |||
| 347 | if (strlen(dt) > 17) { | |||
| 348 | if (dt[17] != '.') { | |||
| 349 | xmlrpc_env_set_fault_formatted( | |||
| 350 | envP, XMLRPC_PARSE_ERROR(-503), | |||
| 351 | "'%c' where only a period is valid", dt[17]); | |||
| 352 | } else { | |||
| 353 | if (dt[18] == '\0') | |||
| 354 | xmlrpc_env_set_fault_formatted( | |||
| 355 | envP, XMLRPC_PARSE_ERROR(-503), "Nothing after decimal point"); | |||
| 356 | else { | |||
| 357 | unsigned int i; | |||
| 358 | for (i = 18; dt[i] != '\0' && !envP->fault_occurred; ++i) { | |||
| 359 | if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int ) _ISdigit)) | |||
| 360 | xmlrpc_env_set_fault_formatted( | |||
| 361 | envP, XMLRPC_PARSE_ERROR(-503), | |||
| 362 | "Non-digit in fractional seconds: '%c'", dt[i]); | |||
| 363 | } | |||
| 364 | } | |||
| 365 | } | |||
| 366 | } | |||
| 367 | } | |||
| 368 | ||||
| 369 | ||||
| 370 | ||||
| 371 | static __inline__ void | |||
| 372 | validateFormatNoRegex(xmlrpc_env * const envP, | |||
| 373 | const char * const dt) { | |||
| 374 | ||||
| 375 | if (strlen(dt) < 17) | |||
| 376 | xmlrpc_env_set_fault_formatted( | |||
| 377 | envP, XMLRPC_PARSE_ERROR(-503), | |||
| 378 | "Invalid length of %u of datetime. " | |||
| 379 | "Must be at least 17 characters", | |||
| 380 | (unsigned)strlen(dt)); | |||
| 381 | else { | |||
| 382 | validateFirst17(envP, dt); | |||
| 383 | ||||
| 384 | validateFractionalSeconds(envP, dt); | |||
| 385 | } | |||
| 386 | } | |||
| 387 | ||||
| 388 | ||||
| 389 | ||||
| 390 | static void | |||
| 391 | validateXmlrpcDatetimeSome(xmlrpc_env * const envP, | |||
| 392 | xmlrpc_datetime const dt) { | |||
| 393 | /*---------------------------------------------------------------------------- | |||
| 394 | Type xmlrpc_datetime is defined such that it can represent a nonexistent | |||
| 395 | datetime such as February 30. | |||
| 396 | ||||
| 397 | Validate that 'dt' doesn't have glaring invalidities such as Hour 25. | |||
| 398 | We leave the possibility of more subtle invalidity such as February 30. | |||
| 399 | -----------------------------------------------------------------------------*/ | |||
| 400 | ||||
| 401 | if (dt.M < 1 || dt.M > 12) | |||
| 402 | xmlrpc_env_set_fault_formatted( | |||
| 403 | envP, XMLRPC_PARSE_ERROR(-503), | |||
| 404 | "Month of year value %u is not in the range 1-12", dt.M); | |||
| 405 | else if (dt.D < 1 || dt.D > 31) | |||
| 406 | xmlrpc_env_set_fault_formatted( | |||
| 407 | envP, XMLRPC_PARSE_ERROR(-503), | |||
| 408 | "Day of month value %u is not in the range 1-31", dt.D); | |||
| 409 | else if (dt.h > 23) | |||
| 410 | xmlrpc_env_set_fault_formatted( | |||
| 411 | envP, XMLRPC_PARSE_ERROR(-503), | |||
| 412 | "Hour of day value %u is not in the range 0-23", dt.h); | |||
| 413 | else if (dt.m > 59) | |||
| 414 | xmlrpc_env_set_fault_formatted( | |||
| 415 | envP, XMLRPC_PARSE_ERROR(-503), | |||
| 416 | "Minute of hour value %u is not in the range 0-59", dt.m); | |||
| 417 | else if (dt.s > 59) | |||
| 418 | xmlrpc_env_set_fault_formatted( | |||
| 419 | envP, XMLRPC_PARSE_ERROR(-503), | |||
| 420 | "Second of minute value %u is not in the range 0-59", dt.s); | |||
| 421 | else if (dt.u > 999999) | |||
| 422 | xmlrpc_env_set_fault_formatted( | |||
| 423 | envP, XMLRPC_PARSE_ERROR(-503), | |||
| 424 | "Microsecond of second value %u is not in the range 0-1M", dt.u); | |||
| 425 | } | |||
| 426 | ||||
| 427 | ||||
| 428 | ||||
| 429 | void | |||
| 430 | xmlrpc_parseDatetime(xmlrpc_env * const envP, | |||
| 431 | const char * const datetimeString, | |||
| 432 | xmlrpc_value ** const valuePP) { | |||
| 433 | /*---------------------------------------------------------------------------- | |||
| 434 | Parse the content of a <datetime.iso8601> XML-RPC XML element, e.g. | |||
| 435 | "20000301T00:00:00". | |||
| 436 | ||||
| 437 | 'str' is that content. | |||
| 438 | ||||
| 439 | Example of the format we parse: "19980717T14:08:55" | |||
| 440 | Note that this is not quite ISO 8601. It's a bizarre combination of | |||
| 441 | two ISO 8601 formats. | |||
| 442 | ||||
| 443 | Note that Xmlrpc-c recognizes various extensions of the XML-RPC | |||
| 444 | <datetime.iso8601> element type. | |||
| 445 | ||||
| 446 | 'str' may not be valid XML-RPC (with extensions). In that case we fail | |||
| 447 | with fault code XMLRPC_PARSE_ERROR. | |||
| 448 | -----------------------------------------------------------------------------*/ | |||
| 449 | xmlrpc_datetime dt; | |||
| 450 | ||||
| 451 | #if HAVE_REGEX1 | |||
| 452 | parseDtRegex(envP, datetimeString, &dt); | |||
| 453 | #else | |||
| 454 | /* Note: validation is not as strong without regex */ | |||
| 455 | validateFormatNoRegex(envP, datetimeString); | |||
| 456 | if (!envP->fault_occurred) | |||
| 457 | parseDtNoRegex(envP, datetimeString, &dt); | |||
| 458 | #endif | |||
| 459 | ||||
| 460 | if (!envP->fault_occurred) { | |||
| ||||
| 461 | validateXmlrpcDatetimeSome(envP, dt); | |||
| 462 | ||||
| 463 | if (!envP->fault_occurred) | |||
| 464 | *valuePP = xmlrpc_datetime_new(envP, dt); | |||
| ||||
| 465 | } | |||
| 466 | } |