1 /******************************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: MapCache tile caching support file: OGC dimensions
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
30 #include "mapcache.h"
31 #include <apr_strings.h>
32 #include <math.h>
33 #include <sys/types.h>
34 #ifdef USE_PCRE
35 #include <pcre.h>
36 #else
37 #include <regex.h>
38 #endif
39
40 typedef struct mapcache_dimension_values mapcache_dimension_values;
41 typedef struct mapcache_dimension_regex mapcache_dimension_regex;
42 typedef struct mapcache_dimension_composite mapcache_dimension_composite;
43
44 struct mapcache_dimension_values {
45 mapcache_dimension dimension;
46 apr_array_header_t *values;
47 int case_sensitive;
48 };
49
50
51 struct mapcache_dimension_regex {
52 mapcache_dimension dimension;
53 char *regex_string;
54 #ifdef USE_PCRE
55 pcre *pcregex;
56 #else
57 regex_t *regex;
58 #endif
59 };
60
61
62
mapcache_requested_dimensions_clone(apr_pool_t * pool,apr_array_header_t * src)63 apr_array_header_t *mapcache_requested_dimensions_clone(apr_pool_t *pool, apr_array_header_t *src) {
64 apr_array_header_t *ret = NULL;
65 if(src) {
66 int i;
67 ret = apr_array_make(pool,src->nelts,sizeof(mapcache_requested_dimension*));
68 for(i=0; i<src->nelts; i++) {
69 mapcache_requested_dimension *tiledim = apr_pcalloc(pool,sizeof(mapcache_requested_dimension));
70 mapcache_requested_dimension *srcdim = APR_ARRAY_IDX(src,i,mapcache_requested_dimension*);
71 *tiledim = *srcdim;
72 APR_ARRAY_PUSH(ret,mapcache_requested_dimension*) = tiledim;
73 }
74 }
75 return ret;
76 }
77
mapcache_set_requested_dimension(mapcache_context * ctx,apr_array_header_t * dimensions,const char * name,const char * value)78 void mapcache_set_requested_dimension(mapcache_context *ctx, apr_array_header_t *dimensions, const char *name, const char *value) {
79 int i;
80 if(!dimensions || dimensions->nelts <= 0) {
81 ctx->set_error(ctx,500,"BUG: no dimensions configure for tile/map");
82 return;
83 }
84 for(i=0;i<dimensions->nelts;i++) {
85 mapcache_requested_dimension *dim = APR_ARRAY_IDX(dimensions,i,mapcache_requested_dimension*);
86 if(!strcasecmp(dim->dimension->name,name)) {
87 dim->requested_value = value?apr_pstrdup(ctx->pool,value):NULL;
88 return;
89 }
90 }
91 ctx->set_error(ctx,500,"BUG: dimension (%s) not found in tile/map",name);
92 }
93
mapcache_set_cached_dimension(mapcache_context * ctx,apr_array_header_t * dimensions,const char * name,const char * value)94 void mapcache_set_cached_dimension(mapcache_context *ctx, apr_array_header_t *dimensions, const char *name, const char *value) {
95 int i;
96 if(!dimensions || dimensions->nelts <= 0) {
97 ctx->set_error(ctx,500,"BUG: no dimensions configure for tile/map");
98 return;
99 }
100 for(i=0;i<dimensions->nelts;i++) {
101 mapcache_requested_dimension *dim = APR_ARRAY_IDX(dimensions,i,mapcache_requested_dimension*);
102 if(!strcasecmp(dim->dimension->name,name)) {
103 dim->cached_value = value?apr_pstrdup(ctx->pool,value):NULL;
104 return;
105 }
106 }
107 ctx->set_error(ctx,500,"BUG: dimension (%s) not found in tile/map",name);
108 }
109
mapcache_tile_set_cached_dimension(mapcache_context * ctx,mapcache_tile * tile,const char * name,const char * value)110 void mapcache_tile_set_cached_dimension(mapcache_context *ctx, mapcache_tile *tile, const char *name, const char *value) {
111 mapcache_set_cached_dimension(ctx,tile->dimensions,name,value);
112 }
113
mapcache_map_set_cached_dimension(mapcache_context * ctx,mapcache_map * map,const char * name,const char * value)114 void mapcache_map_set_cached_dimension(mapcache_context *ctx, mapcache_map *map, const char *name, const char *value) {
115 mapcache_set_cached_dimension(ctx,map->dimensions,name,value);
116 }
mapcache_tile_set_requested_dimension(mapcache_context * ctx,mapcache_tile * tile,const char * name,const char * value)117 void mapcache_tile_set_requested_dimension(mapcache_context *ctx, mapcache_tile *tile, const char *name, const char *value) {
118 mapcache_set_requested_dimension(ctx,tile->dimensions,name,value);
119 }
120
mapcache_map_set_requested_dimension(mapcache_context * ctx,mapcache_map * map,const char * name,const char * value)121 void mapcache_map_set_requested_dimension(mapcache_context *ctx, mapcache_map *map, const char *name, const char *value) {
122 mapcache_set_requested_dimension(ctx,map->dimensions,name,value);
123 }
124
_mapcache_dimension_regex_get_entries_for_value(mapcache_context * ctx,mapcache_dimension * dim,const char * value,mapcache_tileset * tileset,mapcache_extent * extent,mapcache_grid * grid)125 static apr_array_header_t* _mapcache_dimension_regex_get_entries_for_value(mapcache_context *ctx, mapcache_dimension *dim, const char *value,
126 mapcache_tileset *tileset, mapcache_extent *extent, mapcache_grid *grid)
127 {
128 mapcache_dimension_regex *dimension = (mapcache_dimension_regex*)dim;
129 apr_array_header_t *values = apr_array_make(ctx->pool,1,sizeof(char*));
130 #ifdef USE_PCRE
131 int ovector[30];
132 int rc = pcre_exec(dimension->pcregex,NULL,value,strlen(value),0,0,ovector,30);
133 if(rc>0) {
134 APR_ARRAY_PUSH(values,char*) = apr_pstrdup(ctx->pool,value);
135 }
136 #else
137 if(!regexec(dimension->regex,value,0,0,0)) {
138 APR_ARRAY_PUSH(values,char*) = apr_pstrdup(ctx->pool,value);
139 }
140 #endif
141 else {
142 ctx->set_error(ctx,400,"failed to validate requested value for %s (%s)",dim->class_name,dim->name);
143 }
144 return values;
145 }
146
_mapcache_dimension_regex_get_all_entries(mapcache_context * ctx,mapcache_dimension * dim,mapcache_tileset * tileset,mapcache_extent * extent,mapcache_grid * grid)147 static apr_array_header_t* _mapcache_dimension_regex_get_all_entries(mapcache_context *ctx, mapcache_dimension *dim,
148 mapcache_tileset *tileset, mapcache_extent *extent, mapcache_grid *grid)
149 {
150 mapcache_dimension_regex *dimension = (mapcache_dimension_regex*)dim;
151 apr_array_header_t *ret = apr_array_make(ctx->pool,1,sizeof(char*));
152 APR_ARRAY_PUSH(ret,char*) = apr_pstrdup(ctx->pool,dimension->regex_string);
153 return ret;
154 }
155
156
_mapcache_dimension_regex_parse_xml(mapcache_context * ctx,mapcache_dimension * dim,ezxml_t node)157 static void _mapcache_dimension_regex_parse_xml(mapcache_context *ctx, mapcache_dimension *dim,
158 ezxml_t node)
159 {
160 mapcache_dimension_regex *dimension;
161 ezxml_t child_node = ezxml_child(node,"regex");
162
163 dimension = (mapcache_dimension_regex*)dim;
164
165 if(child_node && child_node->txt && *child_node->txt) {
166 dimension->regex_string = apr_pstrdup(ctx->pool,child_node->txt);
167 } else {
168 ctx->set_error(ctx,400,"failed to parse %s regex: no <regex> child supplied",dim->class_name);
169 return;
170 }
171 #ifdef USE_PCRE
172 {
173 const char *pcre_err;
174 int pcre_offset;
175 dimension->pcregex = pcre_compile(dimension->regex_string,0,&pcre_err, &pcre_offset,0);
176 if(!dimension->pcregex) {
177 ctx->set_error(ctx,400,"failed to compile regular expression \"%s\" for %s \"%s\": %s",
178 dimension->regex_string,dim->class_name,dim->name,pcre_err);
179 return;
180 }
181 }
182 #else
183 {
184 int rc = regcomp(dimension->regex, dimension->regex_string, REG_EXTENDED);
185 if(rc) {
186 char errmsg[200];
187 regerror(rc,dimension->regex,errmsg,200);
188 ctx->set_error(ctx,400,"failed to compile regular expression \"%s\" for %s \"%s\": %s",
189 dimension->regex_string,dim->class_name,dim->name,errmsg);
190 return;
191 }
192 }
193 #endif
194
195 }
196
_mapcache_dimension_values_get_entries_for_value(mapcache_context * ctx,mapcache_dimension * dim,const char * value,mapcache_tileset * tileset,mapcache_extent * extent,mapcache_grid * grid)197 static apr_array_header_t* _mapcache_dimension_values_get_entries_for_value(mapcache_context *ctx, mapcache_dimension *dim, const char *value,
198 mapcache_tileset *tileset, mapcache_extent *extent, mapcache_grid *grid)
199 {
200 int i;
201 mapcache_dimension_values *dimension = (mapcache_dimension_values*)dim;
202 apr_array_header_t *values = apr_array_make(ctx->pool,1,sizeof(char*));
203 for(i=0; i<dimension->values->nelts; i++) {
204 char *cur_val = APR_ARRAY_IDX(dimension->values,i,char*);
205 if(dimension->case_sensitive) {
206 if(!strcmp(value,cur_val)) {
207 APR_ARRAY_PUSH(values,char*) = apr_pstrdup(ctx->pool,value);
208 break;
209 }
210 } else {
211 if(!strcasecmp(value,cur_val)) {
212 APR_ARRAY_PUSH(values,char*) = apr_pstrdup(ctx->pool,value);
213 break;
214 }
215 }
216 }
217 if(i == dimension->values->nelts) {
218 ctx->set_error(ctx,400,"failed to validate requested value for %s (%s)",dim->class_name,dim->name);
219 }
220 return values;
221 }
222
_mapcache_dimension_values_get_all_entries(mapcache_context * ctx,mapcache_dimension * dim,mapcache_tileset * tileset,mapcache_extent * extent,mapcache_grid * grid)223 static apr_array_header_t* _mapcache_dimension_values_get_all_entries(mapcache_context *ctx, mapcache_dimension *dim,
224 mapcache_tileset *tileset, mapcache_extent *extent, mapcache_grid *grid)
225 {
226 mapcache_dimension_values *dimension = (mapcache_dimension_values*)dim;
227 apr_array_header_t *ret = apr_array_make(ctx->pool,dimension->values->nelts,sizeof(char*));
228 int i;
229 for(i=0; i<dimension->values->nelts; i++) {
230 APR_ARRAY_PUSH(ret,char*) = apr_pstrdup(ctx->pool,APR_ARRAY_IDX(dimension->values,i,char*));
231 }
232 return ret;
233 }
234
235
_mapcache_dimension_values_parse_xml(mapcache_context * ctx,mapcache_dimension * dim,ezxml_t node)236 static void _mapcache_dimension_values_parse_xml(mapcache_context *ctx, mapcache_dimension *dim,
237 ezxml_t node)
238 {
239 mapcache_dimension_values *dimension;
240 ezxml_t child_node = ezxml_child(node,"value");
241 dimension = (mapcache_dimension_values*)dim;
242
243 if(!child_node) {
244 ctx->set_error(ctx,400,"failed to parse %s values: no <value> children supplied",dim->class_name);
245 return;
246 }
247 for(; child_node; child_node = child_node->next) {
248 const char* entry = child_node->txt;
249 if(!entry || !*entry) {
250 ctx->set_error(ctx,400,"failed to parse %s values: empty <value>",dim->class_name);
251 return;
252 }
253 APR_ARRAY_PUSH(dimension->values,char*) = apr_pstrdup(ctx->pool,entry);
254 }
255
256 child_node = ezxml_child(node,"case_sensitive");
257 if(child_node && child_node->txt) {
258 if(!strcasecmp(child_node->txt,"true")) {
259 dimension->case_sensitive = 1;
260 }
261 }
262
263 if(!dimension->values->nelts) {
264 ctx->set_error(ctx, 400, "<dimension> \"%s\" has no values",dim->name);
265 return;
266 }
267 }
268
269
mapcache_dimension_get_entries_for_value(mapcache_context * ctx,mapcache_dimension * dimension,const char * value,mapcache_tileset * tileset,mapcache_extent * extent,mapcache_grid * grid)270 apr_array_header_t* mapcache_dimension_get_entries_for_value(mapcache_context *ctx, mapcache_dimension *dimension, const char *value,
271 mapcache_tileset *tileset, mapcache_extent *extent, mapcache_grid *grid) {
272 if(!dimension->isTime) {
273 return dimension->_get_entries_for_value(ctx, dimension, value, tileset, extent, grid);
274 } else {
275 return mapcache_dimension_time_get_entries_for_value(ctx, dimension, value, tileset, extent, grid);
276 }
277 }
278
mapcache_dimension_values_create(mapcache_context * ctx,apr_pool_t * pool)279 mapcache_dimension* mapcache_dimension_values_create(mapcache_context *ctx, apr_pool_t *pool)
280 {
281 mapcache_dimension_values *dimension = apr_pcalloc(pool, sizeof(mapcache_dimension_values));
282 dimension->dimension.type = MAPCACHE_DIMENSION_VALUES;
283 dimension->dimension.class_name = "dimension";
284 dimension->values = apr_array_make(pool,1,sizeof(char*));
285 dimension->dimension._get_entries_for_value = _mapcache_dimension_values_get_entries_for_value;
286 dimension->dimension.configuration_parse_xml = _mapcache_dimension_values_parse_xml;
287 dimension->dimension.get_all_entries = _mapcache_dimension_values_get_all_entries;
288 dimension->dimension.get_all_ogc_formatted_entries = _mapcache_dimension_values_get_all_entries;
289 return (mapcache_dimension*)dimension;
290 }
291
mapcache_dimension_regex_create(mapcache_context * ctx,apr_pool_t * pool)292 mapcache_dimension* mapcache_dimension_regex_create(mapcache_context *ctx, apr_pool_t *pool)
293 {
294 mapcache_dimension_regex *dimension = apr_pcalloc(pool, sizeof(mapcache_dimension_regex));
295 dimension->dimension.type = MAPCACHE_DIMENSION_REGEX;
296 dimension->dimension.class_name = "dimension";
297 #ifndef USE_PCRE
298 dimension->regex = (regex_t*)apr_pcalloc(pool, sizeof(regex_t));
299 #endif
300 dimension->dimension._get_entries_for_value = _mapcache_dimension_regex_get_entries_for_value;
301 dimension->dimension.configuration_parse_xml = _mapcache_dimension_regex_parse_xml;
302 dimension->dimension.get_all_entries = _mapcache_dimension_regex_get_all_entries;
303 dimension->dimension.get_all_ogc_formatted_entries = _mapcache_dimension_regex_get_all_entries;
304 return (mapcache_dimension*)dimension;
305 }
306
307
308
309 /* vim: ts=2 sts=2 et sw=2
310 */
311