File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c |
Location: | line 273, column 25 |
Description: | Assigned value is garbage or undefined |
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'); | |||
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 | } |