1 /******************************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: MapCache tile caching support file: Mapguide HTTPTile service
6 * Author: Thomas Bonfort and the MapServer team.
7 *
8 ******************************************************************************
9 * Copyright (c) 1996-2013 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 "mapcache_services.h"
34
35 /** \addtogroup services */
36
37 /** @{ */
38
_create_capabilities_mg(mapcache_context * ctx,mapcache_request_get_capabilities * req,char * url,char * path_info,mapcache_cfg * cfg)39 void _create_capabilities_mg(mapcache_context *ctx, mapcache_request_get_capabilities *req, char *url, char *path_info, mapcache_cfg *cfg)
40 {
41 ctx->set_error(ctx, 501, "mapguide service does not support capapbilities");
42 }
43
44 /**
45 * \brief parse a Mapguide HTTPTile request
46 * \private \memberof mapcache_service_mg
47 * \sa mapcache_service::parse_request()
48 */
_mapcache_service_mg_parse_request(mapcache_context * ctx,mapcache_service * this,mapcache_request ** request,const char * cpathinfo,apr_table_t * params,mapcache_cfg * config)49 void _mapcache_service_mg_parse_request(mapcache_context *ctx, mapcache_service *this, mapcache_request **request,
50 const char *cpathinfo, apr_table_t *params, mapcache_cfg *config)
51 {
52 int index = 0;
53 char *last, *key, *endptr;
54 char *sTileset = NULL;
55 mapcache_tileset *tileset = NULL;
56 mapcache_grid_link *grid_link = NULL;
57 char *pathinfo = NULL;
58 int x=-1,y=-1,z=-1,ygroup=-1,xgroup=1;
59
60 if(cpathinfo) {
61 pathinfo = apr_pstrdup(ctx->pool,cpathinfo);
62 /* parse a path_info like /1.0.0/global_mosaic/0/0/0.jpg */
63 for (key = apr_strtok(pathinfo, "/", &last); key != NULL;
64 key = apr_strtok(NULL, "/", &last)) {
65 if(!*key) continue; /* skip an empty string, could happen if the url contains // */
66 switch(++index) {
67 case 1: /* S[level] */
68 if(*key!='S') {
69 ctx->set_error(ctx,400, "received mapguide request with invalid level %s", key);
70 return;
71 }
72 z = (int)strtol(key+1,&endptr,10);
73 if(*endptr != 0) {
74 ctx->set_error(ctx,400, "failed to parse S level");
75 return;
76 }
77 break;
78 case 2: /* layer name */
79 sTileset = apr_pstrdup(ctx->pool,key);
80 break;
81 case 3: /*rowgroup*/
82 if(*key!='R') {
83 ctx->set_error(ctx,400, "received mapguide request with invalid rowgroup %s", key);
84 return;
85 }
86 ygroup = (int)strtol(key+1,&endptr,10);
87 if(*endptr != 0) {
88 ctx->set_error(ctx,400, "failed to parse rowgroup");
89 return;
90 }
91 break;
92 case 4: /*colgroup*/
93 if(*key!='C') {
94 ctx->set_error(ctx,400, "received mapguide request with invalid colgroup %s", key);
95 return;
96 }
97 xgroup = (int)strtol(key+1,&endptr,10);
98 if(*endptr != 0) {
99 ctx->set_error(ctx,404, "failed to parse colgroup");
100 return;
101 }
102 break;
103 case 5:
104 y = (int)strtol(key,&endptr,10);
105 if(*endptr != '_') {
106 ctx->set_error(ctx,404, "failed to parse y");
107 return;
108 }
109 key = endptr+1;
110 x = (int)strtol(key,&endptr,10);
111 if(*endptr != '.') {
112 ctx->set_error(ctx,404, "failed to parse x");
113 return;
114 }
115 x += xgroup;
116 y += ygroup;
117 break;
118 default:
119 ctx->set_error(ctx,404, "received mapguide request %s with invalid parameter %s", pathinfo, key);
120 return;
121 }
122 }
123 }
124 if(index == 5) {
125 char *gridname;
126 mapcache_request_get_tile *req = (mapcache_request_get_tile*)apr_pcalloc(ctx->pool,sizeof(mapcache_request_get_tile));
127 ((mapcache_request*)req)->type = MAPCACHE_REQUEST_GET_TILE;
128 gridname = sTileset; /*hijack the char* pointer while counting the number of commas */
129 while(*gridname) {
130 if(*gridname == ';') req->ntiles++;
131 gridname++;
132 }
133 req->tiles = (mapcache_tile**)apr_pcalloc(ctx->pool,(req->ntiles+1) * sizeof(mapcache_tile*));
134
135 /* reset the hijacked variables back to default value */
136 gridname = NULL;
137 req->ntiles = 0;
138
139 for (key = apr_strtok(sTileset, ";", &last); key != NULL;
140 key = apr_strtok(NULL, ";", &last)) {
141 tileset = mapcache_configuration_get_tileset(config,key);
142 if(!tileset) {
143 /*tileset not found directly, test if it was given as "name@grid" notation*/
144 char *tname = apr_pstrdup(ctx->pool,key);
145 char *gname = tname;
146 int i;
147 while(*gname) {
148 if(*gname == '@') {
149 *gname = '\0';
150 gname++;
151 break;
152 }
153 gname++;
154 }
155 if(!gname) {
156 ctx->set_error(ctx,404, "received mapguide request with invalid layer %s", key);
157 return;
158 }
159 tileset = mapcache_configuration_get_tileset(config,tname);
160 if(!tileset) {
161 ctx->set_error(ctx,404, "received mapguide request with invalid layer %s", tname);
162 return;
163 }
164 for(i=0; i<tileset->grid_links->nelts; i++) {
165 mapcache_grid_link *sgrid = APR_ARRAY_IDX(tileset->grid_links,i,mapcache_grid_link*);
166 if(!strcmp(sgrid->grid->name,gname)) {
167 grid_link = sgrid;
168 break;
169 }
170 }
171 if(!grid_link) {
172 ctx->set_error(ctx,404, "received mapguide request with invalid grid %s", gname);
173 return;
174 }
175
176 } else {
177 grid_link = APR_ARRAY_IDX(tileset->grid_links,0,mapcache_grid_link*);
178 }
179 if(!gridname) {
180 gridname = grid_link->grid->name;
181 z = grid_link->maxz - z - 1;
182 if(z<0 || z>=grid_link->maxz) {
183 ctx->set_error(ctx,404,"invalid z level");
184 return;
185 }
186 } else {
187 if(strcmp(gridname,grid_link->grid->name)) {
188 ctx->set_error(ctx,400,"received mapguide request with conflicting grids %s and %s",
189 gridname,grid_link->grid->name);
190 return;
191 }
192 }
193 req->tiles[req->ntiles] = mapcache_tileset_tile_create(ctx->pool, tileset, grid_link);
194 switch(grid_link->grid->origin) {
195 case MAPCACHE_GRID_ORIGIN_TOP_LEFT:
196 req->tiles[req->ntiles]->x = x;
197 req->tiles[req->ntiles]->y = y;
198 break;
199 case MAPCACHE_GRID_ORIGIN_BOTTOM_LEFT:
200 req->tiles[req->ntiles]->x = x;
201 req->tiles[req->ntiles]->y = grid_link->grid->levels[z]->maxy - y - 1;
202 break;
203 case MAPCACHE_GRID_ORIGIN_TOP_RIGHT:
204 req->tiles[req->ntiles]->x = grid_link->grid->levels[z]->maxx - x - 1;
205 req->tiles[req->ntiles]->y = y;
206 break;
207 case MAPCACHE_GRID_ORIGIN_BOTTOM_RIGHT:
208 req->tiles[req->ntiles]->x = grid_link->grid->levels[z]->maxx - x - 1;
209 req->tiles[req->ntiles]->y = grid_link->grid->levels[z]->maxy - y - 1;
210 break;
211 }
212 req->tiles[req->ntiles]->z = z;
213 mapcache_tileset_tile_validate(ctx,req->tiles[req->ntiles]);
214 req->ntiles++;
215 GC_CHECK_ERROR(ctx);
216 }
217 *request = (mapcache_request*)req;
218 return;
219 } else {
220 ctx->set_error(ctx,404, "received request with wrong number of arguments", pathinfo);
221 return;
222 }
223 }
224
_mapcache_service_mg_configuration_xml_parse(mapcache_context * ctx,ezxml_t node,mapcache_service * gservice,mapcache_cfg * cfg)225 void _mapcache_service_mg_configuration_xml_parse(mapcache_context *ctx, ezxml_t node, mapcache_service *gservice, mapcache_cfg *cfg) {
226 const char* attr = ezxml_attr(node,"rows_per_folder");
227 mapcache_service_mapguide *service = (mapcache_service_mapguide*)gservice;
228 char *endptr;
229 if(attr && *attr) {
230 service->rows_per_folder = (int)strtol(attr,&endptr,10);
231 if(*endptr != 0) {
232 ctx->set_error(ctx,400, "failed to parse rows_per_folder attribute");
233 return;
234 }
235 }
236 attr = ezxml_attr(node,"cols_per_folder");
237 if(attr && *attr) {
238 service->cols_per_folder = (int)strtol(attr,&endptr,10);
239 if(*endptr != 0) {
240 ctx->set_error(ctx,400, "failed to parse cols_per_folder attribute");
241 return;
242 }
243 }
244
245 }
246
mapcache_service_mapguide_create(mapcache_context * ctx)247 mapcache_service* mapcache_service_mapguide_create(mapcache_context *ctx)
248 {
249 mapcache_service_mapguide* service = (mapcache_service_mapguide*) apr_pcalloc(ctx->pool, sizeof (mapcache_service_mapguide));
250 if (!service) {
251 ctx->set_error(ctx, 500, "failed to allocate mapguide service");
252 return NULL;
253 }
254 service->service.url_prefix = apr_pstrdup(ctx->pool, "mg");
255 service->service.name = apr_pstrdup(ctx->pool, "mapguide");
256 service->service.type = MAPCACHE_SERVICE_MAPGUIDE;
257 service->service.parse_request = _mapcache_service_mg_parse_request;
258 service->service.configuration_parse_xml = _mapcache_service_mg_configuration_xml_parse;
259 service->service.create_capabilities_response = _create_capabilities_mg;
260 service->rows_per_folder = 30;
261 service->cols_per_folder = 30;
262 return (mapcache_service*) service;
263 }
264
265 /** @} */
266 /* vim: ts=2 sts=2 et sw=2
267 */
268