/src/MapServer/src/maptime.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * $id$ |
3 | | * |
4 | | * Project: MapServer |
5 | | * Purpose: Date/Time utility functions. |
6 | | * Author: Steve Lime and the MapServer team. |
7 | | * |
8 | | ****************************************************************************** |
9 | | * Copyright (c) 1996-2005 Regents of the University of Minnesota. |
10 | | * |
11 | | * Permission is hereby granted, free of charge, to any person obtaining a |
12 | | * copy of this software and associated documentation files (the "Software"), |
13 | | * to deal in the Software without restriction, including without limitation |
14 | | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
15 | | * and/or sell copies of the Software, and to permit persons to whom the |
16 | | * Software is furnished to do so, subject to the following conditions: |
17 | | * |
18 | | * The above copyright notice and this permission notice shall be included in |
19 | | * all copies of this Software or works derived from this Software. |
20 | | * |
21 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
22 | | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
23 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
24 | | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
25 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
26 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
27 | | * DEALINGS IN THE SOFTWARE. |
28 | | ****************************************************************************/ |
29 | | |
30 | | #define _GNU_SOURCE /* glibc2 needs this for strptime() */ |
31 | | #include <stdlib.h> |
32 | | #include <stdio.h> |
33 | | #include <time.h> |
34 | | |
35 | | #include "mapserver.h" |
36 | | #include "maptime.h" |
37 | | #include "maperror.h" |
38 | | #include "mapthread.h" |
39 | | |
40 | | typedef struct { |
41 | | char pattern[64]; |
42 | | ms_regex_t *regex; |
43 | | char format[32]; |
44 | | char userformat[32]; |
45 | | MS_TIME_RESOLUTION resolution; |
46 | | } timeFormatObj; |
47 | | |
48 | | static timeFormatObj ms_timeFormats[] = { |
49 | | {"^[0-9]{8}", NULL, "%Y%m%d", "YYYYMMDD", TIME_RESOLUTION_DAY}, |
50 | | {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z", NULL, |
51 | | "%Y-%m-%dT%H:%M:%SZ", "YYYY-MM-DDTHH:MM:SSZ", TIME_RESOLUTION_SECOND}, |
52 | | {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, |
53 | | "%Y-%m-%dT%H:%M:%S", "YYYY-MM-DDTHH:MM:SS", TIME_RESOLUTION_SECOND}, |
54 | | {"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, |
55 | | "%Y-%m-%d %H:%M:%S", "YYYY-MM-DD HH:MM:SS", TIME_RESOLUTION_SECOND}, |
56 | | {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}", NULL, "%Y-%m-%dT%H:%M", |
57 | | "YYYY-MM-DDTHH:MM", TIME_RESOLUTION_MINUTE}, |
58 | | {"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}", NULL, "%Y-%m-%d %H:%M", |
59 | | "YYYY-MM-DD HH:MM", TIME_RESOLUTION_MINUTE}, |
60 | | {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}", NULL, "%Y-%m-%dT%H", |
61 | | "YYYY-MM-DDTHH", TIME_RESOLUTION_HOUR}, |
62 | | {"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}", NULL, "%Y-%m-%d %H", |
63 | | "YYYY-MM-DD HH", TIME_RESOLUTION_HOUR}, |
64 | | {"^[0-9]{4}-[0-9]{2}-[0-9]{2}", NULL, "%Y-%m-%d", "YYYY-MM-DD", |
65 | | TIME_RESOLUTION_DAY}, |
66 | | {"^[0-9]{4}-[0-9]{2}", NULL, "%Y-%m", "YYYY-MM", TIME_RESOLUTION_MONTH}, |
67 | | {"^[0-9]{4}", NULL, "%Y", "YYYY", TIME_RESOLUTION_YEAR}, |
68 | | {"^T[0-9]{2}:[0-9]{2}:[0-9]{2}Z", NULL, "T%H:%M:%SZ", "THH:MM:SSZ", |
69 | | TIME_RESOLUTION_SECOND}, |
70 | | {"^T[0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "T%H:%M:%S", "THH:MM:SS", |
71 | | TIME_RESOLUTION_SECOND}, |
72 | | {"^[0-9]{2}:[0-9]{2}:[0-9]{2}Z", NULL, "%H:%M:%SZ", "HH:MM:SSZ", |
73 | | TIME_RESOLUTION_SECOND}, |
74 | | {"^[0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "%H:%M:%S", "HH:MM:SS", |
75 | | TIME_RESOLUTION_SECOND}}; |
76 | | |
77 | | #define MS_NUMTIMEFORMATS \ |
78 | 0 | (int)(sizeof(ms_timeFormats) / sizeof(ms_timeFormats[0])) |
79 | | |
80 | | int *ms_limited_pattern = NULL; |
81 | | int ms_num_limited_pattern; |
82 | | |
83 | | int ms_time_inited = 0; |
84 | 0 | int msTimeSetup() { |
85 | 0 | if (!ms_time_inited) { |
86 | 0 | msAcquireLock(TLOCK_TIME); |
87 | 0 | if (!ms_time_inited) { |
88 | 0 | int i; |
89 | 0 | for (i = 0; i < MS_NUMTIMEFORMATS; i++) { |
90 | 0 | ms_timeFormats[i].regex = msSmallMalloc(sizeof(ms_regex_t)); |
91 | 0 | if (0 != ms_regcomp(ms_timeFormats[i].regex, ms_timeFormats[i].pattern, |
92 | 0 | MS_REG_EXTENDED | MS_REG_NOSUB)) { |
93 | 0 | msSetError(MS_REGEXERR, "Failed to compile expression (%s).", |
94 | 0 | "msTimeSetup()", ms_timeFormats[i].pattern); |
95 | 0 | return MS_FAILURE; |
96 | | /* TODO: free already init'd regexes */ |
97 | 0 | } |
98 | 0 | } |
99 | 0 | ms_limited_pattern = |
100 | 0 | (int *)msSmallMalloc(sizeof(int) * MS_NUMTIMEFORMATS); |
101 | 0 | ms_num_limited_pattern = 0; |
102 | 0 | ms_time_inited = 1; |
103 | 0 | } |
104 | 0 | msReleaseLock(TLOCK_TIME); |
105 | 0 | } |
106 | 0 | return MS_SUCCESS; |
107 | 0 | } |
108 | | |
109 | 0 | void msTimeCleanup() { |
110 | 0 | if (ms_time_inited) { |
111 | 0 | int i; |
112 | 0 | for (i = 0; i < MS_NUMTIMEFORMATS; i++) { |
113 | 0 | if (ms_timeFormats[i].regex) { |
114 | 0 | ms_regfree(ms_timeFormats[i].regex); |
115 | 0 | msFree(ms_timeFormats[i].regex); |
116 | 0 | ms_timeFormats[i].regex = NULL; |
117 | 0 | } |
118 | 0 | } |
119 | 0 | msFree(ms_limited_pattern); |
120 | 0 | ms_time_inited = 0; |
121 | 0 | } |
122 | 0 | } |
123 | | |
124 | 0 | void msTimeInit(struct tm *time) { |
125 | 0 | time->tm_sec = 0; /* set all members to zero */ |
126 | 0 | time->tm_min = 0; |
127 | 0 | time->tm_hour = 0; |
128 | 0 | time->tm_mday = 0; |
129 | 0 | time->tm_mon = 0; |
130 | 0 | time->tm_year = 0; |
131 | 0 | time->tm_wday = 0; |
132 | 0 | time->tm_yday = 0; |
133 | 0 | time->tm_isdst = 0; |
134 | |
|
135 | 0 | return; |
136 | 0 | } |
137 | | |
138 | 0 | static int compareIntVals(int a, int b) { |
139 | 0 | if (a < b) |
140 | 0 | return -1; |
141 | 0 | else if (a > b) |
142 | 0 | return 1; |
143 | 0 | else |
144 | 0 | return 0; |
145 | 0 | } |
146 | | |
147 | 0 | int msDateCompare(struct tm *time1, struct tm *time2) { |
148 | 0 | int result; |
149 | |
|
150 | 0 | if ((result = compareIntVals(time1->tm_year, time2->tm_year)) != 0) |
151 | 0 | return result; /* not equal based on year */ |
152 | 0 | else if ((result = compareIntVals(time1->tm_mon, time2->tm_mon)) != 0) |
153 | 0 | return result; /* not equal based on month */ |
154 | 0 | else if ((result = compareIntVals(time1->tm_mday, time2->tm_mday)) != 0) |
155 | 0 | return result; /* not equal based on day of month */ |
156 | | |
157 | 0 | return (0); /* must be equal */ |
158 | 0 | } |
159 | | |
160 | 0 | int msTimeCompare(struct tm *time1, struct tm *time2) { |
161 | 0 | int result; |
162 | | |
163 | | // fprintf(stderr, "in msTimeCompare()...\n"); |
164 | | // fprintf(stderr, "time1: %d %d %d %d %d %d\n", time1->tm_year, |
165 | | // time1->tm_mon, time1->tm_mday, time1->tm_hour, time1->tm_min, |
166 | | // time1->tm_sec); fprintf(stderr, "time2: %d %d %d %d %d %d\n", |
167 | | // time2->tm_year, time2->tm_mon, time2->tm_mday, time2->tm_hour, |
168 | | // time2->tm_min, time2->tm_sec); |
169 | |
|
170 | 0 | if ((result = compareIntVals(time1->tm_year, time2->tm_year)) != 0) |
171 | 0 | return result; /* not equal based on year */ |
172 | 0 | else if ((result = compareIntVals(time1->tm_mon, time2->tm_mon)) != 0) |
173 | 0 | return result; /* not equal based on month */ |
174 | 0 | else if ((result = compareIntVals(time1->tm_mday, time2->tm_mday)) != 0) |
175 | 0 | return result; /* not equal based on day of month */ |
176 | 0 | else if ((result = compareIntVals(time1->tm_hour, time2->tm_hour)) != 0) |
177 | 0 | return result; /* not equal based on hour */ |
178 | 0 | else if ((result = compareIntVals(time1->tm_min, time2->tm_min)) != 0) |
179 | 0 | return result; /* not equal based on minute */ |
180 | 0 | else if ((result = compareIntVals(time1->tm_sec, time2->tm_sec)) != 0) |
181 | 0 | return result; /* not equal based on second */ |
182 | | |
183 | 0 | return (0); /* must be equal */ |
184 | 0 | } |
185 | | |
186 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
187 | | #include <sys/timeb.h> |
188 | | void msGettimeofday(struct mstimeval *tp, void *tzp) { |
189 | | struct _timeb theTime; |
190 | | |
191 | | _ftime(&theTime); |
192 | | tp->tv_sec = theTime.time; |
193 | | tp->tv_usec = theTime.millitm * 1000; |
194 | | } |
195 | | #endif |
196 | | |
197 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
198 | | /* we need to provide our own prototype on windows. */ |
199 | | char *strptime(const char *buf, const char *format, struct tm *timeptr); |
200 | | #endif |
201 | | |
202 | 0 | char *msStrptime(const char *s, const char *format, struct tm *tm) { |
203 | 0 | memset(tm, 0, sizeof(struct tm)); |
204 | 0 | return strptime(s, format, tm); |
205 | 0 | } |
206 | | |
207 | | /** |
208 | | return MS_TRUE if the time string matches the timeformat. |
209 | | else return MS_FALSE. |
210 | | */ |
211 | 0 | int msTimeMatchPattern(const char *timestring, const char *timeformat) { |
212 | 0 | int i = -1; |
213 | 0 | if (msTimeSetup() != MS_SUCCESS) { |
214 | 0 | return MS_FALSE; |
215 | 0 | } |
216 | | |
217 | | /* match the pattern format first and then check if the time string */ |
218 | | /* matches the pattern. If it is the case retrurn the MS_TRUE */ |
219 | 0 | for (i = 0; i < MS_NUMTIMEFORMATS; i++) { |
220 | 0 | if (strcasecmp(ms_timeFormats[i].userformat, timeformat) == 0) |
221 | 0 | break; |
222 | 0 | } |
223 | |
|
224 | 0 | if (i >= 0 && i < MS_NUMTIMEFORMATS) { |
225 | 0 | int match = ms_regexec(ms_timeFormats[i].regex, timestring, 0, NULL, 0); |
226 | 0 | if (match == 0) |
227 | 0 | return MS_TRUE; |
228 | 0 | } |
229 | 0 | return MS_FALSE; |
230 | 0 | } |
231 | | |
232 | 0 | void msUnsetLimitedPatternToUse() { |
233 | 0 | msTimeSetup(); |
234 | 0 | ms_num_limited_pattern = 0; |
235 | 0 | } |
236 | | |
237 | 0 | void msSetLimitedPatternsToUse(const char *patternstring) { |
238 | 0 | int *limitedpatternindice = NULL; |
239 | 0 | int numpatterns = 0, ntmp = 0; |
240 | 0 | char **patterns = NULL; |
241 | 0 | msTimeSetup(); |
242 | |
|
243 | 0 | limitedpatternindice = (int *)msSmallMalloc(sizeof(int) * MS_NUMTIMEFORMATS); |
244 | | |
245 | | /* free previous setting */ |
246 | 0 | msUnsetLimitedPatternToUse(); |
247 | |
|
248 | 0 | if (patternstring) { |
249 | 0 | patterns = msStringSplit(patternstring, ',', &ntmp); |
250 | 0 | if (patterns && ntmp >= 1) { |
251 | |
|
252 | 0 | for (int i = 0; i < ntmp; i++) { |
253 | 0 | for (int j = 0; j < MS_NUMTIMEFORMATS; j++) { |
254 | 0 | if (strcasecmp(ms_timeFormats[j].userformat, patterns[i]) == 0) { |
255 | 0 | limitedpatternindice[numpatterns] = j; |
256 | 0 | numpatterns++; |
257 | 0 | break; |
258 | 0 | } |
259 | 0 | } |
260 | 0 | } |
261 | 0 | } |
262 | 0 | msFreeCharArray(patterns, ntmp); |
263 | 0 | } |
264 | |
|
265 | 0 | if (numpatterns > 0) { |
266 | 0 | for (int i = 0; i < numpatterns; i++) |
267 | 0 | ms_limited_pattern[i] = limitedpatternindice[i]; |
268 | |
|
269 | 0 | ms_num_limited_pattern = numpatterns; |
270 | 0 | } |
271 | 0 | free(limitedpatternindice); |
272 | 0 | } |
273 | | |
274 | 0 | int msParseTime(const char *string, struct tm *tm) { |
275 | 0 | int num_patterns = 0; |
276 | |
|
277 | 0 | if (MS_STRING_IS_NULL_OR_EMPTY(string)) |
278 | 0 | return MS_FALSE; /* nothing to parse so bail */ |
279 | | |
280 | 0 | if (msTimeSetup() != MS_SUCCESS) { |
281 | 0 | return MS_FALSE; |
282 | 0 | } |
283 | | |
284 | | /* if limited patterns are set, use them, else use all the patterns defined */ |
285 | 0 | if (ms_num_limited_pattern > 0) |
286 | 0 | num_patterns = ms_num_limited_pattern; |
287 | 0 | else |
288 | 0 | num_patterns = MS_NUMTIMEFORMATS; |
289 | |
|
290 | 0 | for (int i = 0; i < num_patterns; i++) { |
291 | 0 | int match; |
292 | 0 | int indice; |
293 | 0 | if (ms_num_limited_pattern > 0) |
294 | 0 | indice = ms_limited_pattern[i]; |
295 | 0 | else |
296 | 0 | indice = i; |
297 | |
|
298 | 0 | match = ms_regexec(ms_timeFormats[indice].regex, string, 0, NULL, 0); |
299 | | /* test the expression against the string */ |
300 | 0 | if (match == 0) { |
301 | | /* match */ |
302 | 0 | msStrptime(string, ms_timeFormats[indice].format, tm); |
303 | 0 | return (MS_TRUE); |
304 | 0 | } |
305 | 0 | } |
306 | | |
307 | 0 | msSetError(MS_REGEXERR, "Unrecognized date or time format (%s).", |
308 | 0 | "msParseTime()", string); |
309 | 0 | return (MS_FALSE); |
310 | 0 | } |
311 | | |
312 | | /** |
313 | | * Parse the time string and return the reslution |
314 | | */ |
315 | 0 | int msTimeGetResolution(const char *timestring) { |
316 | 0 | int i = 0; |
317 | |
|
318 | 0 | if (!timestring) |
319 | 0 | return -1; |
320 | | |
321 | 0 | for (i = 0; i < MS_NUMTIMEFORMATS; i++) { |
322 | 0 | ms_regex_t *regex = (ms_regex_t *)msSmallMalloc(sizeof(ms_regex_t)); |
323 | 0 | if (ms_regcomp(regex, ms_timeFormats[i].pattern, |
324 | 0 | MS_REG_EXTENDED | MS_REG_NOSUB) != 0) { |
325 | 0 | msSetError(MS_REGEXERR, "Failed to compile expression (%s).", |
326 | 0 | "msParseTime()", ms_timeFormats[i].pattern); |
327 | 0 | msFree(regex); |
328 | 0 | return -1; |
329 | 0 | } |
330 | | /* test the expression against the string */ |
331 | 0 | if (ms_regexec(regex, timestring, 0, NULL, 0) == 0) { |
332 | | /* match */ |
333 | 0 | ms_regfree(regex); |
334 | 0 | msFree(regex); |
335 | 0 | return ms_timeFormats[i].resolution; |
336 | 0 | } |
337 | 0 | ms_regfree(regex); |
338 | 0 | msFree(regex); |
339 | 0 | } |
340 | | |
341 | 0 | return -1; |
342 | 0 | } |
343 | | |
344 | 0 | int _msValidateTime(const char *timestring, const char *timeextent) { |
345 | 0 | int numelements, numextents, i, numranges; |
346 | 0 | struct tm tmtimestart, tmtimeend, tmstart, tmend; |
347 | 0 | char **atimerange = NULL, **atimeelements = NULL, **atimeextents = NULL; |
348 | |
|
349 | 0 | if (!timestring || !timeextent) |
350 | 0 | return MS_FALSE; |
351 | | |
352 | 0 | if (strlen(timestring) == 0 || strlen(timeextent) == 0) |
353 | 0 | return MS_FALSE; |
354 | | |
355 | | /* we first need to parse the timesting that is passed |
356 | | so that we can determine if it is a descrete time |
357 | | or a range */ |
358 | | |
359 | 0 | numelements = 0; |
360 | 0 | atimeelements = msStringSplit(timestring, '/', &numelements); |
361 | 0 | msTimeInit(&tmtimestart); |
362 | 0 | msTimeInit(&tmtimeend); |
363 | |
|
364 | 0 | if (numelements == 1) { /*descrete time*/ |
365 | | /*start end end times are the same*/ |
366 | 0 | if (msParseTime(timestring, &tmtimestart) != MS_TRUE) { |
367 | 0 | msFreeCharArray(atimeelements, numelements); |
368 | 0 | return MS_FALSE; |
369 | 0 | } |
370 | 0 | if (msParseTime(timestring, &tmtimeend) != MS_TRUE) { |
371 | 0 | msFreeCharArray(atimeelements, numelements); |
372 | 0 | return MS_FALSE; |
373 | 0 | } |
374 | 0 | } else if (numelements >= 2) { /*range */ |
375 | 0 | if (msParseTime(atimeelements[0], &tmtimestart) != MS_TRUE) { |
376 | 0 | msFreeCharArray(atimeelements, numelements); |
377 | 0 | return MS_FALSE; |
378 | 0 | } |
379 | 0 | if (msParseTime(atimeelements[1], &tmtimeend) != MS_TRUE) { |
380 | 0 | msFreeCharArray(atimeelements, numelements); |
381 | 0 | return MS_FALSE; |
382 | 0 | } |
383 | 0 | } |
384 | | |
385 | 0 | msFreeCharArray(atimeelements, numelements); |
386 | | |
387 | | /* Now parse the time extent. Extents can be |
388 | | - one range (2004-09-21/2004-09-25/resolution) |
389 | | - multiple rages 2004-09-21/2004-09-25/res1,2004-09-21/2004-09-25/res2 |
390 | | - one value 2004-09-21 |
391 | | - multiple values 2004-09-21,2004-09-22,2004-09-23 |
392 | | */ |
393 | |
|
394 | 0 | numextents = 0; |
395 | 0 | atimeextents = msStringSplit(timeextent, ',', &numextents); |
396 | 0 | if (numextents <= 0) { |
397 | 0 | msFreeCharArray(atimeextents, numextents); |
398 | 0 | return MS_FALSE; |
399 | 0 | } |
400 | | |
401 | | /*the time timestring should at be valid in one of the extents |
402 | | defined */ |
403 | | |
404 | 0 | for (i = 0; i < numextents; i++) { |
405 | | /* build time structure for the extents */ |
406 | 0 | msTimeInit(&tmstart); |
407 | 0 | msTimeInit(&tmend); |
408 | |
|
409 | 0 | numranges = 0; |
410 | 0 | atimerange = msStringSplit(atimeextents[i], '/', &numranges); |
411 | | /* - one value 2004-09-21 */ |
412 | 0 | if (numranges == 1) { |
413 | | /*time tested can either be descrete or a range */ |
414 | |
|
415 | 0 | if (msParseTime(atimerange[0], &tmstart) == MS_TRUE && |
416 | 0 | msParseTime(atimerange[0], &tmend) == MS_TRUE && |
417 | 0 | msTimeCompare(&tmstart, &tmtimestart) <= 0 && |
418 | 0 | msTimeCompare(&tmend, &tmtimeend) >= 0) { |
419 | 0 | msFreeCharArray(atimerange, numranges); |
420 | 0 | msFreeCharArray(atimeextents, numextents); |
421 | 0 | return MS_TRUE; |
422 | 0 | } |
423 | 0 | } |
424 | | /*2004-09-21/2004-09-25/res1*/ |
425 | 0 | else if (numranges >= 2) { |
426 | 0 | if (msParseTime(atimerange[0], &tmstart) == MS_TRUE && |
427 | 0 | msParseTime(atimerange[1], &tmend) == MS_TRUE && |
428 | 0 | msTimeCompare(&tmstart, &tmtimestart) <= 0 && |
429 | 0 | msTimeCompare(&tmend, &tmtimeend) >= 0) { |
430 | 0 | msFreeCharArray(atimerange, numranges); |
431 | 0 | msFreeCharArray(atimeextents, numextents); |
432 | 0 | return MS_TRUE; |
433 | 0 | } |
434 | 0 | } |
435 | 0 | msFreeCharArray(atimerange, numranges); |
436 | 0 | } |
437 | 0 | msFreeCharArray(atimeextents, numextents); |
438 | 0 | return MS_FALSE; |
439 | 0 | } |
440 | | |
441 | 0 | int msValidateTimeValue(const char *timestring, const char *timeextent) { |
442 | 0 | char **atimes = NULL; |
443 | 0 | int i, numtimes = 0; |
444 | | |
445 | | /* we need to validate the time passsed in the request */ |
446 | | /* against the time extent defined */ |
447 | |
|
448 | 0 | if (!timestring || !timeextent) |
449 | 0 | return MS_FALSE; |
450 | | |
451 | | /* To avoid SQL injections */ |
452 | 0 | if (strchr(timestring, '\'')) |
453 | 0 | return MS_FALSE; |
454 | | |
455 | | /* parse the time string. We support descrete times (eg 2004-09-21), */ |
456 | | /* multiple times (2004-09-21, 2004-09-22, ...) */ |
457 | | /* and range(s) (2004-09-21/2004-09-25, 2004-09-27/2004-09-29) */ |
458 | 0 | if (strstr(timestring, ",") == NULL && |
459 | 0 | strstr(timestring, "/") == NULL) { /* discrete time */ |
460 | 0 | return _msValidateTime(timestring, timeextent); |
461 | 0 | } else { |
462 | 0 | atimes = msStringSplit(timestring, ',', &numtimes); |
463 | 0 | if (numtimes >= 1) { /* multiple times */ |
464 | 0 | for (i = 0; i < numtimes; i++) { |
465 | 0 | if (_msValidateTime(atimes[i], timeextent) == MS_FALSE) { |
466 | 0 | msFreeCharArray(atimes, numtimes); |
467 | 0 | return MS_FALSE; |
468 | 0 | } |
469 | 0 | } |
470 | 0 | msFreeCharArray(atimes, numtimes); |
471 | 0 | return MS_TRUE; |
472 | 0 | } else { |
473 | 0 | msFreeCharArray(atimes, numtimes); |
474 | 0 | } |
475 | 0 | } |
476 | 0 | return MS_FALSE; |
477 | 0 | } |