1 /******************************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: MapCache tile caching support file: time dimension support
6 * Author: Thomas Bonfort and the MapServer team.
7 *
8 ******************************************************************************
9 * Copyright (c) 1996-2011 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 #include "mapcache.h"
30 #include <apr_time.h>
31 #include <apr_strings.h>
32 #include <time.h>
33
34 typedef enum {
35 MAPCACHE_TINTERVAL_SECOND,
36 MAPCACHE_TINTERVAL_MINUTE,
37 MAPCACHE_TINTERVAL_HOUR,
38 MAPCACHE_TINTERVAL_DAY,
39 MAPCACHE_TINTERVAL_MONTH,
40 MAPCACHE_TINTERVAL_YEAR
41 } mapcache_time_interval_t;
42
43 #ifndef HAVE_TIMEGM
timegm(struct tm * tm)44 time_t timegm(struct tm *tm)
45 {
46 time_t t, tdiff;
47 struct tm in, gtime, ltime;
48
49 memcpy(&in, tm, sizeof(in));
50 t = mktime(&in);
51
52 memcpy(>ime, gmtime(&t), sizeof(gtime));
53 memcpy(<ime, localtime(&t), sizeof(ltime));
54 gtime.tm_isdst = ltime.tm_isdst;
55 tdiff = t - mktime(>ime);
56
57 memcpy(&in, tm, sizeof(in));
58 return mktime(&in) + tdiff;
59 }
60 #endif
61
62
mapcache_ogc_strptime(const char * value,struct tm * ts,mapcache_time_interval_t * ti)63 char *mapcache_ogc_strptime(const char *value, struct tm *ts, mapcache_time_interval_t *ti) {
64 char *valueptr;
65 memset (ts, '\0', sizeof (*ts));
66 ts->tm_mday = 1;
67 valueptr = strptime(value,"%Y-%m-%dT%H:%M:%SZ",ts);
68 *ti = MAPCACHE_TINTERVAL_SECOND;
69 if(valueptr) return valueptr;
70 valueptr = strptime(value,"%Y-%m-%dT%H:%MZ",ts);
71 *ti = MAPCACHE_TINTERVAL_MINUTE;
72 if(valueptr) return valueptr;
73 valueptr = strptime(value,"%Y-%m-%dT%HZ",ts);
74 *ti = MAPCACHE_TINTERVAL_HOUR;
75 if(valueptr) return valueptr;
76 valueptr = strptime(value,"%Y-%m-%d",ts);
77 *ti = MAPCACHE_TINTERVAL_DAY;
78 if(valueptr) return valueptr;
79 valueptr = strptime(value,"%Y-%m",ts);
80 *ti = MAPCACHE_TINTERVAL_MONTH;
81 if(valueptr) return valueptr;
82 valueptr = strptime(value,"%Y",ts);
83 *ti = MAPCACHE_TINTERVAL_YEAR;
84 if(valueptr) return valueptr;
85 return NULL;
86 }
87
mapcache_dimension_time_get_entries(mapcache_context * ctx,mapcache_dimension * dim,const char * dim_value,mapcache_tileset * tileset,mapcache_extent * extent,mapcache_grid * grid,time_t * intervals,int n_intervals)88 apr_array_header_t* mapcache_dimension_time_get_entries(mapcache_context *ctx, mapcache_dimension *dim, const char *dim_value,
89 mapcache_tileset *tileset, mapcache_extent *extent, mapcache_grid *grid, time_t *intervals, int n_intervals) {
90 int i;
91 apr_array_header_t *time_ids = apr_array_make(ctx->pool,0,sizeof(char*));
92 if(!dim->_get_entries_for_time_range) {
93 ctx->set_error(ctx,500,"dimension does not support time queries");
94 return NULL;
95 }
96 for(i=0;i<n_intervals;i++) {
97 apr_array_header_t *interval_ids = dim->_get_entries_for_time_range(ctx, dim, dim_value,
98 intervals[i*2], intervals[i*2+1],
99 tileset, extent, grid);
100 if(GC_HAS_ERROR(ctx)) {
101 return NULL;
102 }
103 apr_array_cat(time_ids, interval_ids);
104 }
105 return time_ids;
106 }
107
mapcache_dimension_time_get_entries_for_value(mapcache_context * ctx,mapcache_dimension * dimension,const char * value,mapcache_tileset * tileset,mapcache_extent * extent,mapcache_grid * grid)108 apr_array_header_t* mapcache_dimension_time_get_entries_for_value(mapcache_context *ctx, mapcache_dimension *dimension, const char *value,
109 mapcache_tileset *tileset, mapcache_extent *extent, mapcache_grid *grid) {
110
111 /* look if supplied value is a predefined key */
112 /* split multiple values, loop */
113
114 /* extract start and end values */
115 struct tm tm_start,tm_end;
116 time_t *intervals;
117 mapcache_time_interval_t tis,tie;
118 char *valueptr = apr_pstrdup(ctx->pool,value);
119 char *last,*key;
120 int count=1;
121 char * value_scan = (char *)value;
122
123 /*count how many time entries were supplied*/
124 for(; *value_scan; value_scan++) if(*value_scan == ',') count++;
125
126 intervals = apr_pcalloc(ctx->pool,2*count*sizeof(time_t));
127 count = 0;
128
129
130 /* Split the input on ',' */
131 for (key = apr_strtok(valueptr, ",", &last); key != NULL;
132 key = apr_strtok(NULL, ",", &last)) {
133 valueptr = mapcache_ogc_strptime(key,&tm_start,&tis);
134 if(!valueptr) {
135 ctx->set_error(ctx,400,"failed to parse time %s",value);
136 return NULL;
137 }
138
139 if(*valueptr == '/' || (*valueptr == '-' && *(valueptr+1) == '-')) {
140 /* we have a second (end) time */
141 if (*valueptr == '/') {
142 valueptr++;
143 }
144 else {
145 valueptr += 2;
146 }
147 valueptr = mapcache_ogc_strptime(valueptr,&tm_end,&tie);
148 if(!valueptr) {
149 ctx->set_error(ctx,400,"failed to parse end time in %s",value);
150 return NULL;
151 }
152 } else if(*valueptr == 0) {
153 tie = tis;
154 tm_end = tm_start;
155 } else {
156 ctx->set_error(ctx,400,"failed (2) to parse time %s",value);
157 return NULL;
158 }
159 switch(tie) {
160 case MAPCACHE_TINTERVAL_SECOND:
161 tm_end.tm_sec += 1;
162 break;
163 case MAPCACHE_TINTERVAL_MINUTE:
164 tm_end.tm_min += 1;
165 break;
166 case MAPCACHE_TINTERVAL_HOUR:
167 tm_end.tm_hour += 1;
168 break;
169 case MAPCACHE_TINTERVAL_DAY:
170 tm_end.tm_mday += 1;
171 break;
172 case MAPCACHE_TINTERVAL_MONTH:
173 tm_end.tm_mon += 1;
174 break;
175 case MAPCACHE_TINTERVAL_YEAR:
176 tm_end.tm_year += 1;
177 break;
178 }
179 intervals[count*2] = timegm(&tm_start);
180 intervals[count*2+1] = timegm(&tm_end);
181 count++;
182 }
183 return mapcache_dimension_time_get_entries(ctx,dimension,value,tileset,extent,grid,intervals,count);
184 /* end loop */
185 }
186