/src/MapServer/src/maptemplate.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * $id: maptemplate.c 7725 2008-06-21 15:56:58Z sdlime $ |
3 | | * |
4 | | * Project: MapServer |
5 | | * Purpose: Various template processing functions. |
6 | | * Author: Steve Lime and the MapServer team. |
7 | | * |
8 | | ****************************************************************************** |
9 | | * Copyright (c) 1996-2008 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 NEED_IGNORE_RET_VAL |
31 | | |
32 | | #include "maptemplate.h" |
33 | | #include "maphash.h" |
34 | | #include "mapserver.h" |
35 | | #include "maptile.h" |
36 | | #include "mapows.h" |
37 | | |
38 | | #include "cpl_conv.h" |
39 | | |
40 | | #include <sys/types.h> |
41 | | #include <sys/stat.h> |
42 | | #include <time.h> |
43 | | |
44 | | #include <assert.h> |
45 | | #include <ctype.h> |
46 | | |
47 | 0 | static inline void IGUR_sizet(size_t ignored) { |
48 | 0 | (void)ignored; |
49 | 0 | } /* Ignore GCC Unused Result */ |
50 | 0 | static inline void IGUR_voidp(void *ignored) { |
51 | 0 | (void)ignored; |
52 | 0 | } /* Ignore GCC Unused Result */ |
53 | | |
54 | | static const char *const olUrl = "//mapserver.org/lib/10.5.0/ol-mapserver.js"; |
55 | | static const char *const olCssUrl = |
56 | | "//mapserver.org/lib/10.5.0/ol-mapserver.css"; |
57 | | |
58 | | static const char *const olTemplate = |
59 | | "<!DOCTYPE html>\n" |
60 | | "<html lang=\"en\">\n" |
61 | | "<head>\n" |
62 | | " <meta charset=\"UTF-8\">\n" |
63 | | " <meta name=\"viewport\" content=\"width=device-width, " |
64 | | "initial-scale=1.0\">\n" |
65 | | " <title>MapServer Simple Viewer</title>\n" |
66 | | " <link rel=\"stylesheet\" " |
67 | | "href=\"[openlayers_css_url]\">\n" |
68 | | " <link rel=\"shortcut icon\" type=\"image/x-icon\" " |
69 | | "href=\"//mapserver.org/_static/mapserver.ico\" />\n" |
70 | | " <style>\n" |
71 | | " #map {\n" |
72 | | " position: absolute;\n" |
73 | | " top: 0;\n" |
74 | | " left: 0;\n" |
75 | | " width: 100%;\n" |
76 | | " height: 100%;\n" |
77 | | " }\n" |
78 | | " </style>\n" |
79 | | "</head>\n" |
80 | | "<body>\n" |
81 | | " <div id=\"map\"></div>\n" |
82 | | " <script " |
83 | | "src=\"[openlayers_js_url]\"></script>\n" |
84 | | " <script>\n" |
85 | | " [openlayers_layer]\n" |
86 | | " const map = new ol.Map({\n" |
87 | | " layers: [mslayer],\n" |
88 | | " target: 'map',\n" |
89 | | " view: new ol.View()\n" |
90 | | " });\n" |
91 | | " map.getView().fit([[minx], [miny], [maxx], [maxy]], { size: " |
92 | | "map.getSize() });\n" |
93 | | " </script>\n" |
94 | | "</body>\n" |
95 | | "</html>"; |
96 | | |
97 | | static const char *const olLayerMapServerTag = |
98 | | "const mslayer = new ol.layer.Image({\n" |
99 | | " extent: [[minx], [miny], [maxx], [maxy]],\n" |
100 | | " source: new ol.source.Image({\n" |
101 | | " loader: ol.source.mapserver.createLoader({\n" |
102 | | " url: '[mapserv_onlineresource]',\n" |
103 | | " params: {\n" |
104 | | " 'layers': '[layers]'\n" |
105 | | " }\n" |
106 | | " })\n" |
107 | | " })\n" |
108 | | " });"; |
109 | | |
110 | | static const char *const olLayerWMSTag = |
111 | | "if (!ol.proj.get('[openlayers_projection]')) {\n" |
112 | | " ol.proj.addProjection(new ol.proj.Projection({ code : " |
113 | | "'[openlayers_projection]' }));\n" |
114 | | " }\n" |
115 | | " const mslayer = new ol.layer.Image({\n" |
116 | | " source: new ol.source.Image({\n" |
117 | | " loader: ol.source.wms.createLoader({\n" |
118 | | " url: '[mapserv_onlineresource]',\n" |
119 | | " params: {\n" |
120 | | " LAYERS: '[LAYERS]',\n" |
121 | | " VERSION: '[VERSION]',\n" |
122 | | " FORMAT: 'image/png'\n" |
123 | | " },\n" |
124 | | " projection: '[openlayers_projection]',\n" |
125 | | " ratio: 1\n" |
126 | | " })\n" |
127 | | " })\n" |
128 | | " });"; |
129 | | |
130 | | static char *processLine(mapservObj *mapserv, const char *instr, FILE *stream, |
131 | | int mode); |
132 | | |
133 | 0 | static int isValidTemplate(FILE *stream, const char *filename) { |
134 | 0 | char buffer[MS_BUFFER_LENGTH]; |
135 | |
|
136 | 0 | if (fgets(buffer, MS_BUFFER_LENGTH, stream) != NULL) { |
137 | 0 | if (!strcasestr(buffer, MS_TEMPLATE_MAGIC_STRING)) { |
138 | 0 | msSetError( |
139 | 0 | MS_WEBERR, |
140 | 0 | "Missing magic string, %s doesn't look like a MapServer template.", |
141 | 0 | "isValidTemplate()", filename); |
142 | 0 | return MS_FALSE; |
143 | 0 | } |
144 | 0 | } |
145 | | |
146 | 0 | return MS_TRUE; |
147 | 0 | } |
148 | | |
149 | | /* |
150 | | * Redirect to (only use in CGI) |
151 | | * |
152 | | */ |
153 | 0 | int msRedirect(const char *url) { |
154 | 0 | msIO_setHeader("Status", "302 Found"); |
155 | 0 | msIO_setHeader("Uri", "%s", url); |
156 | 0 | msIO_setHeader("Location", "%s", url); |
157 | 0 | msIO_setHeader("Content-Type", "text/html"); |
158 | 0 | msIO_sendHeaders(); |
159 | 0 | return MS_SUCCESS; |
160 | 0 | } |
161 | | |
162 | | /* |
163 | | ** Sets the map extent under a variety of scenarios. |
164 | | */ |
165 | 0 | int setExtent(mapservObj *mapserv) { |
166 | 0 | double cellx, celly, cellsize; |
167 | |
|
168 | 0 | if (mapserv->Mode == TILE) { |
169 | 0 | if (MS_SUCCESS != msTileSetExtent(mapserv)) { |
170 | 0 | return MS_FAILURE; |
171 | 0 | } |
172 | 0 | } |
173 | 0 | switch (mapserv->CoordSource) { |
174 | 0 | case FROMUSERBOX: /* user passed in a map extent */ |
175 | 0 | break; |
176 | 0 | case FROMIMGBOX: /* fully interactive web, most likely with java front end */ |
177 | 0 | cellx = MS_CELLSIZE(mapserv->ImgExt.minx, mapserv->ImgExt.maxx, |
178 | 0 | mapserv->ImgCols); |
179 | 0 | celly = MS_CELLSIZE(mapserv->ImgExt.miny, mapserv->ImgExt.maxy, |
180 | 0 | mapserv->ImgRows); |
181 | 0 | mapserv->map->extent.minx = |
182 | 0 | MS_IMAGE2MAP_X(mapserv->ImgBox.minx, mapserv->ImgExt.minx, cellx); |
183 | 0 | mapserv->map->extent.maxx = |
184 | 0 | MS_IMAGE2MAP_X(mapserv->ImgBox.maxx, mapserv->ImgExt.minx, cellx); |
185 | 0 | mapserv->map->extent.maxy = |
186 | 0 | MS_IMAGE2MAP_Y(mapserv->ImgBox.miny, mapserv->ImgExt.maxy, |
187 | 0 | celly); /* y's are flip flopped because img/map |
188 | | coordinate systems are */ |
189 | 0 | mapserv->map->extent.miny = |
190 | 0 | MS_IMAGE2MAP_Y(mapserv->ImgBox.maxy, mapserv->ImgExt.maxy, celly); |
191 | 0 | break; |
192 | 0 | case FROMIMGPNT: |
193 | 0 | cellx = MS_CELLSIZE(mapserv->ImgExt.minx, mapserv->ImgExt.maxx, |
194 | 0 | mapserv->ImgCols); |
195 | 0 | celly = MS_CELLSIZE(mapserv->ImgExt.miny, mapserv->ImgExt.maxy, |
196 | 0 | mapserv->ImgRows); |
197 | 0 | mapserv->mappnt.x = |
198 | 0 | MS_IMAGE2MAP_X(mapserv->ImgPnt.x, mapserv->ImgExt.minx, cellx); |
199 | 0 | mapserv->mappnt.y = |
200 | 0 | MS_IMAGE2MAP_Y(mapserv->ImgPnt.y, mapserv->ImgExt.maxy, celly); |
201 | |
|
202 | 0 | mapserv->map->extent.minx = |
203 | 0 | mapserv->mappnt.x - |
204 | 0 | .5 * ((mapserv->ImgExt.maxx - mapserv->ImgExt.minx) / |
205 | 0 | mapserv->fZoom); /* create an extent around that point */ |
206 | 0 | mapserv->map->extent.miny = |
207 | 0 | mapserv->mappnt.y - |
208 | 0 | .5 * ((mapserv->ImgExt.maxy - mapserv->ImgExt.miny) / mapserv->fZoom); |
209 | 0 | mapserv->map->extent.maxx = |
210 | 0 | mapserv->mappnt.x + |
211 | 0 | .5 * ((mapserv->ImgExt.maxx - mapserv->ImgExt.minx) / mapserv->fZoom); |
212 | 0 | mapserv->map->extent.maxy = |
213 | 0 | mapserv->mappnt.y + |
214 | 0 | .5 * ((mapserv->ImgExt.maxy - mapserv->ImgExt.miny) / mapserv->fZoom); |
215 | 0 | break; |
216 | 0 | case FROMREFPNT: |
217 | 0 | cellx = MS_CELLSIZE(mapserv->map->reference.extent.minx, |
218 | 0 | mapserv->map->reference.extent.maxx, |
219 | 0 | mapserv->map->reference.width); |
220 | 0 | celly = MS_CELLSIZE(mapserv->map->reference.extent.miny, |
221 | 0 | mapserv->map->reference.extent.maxy, |
222 | 0 | mapserv->map->reference.height); |
223 | 0 | mapserv->mappnt.x = MS_IMAGE2MAP_X( |
224 | 0 | mapserv->RefPnt.x, mapserv->map->reference.extent.minx, cellx); |
225 | 0 | mapserv->mappnt.y = MS_IMAGE2MAP_Y( |
226 | 0 | mapserv->RefPnt.y, mapserv->map->reference.extent.maxy, celly); |
227 | |
|
228 | 0 | mapserv->map->extent.minx = |
229 | 0 | mapserv->mappnt.x - |
230 | 0 | .5 * (mapserv->ImgExt.maxx - |
231 | 0 | mapserv->ImgExt.minx); /* create an extent around that point */ |
232 | 0 | mapserv->map->extent.miny = |
233 | 0 | mapserv->mappnt.y - .5 * (mapserv->ImgExt.maxy - mapserv->ImgExt.miny); |
234 | 0 | mapserv->map->extent.maxx = |
235 | 0 | mapserv->mappnt.x + .5 * (mapserv->ImgExt.maxx - mapserv->ImgExt.minx); |
236 | 0 | mapserv->map->extent.maxy = |
237 | 0 | mapserv->mappnt.y + .5 * (mapserv->ImgExt.maxy - mapserv->ImgExt.miny); |
238 | 0 | break; |
239 | 0 | case FROMBUF: |
240 | 0 | mapserv->map->extent.minx = |
241 | 0 | mapserv->mappnt.x - |
242 | 0 | mapserv |
243 | 0 | ->Buffer; /* create an extent around that point, using the buffer */ |
244 | 0 | mapserv->map->extent.miny = mapserv->mappnt.y - mapserv->Buffer; |
245 | 0 | mapserv->map->extent.maxx = mapserv->mappnt.x + mapserv->Buffer; |
246 | 0 | mapserv->map->extent.maxy = mapserv->mappnt.y + mapserv->Buffer; |
247 | 0 | break; |
248 | 0 | case FROMSCALE: |
249 | 0 | cellsize = |
250 | 0 | (mapserv->ScaleDenom / mapserv->map->resolution) / |
251 | 0 | msInchesPerUnit(mapserv->map->units, |
252 | 0 | 0); /* user supplied a point and a scale denominator */ |
253 | 0 | mapserv->map->extent.minx = |
254 | 0 | mapserv->mappnt.x - cellsize * (mapserv->map->width - 1) / 2.0; |
255 | 0 | mapserv->map->extent.miny = |
256 | 0 | mapserv->mappnt.y - cellsize * (mapserv->map->height - 1) / 2.0; |
257 | 0 | mapserv->map->extent.maxx = |
258 | 0 | mapserv->mappnt.x + cellsize * (mapserv->map->width - 1) / 2.0; |
259 | 0 | mapserv->map->extent.maxy = |
260 | 0 | mapserv->mappnt.y + cellsize * (mapserv->map->height - 1) / 2.0; |
261 | 0 | break; |
262 | 0 | default: /* use the default in the mapfile if it exists */ |
263 | 0 | if ((mapserv->map->extent.minx == mapserv->map->extent.maxx) && |
264 | 0 | (mapserv->map->extent.miny == mapserv->map->extent.maxy)) { |
265 | 0 | msSetError(MS_WEBERR, "No way to generate map extent.", "mapserv()"); |
266 | 0 | return MS_FAILURE; |
267 | 0 | } |
268 | 0 | } |
269 | | |
270 | 0 | mapserv->RawExt = mapserv->map->extent; /* save unaltered extent */ |
271 | |
|
272 | 0 | return MS_SUCCESS; |
273 | 0 | } |
274 | | |
275 | 0 | int checkWebScale(mapservObj *mapserv) { |
276 | 0 | int status; |
277 | 0 | rectObj work_extent = mapserv->map->extent; |
278 | |
|
279 | 0 | mapserv->map->cellsize = msAdjustExtent( |
280 | 0 | &(work_extent), mapserv->map->width, |
281 | 0 | mapserv->map->height); /* we do this cause we need a scale */ |
282 | 0 | if ((status = msCalculateScale(work_extent, mapserv->map->units, |
283 | 0 | mapserv->map->width, mapserv->map->height, |
284 | 0 | mapserv->map->resolution, |
285 | 0 | &mapserv->map->scaledenom)) != MS_SUCCESS) |
286 | 0 | return status; |
287 | | |
288 | 0 | if ((mapserv->map->scaledenom < mapserv->map->web.minscaledenom) && |
289 | 0 | (mapserv->map->web.minscaledenom > 0)) { |
290 | 0 | if (mapserv->map->web.mintemplate) { /* use the template provided */ |
291 | 0 | if (TEMPLATE_TYPE(mapserv->map->web.mintemplate) == MS_FILE) { |
292 | 0 | if ((status = msReturnPage(mapserv, mapserv->map->web.mintemplate, |
293 | 0 | BROWSE, NULL)) != MS_SUCCESS) |
294 | 0 | return status; |
295 | 0 | } else { |
296 | 0 | if ((status = msReturnURL(mapserv, mapserv->map->web.mintemplate, |
297 | 0 | BROWSE)) != MS_SUCCESS) |
298 | 0 | return status; |
299 | 0 | } |
300 | 0 | } else { /* force zoom = 1 (i.e. pan) */ |
301 | 0 | mapserv->fZoom = mapserv->Zoom = 1; |
302 | 0 | mapserv->ZoomDirection = 0; |
303 | 0 | mapserv->CoordSource = FROMSCALE; |
304 | 0 | mapserv->ScaleDenom = mapserv->map->web.minscaledenom; |
305 | 0 | mapserv->mappnt.x = |
306 | 0 | (mapserv->map->extent.maxx + mapserv->map->extent.minx) / |
307 | 0 | 2; /* use center of bad extent */ |
308 | 0 | mapserv->mappnt.y = |
309 | 0 | (mapserv->map->extent.maxy + mapserv->map->extent.miny) / 2; |
310 | 0 | setExtent(mapserv); |
311 | 0 | mapserv->map->cellsize = msAdjustExtent( |
312 | 0 | &(mapserv->map->extent), mapserv->map->width, mapserv->map->height); |
313 | 0 | if ((status = msCalculateScale(mapserv->map->extent, mapserv->map->units, |
314 | 0 | mapserv->map->width, mapserv->map->height, |
315 | 0 | mapserv->map->resolution, |
316 | 0 | &mapserv->map->scaledenom)) != MS_SUCCESS) |
317 | 0 | return status; |
318 | 0 | } |
319 | 0 | } else { |
320 | 0 | if ((mapserv->map->scaledenom > mapserv->map->web.maxscaledenom) && |
321 | 0 | (mapserv->map->web.maxscaledenom > 0)) { |
322 | 0 | if (mapserv->map->web.maxtemplate) { /* use the template provided */ |
323 | 0 | if (TEMPLATE_TYPE(mapserv->map->web.maxtemplate) == MS_FILE) { |
324 | 0 | if ((status = msReturnPage(mapserv, mapserv->map->web.maxtemplate, |
325 | 0 | BROWSE, NULL)) != MS_SUCCESS) |
326 | 0 | return status; |
327 | 0 | } else { |
328 | 0 | if ((status = msReturnURL(mapserv, mapserv->map->web.maxtemplate, |
329 | 0 | BROWSE)) != MS_SUCCESS) |
330 | 0 | return status; |
331 | 0 | } |
332 | 0 | } else { /* force zoom = 1 (i.e. pan) */ |
333 | 0 | mapserv->fZoom = mapserv->Zoom = 1; |
334 | 0 | mapserv->ZoomDirection = 0; |
335 | 0 | mapserv->CoordSource = FROMSCALE; |
336 | 0 | mapserv->ScaleDenom = mapserv->map->web.maxscaledenom; |
337 | 0 | mapserv->mappnt.x = |
338 | 0 | (mapserv->map->extent.maxx + mapserv->map->extent.minx) / |
339 | 0 | 2; /* use center of bad extent */ |
340 | 0 | mapserv->mappnt.y = |
341 | 0 | (mapserv->map->extent.maxy + mapserv->map->extent.miny) / 2; |
342 | 0 | setExtent(mapserv); |
343 | 0 | mapserv->map->cellsize = msAdjustExtent( |
344 | 0 | &(mapserv->map->extent), mapserv->map->width, mapserv->map->height); |
345 | 0 | if ((status = msCalculateScale( |
346 | 0 | mapserv->map->extent, mapserv->map->units, mapserv->map->width, |
347 | 0 | mapserv->map->height, mapserv->map->resolution, |
348 | 0 | &mapserv->map->scaledenom)) != MS_SUCCESS) |
349 | 0 | return status; |
350 | 0 | } |
351 | 0 | } |
352 | 0 | } |
353 | | |
354 | 0 | return MS_SUCCESS; |
355 | 0 | } |
356 | | |
357 | | int msReturnTemplateQuery(mapservObj *mapserv, char *queryFormat, |
358 | 0 | char **papszBuffer) { |
359 | 0 | imageObj *img = NULL; |
360 | 0 | int i, status; |
361 | |
|
362 | 0 | outputFormatObj *outputFormat = NULL; |
363 | 0 | mapObj *map = mapserv->map; |
364 | |
|
365 | 0 | if (!queryFormat) { |
366 | 0 | msSetError(MS_WEBERR, "Return format/mime-type not specified.", |
367 | 0 | "msReturnTemplateQuery()"); |
368 | 0 | return MS_FAILURE; |
369 | 0 | } |
370 | | |
371 | 0 | msApplyDefaultOutputFormats(map); |
372 | |
|
373 | 0 | i = msGetOutputFormatIndex( |
374 | 0 | map, queryFormat); /* queryFormat can be a mime-type or name */ |
375 | 0 | if (i >= 0) |
376 | 0 | outputFormat = map->outputformatlist[i]; |
377 | |
|
378 | 0 | if (outputFormat) { |
379 | 0 | if (MS_RENDERER_PLUGIN(outputFormat)) { |
380 | 0 | msInitializeRendererVTable(outputFormat); |
381 | 0 | } |
382 | 0 | if (MS_RENDERER_OGR(outputFormat)) { |
383 | 0 | checkWebScale(mapserv); |
384 | |
|
385 | 0 | status = msOGRWriteFromQuery(map, outputFormat, mapserv->sendheaders); |
386 | |
|
387 | 0 | return status; |
388 | 0 | } |
389 | | |
390 | 0 | if (!MS_RENDERER_TEMPLATE(outputFormat)) { /* got an image format, return |
391 | | the query results that way */ |
392 | 0 | outputFormatObj *tempOutputFormat = map->outputformat; /* save format */ |
393 | |
|
394 | 0 | checkWebScale(mapserv); |
395 | |
|
396 | 0 | map->outputformat = |
397 | 0 | outputFormat; /* override what was given for IMAGETYPE */ |
398 | 0 | img = msDrawMap(map, MS_TRUE); |
399 | 0 | if (!img) |
400 | 0 | return MS_FAILURE; |
401 | 0 | map->outputformat = tempOutputFormat; /* restore format */ |
402 | |
|
403 | 0 | if (mapserv->sendheaders) { |
404 | 0 | msIO_setHeader("Content-Type", "%s", MS_IMAGE_MIME_TYPE(outputFormat)); |
405 | 0 | msIO_sendHeaders(); |
406 | 0 | } |
407 | 0 | status = msSaveImage(map, img, NULL); |
408 | 0 | msFreeImage(img); |
409 | |
|
410 | 0 | return status; |
411 | 0 | } |
412 | 0 | } |
413 | | |
414 | | /* |
415 | | ** At this point we know we have a template of some sort, either the new style |
416 | | *that references a or the old |
417 | | ** style made up of external files slammed together. Either way we may have to |
418 | | *compute a query map and other |
419 | | ** images. We only create support images IF the querymap has status=MS_ON. |
420 | | */ |
421 | 0 | if (map->querymap.status) { |
422 | 0 | checkWebScale(mapserv); |
423 | 0 | if (msGenerateImages(mapserv, MS_TRUE, MS_TRUE) != MS_SUCCESS) |
424 | 0 | return MS_FAILURE; |
425 | 0 | } |
426 | | |
427 | 0 | if (outputFormat) { |
428 | 0 | const char *file = msGetOutputFormatOption(outputFormat, "FILE", NULL); |
429 | 0 | if (!file) { |
430 | 0 | msSetError(MS_WEBERR, |
431 | 0 | "Template driver requires \"FILE\" format option be set.", |
432 | 0 | "msReturnTemplateQuery()"); |
433 | 0 | return MS_FAILURE; |
434 | 0 | } |
435 | | |
436 | 0 | if (mapserv->sendheaders) { |
437 | 0 | const char *attachment = |
438 | 0 | msGetOutputFormatOption(outputFormat, "ATTACHMENT", NULL); |
439 | 0 | if (attachment) |
440 | 0 | msIO_setHeader("Content-disposition", "attachment; filename=%s", |
441 | 0 | attachment); |
442 | 0 | msIO_setHeader("Content-Type", "%s", outputFormat->mimetype); |
443 | 0 | msIO_sendHeaders(); |
444 | 0 | } |
445 | 0 | if ((status = msReturnPage(mapserv, (char *)file, BROWSE, papszBuffer)) != |
446 | 0 | MS_SUCCESS) |
447 | 0 | return status; |
448 | 0 | } else { |
449 | 0 | if ((status = msReturnNestedTemplateQuery(mapserv, queryFormat, |
450 | 0 | papszBuffer)) != MS_SUCCESS) |
451 | 0 | return status; |
452 | 0 | } |
453 | | |
454 | 0 | return MS_SUCCESS; |
455 | 0 | } |
456 | | |
457 | | /* |
458 | | ** Is a particular layer or group on, that is was it requested explicitly by the |
459 | | *user. |
460 | | */ |
461 | 0 | int isOn(mapservObj *mapserv, char *name, char *group) { |
462 | 0 | int i; |
463 | |
|
464 | 0 | for (i = 0; i < mapserv->NumLayers; i++) { |
465 | 0 | if (name && strcmp(mapserv->Layers[i], name) == 0) |
466 | 0 | return (MS_TRUE); |
467 | 0 | if (group && strcmp(mapserv->Layers[i], group) == 0) |
468 | 0 | return (MS_TRUE); |
469 | 0 | } |
470 | | |
471 | 0 | return (MS_FALSE); |
472 | 0 | } |
473 | | |
474 | | /************************************************************************/ |
475 | | /* int sortLayerByOrder(mapObj *map, char* pszOrder) */ |
476 | | /* */ |
477 | | /* sorth the displaying in ascending or descending order. */ |
478 | | /************************************************************************/ |
479 | 0 | int sortLayerByOrder(mapObj *map, const char *pszOrder) { |
480 | 0 | int *panCurrentOrder = NULL; |
481 | |
|
482 | 0 | if (!map) { |
483 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "sortLayerByOrder()"); |
484 | 0 | return MS_FAILURE; |
485 | 0 | } |
486 | | /* ==================================================================== */ |
487 | | /* The flag "ascending" is in fact not useful since the */ |
488 | | /* default ordering is ascending. */ |
489 | | /* ==================================================================== */ |
490 | | |
491 | | /* -------------------------------------------------------------------- */ |
492 | | /* the map->layerorder should be set at this point in the */ |
493 | | /* sortLayerByMetadata. */ |
494 | | /* -------------------------------------------------------------------- */ |
495 | 0 | if (map->layerorder) { |
496 | 0 | panCurrentOrder = (int *)msSmallMalloc(map->numlayers * sizeof(int)); |
497 | 0 | for (int i = 0; i < map->numlayers; i++) |
498 | 0 | panCurrentOrder[i] = map->layerorder[i]; |
499 | |
|
500 | 0 | if (strcasecmp(pszOrder, "DESCENDING") == 0) { |
501 | 0 | for (int i = 0; i < map->numlayers; i++) |
502 | 0 | map->layerorder[i] = panCurrentOrder[map->numlayers - 1 - i]; |
503 | 0 | } |
504 | |
|
505 | 0 | free(panCurrentOrder); |
506 | 0 | } |
507 | |
|
508 | 0 | return MS_SUCCESS; |
509 | 0 | } |
510 | | |
511 | | /*! |
512 | | * This function set the map->layerorder |
513 | | * index order by the metadata column name |
514 | | */ |
515 | 0 | static int sortLayerByMetadata(mapObj *map, const char *pszMetadata) { |
516 | 0 | int nLegendOrder1; |
517 | 0 | int nLegendOrder2; |
518 | 0 | int i, j; |
519 | 0 | int tmp; |
520 | |
|
521 | 0 | if (!map) { |
522 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "sortLayerByMetadata()"); |
523 | 0 | return MS_FAILURE; |
524 | 0 | } |
525 | | |
526 | | /* |
527 | | * Initiate to default order (Reverse mapfile order) |
528 | | */ |
529 | 0 | if (map->layerorder) { |
530 | 0 | int *pnLayerOrder; |
531 | | |
532 | | /* Backup the original layer order to be able to reverse it */ |
533 | 0 | pnLayerOrder = (int *)msSmallMalloc(map->numlayers * sizeof(int)); |
534 | 0 | for (i = 0; i < map->numlayers; i++) |
535 | 0 | pnLayerOrder[i] = map->layerorder[i]; |
536 | | |
537 | | /* Get a new layerorder array */ |
538 | 0 | free(map->layerorder); |
539 | 0 | map->layerorder = (int *)msSmallMalloc(map->numlayers * sizeof(int)); |
540 | | |
541 | | /* Reverse the layerorder array */ |
542 | 0 | for (i = 0; i < map->numlayers; i++) |
543 | 0 | map->layerorder[i] = pnLayerOrder[map->numlayers - i - 1]; |
544 | |
|
545 | 0 | free(pnLayerOrder); |
546 | 0 | } else { |
547 | 0 | map->layerorder = (int *)msSmallMalloc(map->numlayers * sizeof(int)); |
548 | |
|
549 | 0 | for (i = 0; i < map->numlayers; i++) |
550 | 0 | map->layerorder[i] = map->numlayers - i - 1; |
551 | 0 | } |
552 | |
|
553 | 0 | if (!pszMetadata) |
554 | 0 | return MS_SUCCESS; |
555 | | |
556 | | /* |
557 | | * Bubble sort algo (not very efficient) |
558 | | * should implement a kind of quick sort |
559 | | * algo instead |
560 | | */ |
561 | 0 | for (i = 0; i < map->numlayers - 1; i++) { |
562 | 0 | for (j = 0; j < map->numlayers - 1 - i; j++) { |
563 | 0 | const char *pszLegendOrder1 = msLookupHashTable( |
564 | 0 | &(GET_LAYER(map, map->layerorder[j + 1])->metadata), pszMetadata); |
565 | 0 | const char *pszLegendOrder2 = msLookupHashTable( |
566 | 0 | &(GET_LAYER(map, map->layerorder[j])->metadata), pszMetadata); |
567 | |
|
568 | 0 | if (!pszLegendOrder1 || !pszLegendOrder2) |
569 | 0 | continue; |
570 | | |
571 | 0 | nLegendOrder1 = atoi(pszLegendOrder1); |
572 | 0 | nLegendOrder2 = atoi(pszLegendOrder2); |
573 | |
|
574 | 0 | if (nLegendOrder1 < nLegendOrder2) { /* compare the two neighbors */ |
575 | 0 | tmp = map->layerorder[j]; /* swap a[j] and a[j+1] */ |
576 | 0 | map->layerorder[j] = map->layerorder[j + 1]; |
577 | 0 | map->layerorder[j + 1] = tmp; |
578 | 0 | } |
579 | 0 | } |
580 | 0 | } |
581 | |
|
582 | 0 | return MS_SUCCESS; |
583 | 0 | } |
584 | | |
585 | | /* |
586 | | ** This function return a pointer |
587 | | ** at the beginning of the first occurrence |
588 | | ** of pszTag in pszInstr. |
589 | | ** |
590 | | ** Tag can be [TAG] or [TAG something] |
591 | | */ |
592 | 0 | static const char *findTag(const char *pszInstr, const char *pszTag) { |
593 | 0 | const char *pszStart = NULL; |
594 | 0 | int done = MS_FALSE; |
595 | |
|
596 | 0 | if (!pszInstr || !pszTag) { |
597 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "findTag()"); |
598 | 0 | return NULL; |
599 | 0 | } |
600 | | |
601 | 0 | const int length = |
602 | 0 | strlen(pszTag) + 1; /* adding [ character to the beginning */ |
603 | 0 | char *pszTag1 = (char *)msSmallMalloc(length + 1); |
604 | |
|
605 | 0 | strcpy(pszTag1, "["); |
606 | 0 | strcat(pszTag1, pszTag); |
607 | |
|
608 | 0 | const char *pszTemp = pszInstr; |
609 | 0 | do { |
610 | 0 | pszStart = strstr(pszTemp, pszTag1); |
611 | |
|
612 | 0 | if (pszStart == NULL) |
613 | 0 | done = MS_TRUE; /* tag not found */ |
614 | 0 | else if ((*(pszStart + length) == ']' || *(pszStart + length) == ' ')) |
615 | 0 | done = MS_TRUE; /* valid tag */ |
616 | 0 | else |
617 | 0 | pszTemp += length; /* skip ahead and start over */ |
618 | 0 | } while (!done); |
619 | |
|
620 | 0 | free(pszTag1); |
621 | |
|
622 | 0 | return pszStart; |
623 | 0 | } |
624 | | |
625 | | /* |
626 | | ** This function return a pointer |
627 | | ** to the end of the tag in pszTag |
628 | | ** |
629 | | ** The end of a tag is the next |
630 | | ** non-quoted ']' character. |
631 | | ** Return NULL if not found. |
632 | | */ |
633 | | |
634 | 0 | char *findTagEnd(const char *pszTag) { |
635 | 0 | char *pszEnd = NULL, *pszTmp = (char *)pszTag; |
636 | |
|
637 | 0 | while (pszTmp != NULL) { |
638 | 0 | if (*pszTmp == '"') |
639 | 0 | pszTmp = strchr(pszTmp + 1, '"'); |
640 | 0 | if ((pszTmp == NULL) || (*pszTmp == ']')) { |
641 | 0 | pszEnd = pszTmp; |
642 | 0 | pszTmp = NULL; |
643 | 0 | } else |
644 | 0 | pszTmp++; |
645 | 0 | } |
646 | |
|
647 | 0 | return pszEnd; |
648 | 0 | } |
649 | | |
650 | | /* |
651 | | ** Return a hashtableobj from instr of all |
652 | | ** arguments. hashtable must be freed by caller. |
653 | | */ |
654 | | static int getTagArgs(const char *pszTag, const char *pszInstr, |
655 | 0 | hashTableObj **ppoHashTable) { |
656 | 0 | const char *pszStart, *pszEnd; |
657 | 0 | int nLength; |
658 | 0 | char **papszArgs, **papszVarVal; |
659 | 0 | int nArgs, nDummy; |
660 | 0 | int i; |
661 | |
|
662 | 0 | if (!pszTag || !pszInstr) { |
663 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "getTagArgs()"); |
664 | 0 | return MS_FAILURE; |
665 | 0 | } |
666 | | |
667 | | /* set position to the beginning of tag */ |
668 | 0 | pszStart = findTag(pszInstr, pszTag); |
669 | |
|
670 | 0 | if (pszStart) { |
671 | | /* find ending position */ |
672 | 0 | pszEnd = findTagEnd(pszStart); |
673 | |
|
674 | 0 | if (pszEnd) { |
675 | | /* skip the tag name */ |
676 | 0 | pszStart = pszStart + strlen(pszTag) + 1; |
677 | | |
678 | | /* get length of all args */ |
679 | 0 | nLength = pszEnd - pszStart; |
680 | |
|
681 | 0 | if (nLength > 0) { /* is there arguments ? */ |
682 | 0 | char *pszArgs = (char *)msSmallMalloc(nLength + 1); |
683 | 0 | strlcpy(pszArgs, pszStart, nLength + 1); |
684 | |
|
685 | 0 | if (!(*ppoHashTable)) |
686 | 0 | *ppoHashTable = msCreateHashTable(); |
687 | | |
688 | | /* put all arguments separate by space in a hash table */ |
689 | 0 | papszArgs = msStringTokenize(pszArgs, " ", &nArgs, MS_TRUE); |
690 | | |
691 | | /* msReturnTemplateQuerycheck all argument if they have values */ |
692 | 0 | for (i = 0; i < nArgs; i++) { |
693 | 0 | if (strlen(papszArgs[i]) == 0) { |
694 | 0 | free(papszArgs[i]); |
695 | 0 | continue; |
696 | 0 | } |
697 | | |
698 | 0 | if (strchr(papszArgs[i], '=')) { |
699 | 0 | papszVarVal = |
700 | 0 | msStringTokenize(papszArgs[i], "=", &nDummy, MS_FALSE); |
701 | 0 | msInsertHashTable(*ppoHashTable, papszVarVal[0], papszVarVal[1]); |
702 | 0 | free(papszVarVal[0]); |
703 | 0 | free(papszVarVal[1]); |
704 | 0 | free(papszVarVal); |
705 | 0 | } else /* no value specified. set it to 1 */ |
706 | 0 | msInsertHashTable(*ppoHashTable, papszArgs[i], "1"); |
707 | |
|
708 | 0 | free(papszArgs[i]); |
709 | 0 | } |
710 | 0 | free(papszArgs); |
711 | 0 | free(pszArgs); |
712 | 0 | } |
713 | 0 | } |
714 | 0 | } |
715 | |
|
716 | 0 | return MS_SUCCESS; |
717 | 0 | } |
718 | | |
719 | | /* |
720 | | ** Return a substring from instr between [tag] and [/tag] |
721 | | ** char * returned must be freed by caller. |
722 | | ** pszNextInstr will be a pointer at the end of the |
723 | | ** first occurrence found. |
724 | | */ |
725 | | static int getInlineTag(const char *pszTag, const char *pszInstr, |
726 | 0 | char **pszResult) { |
727 | 0 | const char *pszEnd = NULL; |
728 | 0 | int nInst = 0; |
729 | 0 | int nLength; |
730 | |
|
731 | 0 | *pszResult = NULL; |
732 | |
|
733 | 0 | if (!pszInstr || !pszTag) { |
734 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "getInlineTag()"); |
735 | 0 | return MS_FAILURE; |
736 | 0 | } |
737 | | |
738 | 0 | char *pszEndTag = (char *)msSmallMalloc(strlen(pszTag) + 3); |
739 | 0 | strcpy(pszEndTag, "[/"); |
740 | 0 | strcat(pszEndTag, pszTag); |
741 | | |
742 | | /* find start tag */ |
743 | 0 | const char *pszPatIn = findTag(pszInstr, pszTag); |
744 | 0 | const char *pszPatOut = strstr(pszInstr, pszEndTag); |
745 | |
|
746 | 0 | const char *pszStart = pszPatIn; |
747 | |
|
748 | 0 | const char *pszTmp = pszInstr; |
749 | |
|
750 | 0 | if (pszPatIn) { |
751 | 0 | do { |
752 | 0 | if (pszPatIn && pszPatIn < pszPatOut) { |
753 | 0 | nInst++; |
754 | |
|
755 | 0 | pszTmp = pszPatIn; |
756 | 0 | } |
757 | |
|
758 | 0 | if (pszPatOut && ((pszPatIn == NULL) || pszPatOut < pszPatIn)) { |
759 | 0 | pszEnd = pszPatOut; |
760 | 0 | nInst--; |
761 | |
|
762 | 0 | pszTmp = pszPatOut; |
763 | 0 | } |
764 | |
|
765 | 0 | pszPatIn = findTag(pszTmp + 1, pszTag); |
766 | 0 | pszPatOut = strstr(pszTmp + 1, pszEndTag); |
767 | |
|
768 | 0 | } while (pszTmp != NULL && nInst > 0); |
769 | 0 | } |
770 | |
|
771 | 0 | if (pszStart && pszEnd) { |
772 | | /* find end of start tag */ |
773 | 0 | pszStart = strchr(pszStart, ']'); |
774 | |
|
775 | 0 | if (pszStart) { |
776 | 0 | pszStart++; |
777 | |
|
778 | 0 | nLength = pszEnd - pszStart; |
779 | |
|
780 | 0 | if (nLength > 0) { |
781 | 0 | *pszResult = (char *)msSmallMalloc(nLength + 1); |
782 | | |
783 | | /* copy string between start and end tag */ |
784 | 0 | strlcpy(*pszResult, pszStart, nLength + 1); |
785 | |
|
786 | 0 | (*pszResult)[nLength] = '\0'; |
787 | 0 | } |
788 | 0 | } else { |
789 | 0 | msSetError(MS_WEBERR, "Malformed [%s] tag.", "getInlineTag()", pszTag); |
790 | 0 | return MS_FAILURE; |
791 | 0 | } |
792 | 0 | } |
793 | | |
794 | 0 | msFree(pszEndTag); |
795 | |
|
796 | 0 | return MS_SUCCESS; |
797 | 0 | } |
798 | | |
799 | | /*! |
800 | | * this function process all if tag in pszInstr. |
801 | | * this function return a modified pszInstr. |
802 | | * ht mus contain all variables needed by the function |
803 | | * to interpret if expression. |
804 | | * |
805 | | * If bLastPass is true then all tests for 'null' values will be |
806 | | * considered true if the corresponding value is not set. |
807 | | */ |
808 | 0 | int processIfTag(char **pszInstr, hashTableObj *ht, int bLastPass) { |
809 | | /* char *pszNextInstr = pszInstr; */ |
810 | 0 | const char *pszEnd = NULL; |
811 | |
|
812 | 0 | if (!*pszInstr) { |
813 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "processIfTag()"); |
814 | 0 | return MS_FAILURE; |
815 | 0 | } |
816 | | |
817 | | /* find the if start tag */ |
818 | | |
819 | 0 | const char *pszStart = findTag(*pszInstr, "if"); |
820 | |
|
821 | 0 | while (pszStart) { |
822 | 0 | const char *pszPatIn = findTag(pszStart, "if"); |
823 | 0 | const char *pszPatOut = strstr(pszStart, "[/if]"); |
824 | 0 | const char *pszTmp = pszPatIn; |
825 | |
|
826 | 0 | int nInst = 0; |
827 | 0 | do { |
828 | 0 | if (pszPatIn && pszPatIn < pszPatOut) { |
829 | 0 | nInst++; |
830 | 0 | pszTmp = pszPatIn; |
831 | 0 | } |
832 | |
|
833 | 0 | if (pszPatOut && ((pszPatIn == NULL) || pszPatOut < pszPatIn)) { |
834 | 0 | pszEnd = pszPatOut; |
835 | 0 | nInst--; |
836 | 0 | pszTmp = pszPatOut; |
837 | 0 | } |
838 | |
|
839 | 0 | pszPatIn = findTag(pszTmp + 1, "if"); |
840 | 0 | pszPatOut = strstr(pszTmp + 1, "[/if]"); |
841 | |
|
842 | 0 | } while (nInst > 0); |
843 | | |
844 | | /* get the then string (if expression is true) */ |
845 | 0 | char *pszThen = NULL; |
846 | 0 | if (getInlineTag("if", pszStart, &pszThen) != MS_SUCCESS) { |
847 | 0 | msSetError(MS_WEBERR, "Malformed then if tag.", "processIfTag()"); |
848 | 0 | return MS_FAILURE; |
849 | 0 | } |
850 | | |
851 | | /* retrieve if tag args */ |
852 | 0 | hashTableObj *ifArgs = NULL; |
853 | 0 | if (getTagArgs("if", pszStart, &ifArgs) != MS_SUCCESS) { |
854 | 0 | msSetError(MS_WEBERR, "Malformed args if tag.", "processIfTag()"); |
855 | 0 | return MS_FAILURE; |
856 | 0 | } |
857 | | |
858 | 0 | const char *pszName = msLookupHashTable(ifArgs, "name"); |
859 | 0 | const char *pszValue = msLookupHashTable(ifArgs, "value"); |
860 | 0 | const char *pszOperator = msLookupHashTable(ifArgs, "oper"); |
861 | 0 | if (pszOperator == NULL) /* Default operator if not set is "eq" */ |
862 | 0 | pszOperator = "eq"; |
863 | |
|
864 | 0 | int bEmpty = 0; |
865 | |
|
866 | 0 | if (pszName) { |
867 | | /* build the complete if tag ([if all_args]then string[/if]) */ |
868 | | /* to replace if by then string if expression is true */ |
869 | | /* or by a white space if not. */ |
870 | 0 | const int nLength = pszEnd - pszStart; |
871 | 0 | char *pszIfTag = (char *)msSmallMalloc(nLength + 6); |
872 | 0 | strlcpy(pszIfTag, pszStart, nLength + 1); |
873 | 0 | pszIfTag[nLength] = '\0'; |
874 | 0 | strcat(pszIfTag, "[/if]"); |
875 | |
|
876 | 0 | const char *pszHTValue = msLookupHashTable(ht, pszName); |
877 | |
|
878 | 0 | if (strcmp(pszOperator, "neq") == 0) { |
879 | 0 | if (pszValue && pszHTValue && strcasecmp(pszValue, pszHTValue) != 0) { |
880 | 0 | *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen); |
881 | 0 | } else if (pszHTValue) { |
882 | 0 | *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, ""); |
883 | 0 | bEmpty = 1; |
884 | 0 | } |
885 | 0 | } else if (strcmp(pszOperator, "eq") == 0) { |
886 | 0 | if (pszValue && pszHTValue && strcasecmp(pszValue, pszHTValue) == 0) { |
887 | 0 | *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen); |
888 | 0 | } else if (pszHTValue) { |
889 | 0 | *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, ""); |
890 | 0 | bEmpty = 1; |
891 | 0 | } |
892 | 0 | } else if (strcmp(pszOperator, "isnull") == 0) { |
893 | 0 | if (pszHTValue != NULL) { |
894 | | /* We met a non-null value... condition is false */ |
895 | 0 | *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, ""); |
896 | 0 | bEmpty = 1; |
897 | 0 | } else if (bLastPass) { |
898 | | /* On last pass, if value is still null then condition is true */ |
899 | 0 | *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen); |
900 | 0 | } |
901 | 0 | } else if (strcmp(pszOperator, "isset") == 0) { |
902 | 0 | if (pszHTValue != NULL) { |
903 | | /* Found a non-null value... condition is true */ |
904 | 0 | *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen); |
905 | 0 | } else if (bLastPass) { |
906 | | /* On last pass, if value still not set then condition is false */ |
907 | 0 | *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, ""); |
908 | 0 | bEmpty = 1; |
909 | 0 | } |
910 | 0 | } else { |
911 | 0 | msSetError(MS_WEBERR, "Unsupported operator (%s) in if tag.", |
912 | 0 | "processIfTag()", pszOperator); |
913 | 0 | free(pszIfTag); |
914 | 0 | free(pszThen); |
915 | 0 | msFreeHashTable(ifArgs); |
916 | 0 | return MS_FAILURE; |
917 | 0 | } |
918 | | |
919 | 0 | free(pszIfTag); |
920 | 0 | } |
921 | | |
922 | 0 | free(pszThen); |
923 | |
|
924 | 0 | msFreeHashTable(ifArgs); |
925 | | |
926 | | /* find the if start tag */ |
927 | 0 | if (bEmpty) |
928 | 0 | pszStart = findTag(pszStart, "if"); |
929 | 0 | else |
930 | 0 | pszStart = findTag(pszStart + 1, "if"); |
931 | 0 | } |
932 | | |
933 | 0 | return MS_SUCCESS; |
934 | 0 | } |
935 | | |
936 | | /* Helper function to return the text before the supplied string2 in string1. */ |
937 | 0 | static char *getPreTagText(const char *string1, const char *string2) { |
938 | 0 | int n; |
939 | 0 | char *result, *tmpstr; |
940 | |
|
941 | 0 | if ((tmpstr = strstr(string1, string2)) == NULL) |
942 | 0 | return msStrdup(""); /* return an empty string */ |
943 | | |
944 | 0 | n = strlen(string1) - strlen(tmpstr); |
945 | 0 | result = (char *)msSmallMalloc(n + 1); |
946 | 0 | strlcpy(result, string1, n + 1); |
947 | |
|
948 | 0 | return result; |
949 | 0 | } |
950 | | |
951 | | /* Helper function to return the text after the supplied string2 in string1. */ |
952 | 0 | static char *getPostTagText(const char *string1, const char *string2) { |
953 | 0 | char *tmpstr; |
954 | |
|
955 | 0 | if ((tmpstr = strstr(string1, string2)) == NULL) |
956 | 0 | return msStrdup(""); /* return an empty string */ |
957 | | |
958 | 0 | tmpstr += strlen(string2); /* skip string2 */ |
959 | 0 | return msStrdup(tmpstr); |
960 | 0 | } |
961 | | |
962 | | /* |
963 | | ** Function to process a [feature ...] tag. This tag can *only* be found within |
964 | | ** a [resultset ...][/resultset] block. |
965 | | */ |
966 | | static int processFeatureTag(mapservObj *mapserv, char **line, |
967 | 0 | layerObj *layer) { |
968 | 0 | char *preTag, *postTag; /* text before and after the tag */ |
969 | |
|
970 | 0 | const char *argValue; |
971 | 0 | char *tag, *tagInstance; |
972 | 0 | hashTableObj *tagArgs = NULL; |
973 | |
|
974 | 0 | int limit = -1; |
975 | 0 | const char *trimLast = NULL; |
976 | |
|
977 | 0 | int i, j, status; |
978 | |
|
979 | 0 | if (!*line) { |
980 | 0 | msSetError(MS_WEBERR, "Invalid line pointer.", "processFeatureTag()"); |
981 | 0 | return (MS_FAILURE); |
982 | 0 | } |
983 | | |
984 | 0 | const char *tagStart = findTag(*line, "feature"); |
985 | 0 | if (!tagStart) |
986 | 0 | return (MS_SUCCESS); /* OK, just return; */ |
987 | | |
988 | | /* check for any tag arguments */ |
989 | 0 | if (getTagArgs("feature", tagStart, &tagArgs) != MS_SUCCESS) |
990 | 0 | return (MS_FAILURE); |
991 | 0 | if (tagArgs) { |
992 | 0 | argValue = msLookupHashTable(tagArgs, "limit"); |
993 | 0 | if (argValue) |
994 | 0 | limit = atoi(argValue); |
995 | |
|
996 | 0 | argValue = msLookupHashTable(tagArgs, "trimlast"); |
997 | 0 | if (argValue) |
998 | 0 | trimLast = argValue; |
999 | 0 | } |
1000 | |
|
1001 | 0 | if (strstr(*line, "[/feature]") == |
1002 | 0 | NULL) { /* we know the closing tag must be here, if not throw an error */ |
1003 | 0 | msSetError(MS_WEBERR, "[feature] tag found without closing [/feature].", |
1004 | 0 | "processFeatureTag()"); |
1005 | 0 | msFreeHashTable(tagArgs); |
1006 | 0 | return (MS_FAILURE); |
1007 | 0 | } |
1008 | | |
1009 | 0 | if (getInlineTag("feature", *line, &tag) != MS_SUCCESS) { |
1010 | 0 | msSetError(MS_WEBERR, "Malformed feature tag.", "processFeatureTag()"); |
1011 | 0 | msFreeHashTable(tagArgs); |
1012 | 0 | return MS_FAILURE; |
1013 | 0 | } |
1014 | | |
1015 | 0 | preTag = getPreTagText(*line, "[feature"); |
1016 | 0 | postTag = getPostTagText(*line, "[/feature]"); |
1017 | | |
1018 | | /* start rebuilding **line */ |
1019 | 0 | free(*line); |
1020 | 0 | *line = preTag; |
1021 | | |
1022 | | /* we know the layer has query results or we wouldn't be in this code */ |
1023 | |
|
1024 | | #if 0 |
1025 | | status = msLayerOpen(layer); /* open the layer */ |
1026 | | if(status != MS_SUCCESS) return status; |
1027 | | status = msLayerGetItems(layer); /* retrieve all the item names */ |
1028 | | if(status != MS_SUCCESS) return status; |
1029 | | #endif |
1030 | |
|
1031 | 0 | if (layer->numjoins > 0) { /* initialize necessary JOINs here */ |
1032 | 0 | for (j = 0; j < layer->numjoins; j++) { |
1033 | 0 | status = msJoinConnect(layer, &(layer->joins[j])); |
1034 | 0 | if (status != MS_SUCCESS) { |
1035 | 0 | msFreeHashTable(tagArgs); |
1036 | 0 | msFree(postTag); |
1037 | 0 | msFree(tag); |
1038 | 0 | return status; |
1039 | 0 | } |
1040 | 0 | } |
1041 | 0 | } |
1042 | | |
1043 | 0 | mapserv->LRN = 1; /* layer result counter */ |
1044 | 0 | mapserv->resultlayer = layer; |
1045 | 0 | msInitShape(&(mapserv->resultshape)); |
1046 | |
|
1047 | 0 | if (limit == -1) /* return all */ |
1048 | 0 | limit = layer->resultcache->numresults; |
1049 | 0 | else |
1050 | 0 | limit = MS_MIN(limit, layer->resultcache->numresults); |
1051 | |
|
1052 | 0 | for (i = 0; i < limit; i++) { |
1053 | 0 | status = msLayerGetShape(layer, &(mapserv->resultshape), |
1054 | 0 | &(layer->resultcache->results[i])); |
1055 | 0 | if (status != MS_SUCCESS) { |
1056 | 0 | msFreeHashTable(tagArgs); |
1057 | 0 | msFree(postTag); |
1058 | 0 | msFree(tag); |
1059 | 0 | return status; |
1060 | 0 | } |
1061 | | |
1062 | 0 | mapserv->resultshape.classindex = |
1063 | 0 | msShapeGetClass(layer, layer->map, &mapserv->resultshape, NULL, -1); |
1064 | | |
1065 | | /* prepare any necessary JOINs here (one-to-one only) */ |
1066 | 0 | if (layer->numjoins > 0) { |
1067 | 0 | for (j = 0; j < layer->numjoins; j++) { |
1068 | 0 | if (layer->joins[j].type == MS_JOIN_ONE_TO_ONE) { |
1069 | 0 | msJoinPrepare(&(layer->joins[j]), &(mapserv->resultshape)); |
1070 | 0 | msJoinNext(&(layer->joins[j])); /* fetch the first row */ |
1071 | 0 | } |
1072 | 0 | } |
1073 | 0 | } |
1074 | | |
1075 | | /* |
1076 | | ** if necessary trim a few characters off the end of the tag |
1077 | | */ |
1078 | 0 | if (trimLast && (i == limit - 1)) { |
1079 | 0 | char *ptr; |
1080 | 0 | if ((ptr = strrstr(tag, trimLast)) != NULL) |
1081 | 0 | *ptr = '\0'; |
1082 | 0 | } |
1083 | | |
1084 | | /* process the tag */ |
1085 | 0 | tagInstance = processLine(mapserv, tag, NULL, QUERY); /* do substitutions */ |
1086 | 0 | *line = msStringConcatenate(*line, tagInstance); /* grow the line */ |
1087 | |
|
1088 | 0 | free(tagInstance); |
1089 | 0 | msFreeShape(&(mapserv->resultshape)); /* init too */ |
1090 | |
|
1091 | 0 | mapserv->RN++; /* increment counters */ |
1092 | 0 | mapserv->LRN++; |
1093 | 0 | } |
1094 | | |
1095 | | /* msLayerClose(layer); */ |
1096 | 0 | mapserv->resultlayer = NULL; /* necessary? */ |
1097 | |
|
1098 | 0 | *line = msStringConcatenate(*line, postTag); |
1099 | | |
1100 | | /* |
1101 | | ** clean up |
1102 | | */ |
1103 | 0 | free(postTag); |
1104 | 0 | free(tag); |
1105 | 0 | msFreeHashTable(tagArgs); |
1106 | |
|
1107 | 0 | return (MS_SUCCESS); |
1108 | 0 | } |
1109 | | |
1110 | | /* |
1111 | | ** Function process a [include src="..."] tag. |
1112 | | ** |
1113 | | ** TODO's: |
1114 | | ** - allow URLs |
1115 | | */ |
1116 | | static int processIncludeTag(mapservObj *mapserv, char **line, FILE *stream, |
1117 | 0 | int mode) { |
1118 | 0 | char *tag, *tagEnd; |
1119 | 0 | hashTableObj *tagArgs = NULL; |
1120 | 0 | int tagOffset, tagLength; |
1121 | |
|
1122 | 0 | char *content = NULL, *processedContent = NULL; |
1123 | 0 | const char *src = NULL; |
1124 | |
|
1125 | 0 | FILE *includeStream; |
1126 | 0 | char buffer[MS_BUFFER_LENGTH], path[MS_MAXPATHLEN]; |
1127 | |
|
1128 | 0 | if (!*line) { |
1129 | 0 | msSetError(MS_WEBERR, "Invalid line pointer.", "processIncludeTag()"); |
1130 | 0 | return (MS_FAILURE); |
1131 | 0 | } |
1132 | | |
1133 | 0 | const char *tagStart = findTag(*line, "include"); |
1134 | | |
1135 | | /* It is OK to have no include tags, just return. */ |
1136 | 0 | if (!tagStart) |
1137 | 0 | return MS_SUCCESS; |
1138 | | |
1139 | 0 | while (tagStart) { |
1140 | 0 | tagOffset = tagStart - *line; |
1141 | | |
1142 | | /* check for any tag arguments */ |
1143 | 0 | if (getTagArgs("include", tagStart, &tagArgs) != MS_SUCCESS) { |
1144 | 0 | return (MS_FAILURE); |
1145 | 0 | } |
1146 | 0 | if (tagArgs) { |
1147 | 0 | src = msLookupHashTable(tagArgs, "src"); |
1148 | 0 | } |
1149 | |
|
1150 | 0 | if (!src) |
1151 | 0 | return (MS_SUCCESS); /* don't process the tag, could be something else so |
1152 | | return MS_SUCCESS */ |
1153 | | |
1154 | 0 | if ((includeStream = fopen(msBuildPath(path, mapserv->map->mappath, src), |
1155 | 0 | "r")) == NULL) { |
1156 | 0 | msSetError(MS_IOERR, "%s", "processIncludeTag()", src); |
1157 | 0 | msFreeHashTable(tagArgs); |
1158 | 0 | return MS_FAILURE; |
1159 | 0 | } |
1160 | | |
1161 | 0 | if (isValidTemplate(includeStream, src) != MS_TRUE) { |
1162 | 0 | msFreeHashTable(tagArgs); |
1163 | 0 | fclose(includeStream); |
1164 | 0 | return MS_FAILURE; |
1165 | 0 | } |
1166 | | |
1167 | 0 | while (fgets(buffer, MS_BUFFER_LENGTH, includeStream) != NULL) |
1168 | 0 | content = msStringConcatenate(content, buffer); |
1169 | | |
1170 | | /* done with included file handle */ |
1171 | 0 | fclose(includeStream); |
1172 | | |
1173 | | /* find the end of the tag */ |
1174 | 0 | tagEnd = findTagEnd(tagStart); |
1175 | 0 | tagEnd++; |
1176 | | |
1177 | | /* build the complete tag so we can do substitution */ |
1178 | 0 | tagLength = tagEnd - tagStart; |
1179 | 0 | tag = (char *)msSmallMalloc(tagLength + 1); |
1180 | 0 | strlcpy(tag, tagStart, tagLength + 1); |
1181 | | |
1182 | | /* process any other tags in the content */ |
1183 | 0 | processedContent = processLine(mapserv, content, stream, mode); |
1184 | | |
1185 | | /* do the replacement */ |
1186 | 0 | *line = msReplaceSubstring(*line, tag, processedContent); |
1187 | | |
1188 | | /* clean up */ |
1189 | 0 | free(tag); |
1190 | 0 | tag = NULL; |
1191 | 0 | msFreeHashTable(tagArgs); |
1192 | 0 | tagArgs = NULL; |
1193 | 0 | free(content); |
1194 | 0 | free(processedContent); |
1195 | |
|
1196 | 0 | if ((*line)[tagOffset] != '\0') |
1197 | 0 | tagStart = findTag(*line + tagOffset + 1, "include"); |
1198 | 0 | else |
1199 | 0 | tagStart = NULL; |
1200 | 0 | } |
1201 | | |
1202 | 0 | return (MS_SUCCESS); |
1203 | 0 | } |
1204 | | |
1205 | | /* |
1206 | | ** Function to process a [resultset ...] tag. |
1207 | | */ |
1208 | 0 | static int processResultSetTag(mapservObj *mapserv, char **line, FILE *stream) { |
1209 | 0 | char lineBuffer[MS_BUFFER_LENGTH]; |
1210 | 0 | int foundTagEnd; |
1211 | |
|
1212 | 0 | char *preTag, *postTag; /* text before and after the tag */ |
1213 | |
|
1214 | 0 | char *tag; |
1215 | 0 | hashTableObj *tagArgs = NULL; |
1216 | |
|
1217 | 0 | const char *layerName = NULL; |
1218 | 0 | const char *nodata = NULL; |
1219 | |
|
1220 | 0 | layerObj *lp; |
1221 | |
|
1222 | 0 | if (!*line) { |
1223 | 0 | msSetError(MS_WEBERR, "Invalid line pointer.", "processResultSetTag()"); |
1224 | 0 | return (MS_FAILURE); |
1225 | 0 | } |
1226 | | |
1227 | 0 | const char *tagStart = findTag(*line, "resultset"); |
1228 | 0 | if (!tagStart) |
1229 | 0 | return (MS_SUCCESS); /* OK, just return; */ |
1230 | | |
1231 | 0 | while (tagStart) { |
1232 | | /* initialize the tag arguments */ |
1233 | 0 | layerName = NULL; |
1234 | | |
1235 | | /* check for any tag arguments */ |
1236 | 0 | if (getTagArgs("resultset", tagStart, &tagArgs) != MS_SUCCESS) |
1237 | 0 | return (MS_FAILURE); |
1238 | 0 | if (tagArgs) { |
1239 | 0 | layerName = msLookupHashTable(tagArgs, "layer"); |
1240 | 0 | nodata = msLookupHashTable(tagArgs, "nodata"); |
1241 | 0 | } |
1242 | |
|
1243 | 0 | if (!layerName) { |
1244 | 0 | msSetError(MS_WEBERR, |
1245 | 0 | "[resultset] tag missing required 'layer' argument.", |
1246 | 0 | "processResultSetTag()"); |
1247 | 0 | msFreeHashTable(tagArgs); |
1248 | 0 | return (MS_FAILURE); |
1249 | 0 | } |
1250 | | |
1251 | 0 | const int layerIndex = msGetLayerIndex(mapserv->map, layerName); |
1252 | 0 | if (layerIndex >= mapserv->map->numlayers || layerIndex < 0) { |
1253 | 0 | msSetError(MS_MISCERR, "Layer named '%s' does not exist.", |
1254 | 0 | "processResultSetTag()", layerName); |
1255 | 0 | msFreeHashTable(tagArgs); |
1256 | 0 | return MS_FAILURE; |
1257 | 0 | } |
1258 | 0 | lp = GET_LAYER(mapserv->map, layerIndex); |
1259 | |
|
1260 | 0 | if (strstr(*line, "[/resultset]") == NULL) { /* read ahead */ |
1261 | 0 | if (!stream) { |
1262 | 0 | msSetError(MS_WEBERR, "Invalid file pointer.", "processResultSetTag()"); |
1263 | 0 | msFreeHashTable(tagArgs); |
1264 | 0 | return (MS_FAILURE); |
1265 | 0 | } |
1266 | | |
1267 | 0 | foundTagEnd = MS_FALSE; |
1268 | 0 | while (!foundTagEnd) { |
1269 | 0 | if (fgets(lineBuffer, MS_BUFFER_LENGTH, stream) != NULL) { |
1270 | 0 | *line = msStringConcatenate(*line, lineBuffer); |
1271 | 0 | if (strstr(*line, "[/resultset]") != NULL) |
1272 | 0 | foundTagEnd = MS_TRUE; |
1273 | 0 | } else |
1274 | 0 | break; /* ran out of file */ |
1275 | 0 | } |
1276 | 0 | if (foundTagEnd == MS_FALSE) { |
1277 | 0 | msSetError(MS_WEBERR, |
1278 | 0 | "[resultset] tag found without closing [/resultset].", |
1279 | 0 | "processResultSetTag()"); |
1280 | 0 | msFreeHashTable(tagArgs); |
1281 | 0 | return (MS_FAILURE); |
1282 | 0 | } |
1283 | 0 | } |
1284 | | |
1285 | 0 | if (getInlineTag("resultset", *line, &tag) != MS_SUCCESS) { |
1286 | 0 | msSetError(MS_WEBERR, "Malformed resultset tag.", |
1287 | 0 | "processResultSetTag()"); |
1288 | 0 | msFreeHashTable(tagArgs); |
1289 | 0 | return MS_FAILURE; |
1290 | 0 | } |
1291 | | |
1292 | 0 | preTag = getPreTagText( |
1293 | 0 | *line, "[resultset"); /* TODO: need to handle tags in these */ |
1294 | 0 | postTag = getPostTagText(*line, "[/resultset]"); |
1295 | | |
1296 | | /* start rebuilding **line */ |
1297 | 0 | free(*line); |
1298 | 0 | *line = preTag; |
1299 | | |
1300 | | /* process any includes within the resultset tag */ |
1301 | 0 | if (processIncludeTag(mapserv, &tag, stream, 0) != MS_SUCCESS) { |
1302 | 0 | msFreeHashTable(tagArgs); |
1303 | 0 | return (MS_FAILURE); |
1304 | 0 | } |
1305 | | |
1306 | 0 | if (lp->resultcache && lp->resultcache->numresults > 0) { |
1307 | | /* probably will need a while-loop here to handle multiple instances of |
1308 | | * [feature ...] tags */ |
1309 | 0 | if (processFeatureTag(mapserv, &tag, lp) != MS_SUCCESS) { |
1310 | 0 | msFreeHashTable(tagArgs); |
1311 | 0 | return (MS_FAILURE); /* TODO: how to handle */ |
1312 | 0 | } |
1313 | 0 | *line = msStringConcatenate(*line, tag); |
1314 | 0 | } else if (nodata) { |
1315 | 0 | *line = msStringConcatenate(*line, nodata); |
1316 | 0 | } |
1317 | | |
1318 | 0 | *line = msStringConcatenate(*line, postTag); |
1319 | | |
1320 | | /* clean up */ |
1321 | 0 | free(postTag); |
1322 | 0 | free(tag); |
1323 | |
|
1324 | 0 | tagStart = findTag(*line, "resultset"); |
1325 | 0 | } |
1326 | 0 | msFreeHashTable(tagArgs); |
1327 | |
|
1328 | 0 | return (MS_SUCCESS); |
1329 | 0 | } |
1330 | | |
1331 | | /* |
1332 | | ** Function to process an [item ...] tag: line contains the tag, shape holds the |
1333 | | *attributes. |
1334 | | */ |
1335 | | enum ITEM_ESCAPING { ESCAPE_HTML, ESCAPE_URL, ESCAPE_JSON, ESCAPE_NONE }; |
1336 | | |
1337 | 0 | static int processItemTag(layerObj *layer, char **line, shapeObj *shape) { |
1338 | 0 | int i; |
1339 | |
|
1340 | 0 | char *tagEnd; |
1341 | |
|
1342 | 0 | if (!*line) { |
1343 | 0 | msSetError(MS_WEBERR, "Invalid line pointer.", "processItemTag()"); |
1344 | 0 | return (MS_FAILURE); |
1345 | 0 | } |
1346 | | |
1347 | 0 | const char *tagStart = findTag(*line, "item"); |
1348 | |
|
1349 | 0 | if (!tagStart) |
1350 | 0 | return (MS_SUCCESS); /* OK, just return; */ |
1351 | | |
1352 | 0 | while (tagStart) { |
1353 | 0 | const char *format = "$value"; /* initialize the tag arguments */ |
1354 | 0 | const char *nullFormat = ""; |
1355 | 0 | int precision = -1; |
1356 | 0 | int padding = -1; |
1357 | 0 | const char *name = NULL; |
1358 | 0 | const char *pattern = NULL; |
1359 | 0 | int uc = MS_FALSE; |
1360 | 0 | int lc = MS_FALSE; |
1361 | 0 | int commify = MS_FALSE; |
1362 | 0 | int ignoremissing = MS_FALSE; |
1363 | 0 | int escape = ESCAPE_HTML; |
1364 | 0 | int skip = MS_FALSE; |
1365 | | |
1366 | | /* check for any tag arguments */ |
1367 | 0 | hashTableObj *tagArgs = NULL; |
1368 | 0 | if (getTagArgs("item", tagStart, &tagArgs) != MS_SUCCESS) |
1369 | 0 | return (MS_FAILURE); |
1370 | 0 | if (tagArgs) { |
1371 | 0 | const char *argValue = msLookupHashTable(tagArgs, "name"); |
1372 | 0 | if (argValue) |
1373 | 0 | name = argValue; |
1374 | |
|
1375 | 0 | argValue = msLookupHashTable(tagArgs, "pattern"); |
1376 | 0 | if (argValue) |
1377 | 0 | pattern = argValue; |
1378 | |
|
1379 | 0 | argValue = msLookupHashTable(tagArgs, "precision"); |
1380 | 0 | if (argValue) |
1381 | 0 | precision = atoi(argValue); |
1382 | |
|
1383 | 0 | argValue = msLookupHashTable(tagArgs, "padding"); |
1384 | 0 | if (argValue) |
1385 | 0 | padding = atoi(argValue); |
1386 | |
|
1387 | 0 | argValue = msLookupHashTable(tagArgs, "format"); |
1388 | 0 | if (argValue) |
1389 | 0 | format = argValue; |
1390 | |
|
1391 | 0 | argValue = msLookupHashTable(tagArgs, "nullformat"); |
1392 | 0 | if (argValue) |
1393 | 0 | nullFormat = argValue; |
1394 | |
|
1395 | 0 | argValue = msLookupHashTable(tagArgs, "uc"); |
1396 | 0 | if (argValue && strcasecmp(argValue, "true") == 0) |
1397 | 0 | uc = MS_TRUE; |
1398 | |
|
1399 | 0 | argValue = msLookupHashTable(tagArgs, "lc"); |
1400 | 0 | if (argValue && strcasecmp(argValue, "true") == 0) |
1401 | 0 | lc = MS_TRUE; |
1402 | |
|
1403 | 0 | argValue = msLookupHashTable(tagArgs, "commify"); |
1404 | 0 | if (argValue && strcasecmp(argValue, "true") == 0) |
1405 | 0 | commify = MS_TRUE; |
1406 | |
|
1407 | 0 | argValue = msLookupHashTable(tagArgs, "ignoremissing"); |
1408 | 0 | if (argValue && strcasecmp(argValue, "true") == 0) |
1409 | 0 | ignoremissing = MS_TRUE; |
1410 | |
|
1411 | 0 | argValue = msLookupHashTable(tagArgs, "escape"); |
1412 | 0 | if (argValue && strcasecmp(argValue, "url") == 0) |
1413 | 0 | escape = ESCAPE_URL; |
1414 | 0 | else if (argValue && strcasecmp(argValue, "none") == 0) |
1415 | 0 | escape = ESCAPE_NONE; |
1416 | 0 | else if (argValue && strcasecmp(argValue, "json") == 0) |
1417 | 0 | escape = ESCAPE_JSON; |
1418 | | |
1419 | | /* TODO: deal with sub strings */ |
1420 | 0 | } |
1421 | |
|
1422 | 0 | if (!name) { |
1423 | 0 | msSetError(MS_WEBERR, "Item tag contains no name attribute.", |
1424 | 0 | "processItemTag()"); |
1425 | 0 | return (MS_FAILURE); |
1426 | 0 | } |
1427 | | |
1428 | 0 | for (i = 0; i < layer->numitems; i++) |
1429 | 0 | if (strcasecmp(name, layer->items[i]) == 0) |
1430 | 0 | break; |
1431 | |
|
1432 | 0 | if (i == layer->numitems) { |
1433 | 0 | if (ignoremissing == MS_TRUE) { |
1434 | 0 | skip = MS_TRUE; |
1435 | 0 | } else { |
1436 | 0 | msSetError(MS_WEBERR, "Item name (%s) not found in layer item list.", |
1437 | 0 | "processItemTag()", name); |
1438 | 0 | return (MS_FAILURE); |
1439 | 0 | } |
1440 | 0 | } |
1441 | | |
1442 | | /* |
1443 | | ** now we know which item so build the tagValue |
1444 | | */ |
1445 | | |
1446 | 0 | char *tagValue = NULL; |
1447 | 0 | if (!skip && (shape->values[i] && strlen(shape->values[i]) > 0)) { |
1448 | 0 | char *itemValue = NULL; |
1449 | | |
1450 | | /* set tag text depending on pattern (if necessary), nullFormat can |
1451 | | * contain $value (#3637) */ |
1452 | 0 | if (pattern && msEvalRegex(pattern, shape->values[i]) != MS_TRUE) |
1453 | 0 | tagValue = msStrdup(nullFormat); |
1454 | 0 | else |
1455 | 0 | tagValue = msStrdup(format); |
1456 | |
|
1457 | 0 | if (precision != -1) { |
1458 | 0 | char numberFormat[16]; |
1459 | |
|
1460 | 0 | itemValue = (char *)msSmallMalloc(64); /* plenty big */ |
1461 | 0 | snprintf(numberFormat, sizeof(numberFormat), "%%.%dlf", precision); |
1462 | 0 | snprintf(itemValue, 64, numberFormat, atof(shape->values[i])); |
1463 | 0 | } else |
1464 | 0 | itemValue = msStrdup(shape->values[i]); |
1465 | |
|
1466 | 0 | if (commify == MS_TRUE) |
1467 | 0 | itemValue = msCommifyString(itemValue); |
1468 | | |
1469 | | /* apply other effects */ |
1470 | 0 | if (uc == MS_TRUE) |
1471 | 0 | for (unsigned j = 0; j < strlen(itemValue); j++) |
1472 | 0 | itemValue[j] = toupper(itemValue[j]); |
1473 | 0 | if (lc == MS_TRUE) |
1474 | 0 | for (unsigned j = 0; j < strlen(itemValue); j++) |
1475 | 0 | itemValue[j] = tolower(itemValue[j]); |
1476 | |
|
1477 | 0 | tagValue = msReplaceSubstring(tagValue, "$value", itemValue); |
1478 | 0 | msFree(itemValue); |
1479 | |
|
1480 | 0 | if (padding > 0 && padding < 1000) { |
1481 | 0 | int paddedSize = strlen(tagValue) + padding + 1; |
1482 | 0 | char *paddedValue = NULL; |
1483 | 0 | paddedValue = (char *)msSmallMalloc(paddedSize); |
1484 | 0 | snprintf(paddedValue, paddedSize, "%-*s", padding, tagValue); |
1485 | 0 | msFree(tagValue); |
1486 | 0 | tagValue = paddedValue; |
1487 | 0 | } |
1488 | |
|
1489 | 0 | if (!tagValue) { |
1490 | 0 | msSetError(MS_WEBERR, "Error applying item format.", |
1491 | 0 | "processItemTag()"); |
1492 | 0 | return (MS_FAILURE); /* todo leaking... */ |
1493 | 0 | } |
1494 | 0 | } else { |
1495 | 0 | tagValue = msStrdup(nullFormat); /* attribute value is NULL or empty */ |
1496 | 0 | } |
1497 | | |
1498 | | /* find the end of the tag */ |
1499 | 0 | tagEnd = findTagEnd(tagStart); |
1500 | 0 | tagEnd++; |
1501 | | |
1502 | | /* build the complete tag so we can do substitution */ |
1503 | 0 | const int tagLength = tagEnd - tagStart; |
1504 | 0 | char *tag = (char *)msSmallMalloc(tagLength + 1); |
1505 | 0 | strlcpy(tag, tagStart, tagLength + 1); |
1506 | | |
1507 | | /* do the replacement */ |
1508 | 0 | switch (escape) { |
1509 | 0 | case ESCAPE_HTML: { |
1510 | 0 | char *encodedTagValue = msEncodeHTMLEntities(tagValue); |
1511 | 0 | *line = msReplaceSubstring(*line, tag, encodedTagValue); |
1512 | 0 | msFree(encodedTagValue); |
1513 | 0 | break; |
1514 | 0 | } |
1515 | 0 | case ESCAPE_JSON: { |
1516 | 0 | char *encodedTagValue = msEscapeJSonString(tagValue); |
1517 | 0 | *line = msReplaceSubstring(*line, tag, encodedTagValue); |
1518 | 0 | msFree(encodedTagValue); |
1519 | 0 | break; |
1520 | 0 | } |
1521 | 0 | case ESCAPE_URL: { |
1522 | 0 | char *encodedTagValue = msEncodeUrl(tagValue); |
1523 | 0 | *line = msReplaceSubstring(*line, tag, encodedTagValue); |
1524 | 0 | msFree(encodedTagValue); |
1525 | 0 | break; |
1526 | 0 | } |
1527 | 0 | case ESCAPE_NONE: |
1528 | 0 | *line = msReplaceSubstring(*line, tag, tagValue); |
1529 | 0 | break; |
1530 | 0 | default: |
1531 | 0 | break; |
1532 | 0 | } |
1533 | | |
1534 | | /* clean up */ |
1535 | 0 | free(tag); |
1536 | 0 | msFreeHashTable(tagArgs); |
1537 | 0 | msFree(tagValue); |
1538 | |
|
1539 | 0 | tagStart = findTag(*line, "item"); |
1540 | 0 | } |
1541 | | |
1542 | 0 | return (MS_SUCCESS); |
1543 | 0 | } |
1544 | | |
1545 | | /* |
1546 | | ** Function process any number of MapServer extent tags (e.g. shpext, mapext, |
1547 | | *etc...). |
1548 | | */ |
1549 | | static int processExtentTag(mapservObj *mapserv, char **line, char *name, |
1550 | 0 | rectObj *extent, projectionObj *rectProj) { |
1551 | 0 | rectObj tempExtent; |
1552 | |
|
1553 | 0 | char number[64]; /* holds a single number in the extent */ |
1554 | 0 | char numberFormat[16]; |
1555 | |
|
1556 | 0 | if (!*line) { |
1557 | 0 | msSetError(MS_WEBERR, "Invalid line pointer.", "processExtentTag()"); |
1558 | 0 | return (MS_FAILURE); |
1559 | 0 | } |
1560 | | |
1561 | 0 | const char *tagStart = findTag(*line, name); /* this supports any extent */ |
1562 | | |
1563 | | /* It is OK to have no include tags, just return. */ |
1564 | 0 | if (!tagStart) |
1565 | 0 | return MS_SUCCESS; |
1566 | | |
1567 | 0 | while (tagStart) { |
1568 | 0 | double xExpand = 0, yExpand = 0; /* set tag argument defaults */ |
1569 | 0 | int precision = -1; |
1570 | 0 | const char *format = "$minx $miny $maxx $maxy"; |
1571 | 0 | const char *projectionString = NULL; |
1572 | | |
1573 | | /* hack to handle tags like 'mapext_esc' easily */ |
1574 | 0 | int escape; |
1575 | 0 | if (strstr(name, "_esc")) |
1576 | 0 | escape = ESCAPE_URL; |
1577 | 0 | else |
1578 | 0 | escape = ESCAPE_HTML; |
1579 | |
|
1580 | 0 | const int tagOffset = tagStart - *line; |
1581 | | |
1582 | | /* check for any tag arguments */ |
1583 | 0 | hashTableObj *tagArgs = NULL; |
1584 | 0 | if (getTagArgs(name, tagStart, &tagArgs) != MS_SUCCESS) |
1585 | 0 | return (MS_FAILURE); |
1586 | 0 | if (tagArgs) { |
1587 | 0 | const char *argValue = msLookupHashTable(tagArgs, "expand"); |
1588 | 0 | if (argValue) { |
1589 | 0 | if (strchr(argValue, '%') != NULL) { |
1590 | 0 | float f; |
1591 | 0 | sscanf(argValue, "%f%%", &f); |
1592 | 0 | xExpand = ((f / 100.0) * (extent->maxx - extent->minx)) / 2; |
1593 | 0 | yExpand = ((f / 100.0) * (extent->maxy - extent->miny)) / 2; |
1594 | 0 | } else { |
1595 | 0 | xExpand = atof(argValue); |
1596 | 0 | yExpand = xExpand; |
1597 | 0 | } |
1598 | 0 | } |
1599 | |
|
1600 | 0 | argValue = msLookupHashTable(tagArgs, "escape"); |
1601 | 0 | if (argValue && strcasecmp(argValue, "url") == 0) |
1602 | 0 | escape = ESCAPE_URL; |
1603 | 0 | else if (argValue && strcasecmp(argValue, "none") == 0) |
1604 | 0 | escape = ESCAPE_NONE; |
1605 | |
|
1606 | 0 | argValue = msLookupHashTable(tagArgs, "format"); |
1607 | 0 | if (argValue) |
1608 | 0 | format = argValue; |
1609 | |
|
1610 | 0 | argValue = msLookupHashTable(tagArgs, "precision"); |
1611 | 0 | if (argValue) |
1612 | 0 | precision = atoi(argValue); |
1613 | |
|
1614 | 0 | argValue = msLookupHashTable(tagArgs, "proj"); |
1615 | 0 | if (argValue) |
1616 | 0 | projectionString = argValue; |
1617 | 0 | } |
1618 | |
|
1619 | 0 | tempExtent.minx = extent->minx - xExpand; |
1620 | 0 | tempExtent.miny = extent->miny - yExpand; |
1621 | 0 | tempExtent.maxx = extent->maxx + xExpand; |
1622 | 0 | tempExtent.maxy = extent->maxy + yExpand; |
1623 | | |
1624 | | /* no big deal to convert from file to image coordinates, but what are the |
1625 | | * image parameters */ |
1626 | 0 | if (rectProj && projectionString && |
1627 | 0 | strcasecmp(projectionString, "image") == 0) { |
1628 | 0 | precision = 0; |
1629 | | |
1630 | | /* if necessary, project the shape to match the map */ |
1631 | 0 | if (msProjectionsDiffer(rectProj, &(mapserv->map->projection))) |
1632 | 0 | msProjectRect(rectProj, &mapserv->map->projection, &tempExtent); |
1633 | | |
1634 | | /* convert tempExtent to image coordinates based on the map extent and |
1635 | | * cellsize */ |
1636 | 0 | tempExtent.minx = MS_MAP2IMAGE_X( |
1637 | 0 | tempExtent.minx, mapserv->map->extent.minx, mapserv->map->cellsize); |
1638 | 0 | tempExtent.miny = MS_MAP2IMAGE_Y( |
1639 | 0 | tempExtent.miny, mapserv->map->extent.maxy, mapserv->map->cellsize); |
1640 | 0 | tempExtent.maxx = MS_MAP2IMAGE_X( |
1641 | 0 | tempExtent.minx, mapserv->map->extent.minx, mapserv->map->cellsize); |
1642 | 0 | tempExtent.maxy = MS_MAP2IMAGE_Y( |
1643 | 0 | tempExtent.miny, mapserv->map->extent.maxy, mapserv->map->cellsize); |
1644 | 0 | } else if (rectProj && projectionString) { |
1645 | 0 | projectionObj projection; |
1646 | 0 | msInitProjection(&projection); |
1647 | 0 | msProjectionInheritContextFrom(&projection, &mapserv->map->projection); |
1648 | |
|
1649 | 0 | if (MS_SUCCESS != msLoadProjectionString(&projection, projectionString)) |
1650 | 0 | return MS_FAILURE; |
1651 | | |
1652 | 0 | if (msProjectionsDiffer(rectProj, &projection)) |
1653 | 0 | msProjectRect(rectProj, &projection, &tempExtent); |
1654 | 0 | } |
1655 | | |
1656 | 0 | char *tagValue = msStrdup(format); |
1657 | |
|
1658 | 0 | if (precision != -1) |
1659 | 0 | snprintf(numberFormat, sizeof(numberFormat), "%%.%dlf", precision); |
1660 | 0 | else |
1661 | 0 | snprintf(numberFormat, sizeof(numberFormat), "%%f"); |
1662 | |
|
1663 | 0 | snprintf(number, sizeof(number), numberFormat, tempExtent.minx); |
1664 | 0 | tagValue = msReplaceSubstring(tagValue, "$minx", number); |
1665 | 0 | snprintf(number, sizeof(number), numberFormat, tempExtent.miny); |
1666 | 0 | tagValue = msReplaceSubstring(tagValue, "$miny", number); |
1667 | 0 | snprintf(number, sizeof(number), numberFormat, tempExtent.maxx); |
1668 | 0 | tagValue = msReplaceSubstring(tagValue, "$maxx", number); |
1669 | 0 | snprintf(number, sizeof(number), numberFormat, tempExtent.maxy); |
1670 | 0 | tagValue = msReplaceSubstring(tagValue, "$maxy", number); |
1671 | | |
1672 | | /* find the end of the tag */ |
1673 | 0 | char *tagEnd = findTagEnd(tagStart); |
1674 | 0 | tagEnd++; |
1675 | | |
1676 | | /* build the complete tag so we can do substitution */ |
1677 | 0 | const int tagLength = tagEnd - tagStart; |
1678 | 0 | char *tag = (char *)msSmallMalloc(tagLength + 1); |
1679 | 0 | strlcpy(tag, tagStart, tagLength + 1); |
1680 | | |
1681 | | /* do the replacement */ |
1682 | 0 | switch (escape) { |
1683 | 0 | case ESCAPE_HTML: { |
1684 | 0 | char *encodedTagValue = msEncodeHTMLEntities(tagValue); |
1685 | 0 | *line = msReplaceSubstring(*line, tag, encodedTagValue); |
1686 | 0 | msFree(encodedTagValue); |
1687 | 0 | break; |
1688 | 0 | } |
1689 | 0 | case ESCAPE_URL: { |
1690 | 0 | char *encodedTagValue = msEncodeUrl(tagValue); |
1691 | 0 | *line = msReplaceSubstring(*line, tag, encodedTagValue); |
1692 | 0 | msFree(encodedTagValue); |
1693 | 0 | break; |
1694 | 0 | } |
1695 | 0 | case ESCAPE_NONE: |
1696 | 0 | *line = msReplaceSubstring(*line, tag, tagValue); |
1697 | 0 | break; |
1698 | 0 | default: |
1699 | 0 | break; |
1700 | 0 | } |
1701 | | |
1702 | | /* clean up */ |
1703 | 0 | free(tag); |
1704 | 0 | msFreeHashTable(tagArgs); |
1705 | 0 | msFree(tagValue); |
1706 | |
|
1707 | 0 | if ((*line)[tagOffset] != '\0') |
1708 | 0 | tagStart = findTag(*line + tagOffset + 1, name); |
1709 | 0 | else |
1710 | 0 | tagStart = NULL; |
1711 | 0 | } |
1712 | | |
1713 | 0 | return (MS_SUCCESS); |
1714 | 0 | } |
1715 | | |
1716 | | // RFC 77 TODO: Need to validate these changes with Assefa... |
1717 | | static int processShplabelTag(layerObj *layer, char **line, |
1718 | 0 | shapeObj *origshape) { |
1719 | 0 | char *tagEnd; |
1720 | 0 | shapeObj tShape; |
1721 | 0 | int precision = 0; |
1722 | 0 | int clip_to_map = MS_TRUE; |
1723 | 0 | int use_label_settings = MS_FALSE; |
1724 | 0 | int labelposvalid = MS_FALSE; |
1725 | 0 | pointObj labelPos; |
1726 | 0 | int status; |
1727 | 0 | char number[64]; /* holds a single number in the extent */ |
1728 | 0 | char numberFormat[16]; |
1729 | 0 | shapeObj *shape = NULL; |
1730 | |
|
1731 | 0 | if (!*line) { |
1732 | 0 | msSetError(MS_WEBERR, "Invalid line pointer.", "processShplabelTag()"); |
1733 | 0 | return (MS_FAILURE); |
1734 | 0 | } |
1735 | 0 | if (msCheckParentPointer(layer->map, "map") == MS_FAILURE) |
1736 | 0 | return MS_FAILURE; |
1737 | | |
1738 | 0 | const char *tagStart = findTag(*line, "shplabel"); |
1739 | | |
1740 | | /* It is OK to have no shplabel tags, just return. */ |
1741 | 0 | if (!tagStart) |
1742 | 0 | return MS_SUCCESS; |
1743 | | |
1744 | 0 | if (!origshape || |
1745 | 0 | origshape->numlines <= 0) { /* I suppose we need to make sure the part has |
1746 | | vertices (need shape checker?) */ |
1747 | 0 | msSetError(MS_WEBERR, "Null or empty shape.", "processShplabelTag()"); |
1748 | 0 | return (MS_FAILURE); |
1749 | 0 | } |
1750 | | |
1751 | 0 | while (tagStart) { |
1752 | 0 | if (shape) |
1753 | 0 | msFreeShape(shape); |
1754 | 0 | shape = (shapeObj *)msSmallMalloc(sizeof(shapeObj)); |
1755 | 0 | msInitShape(shape); |
1756 | 0 | msCopyShape(origshape, shape); |
1757 | |
|
1758 | 0 | const char *projectionString = NULL; |
1759 | 0 | const char *format = "$x,$y"; |
1760 | 0 | const int tagOffset = tagStart - *line; |
1761 | |
|
1762 | 0 | hashTableObj *tagArgs = NULL; |
1763 | 0 | if (getTagArgs("shplabel", tagStart, &tagArgs) != MS_SUCCESS) |
1764 | 0 | return (MS_FAILURE); |
1765 | 0 | if (tagArgs) { |
1766 | 0 | const char *argValue = msLookupHashTable(tagArgs, "format"); |
1767 | 0 | if (argValue) |
1768 | 0 | format = argValue; |
1769 | |
|
1770 | 0 | argValue = msLookupHashTable(tagArgs, "precision"); |
1771 | 0 | if (argValue) |
1772 | 0 | precision = atoi(argValue); |
1773 | |
|
1774 | 0 | argValue = msLookupHashTable(tagArgs, "proj"); |
1775 | 0 | if (argValue) |
1776 | 0 | projectionString = argValue; |
1777 | |
|
1778 | 0 | argValue = msLookupHashTable(tagArgs, "clip_to_map"); |
1779 | 0 | if (argValue) { |
1780 | 0 | if (strcasecmp(argValue, "false") == 0) |
1781 | 0 | clip_to_map = MS_FALSE; |
1782 | 0 | } |
1783 | |
|
1784 | 0 | argValue = msLookupHashTable(tagArgs, "use_label_settings"); |
1785 | 0 | if (argValue) { |
1786 | 0 | if (strcasecmp(argValue, "true") == 0) |
1787 | 0 | use_label_settings = MS_TRUE; |
1788 | 0 | } |
1789 | 0 | } |
1790 | |
|
1791 | 0 | labelPos.x = -1; |
1792 | 0 | labelPos.y = -1; |
1793 | 0 | msInitShape(&tShape); |
1794 | |
|
1795 | 0 | tShape.type = MS_SHAPE_LINE; |
1796 | 0 | tShape.line = (lineObj *)msSmallMalloc(sizeof(lineObj)); |
1797 | 0 | tShape.numlines = 1; |
1798 | 0 | tShape.line[0].point = NULL; /* initialize the line */ |
1799 | 0 | tShape.line[0].numpoints = 0; |
1800 | |
|
1801 | 0 | double cellsize; |
1802 | 0 | if (layer->map->cellsize <= 0) |
1803 | 0 | cellsize = |
1804 | 0 | MS_MAX(MS_CELLSIZE(layer->map->extent.minx, layer->map->extent.maxx, |
1805 | 0 | layer->map->width), |
1806 | 0 | MS_CELLSIZE(layer->map->extent.miny, layer->map->extent.maxy, |
1807 | 0 | layer->map->height)); |
1808 | 0 | else |
1809 | 0 | cellsize = layer->map->cellsize; |
1810 | |
|
1811 | 0 | if (shape->type == MS_SHAPE_POINT) { |
1812 | 0 | labelposvalid = MS_FALSE; |
1813 | 0 | if (shape->numlines > 0 && shape->line[0].numpoints > 0) { |
1814 | 0 | labelposvalid = MS_TRUE; |
1815 | 0 | labelPos = shape->line[0].point[0]; |
1816 | 0 | if (layer->transform == MS_TRUE) { |
1817 | 0 | if (layer->project && |
1818 | 0 | msProjectionsDiffer(&(layer->projection), |
1819 | 0 | &(layer->map->projection))) { |
1820 | 0 | reprojectionObj *reprojector = |
1821 | 0 | msLayerGetReprojectorToMap(layer, layer->map); |
1822 | 0 | if (reprojector) { |
1823 | 0 | msProjectShapeEx(reprojector, shape); |
1824 | 0 | } |
1825 | 0 | } |
1826 | |
|
1827 | 0 | labelPos = shape->line[0].point[0]; |
1828 | 0 | labelPos.x = |
1829 | 0 | MS_MAP2IMAGE_X(labelPos.x, layer->map->extent.minx, cellsize); |
1830 | 0 | labelPos.y = |
1831 | 0 | MS_MAP2IMAGE_Y(labelPos.y, layer->map->extent.maxy, cellsize); |
1832 | 0 | } |
1833 | 0 | } |
1834 | 0 | } else if (shape->type == MS_SHAPE_LINE) { |
1835 | 0 | labelposvalid = MS_FALSE; |
1836 | 0 | if (layer->transform == MS_TRUE) { |
1837 | 0 | if (layer->project && msProjectionsDiffer(&(layer->projection), |
1838 | 0 | &(layer->map->projection))) { |
1839 | 0 | reprojectionObj *reprojector = |
1840 | 0 | msLayerGetReprojectorToMap(layer, layer->map); |
1841 | 0 | if (reprojector) { |
1842 | 0 | msProjectShapeEx(reprojector, shape); |
1843 | 0 | } |
1844 | 0 | } |
1845 | |
|
1846 | 0 | if (clip_to_map) |
1847 | 0 | msClipPolylineRect(shape, layer->map->extent); |
1848 | |
|
1849 | 0 | msTransformShapeToPixelRound(shape, layer->map->extent, cellsize); |
1850 | 0 | } else |
1851 | 0 | msOffsetShapeRelativeTo(shape, layer); |
1852 | |
|
1853 | 0 | if (shape->numlines > 0) { |
1854 | 0 | struct label_auto_result lar; |
1855 | 0 | memset(&lar, 0, sizeof(struct label_auto_result)); |
1856 | 0 | if (MS_UNLIKELY(MS_FAILURE == msPolylineLabelPoint(layer->map, shape, |
1857 | 0 | NULL, NULL, &lar, |
1858 | 0 | 0))) { |
1859 | 0 | free(lar.angles); |
1860 | 0 | free(lar.label_points); |
1861 | 0 | return MS_FAILURE; |
1862 | 0 | } |
1863 | 0 | if (lar.num_label_points > 0) { |
1864 | | /* convert to geo */ |
1865 | 0 | labelPos.x = lar.label_points[0].x; |
1866 | 0 | labelPos.y = lar.label_points[0].y; |
1867 | 0 | labelposvalid = MS_TRUE; |
1868 | 0 | } |
1869 | 0 | free(lar.angles); |
1870 | 0 | free(lar.label_points); |
1871 | 0 | } |
1872 | 0 | } else if (shape->type == MS_SHAPE_POLYGON) { |
1873 | 0 | labelposvalid = MS_FALSE; |
1874 | 0 | if (layer->transform == MS_TRUE) { |
1875 | 0 | if (layer->project && msProjectionsDiffer(&(layer->projection), |
1876 | 0 | &(layer->map->projection))) { |
1877 | 0 | reprojectionObj *reprojector = |
1878 | 0 | msLayerGetReprojectorToMap(layer, layer->map); |
1879 | 0 | if (reprojector) { |
1880 | 0 | msProjectShapeEx(reprojector, shape); |
1881 | 0 | } |
1882 | 0 | } |
1883 | |
|
1884 | 0 | if (clip_to_map) |
1885 | 0 | msClipPolygonRect(shape, layer->map->extent); |
1886 | |
|
1887 | 0 | msTransformShapeToPixelRound(shape, layer->map->extent, cellsize); |
1888 | 0 | } else |
1889 | 0 | msOffsetShapeRelativeTo(shape, layer); |
1890 | |
|
1891 | 0 | if (shape->numlines > 0) { |
1892 | 0 | if (msPolygonLabelPoint(shape, &labelPos, -1) == MS_SUCCESS) { |
1893 | 0 | if (labelPos.x == -1 && labelPos.y == -1) |
1894 | 0 | labelposvalid = MS_FALSE; |
1895 | 0 | else |
1896 | 0 | labelposvalid = MS_TRUE; |
1897 | 0 | } |
1898 | 0 | } |
1899 | 0 | } |
1900 | | |
1901 | 0 | if (labelposvalid == MS_TRUE) { |
1902 | 0 | pointObj p1 = {0}; // initialize |
1903 | 0 | pointObj p2 = {0}; |
1904 | 0 | int label_offset_x, label_offset_y; |
1905 | 0 | labelObj *label = NULL; |
1906 | 0 | label_bounds lbounds; |
1907 | 0 | lineObj lbounds_line; |
1908 | 0 | pointObj lbounds_point[5]; |
1909 | 0 | double tmp; |
1910 | |
|
1911 | 0 | p1.x = labelPos.x; |
1912 | 0 | p1.y = labelPos.y; |
1913 | |
|
1914 | 0 | p2.x = labelPos.x; |
1915 | 0 | p2.y = labelPos.y; |
1916 | 0 | if (use_label_settings == MS_TRUE) { |
1917 | | |
1918 | | /* RFC 77: classes (and shapes) can have more than 1 piece of |
1919 | | * annotation, here we only use the first (index=0) */ |
1920 | 0 | if (shape->classindex >= 0 && |
1921 | 0 | layer->class[shape->classindex] -> numlabels > 0) { |
1922 | 0 | label = layer->class[shape->classindex]->labels[0]; |
1923 | 0 | if (msGetLabelStatus(layer->map, layer, shape, label) == MS_ON) { |
1924 | 0 | char *annotext = msShapeGetLabelAnnotation(layer, shape, label); |
1925 | 0 | if (annotext) { |
1926 | 0 | textSymbolObj ts; |
1927 | 0 | initTextSymbol(&ts); |
1928 | 0 | msPopulateTextSymbolForLabelAndString(&ts, label, annotext, |
1929 | 0 | layer->scalefactor, 1.0, 0); |
1930 | |
|
1931 | 0 | label_offset_x = (int)(label->offsetx * layer->scalefactor); |
1932 | 0 | label_offset_y = (int)(label->offsety * layer->scalefactor); |
1933 | 0 | lbounds.poly = &lbounds_line; |
1934 | 0 | lbounds_line.numpoints = 5; |
1935 | 0 | lbounds_line.point = lbounds_point; |
1936 | |
|
1937 | 0 | p1 = get_metrics(&labelPos, label->position, ts.textpath, |
1938 | 0 | label_offset_x, label_offset_y, |
1939 | 0 | label->angle * MS_DEG_TO_RAD, 0, &lbounds); |
1940 | | |
1941 | | /* should we use the point returned from get_metrics?. From few |
1942 | | test done, It seems to return the UL corner of the text. For now |
1943 | | use the bounds.minx/miny */ |
1944 | 0 | p1.x = lbounds.bbox.minx; |
1945 | 0 | p1.y = lbounds.bbox.miny; |
1946 | 0 | p2.x = lbounds.bbox.maxx; |
1947 | 0 | p2.y = lbounds.bbox.maxy; |
1948 | 0 | freeTextSymbol(&ts); |
1949 | 0 | } |
1950 | 0 | } |
1951 | 0 | } |
1952 | 0 | } |
1953 | | |
1954 | | /* y's are flipped because it is in image coordinate systems */ |
1955 | 0 | p1.x = MS_IMAGE2MAP_X(p1.x, layer->map->extent.minx, cellsize); |
1956 | 0 | tmp = p1.y; |
1957 | 0 | p1.y = MS_IMAGE2MAP_Y(p2.y, layer->map->extent.maxy, cellsize); |
1958 | 0 | p2.x = MS_IMAGE2MAP_X(p2.x, layer->map->extent.minx, cellsize); |
1959 | 0 | p2.y = MS_IMAGE2MAP_Y(tmp, layer->map->extent.maxy, cellsize); |
1960 | 0 | if (layer->transform == MS_TRUE) { |
1961 | 0 | if (layer->project && msProjectionsDiffer(&(layer->projection), |
1962 | 0 | &(layer->map->projection))) { |
1963 | 0 | msProjectPoint(&layer->map->projection, &layer->projection, &p1); |
1964 | 0 | msProjectPoint(&layer->map->projection, &layer->projection, &p2); |
1965 | 0 | } |
1966 | 0 | } |
1967 | 0 | msAddPointToLine(&(tShape.line[0]), &p1); |
1968 | 0 | msAddPointToLine(&(tShape.line[0]), &p2); |
1969 | 0 | } else |
1970 | 0 | tShape.numlines = 0; |
1971 | |
|
1972 | 0 | if (projectionString && strcasecmp(projectionString, "image") == 0) { |
1973 | 0 | precision = 0; |
1974 | | |
1975 | | /* if necessary, project the shape to match the map */ |
1976 | 0 | if (msProjectionsDiffer(&(layer->projection), |
1977 | 0 | &(layer->map->projection))) { |
1978 | 0 | reprojectionObj *reprojector = |
1979 | 0 | msLayerGetReprojectorToMap(layer, layer->map); |
1980 | 0 | if (reprojector) { |
1981 | 0 | msProjectShapeEx(reprojector, &tShape); |
1982 | 0 | } |
1983 | 0 | } |
1984 | |
|
1985 | 0 | msClipPolylineRect(&tShape, layer->map->extent); |
1986 | |
|
1987 | 0 | msTransformShapeToPixelRound(&tShape, layer->map->extent, |
1988 | 0 | layer->map->cellsize); |
1989 | 0 | } else if (projectionString) { |
1990 | 0 | projectionObj projection; |
1991 | 0 | msInitProjection(&projection); |
1992 | 0 | msProjectionInheritContextFrom(&projection, &layer->map->projection); |
1993 | |
|
1994 | 0 | status = msLoadProjectionString(&projection, projectionString); |
1995 | 0 | if (status != MS_SUCCESS) |
1996 | 0 | return MS_FAILURE; |
1997 | | |
1998 | 0 | if (msProjectionsDiffer(&(layer->projection), &projection)) |
1999 | 0 | msProjectShape(&layer->projection, &projection, &tShape); |
2000 | 0 | } |
2001 | | |
2002 | | /* do the replacement */ |
2003 | 0 | char *tagValue = msStrdup(format); |
2004 | 0 | if (precision > 0) |
2005 | 0 | snprintf(numberFormat, sizeof(numberFormat), "%%.%dlf", precision); |
2006 | 0 | else |
2007 | 0 | snprintf(numberFormat, sizeof(numberFormat), "%%f"); |
2008 | |
|
2009 | 0 | if (tShape.numlines > 0) { |
2010 | 0 | if (strcasestr(tagValue, "$x") != 0) { |
2011 | 0 | snprintf(number, sizeof(number), numberFormat, |
2012 | 0 | tShape.line[0].point[0].x); |
2013 | 0 | tagValue = msReplaceSubstring(tagValue, "$x", number); |
2014 | 0 | } |
2015 | 0 | if (strcasestr(tagValue, "$y") != 0) { |
2016 | 0 | snprintf(number, sizeof(number), numberFormat, |
2017 | 0 | tShape.line[0].point[0].y); |
2018 | 0 | tagValue = msReplaceSubstring(tagValue, "$y", number); |
2019 | 0 | } |
2020 | |
|
2021 | 0 | if (strcasestr(tagValue, "$minx") != 0) { |
2022 | 0 | snprintf(number, sizeof(number), numberFormat, |
2023 | 0 | tShape.line[0].point[0].x); |
2024 | 0 | tagValue = msReplaceSubstring(tagValue, "$minx", number); |
2025 | 0 | } |
2026 | 0 | if (strcasestr(tagValue, "$miny") != 0) { |
2027 | 0 | snprintf(number, sizeof(number), numberFormat, |
2028 | 0 | tShape.line[0].point[0].y); |
2029 | 0 | tagValue = msReplaceSubstring(tagValue, "$miny", number); |
2030 | 0 | } |
2031 | 0 | if (strcasestr(tagValue, "$maxx") != 0) { |
2032 | 0 | snprintf(number, sizeof(number), numberFormat, |
2033 | 0 | tShape.line[0].point[1].x); |
2034 | 0 | tagValue = msReplaceSubstring(tagValue, "$maxx", number); |
2035 | 0 | } |
2036 | 0 | if (strcasestr(tagValue, "$maxy") != 0) { |
2037 | 0 | snprintf(number, sizeof(number), numberFormat, |
2038 | 0 | tShape.line[0].point[1].y); |
2039 | 0 | tagValue = msReplaceSubstring(tagValue, "$maxy", number); |
2040 | 0 | } |
2041 | 0 | } |
2042 | | |
2043 | | /* find the end of the tag */ |
2044 | 0 | tagEnd = findTagEnd(tagStart); |
2045 | 0 | tagEnd++; |
2046 | | |
2047 | | /* build the complete tag so we can do substitution */ |
2048 | 0 | const int tagLength = tagEnd - tagStart; |
2049 | 0 | char *tag = (char *)msSmallMalloc(tagLength + 1); |
2050 | 0 | strlcpy(tag, tagStart, tagLength + 1); |
2051 | |
|
2052 | 0 | *line = msReplaceSubstring(*line, tag, tagValue); |
2053 | | |
2054 | | /* clean up */ |
2055 | 0 | msFreeShape(&tShape); |
2056 | 0 | free(tag); |
2057 | 0 | msFreeHashTable(tagArgs); |
2058 | 0 | msFree(tagValue); |
2059 | |
|
2060 | 0 | if ((*line)[tagOffset] != '\0') |
2061 | 0 | tagStart = findTag(*line + tagOffset + 1, "shplabel"); |
2062 | 0 | else |
2063 | 0 | tagStart = NULL; |
2064 | 0 | } |
2065 | 0 | if (shape) |
2066 | 0 | msFreeShape(shape); |
2067 | |
|
2068 | 0 | return (MS_SUCCESS); |
2069 | 0 | } |
2070 | | |
2071 | | /* |
2072 | | ** Function to process a [date ...] tag |
2073 | | */ |
2074 | 0 | static int processDateTag(char **line) { |
2075 | 0 | struct tm *datetime; |
2076 | 0 | time_t t; |
2077 | 0 | int result; |
2078 | 0 | char *tag = NULL, *tagEnd; |
2079 | 0 | hashTableObj *tagArgs = NULL; |
2080 | 0 | int tagOffset, tagLength; |
2081 | 0 | #define DATE_BUFLEN 1024 |
2082 | 0 | char datestr[DATE_BUFLEN]; |
2083 | 0 | const char *argValue = NULL; |
2084 | 0 | const char *format, *tz; /* tag parameters */ |
2085 | |
|
2086 | 0 | if (!*line) { |
2087 | 0 | msSetError(MS_WEBERR, "Invalid line pointer.", "processDateTag()"); |
2088 | 0 | return (MS_FAILURE); |
2089 | 0 | } |
2090 | | |
2091 | 0 | const char *tagStart = findTag(*line, "date"); |
2092 | | |
2093 | | /* It is OK to have no date tags, just return. */ |
2094 | 0 | if (!tagStart) |
2095 | 0 | return MS_SUCCESS; |
2096 | | |
2097 | 0 | while (tagStart) { |
2098 | | /* set tag params to defaults */ |
2099 | 0 | format = DEFAULT_DATE_FORMAT; |
2100 | 0 | tz = ""; |
2101 | |
|
2102 | 0 | tagOffset = tagStart - *line; |
2103 | | |
2104 | | /* check for any tag arguments */ |
2105 | 0 | if (getTagArgs("date", tagStart, &tagArgs) != MS_SUCCESS) |
2106 | 0 | return (MS_FAILURE); |
2107 | | |
2108 | 0 | if (tagArgs) { |
2109 | 0 | argValue = msLookupHashTable(tagArgs, "format"); |
2110 | 0 | if (argValue) |
2111 | 0 | format = argValue; |
2112 | 0 | argValue = msLookupHashTable(tagArgs, "tz"); |
2113 | 0 | if (argValue) |
2114 | 0 | tz = argValue; |
2115 | 0 | } |
2116 | |
|
2117 | 0 | t = time(NULL); |
2118 | 0 | if (strncasecmp(tz, "gmt", 4) == 0) { |
2119 | 0 | datetime = gmtime(&t); |
2120 | 0 | } else { |
2121 | 0 | datetime = localtime(&t); |
2122 | 0 | } |
2123 | 0 | result = strftime(datestr, DATE_BUFLEN, format, datetime); |
2124 | | |
2125 | | /* Only do the replacement if the date was successfully written */ |
2126 | 0 | if (result > 0) { |
2127 | | /* find the end of the tag */ |
2128 | 0 | tagEnd = findTagEnd(tagStart); |
2129 | 0 | tagEnd++; |
2130 | | |
2131 | | /* build the complete tag so we can do substitution */ |
2132 | 0 | tagLength = tagEnd - tagStart; |
2133 | 0 | tag = (char *)msSmallMalloc(tagLength + 1); |
2134 | 0 | strlcpy(tag, tagStart, tagLength + 1); |
2135 | | |
2136 | | /* do the replacement */ |
2137 | 0 | *line = msReplaceSubstring(*line, tag, datestr); |
2138 | 0 | } |
2139 | | |
2140 | | /* clean up */ |
2141 | 0 | msFree(tag); |
2142 | 0 | tag = NULL; |
2143 | 0 | msFreeHashTable(tagArgs); |
2144 | 0 | tagArgs = NULL; |
2145 | |
|
2146 | 0 | if ((*line)[tagOffset] != '\0') |
2147 | 0 | tagStart = findTag(*line + tagOffset + 1, "date"); |
2148 | 0 | else |
2149 | 0 | tagStart = NULL; |
2150 | 0 | } |
2151 | | |
2152 | 0 | return (MS_SUCCESS); |
2153 | 0 | } |
2154 | | |
2155 | | /* |
2156 | | ** Function to process a [shpxy ...] tag: line contains the tag, shape holds the |
2157 | | *coordinates. |
2158 | | ** |
2159 | | ** TODO's: |
2160 | | ** - May need to change attribute names. |
2161 | | ** - Need generalization routines (not here, but in mapprimative.c). |
2162 | | ** - Try to avoid all the realloc calls. |
2163 | | */ |
2164 | 0 | static int processShpxyTag(layerObj *layer, char **line, shapeObj *shape) { |
2165 | 0 | int i, j, p; |
2166 | 0 | int status; |
2167 | |
|
2168 | 0 | char *tagEnd; |
2169 | |
|
2170 | 0 | shapeObj tShape; |
2171 | 0 | char point[128]; |
2172 | |
|
2173 | 0 | if (!*line) { |
2174 | 0 | msSetError(MS_WEBERR, "Invalid line pointer.", "processShpxyTag()"); |
2175 | 0 | return (MS_FAILURE); |
2176 | 0 | } |
2177 | 0 | if (msCheckParentPointer(layer->map, "map") == MS_FAILURE) |
2178 | 0 | return MS_FAILURE; |
2179 | | |
2180 | 0 | const char *tagStart = findTag(*line, "shpxy"); |
2181 | | |
2182 | | /* It is OK to have no shpxy tags, just return. */ |
2183 | 0 | if (!tagStart) |
2184 | 0 | return MS_SUCCESS; |
2185 | | |
2186 | 0 | if (!shape || |
2187 | 0 | shape->numlines <= 0) { /* I suppose we need to make sure the part has |
2188 | | vertices (need shape checker?) */ |
2189 | 0 | msSetError(MS_WEBERR, "Null or empty shape.", "processShpxyTag()"); |
2190 | 0 | return (MS_FAILURE); |
2191 | 0 | } |
2192 | | |
2193 | 0 | while (tagStart) { |
2194 | | #ifdef USE_GEOS |
2195 | | double buffer = 0; |
2196 | | int bufferUnits = -1; |
2197 | | #endif |
2198 | | |
2199 | | /* |
2200 | | ** Pointers to static strings, naming convention is: |
2201 | | ** char 1/2 - x=x, y=y, c=coordinate, p=part, s=shape, ir=inner ring, |
2202 | | *or=outer ring |
2203 | | ** last char - h=header, f=footer, s=separator |
2204 | | */ |
2205 | 0 | const char *xh = "", *yh = ""; |
2206 | 0 | const char *xf = ","; |
2207 | 0 | const char *yf = ""; |
2208 | 0 | const char *cs = " "; |
2209 | 0 | const char *ph = "", *pf = ""; |
2210 | 0 | const char *ps = " "; |
2211 | 0 | const char *sh = "", *sf = ""; |
2212 | 0 | const char *irh = "", |
2213 | 0 | *irf = ""; /* inner ring: necessary for complex polygons */ |
2214 | 0 | const char *orh = "", *orf = ""; /* outer ring */ |
2215 | |
|
2216 | 0 | int centroid = MS_FALSE; |
2217 | 0 | int precision = 0; |
2218 | 0 | double scale_x = 1.0; |
2219 | 0 | double scale_y = 1.0; |
2220 | |
|
2221 | 0 | const char *projectionString = NULL; |
2222 | |
|
2223 | 0 | const int tagOffset = tagStart - *line; |
2224 | | |
2225 | | /* check for any tag arguments */ |
2226 | 0 | hashTableObj *tagArgs = NULL; |
2227 | 0 | if (getTagArgs("shpxy", tagStart, &tagArgs) != MS_SUCCESS) |
2228 | 0 | return (MS_FAILURE); |
2229 | 0 | if (tagArgs) { |
2230 | 0 | const char *argValue = msLookupHashTable(tagArgs, "xh"); |
2231 | 0 | if (argValue) |
2232 | 0 | xh = argValue; |
2233 | 0 | argValue = msLookupHashTable(tagArgs, "xf"); |
2234 | 0 | if (argValue) |
2235 | 0 | xf = argValue; |
2236 | |
|
2237 | 0 | argValue = msLookupHashTable(tagArgs, "yh"); |
2238 | 0 | if (argValue) |
2239 | 0 | yh = argValue; |
2240 | 0 | argValue = msLookupHashTable(tagArgs, "yf"); |
2241 | 0 | if (argValue) |
2242 | 0 | yf = argValue; |
2243 | |
|
2244 | 0 | argValue = msLookupHashTable(tagArgs, "cs"); |
2245 | 0 | if (argValue) |
2246 | 0 | cs = argValue; |
2247 | |
|
2248 | 0 | argValue = msLookupHashTable(tagArgs, "irh"); |
2249 | 0 | if (argValue) |
2250 | 0 | irh = argValue; |
2251 | 0 | argValue = msLookupHashTable(tagArgs, "irf"); |
2252 | 0 | if (argValue) |
2253 | 0 | irf = argValue; |
2254 | |
|
2255 | 0 | argValue = msLookupHashTable(tagArgs, "orh"); |
2256 | 0 | if (argValue) |
2257 | 0 | orh = argValue; |
2258 | 0 | argValue = msLookupHashTable(tagArgs, "orf"); |
2259 | 0 | if (argValue) |
2260 | 0 | orf = argValue; |
2261 | |
|
2262 | 0 | argValue = msLookupHashTable(tagArgs, "ph"); |
2263 | 0 | if (argValue) |
2264 | 0 | ph = argValue; |
2265 | 0 | argValue = msLookupHashTable(tagArgs, "pf"); |
2266 | 0 | if (argValue) |
2267 | 0 | pf = argValue; |
2268 | 0 | argValue = msLookupHashTable(tagArgs, "ps"); |
2269 | 0 | if (argValue) |
2270 | 0 | ps = argValue; |
2271 | |
|
2272 | 0 | argValue = msLookupHashTable(tagArgs, "sh"); |
2273 | 0 | if (argValue) |
2274 | 0 | sh = argValue; |
2275 | 0 | argValue = msLookupHashTable(tagArgs, "sf"); |
2276 | 0 | if (argValue) |
2277 | 0 | sf = argValue; |
2278 | |
|
2279 | | #ifdef USE_GEOS |
2280 | | argValue = msLookupHashTable(tagArgs, "buffer"); |
2281 | | if (argValue) { |
2282 | | buffer = atof(argValue); |
2283 | | if (strstr(argValue, "px")) |
2284 | | bufferUnits = MS_PIXELS; /* may support others at some point */ |
2285 | | } |
2286 | | #endif |
2287 | |
|
2288 | 0 | argValue = msLookupHashTable(tagArgs, "precision"); |
2289 | 0 | if (argValue) |
2290 | 0 | precision = atoi(argValue); |
2291 | |
|
2292 | 0 | argValue = msLookupHashTable(tagArgs, "scale"); |
2293 | 0 | if (argValue) { |
2294 | 0 | scale_x = atof(argValue); |
2295 | 0 | scale_y = scale_x; |
2296 | 0 | } |
2297 | |
|
2298 | 0 | argValue = msLookupHashTable(tagArgs, "scale_x"); |
2299 | 0 | if (argValue) |
2300 | 0 | scale_x = atof(argValue); |
2301 | |
|
2302 | 0 | argValue = msLookupHashTable(tagArgs, "scale_y"); |
2303 | 0 | if (argValue) |
2304 | 0 | scale_y = atof(argValue); |
2305 | |
|
2306 | 0 | argValue = msLookupHashTable(tagArgs, "centroid"); |
2307 | 0 | if (argValue) |
2308 | 0 | if (strcasecmp(argValue, "true") == 0) |
2309 | 0 | centroid = MS_TRUE; |
2310 | |
|
2311 | 0 | argValue = msLookupHashTable(tagArgs, "proj"); |
2312 | 0 | if (argValue) |
2313 | 0 | projectionString = argValue; |
2314 | 0 | } |
2315 | | |
2316 | | /* build the per point format strings (version 1 contains the coordinate |
2317 | | * separator, version 2 doesn't) */ |
2318 | 0 | const int pointFormatLength = |
2319 | 0 | strlen(xh) + strlen(xf) + strlen(yh) + strlen(yf) + strlen(cs) + 12 + 1; |
2320 | 0 | char *pointFormat1 = (char *)msSmallMalloc(pointFormatLength); |
2321 | 0 | snprintf(pointFormat1, pointFormatLength, "%s%%.%dlf%s%s%%.%dlf%s%s", xh, |
2322 | 0 | precision, xf, yh, precision, yf, cs); |
2323 | 0 | char *pointFormat2 = (char *)msSmallMalloc(pointFormatLength); |
2324 | 0 | snprintf(pointFormat2, pointFormatLength, "%s%%.%dlf%s%s%%.%dlf%s", xh, |
2325 | 0 | precision, xf, yh, precision, yf); |
2326 | | |
2327 | | /* make a copy of the original shape or compute a centroid if necessary */ |
2328 | 0 | msInitShape(&tShape); |
2329 | 0 | if (centroid == MS_TRUE) { |
2330 | 0 | pointObj p; |
2331 | |
|
2332 | 0 | p.x = (shape->bounds.minx + shape->bounds.maxx) / 2; |
2333 | 0 | p.y = (shape->bounds.miny + shape->bounds.maxy) / 2; |
2334 | |
|
2335 | 0 | tShape.type = MS_SHAPE_POINT; |
2336 | 0 | tShape.line = (lineObj *)msSmallMalloc(sizeof(lineObj)); |
2337 | 0 | tShape.numlines = 1; |
2338 | 0 | tShape.line[0].point = NULL; /* initialize the line */ |
2339 | 0 | tShape.line[0].numpoints = 0; |
2340 | |
|
2341 | 0 | msAddPointToLine(&(tShape.line[0]), &p); |
2342 | 0 | } |
2343 | | |
2344 | | #ifdef USE_GEOS |
2345 | | else if (buffer != 0 && bufferUnits != MS_PIXELS) { |
2346 | | shapeObj *bufferShape = NULL; |
2347 | | |
2348 | | bufferShape = msGEOSBuffer(shape, buffer); |
2349 | | if (!bufferShape) { |
2350 | | free(pointFormat1); |
2351 | | free(pointFormat2); |
2352 | | return (MS_FAILURE); /* buffer failed */ |
2353 | | } |
2354 | | msCopyShape(bufferShape, &tShape); |
2355 | | msFreeShape(bufferShape); |
2356 | | } |
2357 | | #endif |
2358 | 0 | else { |
2359 | 0 | status = msCopyShape(shape, &tShape); |
2360 | 0 | if (status != 0) { |
2361 | 0 | free(pointFormat1); |
2362 | 0 | free(pointFormat2); |
2363 | 0 | return (MS_FAILURE); /* copy failed */ |
2364 | 0 | } |
2365 | 0 | } |
2366 | | |
2367 | | /* no big deal to convert from file to image coordinates, but what are the |
2368 | | * image parameters */ |
2369 | 0 | if (projectionString && strcasecmp(projectionString, "image") == 0) { |
2370 | 0 | precision = 0; |
2371 | | |
2372 | | /* if necessary, project the shape to match the map */ |
2373 | 0 | if (msProjectionsDiffer(&(layer->projection), |
2374 | 0 | &(layer->map->projection))) { |
2375 | 0 | reprojectionObj *reprojector = |
2376 | 0 | msLayerGetReprojectorToMap(layer, layer->map); |
2377 | 0 | if (reprojector) { |
2378 | 0 | msProjectShapeEx(reprojector, &tShape); |
2379 | 0 | } |
2380 | 0 | } |
2381 | |
|
2382 | 0 | switch (tShape.type) { |
2383 | 0 | case (MS_SHAPE_POINT): |
2384 | | /* no clipping necessary */ |
2385 | 0 | break; |
2386 | 0 | case (MS_SHAPE_LINE): |
2387 | 0 | msClipPolylineRect(&tShape, layer->map->extent); |
2388 | 0 | break; |
2389 | 0 | case (MS_SHAPE_POLYGON): |
2390 | 0 | msClipPolygonRect(&tShape, layer->map->extent); |
2391 | 0 | break; |
2392 | 0 | default: |
2393 | | /* TO DO: need an error message here */ |
2394 | 0 | return (MS_FAILURE); |
2395 | 0 | break; |
2396 | 0 | } |
2397 | 0 | msTransformShapeToPixelRound(&tShape, layer->map->extent, |
2398 | 0 | layer->map->cellsize); |
2399 | |
|
2400 | | #ifdef USE_GEOS |
2401 | | if (buffer != 0 && bufferUnits == MS_PIXELS) { |
2402 | | shapeObj *bufferShape = NULL; |
2403 | | |
2404 | | bufferShape = msGEOSBuffer(&tShape, buffer); |
2405 | | if (!bufferShape) { |
2406 | | if (!msIsDegenerateShape( |
2407 | | &tShape)) /* If shape is degenerate this is expected. */ |
2408 | | return (MS_FAILURE); /* buffer failed */ |
2409 | | } else { |
2410 | | msFreeShape(&tShape); /* avoid memory leak */ |
2411 | | msCopyShape(bufferShape, &tShape); |
2412 | | msFreeShape(bufferShape); |
2413 | | } |
2414 | | } |
2415 | | #endif |
2416 | |
|
2417 | 0 | } else if (projectionString) { |
2418 | 0 | projectionObj projection; |
2419 | 0 | msInitProjection(&projection); |
2420 | 0 | msProjectionInheritContextFrom(&projection, &(layer->projection)); |
2421 | |
|
2422 | 0 | status = msLoadProjectionString(&projection, projectionString); |
2423 | 0 | if (status != MS_SUCCESS) |
2424 | 0 | return MS_FAILURE; |
2425 | | |
2426 | 0 | if (msProjectionsDiffer(&(layer->projection), &projection)) |
2427 | 0 | msProjectShape(&layer->projection, &projection, &tShape); |
2428 | 0 | } |
2429 | | |
2430 | | /* TODO: add thinning support here */ |
2431 | | |
2432 | | /* |
2433 | | ** build the coordinate string |
2434 | | */ |
2435 | | |
2436 | 0 | char *coords = NULL; |
2437 | 0 | if (strlen(sh) > 0) |
2438 | 0 | coords = msStringConcatenate(coords, sh); |
2439 | | |
2440 | | /* do we need to handle inner/outer rings */ |
2441 | 0 | if (tShape.type == MS_SHAPE_POLYGON && strlen(orh) > 0 && strlen(irh) > 0) { |
2442 | 0 | int *outers; |
2443 | 0 | int firstPart; /* to keep track of inserting part separators before each |
2444 | | part after the first */ |
2445 | 0 | outers = msGetOuterList(&tShape); |
2446 | 0 | firstPart = 1; |
2447 | | /* loop over rings looking for outers*/ |
2448 | 0 | for (i = 0; i < tShape.numlines; i++) { |
2449 | 0 | int *inners; |
2450 | 0 | if (outers[i]) { |
2451 | | /* this is an outer ring */ |
2452 | 0 | if ((!firstPart) && (strlen(ps) > 0)) |
2453 | 0 | coords = msStringConcatenate(coords, ps); |
2454 | 0 | firstPart = 0; |
2455 | 0 | if (strlen(ph) > 0) |
2456 | 0 | coords = msStringConcatenate(coords, ph); |
2457 | 0 | coords = msStringConcatenate(coords, orh); |
2458 | 0 | for (p = 0; p < tShape.line[i].numpoints - 1; p++) { |
2459 | 0 | snprintf(point, sizeof(point), pointFormat1, |
2460 | 0 | scale_x * tShape.line[i].point[p].x, |
2461 | 0 | scale_y * tShape.line[i].point[p].y); |
2462 | 0 | coords = msStringConcatenate(coords, point); |
2463 | 0 | } |
2464 | 0 | snprintf(point, sizeof(point), pointFormat2, |
2465 | 0 | scale_x * tShape.line[i].point[p].x, |
2466 | 0 | scale_y * tShape.line[i].point[p].y); |
2467 | 0 | coords = msStringConcatenate(coords, point); |
2468 | 0 | coords = msStringConcatenate(coords, orf); |
2469 | |
|
2470 | 0 | inners = msGetInnerList(&tShape, i, outers); |
2471 | | /* loop over rings looking for inners to this outer */ |
2472 | 0 | for (j = 0; j < tShape.numlines; j++) { |
2473 | 0 | if (inners[j]) { |
2474 | | /* j is an inner ring of i */ |
2475 | 0 | coords = msStringConcatenate(coords, irh); |
2476 | 0 | for (p = 0; p < tShape.line[j].numpoints - 1; p++) { |
2477 | 0 | snprintf(point, sizeof(point), pointFormat1, |
2478 | 0 | scale_x * tShape.line[j].point[p].x, |
2479 | 0 | scale_y * tShape.line[j].point[p].y); |
2480 | 0 | coords = msStringConcatenate(coords, point); |
2481 | 0 | } |
2482 | 0 | snprintf(point, sizeof(point), pointFormat2, |
2483 | 0 | scale_x * tShape.line[j].point[p].x, |
2484 | 0 | scale_y * tShape.line[j].point[p].y); |
2485 | 0 | coords = msStringConcatenate(coords, irf); |
2486 | 0 | } |
2487 | 0 | } |
2488 | 0 | free(inners); |
2489 | 0 | if (strlen(pf) > 0) |
2490 | 0 | coords = msStringConcatenate(coords, pf); |
2491 | 0 | } |
2492 | 0 | } /* end of loop over outer rings */ |
2493 | 0 | free(outers); |
2494 | 0 | } else { /* output without ring formatting */ |
2495 | |
|
2496 | 0 | for (i = 0; i < tShape.numlines; i++) { /* e.g. part */ |
2497 | | |
2498 | | /* skip degenerate parts, really should only happen with pixel output */ |
2499 | 0 | if ((tShape.type == MS_SHAPE_LINE && tShape.line[i].numpoints < 2) || |
2500 | 0 | (tShape.type == MS_SHAPE_POLYGON && tShape.line[i].numpoints < 3)) |
2501 | 0 | continue; |
2502 | | |
2503 | 0 | if (strlen(ph) > 0) |
2504 | 0 | coords = msStringConcatenate(coords, ph); |
2505 | |
|
2506 | 0 | for (p = 0; p < tShape.line[i].numpoints - 1; p++) { |
2507 | 0 | snprintf(point, sizeof(point), pointFormat1, |
2508 | 0 | scale_x * tShape.line[i].point[p].x, |
2509 | 0 | scale_y * tShape.line[i].point[p].y); |
2510 | 0 | coords = msStringConcatenate(coords, point); |
2511 | 0 | } |
2512 | 0 | snprintf(point, sizeof(point), pointFormat2, |
2513 | 0 | scale_x * tShape.line[i].point[p].x, |
2514 | 0 | scale_y * tShape.line[i].point[p].y); |
2515 | 0 | coords = msStringConcatenate(coords, point); |
2516 | |
|
2517 | 0 | if (strlen(pf) > 0) |
2518 | 0 | coords = msStringConcatenate(coords, pf); |
2519 | |
|
2520 | 0 | if ((i < tShape.numlines - 1) && (strlen(ps) > 0)) |
2521 | 0 | coords = msStringConcatenate(coords, ps); |
2522 | 0 | } |
2523 | 0 | } |
2524 | 0 | if (strlen(sf) > 0) |
2525 | 0 | coords = msStringConcatenate(coords, sf); |
2526 | |
|
2527 | 0 | msFreeShape(&tShape); |
2528 | | |
2529 | | /* find the end of the tag */ |
2530 | 0 | tagEnd = findTagEnd(tagStart); |
2531 | 0 | tagEnd++; |
2532 | | |
2533 | | /* build the complete tag so we can do substitution */ |
2534 | 0 | const int tagLength = tagEnd - tagStart; |
2535 | 0 | char *tag = (char *)msSmallMalloc(tagLength + 1); |
2536 | 0 | strlcpy(tag, tagStart, tagLength + 1); |
2537 | | |
2538 | | /* do the replacement */ |
2539 | 0 | *line = msReplaceSubstring(*line, tag, coords); |
2540 | | |
2541 | | /* clean up */ |
2542 | 0 | free(tag); |
2543 | 0 | msFreeHashTable(tagArgs); |
2544 | 0 | free(pointFormat1); |
2545 | 0 | free(pointFormat2); |
2546 | 0 | free(coords); |
2547 | |
|
2548 | 0 | if ((*line)[tagOffset] != '\0') |
2549 | 0 | tagStart = findTag(*line + tagOffset + 1, "shpxy"); |
2550 | 0 | else |
2551 | 0 | tagStart = NULL; |
2552 | 0 | } |
2553 | | |
2554 | 0 | return (MS_SUCCESS); |
2555 | 0 | } |
2556 | | |
2557 | | /*! |
2558 | | * this function process all metadata |
2559 | | * in pszInstr. ht mus contain all corresponding |
2560 | | * metadata value. |
2561 | | * |
2562 | | * this function return a modified pszInstr |
2563 | | */ |
2564 | 0 | int processMetadata(char **pszInstr, hashTableObj *ht) { |
2565 | | /* char *pszNextInstr = pszInstr; */ |
2566 | 0 | char *pszEnd; |
2567 | 0 | char *pszMetadataTag; |
2568 | 0 | const char *pszHashName; |
2569 | 0 | const char *pszHashValue; |
2570 | 0 | int nLength, nOffset; |
2571 | |
|
2572 | 0 | hashTableObj *metadataArgs = NULL; |
2573 | |
|
2574 | 0 | if (!*pszInstr) { |
2575 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "processMetadata()"); |
2576 | 0 | return MS_FAILURE; |
2577 | 0 | } |
2578 | | |
2579 | | /* set position to the beginning of metadata tag */ |
2580 | 0 | const char *pszStart = findTag(*pszInstr, "metadata"); |
2581 | |
|
2582 | 0 | while (pszStart) { |
2583 | | /* get metadata args */ |
2584 | 0 | if (getTagArgs("metadata", pszStart, &metadataArgs) != MS_SUCCESS) |
2585 | 0 | return MS_FAILURE; |
2586 | | |
2587 | 0 | pszHashName = msLookupHashTable(metadataArgs, "name"); |
2588 | 0 | pszHashValue = msLookupHashTable(ht, pszHashName); |
2589 | |
|
2590 | 0 | nOffset = pszStart - *pszInstr; |
2591 | |
|
2592 | 0 | if (pszHashName && pszHashValue) { |
2593 | | /* set position to the end of metadata start tag */ |
2594 | 0 | pszEnd = strchr(pszStart, ']'); |
2595 | 0 | pszEnd++; |
2596 | | |
2597 | | /* build the complete metadata tag ([metadata all_args]) */ |
2598 | | /* to replace it by the corresponding value from ht */ |
2599 | 0 | nLength = pszEnd - pszStart; |
2600 | 0 | pszMetadataTag = (char *)msSmallMalloc(nLength + 1); |
2601 | 0 | strlcpy(pszMetadataTag, pszStart, nLength + 1); |
2602 | |
|
2603 | 0 | *pszInstr = msReplaceSubstring(*pszInstr, pszMetadataTag, pszHashValue); |
2604 | |
|
2605 | 0 | free(pszMetadataTag); |
2606 | 0 | pszMetadataTag = NULL; |
2607 | 0 | } |
2608 | |
|
2609 | 0 | msFreeHashTable(metadataArgs); |
2610 | 0 | metadataArgs = NULL; |
2611 | | |
2612 | | /* set position to the beginning of the next metadata tag */ |
2613 | 0 | if ((*pszInstr)[nOffset] != '\0') |
2614 | 0 | pszStart = findTag(*pszInstr + nOffset + 1, "metadata"); |
2615 | 0 | else |
2616 | 0 | pszStart = NULL; |
2617 | 0 | } |
2618 | | |
2619 | 0 | return MS_SUCCESS; |
2620 | 0 | } |
2621 | | |
2622 | | /*! |
2623 | | * this function process all icon tag |
2624 | | * from pszInstr. |
2625 | | * |
2626 | | * This func return a modified pszInstr. |
2627 | | */ |
2628 | | int processIcon(mapObj *map, int nIdxLayer, int nIdxClass, char **pszInstr, |
2629 | 0 | char *pszPrefix) { |
2630 | 0 | int nWidth, nHeight, nLen; |
2631 | 0 | char szImgFname[1024], *pszImgTag; |
2632 | 0 | char szPath[MS_MAXPATHLEN]; |
2633 | 0 | hashTableObj *myHashTable = NULL; |
2634 | 0 | FILE *fIcon; |
2635 | |
|
2636 | 0 | if (!map || nIdxLayer > map->numlayers || nIdxLayer < 0) { |
2637 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "processIcon()"); |
2638 | 0 | return MS_FAILURE; |
2639 | 0 | } |
2640 | | |
2641 | | /* find the beginning of tag */ |
2642 | 0 | pszImgTag = strstr(*pszInstr, "[leg_icon"); |
2643 | |
|
2644 | 0 | while (pszImgTag) { |
2645 | 0 | int i; |
2646 | 0 | char szStyleCode[512] = ""; |
2647 | 0 | classObj *thisClass = NULL; |
2648 | | |
2649 | | /* It's okay to have no classes... we'll generate an empty icon in this case |
2650 | | */ |
2651 | 0 | if (nIdxClass >= 0 && nIdxClass < GET_LAYER(map, nIdxLayer)->numclasses) |
2652 | 0 | thisClass = GET_LAYER(map, nIdxLayer)->class[nIdxClass]; |
2653 | |
|
2654 | 0 | if (getTagArgs("leg_icon", pszImgTag, &myHashTable) != MS_SUCCESS) |
2655 | 0 | return MS_FAILURE; |
2656 | | |
2657 | | /* if no specified width or height, set them to map default */ |
2658 | 0 | if (!msLookupHashTable(myHashTable, "width") || |
2659 | 0 | !msLookupHashTable(myHashTable, "height")) { |
2660 | 0 | nWidth = map->legend.keysizex; |
2661 | 0 | nHeight = map->legend.keysizey; |
2662 | 0 | } else { |
2663 | 0 | nWidth = atoi(msLookupHashTable(myHashTable, "width")); |
2664 | 0 | nHeight = atoi(msLookupHashTable(myHashTable, "height")); |
2665 | 0 | } |
2666 | | |
2667 | | /* Create a unique and predictable filename to cache the legend icons. |
2668 | | * Include some key parameters from the first 2 styles |
2669 | | */ |
2670 | 0 | for (i = 0; i < 2 && thisClass && i < thisClass->numstyles; i++) { |
2671 | 0 | styleObj *style; |
2672 | 0 | char *pszSymbolNameHash = NULL; |
2673 | 0 | style = thisClass->styles[i]; |
2674 | 0 | if (style->symbolname) |
2675 | 0 | pszSymbolNameHash = msHashString(style->symbolname); |
2676 | |
|
2677 | 0 | snprintf(szStyleCode + strlen(szStyleCode), 255, "s%d_%x_%x_%d_%s_%g", i, |
2678 | 0 | MS_COLOR_GETRGB(style->color), |
2679 | 0 | MS_COLOR_GETRGB(style->outlinecolor), style->symbol, |
2680 | 0 | pszSymbolNameHash ? pszSymbolNameHash : "", style->angle); |
2681 | 0 | msFree(pszSymbolNameHash); |
2682 | 0 | } |
2683 | |
|
2684 | 0 | snprintf(szImgFname, sizeof(szImgFname), "%s_%d_%d_%d_%d_%s.%s%c", |
2685 | 0 | pszPrefix, nIdxLayer, nIdxClass, nWidth, nHeight, szStyleCode, |
2686 | 0 | MS_IMAGE_EXTENSION(map->outputformat), '\0'); |
2687 | |
|
2688 | 0 | char *pszFullImgFname = msStrdup( |
2689 | 0 | msBuildPath3(szPath, map->mappath, map->web.imagepath, szImgFname)); |
2690 | | |
2691 | | /* check if icon already exist in cache */ |
2692 | 0 | if ((fIcon = fopen(pszFullImgFname, "r")) != NULL) { |
2693 | | /* File already exists. No need to generate it again */ |
2694 | 0 | fclose(fIcon); |
2695 | 0 | } else { |
2696 | | /* Create an image corresponding to the current class */ |
2697 | 0 | imageObj *img = NULL; |
2698 | |
|
2699 | 0 | if (thisClass == NULL) { |
2700 | | /* Nonexistent class. Create an empty image */ |
2701 | 0 | img = msCreateLegendIcon(map, NULL, NULL, nWidth, nHeight, MS_TRUE); |
2702 | 0 | } else { |
2703 | 0 | img = msCreateLegendIcon(map, GET_LAYER(map, nIdxLayer), thisClass, |
2704 | 0 | nWidth, nHeight, MS_TRUE); |
2705 | 0 | } |
2706 | |
|
2707 | 0 | if (!img) { |
2708 | 0 | if (myHashTable) |
2709 | 0 | msFreeHashTable(myHashTable); |
2710 | |
|
2711 | 0 | msSetError(MS_IMGERR, "Error while creating image.", "processIcon()"); |
2712 | 0 | msFree(pszFullImgFname); |
2713 | 0 | return MS_FAILURE; |
2714 | 0 | } |
2715 | | |
2716 | | /* save it with a unique file name */ |
2717 | 0 | if (msSaveImage(map, img, pszFullImgFname) != MS_SUCCESS) { |
2718 | 0 | if (myHashTable) |
2719 | 0 | msFreeHashTable(myHashTable); |
2720 | |
|
2721 | 0 | msFreeImage(img); |
2722 | |
|
2723 | 0 | msSetError(MS_IOERR, "Error saving GD image to disk (%s).", |
2724 | 0 | "processIcon()", pszFullImgFname); |
2725 | 0 | msFree(pszFullImgFname); |
2726 | 0 | return MS_FAILURE; |
2727 | 0 | } |
2728 | | |
2729 | 0 | msFreeImage(img); |
2730 | 0 | } |
2731 | | |
2732 | 0 | msFree(pszFullImgFname); |
2733 | |
|
2734 | 0 | nLen = (strchr(pszImgTag, ']') + 1) - pszImgTag; |
2735 | |
|
2736 | 0 | if (nLen > 0) { |
2737 | 0 | char *pszTag; |
2738 | | |
2739 | | /* rebuild image tag ([leg_class_img all_args]) */ |
2740 | | /* to replace it by the image url */ |
2741 | 0 | pszTag = (char *)msSmallMalloc(nLen + 1); |
2742 | 0 | strlcpy(pszTag, pszImgTag, nLen + 1); |
2743 | |
|
2744 | 0 | char *pszFullImgUrlFname = (char *)msSmallMalloc( |
2745 | 0 | strlen(map->web.imageurl) + strlen(szImgFname) + 1); |
2746 | 0 | strcpy(pszFullImgUrlFname, map->web.imageurl); |
2747 | 0 | strcat(pszFullImgUrlFname, szImgFname); |
2748 | |
|
2749 | 0 | *pszInstr = msReplaceSubstring(*pszInstr, pszTag, pszFullImgUrlFname); |
2750 | |
|
2751 | 0 | msFree(pszFullImgUrlFname); |
2752 | 0 | msFree(pszTag); |
2753 | | |
2754 | | /* find the beginning of tag */ |
2755 | 0 | pszImgTag = strstr(*pszInstr, "[leg_icon"); |
2756 | 0 | } else { |
2757 | 0 | pszImgTag = NULL; |
2758 | 0 | } |
2759 | |
|
2760 | 0 | if (myHashTable) { |
2761 | 0 | msFreeHashTable(myHashTable); |
2762 | 0 | myHashTable = NULL; |
2763 | 0 | } |
2764 | 0 | } |
2765 | | |
2766 | 0 | return MS_SUCCESS; |
2767 | 0 | } |
2768 | | |
2769 | | /*! |
2770 | | * Replace all tags from group template |
2771 | | * with correct value. |
2772 | | * |
2773 | | * this function return a buffer containing |
2774 | | * the template with correct values. |
2775 | | * |
2776 | | * buffer must be freed by caller. |
2777 | | */ |
2778 | | int generateGroupTemplate(char *pszGroupTemplate, mapObj *map, |
2779 | | char *pszGroupName, hashTableObj *oGroupArgs, |
2780 | 0 | char **pszTemp, char *pszPrefix) { |
2781 | 0 | hashTableObj *myHashTable; |
2782 | 0 | char pszStatus[3]; |
2783 | 0 | char *pszClassImg; |
2784 | 0 | const char *pszOptFlag = NULL; |
2785 | 0 | int i, j; |
2786 | 0 | int nOptFlag = 15; |
2787 | 0 | int bShowGroup; |
2788 | |
|
2789 | 0 | *pszTemp = NULL; |
2790 | |
|
2791 | 0 | if (!pszGroupName || !pszGroupTemplate) { |
2792 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "generateGroupTemplate()"); |
2793 | 0 | return MS_FAILURE; |
2794 | 0 | } |
2795 | | |
2796 | | /* |
2797 | | * Get the opt_flag is any. |
2798 | | */ |
2799 | 0 | if (oGroupArgs) |
2800 | 0 | pszOptFlag = msLookupHashTable(oGroupArgs, "opt_flag"); |
2801 | |
|
2802 | 0 | if (pszOptFlag) |
2803 | 0 | nOptFlag = atoi(pszOptFlag); |
2804 | | |
2805 | | /* |
2806 | | * Check all layers, if one in the group |
2807 | | * should be visible, print the group. |
2808 | | * (Check for opt_flag) |
2809 | | */ |
2810 | 0 | bShowGroup = 0; |
2811 | 0 | for (j = 0; j < map->numlayers; j++) { |
2812 | 0 | if (GET_LAYER(map, map->layerorder[j])->group && |
2813 | 0 | strcmp(GET_LAYER(map, map->layerorder[j])->group, pszGroupName) == 0) { |
2814 | | /* don't display layer is off. */ |
2815 | 0 | if ((nOptFlag & 2) == 0 && |
2816 | 0 | GET_LAYER(map, map->layerorder[j])->status == MS_OFF) |
2817 | 0 | bShowGroup = 0; |
2818 | 0 | else |
2819 | 0 | bShowGroup = 1; |
2820 | | |
2821 | | /* don't display layer is query. */ |
2822 | 0 | if ((nOptFlag & 4) == 0 && |
2823 | 0 | GET_LAYER(map, map->layerorder[j])->type == MS_LAYER_QUERY) |
2824 | 0 | bShowGroup = 0; |
2825 | | |
2826 | | /* don't display layer if out of scale. */ |
2827 | 0 | if ((nOptFlag & 1) == 0) { |
2828 | 0 | if (map->scaledenom > 0) { |
2829 | 0 | if ((GET_LAYER(map, map->layerorder[j])->maxscaledenom > 0) && |
2830 | 0 | (map->scaledenom > |
2831 | 0 | GET_LAYER(map, map->layerorder[j])->maxscaledenom)) |
2832 | 0 | bShowGroup = 0; |
2833 | 0 | if ((GET_LAYER(map, map->layerorder[j])->minscaledenom > 0) && |
2834 | 0 | (map->scaledenom <= |
2835 | 0 | GET_LAYER(map, map->layerorder[j])->minscaledenom)) |
2836 | 0 | bShowGroup = 0; |
2837 | 0 | } |
2838 | 0 | } |
2839 | | |
2840 | | /* The group contains one visible layer */ |
2841 | | /* Draw the group */ |
2842 | 0 | if (bShowGroup) |
2843 | 0 | break; |
2844 | 0 | } |
2845 | 0 | } |
2846 | |
|
2847 | 0 | if (!bShowGroup) |
2848 | 0 | return MS_SUCCESS; |
2849 | | |
2850 | | /* |
2851 | | * Work from a copy |
2852 | | */ |
2853 | 0 | *pszTemp = (char *)msSmallMalloc(strlen(pszGroupTemplate) + 1); |
2854 | 0 | strcpy(*pszTemp, pszGroupTemplate); |
2855 | | |
2856 | | /* |
2857 | | * Change group tags |
2858 | | */ |
2859 | 0 | *pszTemp = msReplaceSubstring(*pszTemp, "[leg_group_name]", pszGroupName); |
2860 | | |
2861 | | /* |
2862 | | * Create a hash table that contain info |
2863 | | * on current layer |
2864 | | */ |
2865 | 0 | myHashTable = msCreateHashTable(); |
2866 | | |
2867 | | /* |
2868 | | * Check for the first layer |
2869 | | * that belong to this group. |
2870 | | * Get his status and check for if. |
2871 | | */ |
2872 | 0 | for (j = 0; j < map->numlayers; j++) { |
2873 | 0 | if (GET_LAYER(map, map->layerorder[j])->group && |
2874 | 0 | strcmp(GET_LAYER(map, map->layerorder[j])->group, pszGroupName) == 0) { |
2875 | 0 | snprintf(pszStatus, sizeof(pszStatus), "%d", |
2876 | 0 | GET_LAYER(map, map->layerorder[j])->status); |
2877 | 0 | msInsertHashTable(myHashTable, "layer_status", pszStatus); |
2878 | 0 | msInsertHashTable( |
2879 | 0 | myHashTable, "layer_visible", |
2880 | 0 | msLayerIsVisible(map, GET_LAYER(map, map->layerorder[j])) ? "1" |
2881 | 0 | : "0"); |
2882 | 0 | msInsertHashTable( |
2883 | 0 | myHashTable, "layer_queryable", |
2884 | 0 | msIsLayerQueryable(GET_LAYER(map, map->layerorder[j])) ? "1" : "0"); |
2885 | 0 | msInsertHashTable(myHashTable, "group_name", pszGroupName); |
2886 | |
|
2887 | 0 | if (processIfTag(pszTemp, myHashTable, MS_FALSE) != MS_SUCCESS) |
2888 | 0 | return MS_FAILURE; |
2889 | | |
2890 | 0 | if (processIfTag(pszTemp, &(GET_LAYER(map, map->layerorder[j])->metadata), |
2891 | 0 | MS_FALSE) != MS_SUCCESS) |
2892 | 0 | return MS_FAILURE; |
2893 | | |
2894 | 0 | if (processMetadata(pszTemp, |
2895 | 0 | &GET_LAYER(map, map->layerorder[j])->metadata) != |
2896 | 0 | MS_SUCCESS) |
2897 | 0 | return MS_FAILURE; |
2898 | | |
2899 | 0 | break; |
2900 | 0 | } |
2901 | 0 | } |
2902 | | |
2903 | 0 | msFreeHashTable(myHashTable); |
2904 | | |
2905 | | /* |
2906 | | * Process all metadata tags |
2907 | | * only web object is accessible |
2908 | | */ |
2909 | 0 | if (processMetadata(pszTemp, &(map->web.metadata)) != MS_SUCCESS) |
2910 | 0 | return MS_FAILURE; |
2911 | | |
2912 | | /* |
2913 | | * check for if tag |
2914 | | */ |
2915 | 0 | if (processIfTag(pszTemp, &(map->web.metadata), MS_TRUE) != MS_SUCCESS) |
2916 | 0 | return MS_FAILURE; |
2917 | | |
2918 | | /* |
2919 | | * Check if leg_icon tag exist |
2920 | | * if so display the first layer first class icon |
2921 | | */ |
2922 | 0 | pszClassImg = strstr(*pszTemp, "[leg_icon"); |
2923 | 0 | if (pszClassImg) { |
2924 | | /* find first layer of this group */ |
2925 | 0 | for (i = 0; i < map->numlayers; i++) |
2926 | 0 | if (GET_LAYER(map, map->layerorder[i])->group && |
2927 | 0 | strcmp(GET_LAYER(map, map->layerorder[i])->group, pszGroupName) == 0) |
2928 | 0 | processIcon(map, map->layerorder[i], 0, pszTemp, pszPrefix); |
2929 | 0 | } |
2930 | |
|
2931 | 0 | return MS_SUCCESS; |
2932 | 0 | } |
2933 | | |
2934 | | /*! |
2935 | | * Replace all tags from layer template |
2936 | | * with correct value. |
2937 | | * |
2938 | | * this function return a buffer containing |
2939 | | * the template with correct values. |
2940 | | * |
2941 | | * buffer must be freed by caller. |
2942 | | */ |
2943 | | int generateLayerTemplate(char *pszLayerTemplate, mapObj *map, int nIdxLayer, |
2944 | | hashTableObj *oLayerArgs, char **pszTemp, |
2945 | 0 | char *pszPrefix) { |
2946 | 0 | hashTableObj *myHashTable; |
2947 | 0 | char szStatus[10]; |
2948 | 0 | char szType[10]; |
2949 | |
|
2950 | 0 | int nOptFlag = 0; |
2951 | 0 | const char *pszOptFlag = NULL; |
2952 | 0 | char *pszClassImg; |
2953 | |
|
2954 | 0 | char |
2955 | 0 | szTmpstr[128]; /* easily big enough for the couple of instances we need */ |
2956 | |
|
2957 | 0 | *pszTemp = NULL; |
2958 | |
|
2959 | 0 | if (!pszLayerTemplate || !map || nIdxLayer > map->numlayers || |
2960 | 0 | nIdxLayer < 0) { |
2961 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "generateLayerTemplate()"); |
2962 | 0 | return MS_FAILURE; |
2963 | 0 | } |
2964 | | |
2965 | 0 | if (oLayerArgs) |
2966 | 0 | pszOptFlag = msLookupHashTable(oLayerArgs, "opt_flag"); |
2967 | |
|
2968 | 0 | if (pszOptFlag) |
2969 | 0 | nOptFlag = atoi(pszOptFlag); |
2970 | | |
2971 | | /* don't display deleted layers */ |
2972 | 0 | if (GET_LAYER(map, nIdxLayer)->status == MS_DELETE) |
2973 | 0 | return MS_SUCCESS; |
2974 | | |
2975 | | /* don't display layer is off. */ |
2976 | | /* check this if Opt flag is not set */ |
2977 | 0 | if ((nOptFlag & 2) == 0 && GET_LAYER(map, nIdxLayer)->status == MS_OFF) |
2978 | 0 | return MS_SUCCESS; |
2979 | | |
2980 | | /* don't display layer is query. */ |
2981 | | /* check this if Opt flag is not set */ |
2982 | 0 | if ((nOptFlag & 4) == 0 && GET_LAYER(map, nIdxLayer)->type == MS_LAYER_QUERY) |
2983 | 0 | return MS_SUCCESS; |
2984 | | |
2985 | | /* don't display layer if out of scale. */ |
2986 | | /* check this if Opt flag is not set */ |
2987 | 0 | if ((nOptFlag & 1) == 0) { |
2988 | 0 | if (map->scaledenom > 0) { |
2989 | 0 | if ((GET_LAYER(map, nIdxLayer)->maxscaledenom > 0) && |
2990 | 0 | (map->scaledenom > GET_LAYER(map, nIdxLayer)->maxscaledenom)) |
2991 | 0 | return MS_SUCCESS; |
2992 | 0 | if ((GET_LAYER(map, nIdxLayer)->minscaledenom > 0) && |
2993 | 0 | (map->scaledenom <= GET_LAYER(map, nIdxLayer)->minscaledenom)) |
2994 | 0 | return MS_SUCCESS; |
2995 | 0 | } |
2996 | 0 | } |
2997 | | |
2998 | | /* |
2999 | | * Work from a copy |
3000 | | */ |
3001 | 0 | *pszTemp = msStrdup(pszLayerTemplate); |
3002 | | |
3003 | | /* |
3004 | | * Change layer tags |
3005 | | */ |
3006 | 0 | *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_name]", |
3007 | 0 | GET_LAYER(map, nIdxLayer)->name); |
3008 | 0 | *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_group]", |
3009 | 0 | GET_LAYER(map, nIdxLayer)->group); |
3010 | |
|
3011 | 0 | snprintf(szTmpstr, sizeof(szTmpstr), "%d", nIdxLayer); |
3012 | 0 | *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_index]", szTmpstr); |
3013 | |
|
3014 | 0 | snprintf(szTmpstr, sizeof(szTmpstr), "%g", |
3015 | 0 | GET_LAYER(map, nIdxLayer)->minscaledenom); |
3016 | 0 | *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_minscale]", szTmpstr); |
3017 | 0 | *pszTemp = |
3018 | 0 | msReplaceSubstring(*pszTemp, "[leg_layer_minscaledenom]", szTmpstr); |
3019 | 0 | snprintf(szTmpstr, sizeof(szTmpstr), "%g", |
3020 | 0 | GET_LAYER(map, nIdxLayer)->maxscaledenom); |
3021 | 0 | *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_maxscale]", szTmpstr); |
3022 | 0 | *pszTemp = |
3023 | 0 | msReplaceSubstring(*pszTemp, "[leg_layer_maxscaledenom]", szTmpstr); |
3024 | | |
3025 | | /* |
3026 | | * Create a hash table that contain info |
3027 | | * on current layer |
3028 | | */ |
3029 | 0 | myHashTable = msCreateHashTable(); |
3030 | | |
3031 | | /* |
3032 | | * for now, only status and type is required by template |
3033 | | */ |
3034 | 0 | snprintf(szStatus, sizeof(szStatus), "%d", GET_LAYER(map, nIdxLayer)->status); |
3035 | 0 | msInsertHashTable(myHashTable, "layer_status", szStatus); |
3036 | |
|
3037 | 0 | snprintf(szType, sizeof(szType), "%d", GET_LAYER(map, nIdxLayer)->type); |
3038 | 0 | msInsertHashTable(myHashTable, "layer_type", szType); |
3039 | |
|
3040 | 0 | msInsertHashTable( |
3041 | 0 | myHashTable, "layer_name", |
3042 | 0 | (GET_LAYER(map, nIdxLayer)->name) ? GET_LAYER(map, nIdxLayer)->name : ""); |
3043 | 0 | msInsertHashTable(myHashTable, "layer_group", |
3044 | 0 | (GET_LAYER(map, nIdxLayer)->group) |
3045 | 0 | ? GET_LAYER(map, nIdxLayer)->group |
3046 | 0 | : ""); |
3047 | 0 | msInsertHashTable(myHashTable, "layer_visible", |
3048 | 0 | msLayerIsVisible(map, GET_LAYER(map, nIdxLayer)) ? "1" |
3049 | 0 | : "0"); |
3050 | 0 | msInsertHashTable(myHashTable, "layer_queryable", |
3051 | 0 | msIsLayerQueryable(GET_LAYER(map, nIdxLayer)) ? "1" : "0"); |
3052 | |
|
3053 | 0 | if (processIfTag(pszTemp, myHashTable, MS_FALSE) != MS_SUCCESS) |
3054 | 0 | return MS_FAILURE; |
3055 | | |
3056 | 0 | if (processIfTag(pszTemp, &(GET_LAYER(map, nIdxLayer)->metadata), MS_FALSE) != |
3057 | 0 | MS_SUCCESS) |
3058 | 0 | return MS_FAILURE; |
3059 | | |
3060 | 0 | if (processIfTag(pszTemp, &(map->web.metadata), MS_TRUE) != MS_SUCCESS) |
3061 | 0 | return MS_FAILURE; |
3062 | | |
3063 | 0 | msFreeHashTable(myHashTable); |
3064 | | |
3065 | | /* |
3066 | | * Check if leg_icon tag exist |
3067 | | * if so display the first class icon |
3068 | | */ |
3069 | 0 | pszClassImg = strstr(*pszTemp, "[leg_icon"); |
3070 | 0 | if (pszClassImg) { |
3071 | 0 | processIcon(map, nIdxLayer, 0, pszTemp, pszPrefix); |
3072 | 0 | } |
3073 | | |
3074 | | /* process all metadata tags |
3075 | | * only current layer and web object |
3076 | | * metadata are accessible |
3077 | | */ |
3078 | 0 | if (processMetadata(pszTemp, &GET_LAYER(map, nIdxLayer)->metadata) != |
3079 | 0 | MS_SUCCESS) |
3080 | 0 | return MS_FAILURE; |
3081 | | |
3082 | 0 | if (processMetadata(pszTemp, &(map->web.metadata)) != MS_SUCCESS) |
3083 | 0 | return MS_FAILURE; |
3084 | | |
3085 | 0 | return MS_SUCCESS; |
3086 | 0 | } |
3087 | | |
3088 | | /*! |
3089 | | * Replace all tags from class template |
3090 | | * with correct value. |
3091 | | * |
3092 | | * this function return a buffer containing |
3093 | | * the template with correct values. |
3094 | | * |
3095 | | * buffer must be freed by caller. |
3096 | | */ |
3097 | | int generateClassTemplate(char *pszClassTemplate, mapObj *map, int nIdxLayer, |
3098 | | int nIdxClass, hashTableObj *oClassArgs, |
3099 | 0 | char **pszTemp, char *pszPrefix) { |
3100 | 0 | hashTableObj *myHashTable; |
3101 | 0 | char szStatus[10]; |
3102 | 0 | char szType[10]; |
3103 | |
|
3104 | 0 | char *pszClassImg; |
3105 | 0 | int nOptFlag = 0; |
3106 | 0 | const char *pszOptFlag = NULL; |
3107 | |
|
3108 | 0 | char |
3109 | 0 | szTmpstr[128]; /* easily big enough for the couple of instances we need */ |
3110 | |
|
3111 | 0 | *pszTemp = NULL; |
3112 | |
|
3113 | 0 | if (!pszClassTemplate || !map || nIdxLayer > map->numlayers || |
3114 | 0 | nIdxLayer < 0 || nIdxClass > GET_LAYER(map, nIdxLayer)->numclasses || |
3115 | 0 | nIdxClass < 0) { |
3116 | |
|
3117 | 0 | msSetError(MS_WEBERR, "Invalid pointer.", "generateClassTemplate()"); |
3118 | 0 | return MS_FAILURE; |
3119 | 0 | } |
3120 | | |
3121 | 0 | if (oClassArgs) |
3122 | 0 | pszOptFlag = msLookupHashTable(oClassArgs, "Opt_flag"); |
3123 | |
|
3124 | 0 | if (pszOptFlag) |
3125 | 0 | nOptFlag = atoi(pszOptFlag); |
3126 | | |
3127 | | /* don't display deleted layers */ |
3128 | 0 | if (GET_LAYER(map, nIdxLayer)->status == MS_DELETE) |
3129 | 0 | return MS_SUCCESS; |
3130 | | |
3131 | | /* don't display class if layer is off. */ |
3132 | | /* check this if Opt flag is not set */ |
3133 | 0 | if ((nOptFlag & 2) == 0 && GET_LAYER(map, nIdxLayer)->status == MS_OFF) |
3134 | 0 | return MS_SUCCESS; |
3135 | | |
3136 | | /* don't display class if layer is query. */ |
3137 | | /* check this if Opt flag is not set */ |
3138 | 0 | if ((nOptFlag & 4) == 0 && GET_LAYER(map, nIdxLayer)->type == MS_LAYER_QUERY) |
3139 | 0 | return MS_SUCCESS; |
3140 | | |
3141 | | /* don't display layer if out of scale. */ |
3142 | | /* check this if Opt flag is not set */ |
3143 | 0 | if ((nOptFlag & 1) == 0) { |
3144 | 0 | if (map->scaledenom > 0) { |
3145 | 0 | if ((GET_LAYER(map, nIdxLayer)->maxscaledenom > 0) && |
3146 | 0 | (map->scaledenom > GET_LAYER(map, nIdxLayer)->maxscaledenom)) |
3147 | 0 | return MS_SUCCESS; |
3148 | 0 | if ((GET_LAYER(map, nIdxLayer)->minscaledenom > 0) && |
3149 | 0 | (map->scaledenom <= GET_LAYER(map, nIdxLayer)->minscaledenom)) |
3150 | 0 | return MS_SUCCESS; |
3151 | 0 | } |
3152 | 0 | } |
3153 | | |
3154 | | /* |
3155 | | * Work from a copy |
3156 | | */ |
3157 | 0 | *pszTemp = (char *)msSmallMalloc(strlen(pszClassTemplate) + 1); |
3158 | 0 | strcpy(*pszTemp, pszClassTemplate); |
3159 | | |
3160 | | /* |
3161 | | * Change class tags |
3162 | | */ |
3163 | 0 | *pszTemp = |
3164 | 0 | msReplaceSubstring(*pszTemp, "[leg_class_name]", |
3165 | 0 | GET_LAYER(map, nIdxLayer)->class[nIdxClass] -> name); |
3166 | 0 | *pszTemp = |
3167 | 0 | msReplaceSubstring(*pszTemp, "[leg_class_title]", |
3168 | 0 | GET_LAYER(map, nIdxLayer)->class[nIdxClass] -> title); |
3169 | 0 | *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_name]", |
3170 | 0 | GET_LAYER(map, nIdxLayer)->name); |
3171 | |
|
3172 | 0 | snprintf(szTmpstr, sizeof(szTmpstr), "%d", nIdxClass); |
3173 | 0 | *pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_index]", szTmpstr); |
3174 | |
|
3175 | 0 | snprintf(szTmpstr, sizeof(szTmpstr), "%g", |
3176 | 0 | GET_LAYER(map, nIdxLayer)->class[nIdxClass] -> minscaledenom); |
3177 | 0 | *pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_minscale]", szTmpstr); |
3178 | 0 | *pszTemp = |
3179 | 0 | msReplaceSubstring(*pszTemp, "[leg_class_minscaledenom]", szTmpstr); |
3180 | 0 | snprintf(szTmpstr, sizeof(szTmpstr), "%g", |
3181 | 0 | GET_LAYER(map, nIdxLayer)->class[nIdxClass] -> maxscaledenom); |
3182 | 0 | *pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_maxscale]", szTmpstr); |
3183 | 0 | *pszTemp = |
3184 | 0 | msReplaceSubstring(*pszTemp, "[leg_class_maxscaledenom]", szTmpstr); |
3185 | | |
3186 | | /* |
3187 | | * Create a hash table that contain info |
3188 | | * on current layer |
3189 | | */ |
3190 | 0 | myHashTable = msCreateHashTable(); |
3191 | | |
3192 | | /* |
3193 | | * for now, only status, type, name and group are required by template |
3194 | | */ |
3195 | 0 | snprintf(szStatus, sizeof(szStatus), "%d", GET_LAYER(map, nIdxLayer)->status); |
3196 | 0 | msInsertHashTable(myHashTable, "layer_status", szStatus); |
3197 | |
|
3198 | 0 | snprintf(szType, sizeof(szType), "%d", GET_LAYER(map, nIdxLayer)->type); |
3199 | 0 | msInsertHashTable(myHashTable, "layer_type", szType); |
3200 | |
|
3201 | 0 | msInsertHashTable( |
3202 | 0 | myHashTable, "layer_name", |
3203 | 0 | (GET_LAYER(map, nIdxLayer)->name) ? GET_LAYER(map, nIdxLayer)->name : ""); |
3204 | 0 | msInsertHashTable(myHashTable, "layer_group", |
3205 | 0 | (GET_LAYER(map, nIdxLayer)->group) |
3206 | 0 | ? GET_LAYER(map, nIdxLayer)->group |
3207 | 0 | : ""); |
3208 | 0 | msInsertHashTable(myHashTable, "layer_visible", |
3209 | 0 | msLayerIsVisible(map, GET_LAYER(map, nIdxLayer)) ? "1" |
3210 | 0 | : "0"); |
3211 | 0 | msInsertHashTable(myHashTable, "layer_queryable", |
3212 | 0 | msIsLayerQueryable(GET_LAYER(map, nIdxLayer)) ? "1" : "0"); |
3213 | 0 | msInsertHashTable(myHashTable, "class_name", |
3214 | 0 | (GET_LAYER(map, nIdxLayer)->class[nIdxClass] -> name) |
3215 | 0 | ? GET_LAYER(map, nIdxLayer)->class[nIdxClass] -> name |
3216 | 0 | : ""); |
3217 | |
|
3218 | 0 | if (processIfTag(pszTemp, myHashTable, MS_FALSE) != MS_SUCCESS) |
3219 | 0 | return MS_FAILURE; |
3220 | | |
3221 | 0 | if (processIfTag(pszTemp, &(GET_LAYER(map, nIdxLayer)->metadata), MS_FALSE) != |
3222 | 0 | MS_SUCCESS) |
3223 | 0 | return MS_FAILURE; |
3224 | | |
3225 | 0 | if (processIfTag(pszTemp, &(map->web.metadata), MS_TRUE) != MS_SUCCESS) |
3226 | 0 | return MS_FAILURE; |
3227 | | |
3228 | 0 | msFreeHashTable(myHashTable); |
3229 | | |
3230 | | /* |
3231 | | * Check if leg_icon tag exist |
3232 | | */ |
3233 | 0 | pszClassImg = strstr(*pszTemp, "[leg_icon"); |
3234 | 0 | if (pszClassImg) { |
3235 | 0 | processIcon(map, nIdxLayer, nIdxClass, pszTemp, pszPrefix); |
3236 | 0 | } |
3237 | | |
3238 | | /* process all metadata tags |
3239 | | * only current layer and web object |
3240 | | * metadata are accessible |
3241 | | */ |
3242 | 0 | if (processMetadata(pszTemp, &GET_LAYER(map, nIdxLayer)->metadata) != |
3243 | 0 | MS_SUCCESS) |
3244 | 0 | return MS_FAILURE; |
3245 | | |
3246 | 0 | if (processMetadata(pszTemp, &(map->web.metadata)) != MS_SUCCESS) |
3247 | 0 | return MS_FAILURE; |
3248 | | |
3249 | 0 | return MS_SUCCESS; |
3250 | 0 | } |
3251 | | |
3252 | 0 | char *generateLegendTemplate(mapservObj *mapserv) { |
3253 | 0 | FILE *stream; |
3254 | 0 | char *file = NULL; |
3255 | 0 | int length; |
3256 | 0 | char *pszResult = NULL; |
3257 | 0 | char *legGroupHtml = NULL; |
3258 | 0 | char *legLayerHtml = NULL; |
3259 | 0 | char *legClassHtml = NULL; |
3260 | 0 | char *legLayerHtmlCopy = NULL; |
3261 | 0 | char *legClassHtmlCopy = NULL; |
3262 | 0 | char *legGroupHtmlCopy = NULL; |
3263 | |
|
3264 | 0 | char *legHeaderHtml = NULL; |
3265 | 0 | char *legFooterHtml = NULL; |
3266 | |
|
3267 | 0 | char *pszPrefix = NULL; |
3268 | 0 | char *pszMapFname = NULL; |
3269 | |
|
3270 | 0 | struct stat tmpStat; |
3271 | |
|
3272 | 0 | const char *pszOrderMetadata = NULL; |
3273 | 0 | const char *pszOrder = NULL; |
3274 | |
|
3275 | 0 | int i, j, k; |
3276 | 0 | char **papszGroups = NULL; |
3277 | 0 | int nGroupNames = 0; |
3278 | |
|
3279 | 0 | const char *pszOrderValue; |
3280 | |
|
3281 | 0 | hashTableObj *groupArgs = NULL; |
3282 | 0 | hashTableObj *layerArgs = NULL; |
3283 | 0 | hashTableObj *classArgs = NULL; |
3284 | |
|
3285 | 0 | ms_regex_t re; /* compiled regular expression to be matched */ |
3286 | |
|
3287 | 0 | int *panCurrentDrawingOrder = NULL; |
3288 | 0 | char szPath[MS_MAXPATHLEN]; |
3289 | |
|
3290 | 0 | if (ms_regcomp(&re, MS_TEMPLATE_EXPR, |
3291 | 0 | MS_REG_EXTENDED | MS_REG_NOSUB | MS_REG_ICASE) != 0) { |
3292 | 0 | msSetError(MS_IOERR, "Error regcomp.", "generateLegendTemplate()"); |
3293 | 0 | return NULL; |
3294 | 0 | } |
3295 | | |
3296 | 0 | if (ms_regexec(&re, mapserv->map->legend.template, 0, NULL, 0) != |
3297 | 0 | 0) { /* no match */ |
3298 | 0 | msSetError(MS_IOERR, "Invalid template file name.", |
3299 | 0 | "generateLegendTemplate()"); |
3300 | 0 | ms_regfree(&re); |
3301 | 0 | return NULL; |
3302 | 0 | } |
3303 | 0 | ms_regfree(&re); |
3304 | | |
3305 | | /* -------------------------------------------------------------------- */ |
3306 | | /* Save the current drawing order. The drawing order is reset */ |
3307 | | /* at the end of the function. */ |
3308 | | /* -------------------------------------------------------------------- */ |
3309 | 0 | if (mapserv->map->numlayers > 0) { |
3310 | 0 | panCurrentDrawingOrder = |
3311 | 0 | (int *)msSmallMalloc(sizeof(int) * mapserv->map->numlayers); |
3312 | |
|
3313 | 0 | for (i = 0; i < mapserv->map->numlayers; i++) { |
3314 | 0 | if (mapserv->map->layerorder) |
3315 | 0 | panCurrentDrawingOrder[i] = mapserv->map->layerorder[i]; |
3316 | 0 | else |
3317 | 0 | panCurrentDrawingOrder[i] = i; |
3318 | 0 | } |
3319 | 0 | } |
3320 | | |
3321 | | /* |
3322 | | * build prefix filename |
3323 | | * for legend icon creation |
3324 | | */ |
3325 | 0 | for (i = 0; i < mapserv->request->NumParams; |
3326 | 0 | i++) /* find the mapfile parameter first */ |
3327 | 0 | if (strcasecmp(mapserv->request->ParamNames[i], "map") == 0) |
3328 | 0 | break; |
3329 | |
|
3330 | 0 | if (i == mapserv->request->NumParams) { |
3331 | 0 | const char *ms_mapfile = CPLGetConfigOption("MS_MAPFILE", NULL); |
3332 | 0 | if (ms_mapfile) |
3333 | 0 | pszMapFname = msStringConcatenate(pszMapFname, ms_mapfile); |
3334 | 0 | } else { |
3335 | 0 | if (getenv(mapserv->request->ParamValues[i])) /* an environment references |
3336 | | the actual file to use */ |
3337 | 0 | pszMapFname = msStringConcatenate( |
3338 | 0 | pszMapFname, getenv(mapserv->request->ParamValues[i])); |
3339 | 0 | else |
3340 | 0 | pszMapFname = |
3341 | 0 | msStringConcatenate(pszMapFname, mapserv->request->ParamValues[i]); |
3342 | 0 | } |
3343 | |
|
3344 | 0 | if (pszMapFname) { |
3345 | 0 | if (stat(pszMapFname, &tmpStat) != -1) { |
3346 | 0 | int nLen; |
3347 | |
|
3348 | 0 | nLen = (mapserv->map->name ? strlen(mapserv->map->name) : 0) + 50; |
3349 | 0 | pszPrefix = (char *)msSmallMalloc((nLen + 1) * sizeof(char)); |
3350 | 0 | snprintf(pszPrefix, nLen, "%s_%ld_%ld", mapserv->map->name, |
3351 | 0 | (long)tmpStat.st_size, (long)tmpStat.st_mtime); |
3352 | 0 | pszPrefix[nLen] = '\0'; |
3353 | 0 | } |
3354 | |
|
3355 | 0 | free(pszMapFname); |
3356 | 0 | pszMapFname = NULL; |
3357 | 0 | } else { |
3358 | | /* -------------------------------------------------------------------- */ |
3359 | | /* map file name may not be available when the template functions */ |
3360 | | /* are called from mapscript. Use the time stamp as prefix. */ |
3361 | | /* -------------------------------------------------------------------- */ |
3362 | 0 | char pszTime[20]; |
3363 | |
|
3364 | 0 | snprintf(pszTime, sizeof(pszTime), "%ld", (long)time(NULL)); |
3365 | 0 | pszPrefix = msStringConcatenate(pszPrefix, pszTime); |
3366 | 0 | } |
3367 | | |
3368 | | /* open template */ |
3369 | 0 | if ((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, |
3370 | 0 | mapserv->map->legend.template), |
3371 | 0 | "r")) == NULL) { |
3372 | 0 | msSetError(MS_IOERR, "Error while opening template file.", |
3373 | 0 | "generateLegendTemplate()"); |
3374 | 0 | free(pszResult); |
3375 | 0 | pszResult = NULL; |
3376 | 0 | goto error; |
3377 | 0 | } |
3378 | | |
3379 | 0 | fseek(stream, 0, SEEK_END); |
3380 | 0 | long lengthLong = ftell(stream); |
3381 | 0 | rewind(stream); |
3382 | 0 | if (lengthLong < 0 || lengthLong > INT_MAX - 1) { |
3383 | 0 | msSetError(MS_IOERR, "Too large template file.", |
3384 | 0 | "generateLegendTemplate()"); |
3385 | 0 | free(pszResult); |
3386 | 0 | pszResult = NULL; |
3387 | 0 | goto error; |
3388 | 0 | } |
3389 | 0 | length = (int)lengthLong; |
3390 | |
|
3391 | 0 | file = (char *)malloc(length + 1); |
3392 | 0 | if (file == NULL) { |
3393 | 0 | msSetError(MS_IOERR, "Cannot allocate memory for template file.", |
3394 | 0 | "generateLegendTemplate()"); |
3395 | 0 | free(pszResult); |
3396 | 0 | pszResult = NULL; |
3397 | 0 | goto error; |
3398 | 0 | } |
3399 | | |
3400 | | /* |
3401 | | * Read all the template file |
3402 | | */ |
3403 | 0 | IGUR_sizet(fread(file, length, 1, stream)); |
3404 | | /* E. Rouault: the below issue is due to opening in "r" mode, which is a |
3405 | | * synonymous of "rt" on Windows. In that mode \r\n are turned into \n, |
3406 | | * consequently less bytes are written in the output buffer than requested. |
3407 | | * A potential fix might be to open in "rb" mode, but is the code ready |
3408 | | * to deal with Windows \r\n end of lines ? */ |
3409 | | /* Disabled for now due to Windows issue, see ticket #3814 |
3410 | | if( 1 != fread(file, length, 1, stream)) { |
3411 | | msSetError(MS_IOERR, "Error while reading template file.", |
3412 | | "generateLegendTemplate()"); free(file); fclose(stream); return NULL; |
3413 | | } |
3414 | | */ |
3415 | 0 | file[length] = '\0'; |
3416 | |
|
3417 | 0 | if (msValidateContexts(mapserv->map) != |
3418 | 0 | MS_SUCCESS) { /* make sure there are no recursive REQUIRES or |
3419 | | LABELREQUIRES expressions */ |
3420 | 0 | if (pszResult) |
3421 | 0 | free(pszResult); |
3422 | 0 | pszResult = NULL; |
3423 | 0 | goto error; |
3424 | 0 | } |
3425 | | |
3426 | | /* |
3427 | | * Separate header/footer, groups, layers and class |
3428 | | */ |
3429 | 0 | getInlineTag("leg_header_html", file, &legHeaderHtml); |
3430 | 0 | getInlineTag("leg_footer_html", file, &legFooterHtml); |
3431 | 0 | getInlineTag("leg_group_html", file, &legGroupHtml); |
3432 | 0 | getInlineTag("leg_layer_html", file, &legLayerHtml); |
3433 | 0 | getInlineTag("leg_class_html", file, &legClassHtml); |
3434 | | |
3435 | | /* |
3436 | | * Retrieve arguments of all three parts |
3437 | | */ |
3438 | 0 | if (legGroupHtml) |
3439 | 0 | if (getTagArgs("leg_group_html", file, &groupArgs) != MS_SUCCESS) { |
3440 | 0 | if (pszResult) |
3441 | 0 | free(pszResult); |
3442 | 0 | pszResult = NULL; |
3443 | 0 | goto error; |
3444 | 0 | } |
3445 | | |
3446 | 0 | if (legLayerHtml) |
3447 | 0 | if (getTagArgs("leg_layer_html", file, &layerArgs) != MS_SUCCESS) { |
3448 | 0 | if (pszResult) |
3449 | 0 | free(pszResult); |
3450 | 0 | pszResult = NULL; |
3451 | 0 | goto error; |
3452 | 0 | } |
3453 | | |
3454 | 0 | if (legClassHtml) |
3455 | 0 | if (getTagArgs("leg_class_html", file, &classArgs) != MS_SUCCESS) { |
3456 | 0 | if (pszResult) |
3457 | 0 | free(pszResult); |
3458 | 0 | pszResult = NULL; |
3459 | 0 | goto error; |
3460 | 0 | } |
3461 | | |
3462 | 0 | mapserv->map->cellsize = msAdjustExtent( |
3463 | 0 | &(mapserv->map->extent), mapserv->map->width, mapserv->map->height); |
3464 | 0 | if (msCalculateScale(mapserv->map->extent, mapserv->map->units, |
3465 | 0 | mapserv->map->width, mapserv->map->height, |
3466 | 0 | mapserv->map->resolution, |
3467 | 0 | &mapserv->map->scaledenom) != MS_SUCCESS) { |
3468 | 0 | if (pszResult) |
3469 | 0 | free(pszResult); |
3470 | 0 | pszResult = NULL; |
3471 | 0 | goto error; |
3472 | 0 | } |
3473 | | |
3474 | | /* start with the header if present */ |
3475 | 0 | if (legHeaderHtml) |
3476 | 0 | pszResult = msStringConcatenate(pszResult, legHeaderHtml); |
3477 | | |
3478 | | /********************************************************************/ |
3479 | | |
3480 | | /* |
3481 | | * order layers if order_metadata args is set |
3482 | | * If not, keep default order |
3483 | | */ |
3484 | 0 | pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata"); |
3485 | |
|
3486 | 0 | if (sortLayerByMetadata(mapserv->map, pszOrderMetadata) != MS_SUCCESS) { |
3487 | 0 | if (pszResult) |
3488 | 0 | free(pszResult); |
3489 | 0 | pszResult = NULL; |
3490 | 0 | goto error; |
3491 | 0 | } |
3492 | | |
3493 | | /* -------------------------------------------------------------------- */ |
3494 | | /* if the order tag is set to ascending or descending, the */ |
3495 | | /* current order will be changed to correspond to that. */ |
3496 | | /* -------------------------------------------------------------------- */ |
3497 | 0 | pszOrder = msLookupHashTable(layerArgs, "order"); |
3498 | 0 | if (pszOrder && ((strcasecmp(pszOrder, "ASCENDING") == 0) || |
3499 | 0 | (strcasecmp(pszOrder, "DESCENDING") == 0))) { |
3500 | 0 | if (sortLayerByOrder(mapserv->map, pszOrder) != MS_SUCCESS) { |
3501 | 0 | if (pszResult) |
3502 | 0 | free(pszResult); |
3503 | 0 | pszResult = NULL; |
3504 | 0 | goto error; |
3505 | 0 | } |
3506 | 0 | } |
3507 | | |
3508 | 0 | if (legGroupHtml) { |
3509 | | /* retrieve group names */ |
3510 | 0 | papszGroups = msGetAllGroupNames(mapserv->map, &nGroupNames); |
3511 | |
|
3512 | 0 | for (i = 0; i < nGroupNames; i++) { |
3513 | | /* process group tags */ |
3514 | 0 | if (generateGroupTemplate(legGroupHtml, mapserv->map, papszGroups[i], |
3515 | 0 | groupArgs, &legGroupHtmlCopy, |
3516 | 0 | pszPrefix) != MS_SUCCESS) { |
3517 | 0 | if (pszResult) |
3518 | 0 | free(pszResult); |
3519 | 0 | pszResult = NULL; |
3520 | 0 | goto error; |
3521 | 0 | } |
3522 | | |
3523 | | /* concatenate it to final result */ |
3524 | 0 | pszResult = msStringConcatenate(pszResult, legGroupHtmlCopy); |
3525 | | |
3526 | | /* |
3527 | | if(!pszResult) |
3528 | | { |
3529 | | if(pszResult) |
3530 | | free(pszResult); |
3531 | | pszResult=NULL; |
3532 | | goto error; |
3533 | | } |
3534 | | */ |
3535 | |
|
3536 | 0 | if (legGroupHtmlCopy) { |
3537 | 0 | free(legGroupHtmlCopy); |
3538 | 0 | legGroupHtmlCopy = NULL; |
3539 | 0 | } |
3540 | | |
3541 | | /* for all layers in group */ |
3542 | 0 | if (legLayerHtml) { |
3543 | 0 | for (j = 0; j < mapserv->map->numlayers; j++) { |
3544 | | /* |
3545 | | * if order_metadata is set and the order |
3546 | | * value is less than 0, don't display it |
3547 | | */ |
3548 | 0 | pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata"); |
3549 | 0 | if (pszOrderMetadata) { |
3550 | 0 | pszOrderValue = msLookupHashTable( |
3551 | 0 | &(GET_LAYER(mapserv->map, mapserv->map->layerorder[j]) |
3552 | 0 | ->metadata), |
3553 | 0 | pszOrderMetadata); |
3554 | 0 | if (pszOrderValue) { |
3555 | 0 | const int nLegendOrder = atoi(pszOrderValue); |
3556 | 0 | if (nLegendOrder < 0) |
3557 | 0 | continue; |
3558 | 0 | } |
3559 | 0 | } |
3560 | 0 | if (mapserv->hittest && |
3561 | 0 | mapserv->hittest->layerhits[mapserv->map->layerorder[j]].status == |
3562 | 0 | 0) { |
3563 | 0 | continue; |
3564 | 0 | } |
3565 | | |
3566 | 0 | if (GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group && |
3567 | 0 | strcmp( |
3568 | 0 | GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group, |
3569 | 0 | papszGroups[i]) == 0) { |
3570 | | /* process all layer tags */ |
3571 | 0 | if (generateLayerTemplate( |
3572 | 0 | legLayerHtml, mapserv->map, mapserv->map->layerorder[j], |
3573 | 0 | layerArgs, &legLayerHtmlCopy, pszPrefix) != MS_SUCCESS) { |
3574 | 0 | if (pszResult) |
3575 | 0 | free(pszResult); |
3576 | 0 | pszResult = NULL; |
3577 | 0 | goto error; |
3578 | 0 | } |
3579 | | |
3580 | | /* concatenate to final result */ |
3581 | 0 | pszResult = msStringConcatenate(pszResult, legLayerHtmlCopy); |
3582 | |
|
3583 | 0 | if (legLayerHtmlCopy) { |
3584 | 0 | free(legLayerHtmlCopy); |
3585 | 0 | legLayerHtmlCopy = NULL; |
3586 | 0 | } |
3587 | | |
3588 | | /* for all classes in layer */ |
3589 | 0 | if (legClassHtml) { |
3590 | 0 | for (k = 0; |
3591 | 0 | k < GET_LAYER(mapserv->map, mapserv->map->layerorder[j]) |
3592 | 0 | ->numclasses; |
3593 | 0 | k++) { |
3594 | | /* process all class tags */ |
3595 | 0 | if (!GET_LAYER(mapserv->map, mapserv->map->layerorder[j]) |
3596 | 0 | ->class[k] -> name) |
3597 | 0 | continue; |
3598 | 0 | if (mapserv->hittest && |
3599 | 0 | mapserv->hittest->layerhits[mapserv->map->layerorder[j]] |
3600 | 0 | .classhits[k] |
3601 | 0 | .status == 0) { |
3602 | 0 | continue; |
3603 | 0 | } |
3604 | | |
3605 | 0 | if (generateClassTemplate(legClassHtml, mapserv->map, |
3606 | 0 | mapserv->map->layerorder[j], k, |
3607 | 0 | classArgs, &legClassHtmlCopy, |
3608 | 0 | pszPrefix) != MS_SUCCESS) { |
3609 | 0 | if (pszResult) |
3610 | 0 | free(pszResult); |
3611 | 0 | pszResult = NULL; |
3612 | 0 | goto error; |
3613 | 0 | } |
3614 | | |
3615 | | /* concatenate to final result */ |
3616 | 0 | pszResult = msStringConcatenate(pszResult, legClassHtmlCopy); |
3617 | |
|
3618 | 0 | if (legClassHtmlCopy) { |
3619 | 0 | free(legClassHtmlCopy); |
3620 | 0 | legClassHtmlCopy = NULL; |
3621 | 0 | } |
3622 | 0 | } |
3623 | 0 | } |
3624 | 0 | } |
3625 | 0 | } |
3626 | 0 | } else if (legClassHtml) { /* no layer template specified but class and |
3627 | | group template */ |
3628 | 0 | for (j = 0; j < mapserv->map->numlayers; j++) { |
3629 | | /* |
3630 | | * if order_metadata is set and the order |
3631 | | * value is less than 0, don't display it |
3632 | | */ |
3633 | 0 | pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata"); |
3634 | 0 | if (pszOrderMetadata) { |
3635 | 0 | pszOrderValue = msLookupHashTable( |
3636 | 0 | &(GET_LAYER(mapserv->map, mapserv->map->layerorder[j]) |
3637 | 0 | ->metadata), |
3638 | 0 | pszOrderMetadata); |
3639 | 0 | if (pszOrderValue) { |
3640 | 0 | const int nLegendOrder = atoi(pszOrderValue); |
3641 | 0 | if (nLegendOrder < 0) |
3642 | 0 | continue; |
3643 | 0 | } |
3644 | 0 | } |
3645 | 0 | if (mapserv->hittest && |
3646 | 0 | mapserv->hittest->layerhits[mapserv->map->layerorder[j]].status == |
3647 | 0 | 0) { |
3648 | 0 | continue; |
3649 | 0 | } |
3650 | | |
3651 | 0 | if (GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group && |
3652 | 0 | strcmp( |
3653 | 0 | GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group, |
3654 | 0 | papszGroups[i]) == 0) { |
3655 | | /* for all classes in layer */ |
3656 | |
|
3657 | 0 | for (k = 0; k < GET_LAYER(mapserv->map, mapserv->map->layerorder[j]) |
3658 | 0 | ->numclasses; |
3659 | 0 | k++) { |
3660 | | /* process all class tags */ |
3661 | 0 | if (!GET_LAYER(mapserv->map, mapserv->map->layerorder[j]) |
3662 | 0 | ->class[k] -> name) |
3663 | 0 | continue; |
3664 | 0 | if (mapserv->hittest && |
3665 | 0 | mapserv->hittest->layerhits[mapserv->map->layerorder[j]] |
3666 | 0 | .classhits[k] |
3667 | 0 | .status == 0) { |
3668 | 0 | continue; |
3669 | 0 | } |
3670 | | |
3671 | 0 | if (generateClassTemplate(legClassHtml, mapserv->map, |
3672 | 0 | mapserv->map->layerorder[j], k, |
3673 | 0 | classArgs, &legClassHtmlCopy, |
3674 | 0 | pszPrefix) != MS_SUCCESS) { |
3675 | 0 | if (pszResult) |
3676 | 0 | free(pszResult); |
3677 | 0 | pszResult = NULL; |
3678 | 0 | goto error; |
3679 | 0 | } |
3680 | | |
3681 | | /* concatenate to final result */ |
3682 | 0 | pszResult = msStringConcatenate(pszResult, legClassHtmlCopy); |
3683 | |
|
3684 | 0 | if (legClassHtmlCopy) { |
3685 | 0 | free(legClassHtmlCopy); |
3686 | 0 | legClassHtmlCopy = NULL; |
3687 | 0 | } |
3688 | 0 | } |
3689 | 0 | } |
3690 | 0 | } |
3691 | 0 | } |
3692 | 0 | } |
3693 | 0 | } else { |
3694 | | /* if no group template specified */ |
3695 | 0 | if (legLayerHtml) { |
3696 | 0 | for (j = 0; j < mapserv->map->numlayers; j++) { |
3697 | | /* |
3698 | | * if order_metadata is set and the order |
3699 | | * value is less than 0, don't display it |
3700 | | */ |
3701 | 0 | pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata"); |
3702 | 0 | if (pszOrderMetadata) { |
3703 | 0 | pszOrderValue = msLookupHashTable( |
3704 | 0 | &(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->metadata), |
3705 | 0 | pszOrderMetadata); |
3706 | 0 | if (pszOrderValue) { |
3707 | 0 | const int nLegendOrder = atoi(pszOrderValue); |
3708 | 0 | if (nLegendOrder < 0) |
3709 | 0 | continue; |
3710 | 0 | } |
3711 | 0 | } |
3712 | 0 | if (mapserv->hittest && |
3713 | 0 | mapserv->hittest->layerhits[mapserv->map->layerorder[j]].status == |
3714 | 0 | 0) { |
3715 | 0 | continue; |
3716 | 0 | } |
3717 | | |
3718 | | /* process a layer tags */ |
3719 | 0 | if (generateLayerTemplate(legLayerHtml, mapserv->map, |
3720 | 0 | mapserv->map->layerorder[j], layerArgs, |
3721 | 0 | &legLayerHtmlCopy, pszPrefix) != MS_SUCCESS) { |
3722 | 0 | if (pszResult) |
3723 | 0 | free(pszResult); |
3724 | 0 | pszResult = NULL; |
3725 | 0 | goto error; |
3726 | 0 | } |
3727 | | |
3728 | | /* concatenate to final result */ |
3729 | 0 | pszResult = msStringConcatenate(pszResult, legLayerHtmlCopy); |
3730 | |
|
3731 | 0 | if (legLayerHtmlCopy) { |
3732 | 0 | free(legLayerHtmlCopy); |
3733 | 0 | legLayerHtmlCopy = NULL; |
3734 | 0 | } |
3735 | | |
3736 | | /* for all classes in layer */ |
3737 | 0 | if (legClassHtml) { |
3738 | 0 | for (k = 0; |
3739 | 0 | k < |
3740 | 0 | GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->numclasses; |
3741 | 0 | k++) { |
3742 | | /* process all class tags */ |
3743 | 0 | if (!GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->class[k] |
3744 | 0 | -> name) |
3745 | 0 | continue; |
3746 | 0 | if (mapserv->hittest && |
3747 | 0 | mapserv->hittest->layerhits[mapserv->map->layerorder[j]] |
3748 | 0 | .classhits[k] |
3749 | 0 | .status == 0) { |
3750 | 0 | continue; |
3751 | 0 | } |
3752 | | |
3753 | 0 | if (generateClassTemplate( |
3754 | 0 | legClassHtml, mapserv->map, mapserv->map->layerorder[j], k, |
3755 | 0 | classArgs, &legClassHtmlCopy, pszPrefix) != MS_SUCCESS) { |
3756 | 0 | if (pszResult) |
3757 | 0 | free(pszResult); |
3758 | 0 | pszResult = NULL; |
3759 | 0 | goto error; |
3760 | 0 | } |
3761 | | |
3762 | | /* concatenate to final result */ |
3763 | 0 | pszResult = msStringConcatenate(pszResult, legClassHtmlCopy); |
3764 | |
|
3765 | 0 | if (legClassHtmlCopy) { |
3766 | 0 | free(legClassHtmlCopy); |
3767 | 0 | legClassHtmlCopy = NULL; |
3768 | 0 | } |
3769 | 0 | } |
3770 | 0 | } |
3771 | 0 | } |
3772 | 0 | } else { /* if no group and layer template specified */ |
3773 | 0 | if (legClassHtml) { |
3774 | 0 | for (j = 0; j < mapserv->map->numlayers; j++) { |
3775 | | /* |
3776 | | * if order_metadata is set and the order |
3777 | | * value is less than 0, don't display it |
3778 | | */ |
3779 | 0 | pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata"); |
3780 | 0 | if (pszOrderMetadata) { |
3781 | 0 | pszOrderValue = msLookupHashTable( |
3782 | 0 | &(GET_LAYER(mapserv->map, mapserv->map->layerorder[j]) |
3783 | 0 | ->metadata), |
3784 | 0 | pszOrderMetadata); |
3785 | 0 | if (pszOrderValue) { |
3786 | 0 | const int nLegendOrder = atoi(pszOrderValue); |
3787 | 0 | if (nLegendOrder < 0) |
3788 | 0 | continue; |
3789 | 0 | } |
3790 | 0 | } |
3791 | 0 | if (mapserv->hittest && |
3792 | 0 | mapserv->hittest->layerhits[mapserv->map->layerorder[j]].status == |
3793 | 0 | 0) { |
3794 | 0 | continue; |
3795 | 0 | } |
3796 | | |
3797 | 0 | for (k = 0; |
3798 | 0 | k < |
3799 | 0 | GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->numclasses; |
3800 | 0 | k++) { |
3801 | 0 | if (!GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->class[k] |
3802 | 0 | -> name) |
3803 | 0 | continue; |
3804 | 0 | if (mapserv->hittest && |
3805 | 0 | mapserv->hittest->layerhits[mapserv->map->layerorder[j]] |
3806 | 0 | .classhits[k] |
3807 | 0 | .status == 0) { |
3808 | 0 | continue; |
3809 | 0 | } |
3810 | | |
3811 | 0 | if (generateClassTemplate( |
3812 | 0 | legClassHtml, mapserv->map, mapserv->map->layerorder[j], k, |
3813 | 0 | classArgs, &legClassHtmlCopy, pszPrefix) != MS_SUCCESS) { |
3814 | 0 | if (pszResult) |
3815 | 0 | free(pszResult); |
3816 | 0 | pszResult = NULL; |
3817 | 0 | goto error; |
3818 | 0 | } |
3819 | | |
3820 | 0 | pszResult = msStringConcatenate(pszResult, legClassHtmlCopy); |
3821 | |
|
3822 | 0 | if (legClassHtmlCopy) { |
3823 | 0 | free(legClassHtmlCopy); |
3824 | 0 | legClassHtmlCopy = NULL; |
3825 | 0 | } |
3826 | 0 | } |
3827 | 0 | } |
3828 | 0 | } |
3829 | 0 | } |
3830 | 0 | } |
3831 | | |
3832 | | /* finish with the footer if present */ |
3833 | 0 | if (legFooterHtml) |
3834 | 0 | pszResult = msStringConcatenate(pszResult, legFooterHtml); |
3835 | | |
3836 | | /* |
3837 | | * if we reach this point, that mean no error was generated. |
3838 | | * So check if template is null and initialize it to <space>. |
3839 | | */ |
3840 | 0 | if (pszResult == NULL) { |
3841 | 0 | pszResult = msStringConcatenate(pszResult, " "); |
3842 | 0 | } |
3843 | | |
3844 | | /********************************************************************/ |
3845 | |
|
3846 | 0 | error: |
3847 | |
|
3848 | 0 | if (papszGroups) { |
3849 | 0 | for (i = 0; i < nGroupNames; i++) |
3850 | 0 | msFree(papszGroups[i]); |
3851 | |
|
3852 | 0 | msFree(papszGroups); |
3853 | 0 | } |
3854 | |
|
3855 | 0 | msFreeHashTable(groupArgs); |
3856 | 0 | msFreeHashTable(layerArgs); |
3857 | 0 | msFreeHashTable(classArgs); |
3858 | |
|
3859 | 0 | msFree(file); |
3860 | |
|
3861 | 0 | msFree(legGroupHtmlCopy); |
3862 | 0 | msFree(legLayerHtmlCopy); |
3863 | 0 | msFree(legClassHtmlCopy); |
3864 | |
|
3865 | 0 | msFree(legHeaderHtml); |
3866 | 0 | msFree(legFooterHtml); |
3867 | |
|
3868 | 0 | msFree(legGroupHtml); |
3869 | 0 | msFree(legLayerHtml); |
3870 | 0 | msFree(legClassHtml); |
3871 | 0 | msFree(pszPrefix); |
3872 | |
|
3873 | 0 | if (stream) |
3874 | 0 | fclose(stream); |
3875 | | |
3876 | | /* -------------------------------------------------------------------- */ |
3877 | | /* Reset the layerdrawing order. */ |
3878 | | /* -------------------------------------------------------------------- */ |
3879 | 0 | if (panCurrentDrawingOrder && mapserv->map->layerorder) { |
3880 | 0 | for (i = 0; i < mapserv->map->numlayers; i++) |
3881 | 0 | mapserv->map->layerorder[i] = panCurrentDrawingOrder[i]; |
3882 | |
|
3883 | 0 | free(panCurrentDrawingOrder); |
3884 | 0 | } |
3885 | |
|
3886 | 0 | return pszResult; |
3887 | 0 | } |
3888 | | |
3889 | 0 | char *processOneToManyJoin(mapservObj *mapserv, joinObj *join) { |
3890 | 0 | int records = MS_FALSE; |
3891 | 0 | FILE *stream = NULL; |
3892 | 0 | char *outbuf; |
3893 | 0 | char line[MS_BUFFER_LENGTH], *tmpline; |
3894 | 0 | char szPath[MS_MAXPATHLEN]; |
3895 | |
|
3896 | 0 | if ((outbuf = msStrdup("")) == NULL) |
3897 | 0 | return (NULL); /* empty at first */ |
3898 | | |
3899 | 0 | msJoinPrepare(join, &(mapserv->resultshape)); /* execute the join */ |
3900 | 0 | while (msJoinNext(join) == MS_SUCCESS) { |
3901 | | /* First time through, deal with the header (if necessary) and open the main |
3902 | | * template. We only */ |
3903 | | /* want to do this if there are joined records. */ |
3904 | 0 | if (records == MS_FALSE) { |
3905 | 0 | if (join->header != NULL) { |
3906 | | /* coverity[dead_error_line] */ |
3907 | 0 | if (stream) |
3908 | 0 | fclose(stream); |
3909 | 0 | if ((stream = |
3910 | 0 | fopen(msBuildPath(szPath, mapserv->map->mappath, join->header), |
3911 | 0 | "r")) == NULL) { |
3912 | 0 | msSetError(MS_IOERR, "Error while opening join header file %s.", |
3913 | 0 | "processOneToManyJoin()", join->header); |
3914 | 0 | msFree(outbuf); |
3915 | 0 | return (NULL); |
3916 | 0 | } |
3917 | | |
3918 | 0 | if (isValidTemplate(stream, join->header) != MS_TRUE) { |
3919 | 0 | fclose(stream); |
3920 | 0 | msFree(outbuf); |
3921 | 0 | return NULL; |
3922 | 0 | } |
3923 | | |
3924 | | /* echo file to the output buffer, no substitutions */ |
3925 | 0 | while (fgets(line, MS_BUFFER_LENGTH, stream) != NULL) |
3926 | 0 | outbuf = msStringConcatenate(outbuf, line); |
3927 | |
|
3928 | 0 | fclose(stream); |
3929 | 0 | stream = NULL; |
3930 | 0 | } |
3931 | | |
3932 | 0 | if ((stream = |
3933 | 0 | fopen(msBuildPath(szPath, mapserv->map->mappath, join->template), |
3934 | 0 | "r")) == NULL) { |
3935 | 0 | msSetError(MS_IOERR, "Error while opening join template file %s.", |
3936 | 0 | "processOneToManyJoin()", join->template); |
3937 | 0 | msFree(outbuf); |
3938 | 0 | return (NULL); |
3939 | 0 | } |
3940 | | |
3941 | 0 | if (isValidTemplate(stream, join->template) != MS_TRUE) { |
3942 | 0 | fclose(stream); |
3943 | 0 | msFree(outbuf); |
3944 | 0 | return NULL; |
3945 | 0 | } |
3946 | | |
3947 | 0 | records = MS_TRUE; |
3948 | 0 | } |
3949 | | |
3950 | 0 | while (fgets(line, MS_BUFFER_LENGTH, stream) != |
3951 | 0 | NULL) { /* now on to the end of the template */ |
3952 | 0 | if (strchr(line, '[') != NULL) { |
3953 | 0 | tmpline = |
3954 | 0 | processLine(mapserv, line, NULL, |
3955 | 0 | QUERY); /* no multiline tags are allowed in a join */ |
3956 | 0 | if (!tmpline) { |
3957 | 0 | msFree(outbuf); |
3958 | 0 | fclose(stream); |
3959 | 0 | return NULL; |
3960 | 0 | } |
3961 | 0 | outbuf = msStringConcatenate(outbuf, tmpline); |
3962 | 0 | free(tmpline); |
3963 | 0 | } else /* no subs, just echo */ |
3964 | 0 | outbuf = msStringConcatenate(outbuf, line); |
3965 | 0 | } |
3966 | | |
3967 | 0 | rewind(stream); |
3968 | 0 | IGUR_voidp( |
3969 | 0 | fgets(line, MS_BUFFER_LENGTH, |
3970 | 0 | stream)); /* skip the first line since it's the magic string */ |
3971 | 0 | } /* next record */ |
3972 | | |
3973 | 0 | if (records == MS_TRUE && join->footer) { |
3974 | 0 | if (stream) |
3975 | 0 | fclose(stream); |
3976 | 0 | if ((stream = |
3977 | 0 | fopen(msBuildPath(szPath, mapserv->map->mappath, join->footer), |
3978 | 0 | "r")) == NULL) { |
3979 | 0 | msSetError(MS_IOERR, "Error while opening join footer file %s.", |
3980 | 0 | "processOneToManyJoin()", join->footer); |
3981 | 0 | msFree(outbuf); |
3982 | 0 | return (NULL); |
3983 | 0 | } |
3984 | | |
3985 | 0 | if (isValidTemplate(stream, join->footer) != MS_TRUE) { |
3986 | 0 | msFree(outbuf); |
3987 | 0 | fclose(stream); |
3988 | 0 | return NULL; |
3989 | 0 | } |
3990 | | |
3991 | | /* echo file to the output buffer, no substitutions */ |
3992 | 0 | while (fgets(line, MS_BUFFER_LENGTH, stream) != NULL) |
3993 | 0 | outbuf = msStringConcatenate(outbuf, line); |
3994 | |
|
3995 | 0 | fclose(stream); |
3996 | 0 | stream = NULL; |
3997 | 0 | } |
3998 | | |
3999 | | /* clear any data associated with the join */ |
4000 | 0 | msFreeCharArray(join->values, join->numitems); |
4001 | 0 | join->values = NULL; |
4002 | |
|
4003 | 0 | if (stream) |
4004 | 0 | fclose(stream); |
4005 | |
|
4006 | 0 | return (outbuf); |
4007 | 0 | } |
4008 | | |
4009 | | /* |
4010 | | ** Process a single line in the template. A few tags (e.g. |
4011 | | *[resultset]...[/resultset]) can be multi-line so |
4012 | | ** we pass the filehandle to look ahead if necessary. |
4013 | | */ |
4014 | | static char *processLine(mapservObj *mapserv, const char *instr, FILE *stream, |
4015 | 0 | int mode) { |
4016 | 0 | int i, j; |
4017 | 0 | #define PROCESSLINE_BUFLEN 5120 |
4018 | 0 | char repstr[PROCESSLINE_BUFLEN], substr[PROCESSLINE_BUFLEN], |
4019 | 0 | *outstr; /* repstr = replace string, substr = sub string */ |
4020 | 0 | struct hashObj *tp = NULL; |
4021 | 0 | char *encodedstr; |
4022 | |
|
4023 | 0 | rectObj llextent; |
4024 | 0 | pointObj llpoint; |
4025 | |
|
4026 | 0 | outstr = msStrdup(instr); /* work from a copy */ |
4027 | |
|
4028 | 0 | if (strstr(outstr, "[version]")) |
4029 | 0 | outstr = msReplaceSubstring(outstr, "[version]", msGetVersion()); |
4030 | |
|
4031 | 0 | snprintf(repstr, PROCESSLINE_BUFLEN, "%s%s%s.%s", mapserv->map->web.imageurl, |
4032 | 0 | mapserv->map->name, mapserv->Id, |
4033 | 0 | MS_IMAGE_EXTENSION(mapserv->map->outputformat)); |
4034 | 0 | outstr = msReplaceSubstring(outstr, "[img]", repstr); |
4035 | 0 | snprintf(repstr, PROCESSLINE_BUFLEN, "%s%sref%s.%s", |
4036 | 0 | mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, |
4037 | 0 | MS_IMAGE_EXTENSION(mapserv->map->outputformat)); |
4038 | 0 | outstr = msReplaceSubstring(outstr, "[ref]", repstr); |
4039 | |
|
4040 | 0 | if (strstr(outstr, "[errmsg")) { |
4041 | 0 | char *errmsg = msGetErrorString(";"); |
4042 | 0 | if (!errmsg) |
4043 | 0 | errmsg = |
4044 | 0 | msStrdup("Error message buffer is empty."); /* should never happen, |
4045 | | but just in case... */ |
4046 | 0 | outstr = msReplaceSubstring(outstr, "[errmsg]", errmsg); |
4047 | 0 | encodedstr = msEncodeUrl(errmsg); |
4048 | 0 | outstr = msReplaceSubstring(outstr, "[errmsg_esc]", encodedstr); |
4049 | 0 | free(errmsg); |
4050 | 0 | free(encodedstr); |
4051 | 0 | } |
4052 | |
|
4053 | 0 | if (strstr(outstr, "[legend]")) { |
4054 | | /* if there's a template legend specified, use it */ |
4055 | 0 | if (mapserv->map->legend.template) { |
4056 | 0 | char *legendTemplate; |
4057 | |
|
4058 | 0 | legendTemplate = generateLegendTemplate(mapserv); |
4059 | 0 | if (legendTemplate) { |
4060 | 0 | outstr = msReplaceSubstring(outstr, "[legend]", legendTemplate); |
4061 | |
|
4062 | 0 | free(legendTemplate); |
4063 | 0 | } else /* error already generated by (generateLegendTemplate()) */ |
4064 | 0 | return NULL; |
4065 | 0 | } else { /* if not display gif image with all legend icon */ |
4066 | 0 | snprintf(repstr, PROCESSLINE_BUFLEN, "%s%sleg%s.%s", |
4067 | 0 | mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, |
4068 | 0 | MS_IMAGE_EXTENSION(mapserv->map->outputformat)); |
4069 | 0 | outstr = msReplaceSubstring(outstr, "[legend]", repstr); |
4070 | 0 | } |
4071 | 0 | } |
4072 | | |
4073 | 0 | snprintf(repstr, PROCESSLINE_BUFLEN, "%s%ssb%s.%s", |
4074 | 0 | mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, |
4075 | 0 | MS_IMAGE_EXTENSION(mapserv->map->outputformat)); |
4076 | 0 | outstr = msReplaceSubstring(outstr, "[scalebar]", repstr); |
4077 | |
|
4078 | 0 | if (mapserv->savequery) { |
4079 | 0 | snprintf(repstr, PROCESSLINE_BUFLEN, "%s%s%s%s", |
4080 | 0 | mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, |
4081 | 0 | MS_QUERY_EXTENSION); |
4082 | 0 | outstr = msReplaceSubstring(outstr, "[queryfile]", repstr); |
4083 | 0 | } |
4084 | |
|
4085 | 0 | if (mapserv->savemap) { |
4086 | 0 | snprintf(repstr, PROCESSLINE_BUFLEN, "%s%s%s.map", |
4087 | 0 | mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id); |
4088 | 0 | outstr = msReplaceSubstring(outstr, "[map]", repstr); |
4089 | 0 | } |
4090 | |
|
4091 | 0 | if (strstr(outstr, "[mapserv_onlineresource]")) { |
4092 | 0 | char *ol; |
4093 | 0 | #if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ |
4094 | 0 | defined(USE_SOS_SVR) || defined(USE_WMS_LYR) || defined(USE_WFS_LYR) |
4095 | 0 | ol = msOWSGetOnlineResource(mapserv->map, "O", "onlineresource", |
4096 | 0 | mapserv->request); |
4097 | | #else |
4098 | | ol = msBuildOnlineResource(mapserv->map, mapserv->request); |
4099 | | #endif |
4100 | 0 | outstr = msReplaceSubstring(outstr, "[mapserv_onlineresource]", ol); |
4101 | 0 | msFree(ol); |
4102 | 0 | } |
4103 | |
|
4104 | 0 | if (getenv("HTTP_HOST")) { |
4105 | 0 | snprintf(repstr, PROCESSLINE_BUFLEN, "%s", getenv("HTTP_HOST")); |
4106 | 0 | outstr = msReplaceSubstring(outstr, "[host]", repstr); |
4107 | 0 | } |
4108 | 0 | if (getenv("SERVER_PORT")) { |
4109 | 0 | snprintf(repstr, PROCESSLINE_BUFLEN, "%s", getenv("SERVER_PORT")); |
4110 | 0 | outstr = msReplaceSubstring(outstr, "[port]", repstr); |
4111 | 0 | } |
4112 | |
|
4113 | 0 | snprintf(repstr, PROCESSLINE_BUFLEN, "%s", mapserv->Id); |
4114 | 0 | outstr = msReplaceSubstring(outstr, "[id]", repstr); |
4115 | |
|
4116 | 0 | repstr[0] = '\0'; /* Layer list for a "POST" request */ |
4117 | 0 | for (i = 0; i < mapserv->NumLayers; i++) { |
4118 | 0 | strlcat(repstr, mapserv->Layers[i], sizeof(repstr)); |
4119 | 0 | strlcat(repstr, " ", sizeof(repstr)); |
4120 | 0 | } |
4121 | 0 | msStringTrimBlanks(repstr); |
4122 | 0 | encodedstr = msEncodeHTMLEntities(repstr); |
4123 | 0 | outstr = msReplaceSubstring(outstr, "[layers]", encodedstr); |
4124 | 0 | free(encodedstr); |
4125 | |
|
4126 | 0 | encodedstr = msEncodeUrl(repstr); |
4127 | 0 | outstr = msReplaceSubstring(outstr, "[layers_esc]", encodedstr); |
4128 | 0 | free(encodedstr); |
4129 | |
|
4130 | 0 | strcpy(repstr, ""); /* list of ALL layers that can be toggled */ |
4131 | 0 | repstr[0] = '\0'; |
4132 | 0 | for (i = 0; i < mapserv->map->numlayers; i++) { |
4133 | 0 | if (GET_LAYER(mapserv->map, i)->status != MS_DEFAULT && |
4134 | 0 | GET_LAYER(mapserv->map, i)->name != NULL) { |
4135 | 0 | strlcat(repstr, GET_LAYER(mapserv->map, i)->name, sizeof(repstr)); |
4136 | 0 | strlcat(repstr, " ", sizeof(repstr)); |
4137 | 0 | } |
4138 | 0 | } |
4139 | 0 | msStringTrimBlanks(repstr); |
4140 | 0 | outstr = msReplaceSubstring(outstr, "[toggle_layers]", repstr); |
4141 | |
|
4142 | 0 | encodedstr = msEncodeUrl(repstr); |
4143 | 0 | outstr = msReplaceSubstring(outstr, "[toggle_layers_esc]", encodedstr); |
4144 | 0 | free(encodedstr); |
4145 | |
|
4146 | 0 | for (i = 0; i < mapserv->map->numlayers; |
4147 | 0 | i++) { /* Set form widgets (i.e. checkboxes, radio and select lists), |
4148 | | note that default layers don't show up here */ |
4149 | 0 | if (isOn(mapserv, GET_LAYER(mapserv->map, i)->name, |
4150 | 0 | GET_LAYER(mapserv->map, i)->group) == MS_TRUE) { |
4151 | 0 | if (GET_LAYER(mapserv->map, i)->group) { |
4152 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", |
4153 | 0 | GET_LAYER(mapserv->map, i)->group); |
4154 | 0 | outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\""); |
4155 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", |
4156 | 0 | GET_LAYER(mapserv->map, i)->group); |
4157 | 0 | outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\""); |
4158 | 0 | } |
4159 | 0 | if (GET_LAYER(mapserv->map, i)->name) { |
4160 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", |
4161 | 0 | GET_LAYER(mapserv->map, i)->name); |
4162 | 0 | outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\""); |
4163 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", |
4164 | 0 | GET_LAYER(mapserv->map, i)->name); |
4165 | 0 | outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\""); |
4166 | 0 | } |
4167 | 0 | } else { |
4168 | 0 | if (GET_LAYER(mapserv->map, i)->group) { |
4169 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", |
4170 | 0 | GET_LAYER(mapserv->map, i)->group); |
4171 | 0 | outstr = msReplaceSubstring(outstr, substr, ""); |
4172 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", |
4173 | 0 | GET_LAYER(mapserv->map, i)->group); |
4174 | 0 | outstr = msReplaceSubstring(outstr, substr, ""); |
4175 | 0 | } |
4176 | 0 | if (GET_LAYER(mapserv->map, i)->name) { |
4177 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", |
4178 | 0 | GET_LAYER(mapserv->map, i)->name); |
4179 | 0 | outstr = msReplaceSubstring(outstr, substr, ""); |
4180 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", |
4181 | 0 | GET_LAYER(mapserv->map, i)->name); |
4182 | 0 | outstr = msReplaceSubstring(outstr, substr, ""); |
4183 | 0 | } |
4184 | 0 | } |
4185 | 0 | } |
4186 | |
|
4187 | 0 | for (i = -1; i <= 1; i++) { /* make zoom direction persistent */ |
4188 | 0 | if (mapserv->ZoomDirection == i) { |
4189 | 0 | snprintf(substr, sizeof(substr), "[zoomdir_%d_select]", i); |
4190 | 0 | outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\""); |
4191 | 0 | snprintf(substr, sizeof(substr), "[zoomdir_%d_check]", i); |
4192 | 0 | outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\""); |
4193 | 0 | } else { |
4194 | 0 | snprintf(substr, sizeof(substr), "[zoomdir_%d_select]", i); |
4195 | 0 | outstr = msReplaceSubstring(outstr, substr, ""); |
4196 | 0 | snprintf(substr, sizeof(substr), "[zoomdir_%d_check]", i); |
4197 | 0 | outstr = msReplaceSubstring(outstr, substr, ""); |
4198 | 0 | } |
4199 | 0 | } |
4200 | |
|
4201 | 0 | for (i = MINZOOM; i <= MAXZOOM; i++) { /* make zoom persistent */ |
4202 | 0 | if (mapserv->Zoom == i) { |
4203 | 0 | snprintf(substr, sizeof(substr), "[zoom_%d_select]", i); |
4204 | 0 | outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\""); |
4205 | 0 | snprintf(substr, sizeof(substr), "[zoom_%d_check]", i); |
4206 | 0 | outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\""); |
4207 | 0 | } else { |
4208 | 0 | snprintf(substr, sizeof(substr), "[zoom_%d_select]", i); |
4209 | 0 | outstr = msReplaceSubstring(outstr, substr, ""); |
4210 | 0 | snprintf(substr, sizeof(substr), "[zoom_%d_check]", i); |
4211 | 0 | outstr = msReplaceSubstring(outstr, substr, ""); |
4212 | 0 | } |
4213 | 0 | } |
4214 | | |
4215 | | /* allow web object metadata access in template */ |
4216 | | |
4217 | | /* |
4218 | | * reworked by SG to use HashTable methods |
4219 | | */ |
4220 | |
|
4221 | 0 | if (strstr(outstr, "web_")) { |
4222 | 0 | for (j = 0; j < MS_HASHSIZE; j++) { |
4223 | 0 | if (mapserv->map->web.metadata.items[j] != NULL) { |
4224 | 0 | for (tp = mapserv->map->web.metadata.items[j]; tp != NULL; |
4225 | 0 | tp = tp->next) { |
4226 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[web_%s]", tp->key); |
4227 | 0 | outstr = msReplaceSubstring(outstr, substr, tp->data); |
4228 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[web_%s_esc]", tp->key); |
4229 | |
|
4230 | 0 | encodedstr = msEncodeUrl(tp->data); |
4231 | 0 | outstr = msReplaceSubstring(outstr, substr, encodedstr); |
4232 | 0 | free(encodedstr); |
4233 | 0 | } |
4234 | 0 | } |
4235 | 0 | } |
4236 | 0 | } |
4237 | | |
4238 | | /* allow layer metadata access in template */ |
4239 | 0 | for (i = 0; i < mapserv->map->numlayers; i++) { |
4240 | 0 | if (GET_LAYER(mapserv->map, i)->name && |
4241 | 0 | strstr(outstr, GET_LAYER(mapserv->map, i)->name)) { |
4242 | 0 | for (j = 0; j < MS_HASHSIZE; j++) { |
4243 | 0 | if (GET_LAYER(mapserv->map, i)->metadata.items[j] != NULL) { |
4244 | 0 | for (tp = GET_LAYER(mapserv->map, i)->metadata.items[j]; tp != NULL; |
4245 | 0 | tp = tp->next) { |
4246 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s]", |
4247 | 0 | GET_LAYER(mapserv->map, i)->name, tp->key); |
4248 | 0 | if (GET_LAYER(mapserv->map, i)->status == MS_ON) |
4249 | 0 | outstr = msReplaceSubstring(outstr, substr, tp->data); |
4250 | 0 | else |
4251 | 0 | outstr = msReplaceSubstring(outstr, substr, ""); |
4252 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s_esc]", |
4253 | 0 | GET_LAYER(mapserv->map, i)->name, tp->key); |
4254 | 0 | if (GET_LAYER(mapserv->map, i)->status == MS_ON) { |
4255 | 0 | encodedstr = msEncodeUrl(tp->data); |
4256 | 0 | outstr = msReplaceSubstring(outstr, substr, encodedstr); |
4257 | 0 | free(encodedstr); |
4258 | 0 | } else |
4259 | 0 | outstr = msReplaceSubstring(outstr, substr, ""); |
4260 | 0 | } |
4261 | 0 | } |
4262 | 0 | } |
4263 | 0 | } |
4264 | 0 | } |
4265 | |
|
4266 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->mappnt.x); |
4267 | 0 | outstr = msReplaceSubstring(outstr, "[mapx]", repstr); |
4268 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->mappnt.y); |
4269 | 0 | outstr = msReplaceSubstring(outstr, "[mapy]", repstr); |
4270 | |
|
4271 | 0 | snprintf(repstr, sizeof(repstr), "%f", |
4272 | 0 | mapserv->map->extent.minx); /* Individual mapextent elements for |
4273 | | spatial query building, deprecated. */ |
4274 | 0 | outstr = msReplaceSubstring(outstr, "[minx]", repstr); |
4275 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->map->extent.maxx); |
4276 | 0 | outstr = msReplaceSubstring(outstr, "[maxx]", repstr); |
4277 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->map->extent.miny); |
4278 | 0 | outstr = msReplaceSubstring(outstr, "[miny]", repstr); |
4279 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->map->extent.maxy); |
4280 | 0 | outstr = msReplaceSubstring(outstr, "[maxy]", repstr); |
4281 | |
|
4282 | 0 | if (processDateTag(&outstr) != MS_SUCCESS) |
4283 | 0 | return (NULL); |
4284 | | |
4285 | 0 | if (processExtentTag(mapserv, &outstr, "mapext", &(mapserv->map->extent), |
4286 | 0 | &(mapserv->map->projection)) != MS_SUCCESS) |
4287 | 0 | return (NULL); |
4288 | 0 | if (processExtentTag(mapserv, &outstr, "mapext_esc", &(mapserv->map->extent), |
4289 | 0 | &(mapserv->map->projection)) != |
4290 | 0 | MS_SUCCESS) /* deprecated */ |
4291 | 0 | return (NULL); |
4292 | | |
4293 | 0 | snprintf(repstr, sizeof(repstr), "%f", |
4294 | 0 | (mapserv->map->extent.maxx - |
4295 | 0 | mapserv->map->extent |
4296 | 0 | .minx)); /* useful for creating cacheable extents (i.e. 0 0 dx |
4297 | | dy) with legends and scalebars */ |
4298 | 0 | outstr = msReplaceSubstring(outstr, "[dx]", repstr); |
4299 | 0 | snprintf(repstr, sizeof(repstr), "%f", |
4300 | 0 | (mapserv->map->extent.maxy - mapserv->map->extent.miny)); |
4301 | 0 | outstr = msReplaceSubstring(outstr, "[dy]", repstr); |
4302 | |
|
4303 | 0 | snprintf(repstr, sizeof(repstr), "%f", |
4304 | 0 | mapserv->RawExt.minx); /* Individual raw extent elements for spatial |
4305 | | query building, deprecated. */ |
4306 | 0 | outstr = msReplaceSubstring(outstr, "[rawminx]", repstr); |
4307 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->RawExt.maxx); |
4308 | 0 | outstr = msReplaceSubstring(outstr, "[rawmaxx]", repstr); |
4309 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->RawExt.miny); |
4310 | 0 | outstr = msReplaceSubstring(outstr, "[rawminy]", repstr); |
4311 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->RawExt.maxy); |
4312 | 0 | outstr = msReplaceSubstring(outstr, "[rawmaxy]", repstr); |
4313 | |
|
4314 | 0 | if (processExtentTag(mapserv, &outstr, "rawext", &(mapserv->RawExt), |
4315 | 0 | &(mapserv->map->projection)) != MS_SUCCESS) |
4316 | 0 | return (NULL); |
4317 | 0 | if (processExtentTag(mapserv, &outstr, "rawext_esc", &(mapserv->RawExt), |
4318 | 0 | &(mapserv->map->projection)) != |
4319 | 0 | MS_SUCCESS) /* deprecated */ |
4320 | 0 | return (NULL); |
4321 | | |
4322 | 0 | if ((strstr(outstr, "lat]") || strstr(outstr, "lon]") || |
4323 | 0 | strstr(outstr, "lon_esc]")) && |
4324 | 0 | mapserv->map->projection.proj != NULL) { |
4325 | 0 | llextent = mapserv->map->extent; |
4326 | 0 | llpoint = mapserv->mappnt; |
4327 | 0 | if (!msProjIsGeographicCRS(&(mapserv->map->projection))) { |
4328 | 0 | msProjectRect(&(mapserv->map->projection), &(mapserv->map->latlon), |
4329 | 0 | &llextent); |
4330 | 0 | msProjectPoint(&(mapserv->map->projection), &(mapserv->map->latlon), |
4331 | 0 | &llpoint); |
4332 | 0 | } |
4333 | 0 | snprintf(repstr, sizeof(repstr), "%f", llpoint.x); |
4334 | 0 | outstr = msReplaceSubstring(outstr, "[maplon]", repstr); |
4335 | 0 | snprintf(repstr, sizeof(repstr), "%f", llpoint.y); |
4336 | 0 | outstr = msReplaceSubstring(outstr, "[maplat]", repstr); |
4337 | |
|
4338 | 0 | snprintf(repstr, sizeof(repstr), "%f", |
4339 | 0 | llextent.minx); /* map extent as lat/long */ |
4340 | 0 | outstr = msReplaceSubstring(outstr, "[minlon]", repstr); |
4341 | 0 | snprintf(repstr, sizeof(repstr), "%f", llextent.maxx); |
4342 | 0 | outstr = msReplaceSubstring(outstr, "[maxlon]", repstr); |
4343 | 0 | snprintf(repstr, sizeof(repstr), "%f", llextent.miny); |
4344 | 0 | outstr = msReplaceSubstring(outstr, "[minlat]", repstr); |
4345 | 0 | snprintf(repstr, sizeof(repstr), "%f", llextent.maxy); |
4346 | 0 | outstr = msReplaceSubstring(outstr, "[maxlat]", repstr); |
4347 | |
|
4348 | 0 | if (processExtentTag(mapserv, &outstr, "mapext_latlon", &(llextent), |
4349 | 0 | NULL) != MS_SUCCESS) |
4350 | 0 | return (NULL); |
4351 | 0 | if (processExtentTag(mapserv, &outstr, "mapext_latlon_esc", &(llextent), |
4352 | 0 | NULL) != MS_SUCCESS) /* deprecated */ |
4353 | 0 | return (NULL); |
4354 | 0 | } |
4355 | | |
4356 | | /* submitted by J.F (bug 1102) */ |
4357 | 0 | if (mapserv->map->reference.status == MS_ON) { |
4358 | 0 | snprintf(repstr, sizeof(repstr), "%f", |
4359 | 0 | mapserv->map->reference.extent |
4360 | 0 | .minx); /* Individual reference map extent elements for spatial |
4361 | | query building, deprecated. */ |
4362 | 0 | outstr = msReplaceSubstring(outstr, "[refminx]", repstr); |
4363 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->map->reference.extent.maxx); |
4364 | 0 | outstr = msReplaceSubstring(outstr, "[refmaxx]", repstr); |
4365 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->map->reference.extent.miny); |
4366 | 0 | outstr = msReplaceSubstring(outstr, "[refminy]", repstr); |
4367 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->map->reference.extent.maxy); |
4368 | 0 | outstr = msReplaceSubstring(outstr, "[refmaxy]", repstr); |
4369 | |
|
4370 | 0 | if (processExtentTag(mapserv, &outstr, "refext", |
4371 | 0 | &(mapserv->map->reference.extent), |
4372 | 0 | &(mapserv->map->projection)) != MS_SUCCESS) |
4373 | 0 | return (NULL); |
4374 | 0 | if (processExtentTag( |
4375 | 0 | mapserv, &outstr, "refext_esc", &(mapserv->map->reference.extent), |
4376 | 0 | &(mapserv->map->projection)) != MS_SUCCESS) /* deprecated */ |
4377 | 0 | return (NULL); |
4378 | 0 | } |
4379 | | |
4380 | 0 | snprintf(repstr, sizeof(repstr), "%d %d", mapserv->map->width, |
4381 | 0 | mapserv->map->height); |
4382 | 0 | outstr = msReplaceSubstring(outstr, "[mapsize]", repstr); |
4383 | |
|
4384 | 0 | encodedstr = msEncodeUrl(repstr); |
4385 | 0 | outstr = msReplaceSubstring(outstr, "[mapsize_esc]", encodedstr); |
4386 | 0 | free(encodedstr); |
4387 | |
|
4388 | 0 | snprintf(repstr, sizeof(repstr), "%d", mapserv->map->width); |
4389 | 0 | outstr = msReplaceSubstring(outstr, "[mapwidth]", repstr); |
4390 | 0 | snprintf(repstr, sizeof(repstr), "%d", mapserv->map->height); |
4391 | 0 | outstr = msReplaceSubstring(outstr, "[mapheight]", repstr); |
4392 | |
|
4393 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->map->scaledenom); |
4394 | 0 | outstr = msReplaceSubstring(outstr, "[scale]", repstr); |
4395 | 0 | outstr = msReplaceSubstring(outstr, "[scaledenom]", repstr); |
4396 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->map->cellsize); |
4397 | 0 | outstr = msReplaceSubstring(outstr, "[cellsize]", repstr); |
4398 | |
|
4399 | 0 | snprintf(repstr, sizeof(repstr), "%.1f %.1f", (mapserv->map->width) / 2.0, |
4400 | 0 | (mapserv->map->height) / |
4401 | 0 | 2.0); /* not subtracting 1 from image dimensions (see bug 633) */ |
4402 | 0 | outstr = msReplaceSubstring(outstr, "[center]", repstr); |
4403 | 0 | snprintf(repstr, sizeof(repstr), "%.1f", (mapserv->map->width) / 2.0); |
4404 | 0 | outstr = msReplaceSubstring(outstr, "[center_x]", repstr); |
4405 | 0 | snprintf(repstr, sizeof(repstr), "%.1f", (mapserv->map->height) / 2.0); |
4406 | 0 | outstr = msReplaceSubstring(outstr, "[center_y]", repstr); |
4407 | | |
4408 | | /* These are really for situations with multiple result sets only, but often |
4409 | | * used in header/footer */ |
4410 | 0 | snprintf(repstr, sizeof(repstr), "%d", |
4411 | 0 | mapserv->NR); /* total number of results */ |
4412 | 0 | outstr = msReplaceSubstring(outstr, "[nr]", repstr); |
4413 | 0 | snprintf(repstr, sizeof(repstr), "%d", |
4414 | 0 | mapserv->NL); /* total number of layers with results */ |
4415 | 0 | outstr = msReplaceSubstring(outstr, "[nl]", repstr); |
4416 | |
|
4417 | 0 | if (mapserv->resultlayer) { |
4418 | 0 | if (strstr(outstr, "[items]") != NULL) { |
4419 | 0 | char *itemstr = NULL; |
4420 | |
|
4421 | 0 | itemstr = msJoinStrings(mapserv->resultlayer->items, |
4422 | 0 | mapserv->resultlayer->numitems, ","); |
4423 | 0 | outstr = msReplaceSubstring(outstr, "[items]", itemstr); |
4424 | 0 | free(itemstr); |
4425 | 0 | } |
4426 | |
|
4427 | 0 | snprintf(repstr, sizeof(repstr), "%d", |
4428 | 0 | mapserv->NLR); /* total number of results within this layer */ |
4429 | 0 | outstr = msReplaceSubstring(outstr, "[nlr]", repstr); |
4430 | 0 | snprintf( |
4431 | 0 | repstr, sizeof(repstr), "%d", |
4432 | 0 | mapserv |
4433 | 0 | ->RN); /* sequential (eg. 1..n) result number within all layers */ |
4434 | 0 | outstr = msReplaceSubstring(outstr, "[rn]", repstr); |
4435 | 0 | snprintf( |
4436 | 0 | repstr, sizeof(repstr), "%d", |
4437 | 0 | mapserv |
4438 | 0 | ->LRN); /* sequential (eg. 1..n) result number within this layer */ |
4439 | 0 | outstr = msReplaceSubstring(outstr, "[lrn]", repstr); |
4440 | 0 | outstr = msReplaceSubstring( |
4441 | 0 | outstr, "[cl]", mapserv->resultlayer->name); /* current layer name */ |
4442 | | /* if(resultlayer->description) outstr = msReplaceSubstring(outstr, "[cd]", |
4443 | | * resultlayer->description); */ /* current layer description */ |
4444 | | |
4445 | | /* allow layer metadata access when there is a current result layer |
4446 | | * (implicitly a query template) */ |
4447 | 0 | if (strstr(outstr, "[metadata_")) { |
4448 | 0 | for (i = 0; i < MS_HASHSIZE; i++) { |
4449 | 0 | if (mapserv->resultlayer->metadata.items[i] != NULL) { |
4450 | 0 | for (tp = mapserv->resultlayer->metadata.items[i]; tp != NULL; |
4451 | 0 | tp = tp->next) { |
4452 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[metadata_%s]", tp->key); |
4453 | 0 | outstr = msReplaceSubstring(outstr, substr, tp->data); |
4454 | |
|
4455 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[metadata_%s_esc]", tp->key); |
4456 | 0 | encodedstr = msEncodeUrl(tp->data); |
4457 | 0 | outstr = msReplaceSubstring(outstr, substr, encodedstr); |
4458 | 0 | free(encodedstr); |
4459 | 0 | } |
4460 | 0 | } |
4461 | 0 | } |
4462 | 0 | } |
4463 | 0 | } |
4464 | |
|
4465 | 0 | if (mode != QUERY) { |
4466 | 0 | if (processResultSetTag(mapserv, &outstr, stream) != MS_SUCCESS) { |
4467 | 0 | msFree(outstr); |
4468 | 0 | return (NULL); |
4469 | 0 | } |
4470 | 0 | } else { /* return shape and/or values */ |
4471 | |
|
4472 | 0 | assert(mapserv->resultlayer); |
4473 | | |
4474 | 0 | snprintf( |
4475 | 0 | repstr, sizeof(repstr), "%f %f", |
4476 | 0 | (mapserv->resultshape.bounds.maxx + mapserv->resultshape.bounds.minx) / |
4477 | 0 | 2, |
4478 | 0 | (mapserv->resultshape.bounds.maxy + mapserv->resultshape.bounds.miny) / |
4479 | 0 | 2); |
4480 | 0 | outstr = msReplaceSubstring(outstr, "[shpmid]", repstr); |
4481 | 0 | snprintf( |
4482 | 0 | repstr, sizeof(repstr), "%f", |
4483 | 0 | (mapserv->resultshape.bounds.maxx + mapserv->resultshape.bounds.minx) / |
4484 | 0 | 2); |
4485 | 0 | outstr = msReplaceSubstring(outstr, "[shpmidx]", repstr); |
4486 | 0 | snprintf( |
4487 | 0 | repstr, sizeof(repstr), "%f", |
4488 | 0 | (mapserv->resultshape.bounds.maxy + mapserv->resultshape.bounds.miny) / |
4489 | 0 | 2); |
4490 | 0 | outstr = msReplaceSubstring(outstr, "[shpmidy]", repstr); |
4491 | |
|
4492 | 0 | if (processExtentTag(mapserv, &outstr, "shpext", |
4493 | 0 | &(mapserv->resultshape.bounds), |
4494 | 0 | &(mapserv->resultlayer->projection)) != MS_SUCCESS) |
4495 | 0 | return (NULL); |
4496 | 0 | if (processExtentTag( |
4497 | 0 | mapserv, &outstr, "shpext_esc", &(mapserv->resultshape.bounds), |
4498 | 0 | &(mapserv->resultlayer->projection)) != MS_SUCCESS) /* deprecated */ |
4499 | 0 | return (NULL); |
4500 | | |
4501 | 0 | snprintf(repstr, sizeof(repstr), "%d", mapserv->resultshape.classindex); |
4502 | 0 | outstr = msReplaceSubstring(outstr, "[shpclass]", repstr); |
4503 | |
|
4504 | 0 | if (processShpxyTag(mapserv->resultlayer, &outstr, &mapserv->resultshape) != |
4505 | 0 | MS_SUCCESS) |
4506 | 0 | return (NULL); |
4507 | | |
4508 | 0 | if (processShplabelTag(mapserv->resultlayer, &outstr, |
4509 | 0 | &mapserv->resultshape) != MS_SUCCESS) |
4510 | 0 | return (NULL); |
4511 | | |
4512 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->resultshape.bounds.minx); |
4513 | 0 | outstr = msReplaceSubstring(outstr, "[shpminx]", repstr); |
4514 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->resultshape.bounds.miny); |
4515 | 0 | outstr = msReplaceSubstring(outstr, "[shpminy]", repstr); |
4516 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->resultshape.bounds.maxx); |
4517 | 0 | outstr = msReplaceSubstring(outstr, "[shpmaxx]", repstr); |
4518 | 0 | snprintf(repstr, sizeof(repstr), "%f", mapserv->resultshape.bounds.maxy); |
4519 | 0 | outstr = msReplaceSubstring(outstr, "[shpmaxy]", repstr); |
4520 | |
|
4521 | 0 | snprintf(repstr, sizeof(repstr), "%ld", mapserv->resultshape.index); |
4522 | 0 | outstr = msReplaceSubstring(outstr, "[shpidx]", repstr); |
4523 | 0 | snprintf(repstr, sizeof(repstr), "%d", mapserv->resultshape.tileindex); |
4524 | 0 | outstr = msReplaceSubstring(outstr, "[tileidx]", repstr); |
4525 | | |
4526 | | /* return ALL attributes in one delimited list */ |
4527 | 0 | if (strstr(outstr, "[values]") != NULL) { |
4528 | 0 | char *valuestr = NULL; |
4529 | |
|
4530 | 0 | valuestr = msJoinStrings(mapserv->resultshape.values, |
4531 | 0 | mapserv->resultlayer->numitems, ","); |
4532 | 0 | outstr = msReplaceSubstring(outstr, "[values]", valuestr); |
4533 | 0 | free(valuestr); |
4534 | 0 | } |
4535 | |
|
4536 | 0 | for (i = 0; i < mapserv->resultlayer->numitems; i++) { |
4537 | | /* by default let's encode attributes for HTML presentation */ |
4538 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s]", |
4539 | 0 | mapserv->resultlayer->items[i]); |
4540 | 0 | if (strstr(outstr, substr) != NULL) { |
4541 | 0 | encodedstr = msEncodeHTMLEntities(mapserv->resultshape.values[i]); |
4542 | 0 | outstr = msReplaceSubstring(outstr, substr, encodedstr); |
4543 | 0 | free(encodedstr); |
4544 | 0 | } |
4545 | | |
4546 | | /* of course you might want to embed that data in URLs */ |
4547 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_esc]", |
4548 | 0 | mapserv->resultlayer->items[i]); |
4549 | 0 | if (strstr(outstr, substr) != NULL) { |
4550 | 0 | encodedstr = msEncodeUrl(mapserv->resultshape.values[i]); |
4551 | 0 | outstr = msReplaceSubstring(outstr, substr, encodedstr); |
4552 | 0 | free(encodedstr); |
4553 | 0 | } |
4554 | | |
4555 | | /* or you might want to access the attributes unaltered */ |
4556 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_raw]", |
4557 | 0 | mapserv->resultlayer->items[i]); |
4558 | 0 | if (strstr(outstr, substr) != NULL) |
4559 | 0 | outstr = |
4560 | 0 | msReplaceSubstring(outstr, substr, mapserv->resultshape.values[i]); |
4561 | 0 | } |
4562 | |
|
4563 | 0 | if (processItemTag(mapserv->resultlayer, &outstr, &mapserv->resultshape) != |
4564 | 0 | MS_SUCCESS) |
4565 | 0 | return (NULL); |
4566 | | |
4567 | | /* handle joins in this next section */ |
4568 | 0 | for (i = 0; i < mapserv->resultlayer->numjoins; i++) { |
4569 | 0 | if (mapserv->resultlayer->joins[i].values) { /* join has data */ |
4570 | 0 | for (j = 0; j < mapserv->resultlayer->joins[i].numitems; j++) { |
4571 | | /* by default let's encode attributes for HTML presentation */ |
4572 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s]", |
4573 | 0 | mapserv->resultlayer->joins[i].name, |
4574 | 0 | mapserv->resultlayer->joins[i].items[j]); |
4575 | 0 | if (strstr(outstr, substr) != NULL) { |
4576 | 0 | encodedstr = |
4577 | 0 | msEncodeHTMLEntities(mapserv->resultlayer->joins[i].values[j]); |
4578 | 0 | outstr = msReplaceSubstring(outstr, substr, encodedstr); |
4579 | 0 | free(encodedstr); |
4580 | 0 | } |
4581 | | |
4582 | | /* of course you might want to embed that data in URLs */ |
4583 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s_esc]", |
4584 | 0 | mapserv->resultlayer->joins[i].name, |
4585 | 0 | mapserv->resultlayer->joins[i].items[j]); |
4586 | 0 | if (strstr(outstr, substr) != NULL) { |
4587 | 0 | encodedstr = msEncodeUrl(mapserv->resultlayer->joins[i].values[j]); |
4588 | 0 | outstr = msReplaceSubstring(outstr, substr, encodedstr); |
4589 | 0 | free(encodedstr); |
4590 | 0 | } |
4591 | | |
4592 | | /* or you might want to access the attributes unaltered */ |
4593 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s_raw]", |
4594 | 0 | mapserv->resultlayer->joins[i].name, |
4595 | 0 | mapserv->resultlayer->joins[i].items[j]); |
4596 | 0 | if (strstr(outstr, substr) != NULL) |
4597 | 0 | outstr = msReplaceSubstring( |
4598 | 0 | outstr, substr, mapserv->resultlayer->joins[i].values[j]); |
4599 | 0 | } |
4600 | 0 | } else if (mapserv->resultlayer->joins[i].type == |
4601 | 0 | MS_JOIN_ONE_TO_MANY) { /* one-to-many join */ |
4602 | 0 | char *joinTemplate = NULL; |
4603 | |
|
4604 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[join_%s]", |
4605 | 0 | mapserv->resultlayer->joins[i].name); |
4606 | 0 | if (strstr(outstr, substr) != NULL) { |
4607 | 0 | joinTemplate = |
4608 | 0 | processOneToManyJoin(mapserv, &(mapserv->resultlayer->joins[i])); |
4609 | 0 | if (joinTemplate) { |
4610 | 0 | outstr = msReplaceSubstring(outstr, substr, joinTemplate); |
4611 | 0 | free(joinTemplate); |
4612 | 0 | } else |
4613 | 0 | return NULL; |
4614 | 0 | } |
4615 | 0 | } |
4616 | 0 | } /* next join */ |
4617 | |
|
4618 | 0 | } /* end query mode specific substitutions */ |
4619 | | |
4620 | 0 | if (processIncludeTag(mapserv, &outstr, stream, mode) != MS_SUCCESS) { |
4621 | 0 | msFree(outstr); |
4622 | 0 | return (NULL); |
4623 | 0 | } |
4624 | | |
4625 | 0 | for (i = 0; i < mapserv->request->NumParams; i++) { |
4626 | | /* Replace [variable] tags using values from URL. We cannot offer a |
4627 | | * [variable_raw] option here due to the risk of XSS. |
4628 | | * |
4629 | | * Replacement is case-insensitive. (#4511) |
4630 | | */ |
4631 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s]", |
4632 | 0 | mapserv->request->ParamNames[i]); |
4633 | 0 | encodedstr = msEncodeHTMLEntities(mapserv->request->ParamValues[i]); |
4634 | 0 | outstr = msCaseReplaceSubstring(outstr, substr, encodedstr); |
4635 | 0 | free(encodedstr); |
4636 | |
|
4637 | 0 | snprintf(substr, PROCESSLINE_BUFLEN, "[%s_esc]", |
4638 | 0 | mapserv->request->ParamNames[i]); |
4639 | 0 | encodedstr = msEncodeUrl(mapserv->request->ParamValues[i]); |
4640 | 0 | outstr = msCaseReplaceSubstring(outstr, substr, encodedstr); |
4641 | 0 | free(encodedstr); |
4642 | 0 | } |
4643 | |
|
4644 | 0 | return (outstr); |
4645 | 0 | } |
4646 | | |
4647 | 0 | #define MS_TEMPLATE_BUFFER 1024 /* 1k */ |
4648 | | |
4649 | | int msReturnPage(mapservObj *mapserv, char *html, int mode, |
4650 | 0 | char **papszBuffer) { |
4651 | 0 | FILE *stream; |
4652 | 0 | char line[MS_BUFFER_LENGTH], *tmpline; |
4653 | 0 | int nBufferSize = 0; |
4654 | 0 | int nCurrentSize = 0; |
4655 | |
|
4656 | 0 | ms_regex_t re; /* compiled regular expression to be matched */ |
4657 | 0 | char szPath[MS_MAXPATHLEN]; |
4658 | |
|
4659 | 0 | if (!html) { |
4660 | 0 | msSetError(MS_WEBERR, "No template specified", "msReturnPage()"); |
4661 | 0 | return MS_FAILURE; |
4662 | 0 | } |
4663 | | |
4664 | 0 | if (ms_regcomp(&re, MS_TEMPLATE_EXPR, |
4665 | 0 | MS_REG_EXTENDED | MS_REG_NOSUB | MS_REG_ICASE) != 0) { |
4666 | 0 | msSetError(MS_REGEXERR, NULL, "msReturnPage()"); |
4667 | 0 | return MS_FAILURE; |
4668 | 0 | } |
4669 | | |
4670 | 0 | if (ms_regexec(&re, html, 0, NULL, 0) != 0) { /* no match */ |
4671 | 0 | ms_regfree(&re); |
4672 | 0 | msSetError(MS_WEBERR, "Malformed template name (%s).", "msReturnPage()", |
4673 | 0 | html); |
4674 | 0 | return MS_FAILURE; |
4675 | 0 | } |
4676 | 0 | ms_regfree(&re); |
4677 | |
|
4678 | 0 | if ((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, html), "r")) == |
4679 | 0 | NULL) { |
4680 | 0 | msSetError(MS_IOERR, "%s", "msReturnPage()", html); |
4681 | 0 | return MS_FAILURE; |
4682 | 0 | } |
4683 | | |
4684 | 0 | if (isValidTemplate(stream, html) != MS_TRUE) { |
4685 | 0 | fclose(stream); |
4686 | 0 | return MS_FAILURE; |
4687 | 0 | } |
4688 | | |
4689 | 0 | if (papszBuffer) { |
4690 | 0 | if ((*papszBuffer) == NULL) { |
4691 | 0 | (*papszBuffer) = (char *)msSmallMalloc(MS_TEMPLATE_BUFFER); |
4692 | 0 | (*papszBuffer)[0] = '\0'; |
4693 | 0 | nBufferSize = MS_TEMPLATE_BUFFER; |
4694 | 0 | nCurrentSize = 0; |
4695 | 0 | } else { |
4696 | 0 | nCurrentSize = strlen((*papszBuffer)); |
4697 | 0 | nBufferSize = nCurrentSize; |
4698 | 0 | } |
4699 | 0 | } |
4700 | |
|
4701 | 0 | while (fgets(line, MS_BUFFER_LENGTH, stream) != |
4702 | 0 | NULL) { /* now on to the end of the file */ |
4703 | |
|
4704 | 0 | if (strchr(line, '[') != NULL) { |
4705 | 0 | tmpline = processLine(mapserv, line, stream, mode); |
4706 | 0 | if (!tmpline) { |
4707 | 0 | fclose(stream); |
4708 | 0 | return MS_FAILURE; |
4709 | 0 | } |
4710 | | |
4711 | 0 | if (papszBuffer) { |
4712 | 0 | if (nBufferSize <= (int)(nCurrentSize + strlen(tmpline) + 1)) { |
4713 | 0 | const int nExpandBuffer = (strlen(tmpline) / MS_TEMPLATE_BUFFER) + 1; |
4714 | 0 | nBufferSize = |
4715 | 0 | MS_TEMPLATE_BUFFER * nExpandBuffer + strlen((*papszBuffer)); |
4716 | 0 | (*papszBuffer) = (char *)msSmallRealloc((*papszBuffer), |
4717 | 0 | sizeof(char) * nBufferSize); |
4718 | 0 | } |
4719 | 0 | strcat((*papszBuffer), tmpline); |
4720 | 0 | nCurrentSize += strlen(tmpline); |
4721 | 0 | } else |
4722 | 0 | msIO_fwrite(tmpline, strlen(tmpline), 1, stdout); |
4723 | |
|
4724 | 0 | free(tmpline); |
4725 | 0 | } else { |
4726 | 0 | if (papszBuffer) { |
4727 | 0 | if (nBufferSize <= (int)(nCurrentSize + strlen(line))) { |
4728 | 0 | const int nExpandBuffer = (strlen(line) / MS_TEMPLATE_BUFFER) + 1; |
4729 | 0 | nBufferSize = |
4730 | 0 | MS_TEMPLATE_BUFFER * nExpandBuffer + strlen((*papszBuffer)); |
4731 | 0 | (*papszBuffer) = (char *)msSmallRealloc((*papszBuffer), |
4732 | 0 | sizeof(char) * nBufferSize); |
4733 | 0 | } |
4734 | 0 | strcat((*papszBuffer), line); |
4735 | 0 | nCurrentSize += strlen(line); |
4736 | 0 | } else |
4737 | 0 | msIO_fwrite(line, strlen(line), 1, stdout); |
4738 | 0 | } |
4739 | 0 | if (!papszBuffer) |
4740 | 0 | fflush(stdout); |
4741 | 0 | } /* next line */ |
4742 | | |
4743 | 0 | fclose(stream); |
4744 | |
|
4745 | 0 | return MS_SUCCESS; |
4746 | 0 | } |
4747 | | |
4748 | 0 | int msReturnURL(mapservObj *ms, const char *url, int mode) { |
4749 | 0 | char *tmpurl; |
4750 | |
|
4751 | 0 | if (url == NULL) { |
4752 | 0 | msSetError(MS_WEBERR, "Empty URL.", "msReturnURL()"); |
4753 | 0 | return MS_FAILURE; |
4754 | 0 | } |
4755 | | |
4756 | 0 | tmpurl = |
4757 | 0 | processLine(ms, url, NULL, mode); /* URL templates can't handle multi-line |
4758 | | tags, hence the NULL file pointer */ |
4759 | |
|
4760 | 0 | if (!tmpurl) |
4761 | 0 | return MS_FAILURE; |
4762 | | |
4763 | 0 | msRedirect(tmpurl); |
4764 | 0 | free(tmpurl); |
4765 | |
|
4766 | 0 | return MS_SUCCESS; |
4767 | 0 | } |
4768 | | |
4769 | | /* |
4770 | | ** Legacy query template parsing where you use headers, footers and such... |
4771 | | */ |
4772 | | int msReturnNestedTemplateQuery(mapservObj *mapserv, char *pszMimeType, |
4773 | 0 | char **papszBuffer) { |
4774 | 0 | int status; |
4775 | 0 | int i, j, k; |
4776 | 0 | char buffer[1024]; |
4777 | 0 | int nBufferSize = 0; |
4778 | 0 | int nCurrentSize = 0; |
4779 | 0 | int nExpandBuffer = 0; |
4780 | |
|
4781 | 0 | char *template; |
4782 | |
|
4783 | 0 | layerObj *lp = NULL; |
4784 | |
|
4785 | 0 | if (papszBuffer) { |
4786 | 0 | (*papszBuffer) = (char *)msSmallMalloc(MS_TEMPLATE_BUFFER); |
4787 | 0 | (*papszBuffer)[0] = '\0'; |
4788 | 0 | nBufferSize = MS_TEMPLATE_BUFFER; |
4789 | 0 | nCurrentSize = 0; |
4790 | 0 | nExpandBuffer = 1; |
4791 | 0 | } |
4792 | |
|
4793 | 0 | msInitShape(&(mapserv->resultshape)); |
4794 | |
|
4795 | 0 | if ((mapserv->Mode == ITEMQUERY) || |
4796 | 0 | (mapserv->Mode == QUERY)) { /* may need to handle a URL result set since |
4797 | | these modes return exactly 1 result */ |
4798 | |
|
4799 | 0 | for (i = (mapserv->map->numlayers - 1); i >= 0; i--) { |
4800 | 0 | lp = (GET_LAYER(mapserv->map, i)); |
4801 | |
|
4802 | 0 | if (!lp->resultcache) |
4803 | 0 | continue; |
4804 | 0 | if (lp->resultcache->numresults > 0) |
4805 | 0 | break; |
4806 | 0 | } |
4807 | |
|
4808 | 0 | if (i >= 0) { /* at least if no result found, mapserver will display an |
4809 | | empty template. */ |
4810 | |
|
4811 | 0 | if (lp->resultcache->results[0].classindex >= 0 && |
4812 | 0 | lp->class[(int)(lp->resultcache->results[0].classindex)] |
4813 | 0 | -> template) |
4814 | 0 | template = |
4815 | 0 | lp->class[(int)(lp->resultcache->results[0].classindex)]->template; |
4816 | 0 | else |
4817 | 0 | template = lp->template; |
4818 | |
|
4819 | 0 | if (template == NULL) { |
4820 | 0 | msSetError(MS_WEBERR, "No template for layer %s or it's classes.", |
4821 | 0 | "msReturnNestedTemplateQuery()", lp->name); |
4822 | 0 | return MS_FAILURE; |
4823 | 0 | } |
4824 | | |
4825 | 0 | if (TEMPLATE_TYPE(template) == MS_URL) { |
4826 | 0 | mapserv->resultlayer = lp; |
4827 | |
|
4828 | | #if 0 |
4829 | | status = msLayerOpen(lp); |
4830 | | if(status != MS_SUCCESS) return status; |
4831 | | |
4832 | | status = msLayerGetItems(lp); /* retrieve all the item names */ |
4833 | | if(status != MS_SUCCESS) return status; |
4834 | | #endif |
4835 | |
|
4836 | 0 | status = msLayerGetShape(lp, &(mapserv->resultshape), |
4837 | 0 | &(lp->resultcache->results[0])); |
4838 | 0 | if (status != MS_SUCCESS) |
4839 | 0 | return status; |
4840 | | |
4841 | 0 | if (lp->numjoins > 0) { |
4842 | 0 | for (k = 0; k < lp->numjoins; k++) { |
4843 | 0 | status = msJoinConnect(lp, &(lp->joins[k])); |
4844 | 0 | if (status != MS_SUCCESS) |
4845 | 0 | return status; |
4846 | | |
4847 | 0 | msJoinPrepare(&(lp->joins[k]), &(mapserv->resultshape)); |
4848 | 0 | msJoinNext(&(lp->joins[k])); /* fetch the first row */ |
4849 | 0 | } |
4850 | 0 | } |
4851 | | |
4852 | 0 | if (papszBuffer == NULL) { |
4853 | 0 | if (msReturnURL(mapserv, template, QUERY) != MS_SUCCESS) |
4854 | 0 | return MS_FAILURE; |
4855 | 0 | } |
4856 | | |
4857 | 0 | msFreeShape(&(mapserv->resultshape)); |
4858 | | /* msLayerClose(lp); */ |
4859 | 0 | mapserv->resultlayer = NULL; |
4860 | |
|
4861 | 0 | return MS_SUCCESS; |
4862 | 0 | } |
4863 | 0 | } |
4864 | 0 | } |
4865 | | |
4866 | | /* |
4867 | | ** Now we know we're making a template sandwich |
4868 | | */ |
4869 | 0 | mapserv->NR = mapserv->NL = 0; |
4870 | 0 | for (i = 0; i < mapserv->map->numlayers; i++) { /* compute some totals */ |
4871 | 0 | lp = (GET_LAYER(mapserv->map, i)); |
4872 | |
|
4873 | 0 | if (!lp->resultcache) |
4874 | 0 | continue; |
4875 | | |
4876 | 0 | if (lp->resultcache->numresults > 0) { |
4877 | 0 | mapserv->NL++; |
4878 | 0 | mapserv->NR += lp->resultcache->numresults; |
4879 | 0 | } |
4880 | 0 | } |
4881 | | |
4882 | | /* |
4883 | | ** Is this step really necessary for buffered output? Legend and browse |
4884 | | *templates don't deal with mime-types |
4885 | | ** so why should this. Note that new-style templates don't buffer the |
4886 | | *mime-type either. |
4887 | | */ |
4888 | 0 | if (papszBuffer && mapserv->sendheaders) { |
4889 | 0 | snprintf(buffer, sizeof(buffer), "Content-Type: %s%c%c", pszMimeType, 10, |
4890 | 0 | 10); |
4891 | 0 | if (nBufferSize <= (int)(nCurrentSize + strlen(buffer) + 1)) { |
4892 | 0 | nExpandBuffer++; |
4893 | 0 | (*papszBuffer) = (char *)msSmallRealloc( |
4894 | 0 | (*papszBuffer), MS_TEMPLATE_BUFFER * nExpandBuffer); |
4895 | 0 | nBufferSize = MS_TEMPLATE_BUFFER * nExpandBuffer; |
4896 | 0 | } |
4897 | 0 | strcat((*papszBuffer), buffer); |
4898 | 0 | nCurrentSize += strlen(buffer); |
4899 | 0 | } else if (mapserv->sendheaders) { |
4900 | 0 | msIO_setHeader("Content-Type", "%s", pszMimeType); |
4901 | 0 | msIO_sendHeaders(); |
4902 | 0 | } |
4903 | |
|
4904 | 0 | if (mapserv->map->web.header) { |
4905 | 0 | if (msReturnPage(mapserv, mapserv->map->web.header, BROWSE, papszBuffer) != |
4906 | 0 | MS_SUCCESS) |
4907 | 0 | return MS_FAILURE; |
4908 | 0 | } |
4909 | | |
4910 | 0 | mapserv->RN = 1; /* overall result number */ |
4911 | 0 | for (i = 0; i < mapserv->map->numlayers; i++) { |
4912 | 0 | mapserv->resultlayer = lp = |
4913 | 0 | (GET_LAYER(mapserv->map, mapserv->map->layerorder[i])); |
4914 | |
|
4915 | 0 | if (!lp->resultcache) |
4916 | 0 | continue; |
4917 | 0 | if (lp->resultcache->numresults <= 0) |
4918 | 0 | continue; |
4919 | | |
4920 | 0 | mapserv->NLR = lp->resultcache->numresults; |
4921 | |
|
4922 | | #if 0 |
4923 | | status = msLayerOpen(lp); /* open this layer */ |
4924 | | if(status != MS_SUCCESS) return status; |
4925 | | |
4926 | | status = msLayerGetItems(lp); /* retrieve all the item names */ |
4927 | | if(status != MS_SUCCESS) return status; |
4928 | | #endif |
4929 | |
|
4930 | 0 | if (lp->numjoins > 0) { /* open any necessary JOINs here */ |
4931 | 0 | for (k = 0; k < lp->numjoins; k++) { |
4932 | 0 | status = msJoinConnect(lp, &(lp->joins[k])); |
4933 | 0 | if (status != MS_SUCCESS) |
4934 | 0 | return status; |
4935 | 0 | } |
4936 | 0 | } |
4937 | | |
4938 | 0 | if (lp->header) { |
4939 | 0 | if (msReturnPage(mapserv, lp->header, BROWSE, papszBuffer) != MS_SUCCESS) |
4940 | 0 | return MS_FAILURE; |
4941 | 0 | } |
4942 | | |
4943 | 0 | mapserv->LRN = 1; /* layer result number */ |
4944 | 0 | for (j = 0; j < lp->resultcache->numresults; j++) { |
4945 | 0 | status = msLayerGetShape(lp, &(mapserv->resultshape), |
4946 | 0 | &(lp->resultcache->results[j])); |
4947 | 0 | if (status != MS_SUCCESS) |
4948 | 0 | return status; |
4949 | | |
4950 | | /* prepare any necessary JOINs here (one-to-one only) */ |
4951 | 0 | if (lp->numjoins > 0) { |
4952 | 0 | for (k = 0; k < lp->numjoins; k++) { |
4953 | 0 | if (lp->joins[k].type == MS_JOIN_ONE_TO_ONE) { |
4954 | 0 | msJoinPrepare(&(lp->joins[k]), &(mapserv->resultshape)); |
4955 | 0 | msJoinNext(&(lp->joins[k])); /* fetch the first row */ |
4956 | 0 | } |
4957 | 0 | } |
4958 | 0 | } |
4959 | |
|
4960 | 0 | if (lp->resultcache->results[j].classindex >= 0 && |
4961 | 0 | lp->class[(int)(lp->resultcache->results[j].classindex)] |
4962 | 0 | -> template) |
4963 | 0 | template = |
4964 | 0 | lp->class[(int)(lp->resultcache->results[j].classindex)]->template; |
4965 | 0 | else |
4966 | 0 | template = lp->template; |
4967 | |
|
4968 | 0 | if (msReturnPage(mapserv, template, QUERY, papszBuffer) != MS_SUCCESS) { |
4969 | 0 | msFreeShape(&(mapserv->resultshape)); |
4970 | 0 | return MS_FAILURE; |
4971 | 0 | } |
4972 | | |
4973 | 0 | msFreeShape(&(mapserv->resultshape)); /* init too */ |
4974 | |
|
4975 | 0 | mapserv->RN++; /* increment counters */ |
4976 | 0 | mapserv->LRN++; |
4977 | 0 | } |
4978 | | |
4979 | 0 | if (lp->footer) { |
4980 | 0 | if (msReturnPage(mapserv, lp->footer, BROWSE, papszBuffer) != MS_SUCCESS) |
4981 | 0 | return MS_FAILURE; |
4982 | 0 | } |
4983 | | |
4984 | | /* msLayerClose(lp); */ |
4985 | 0 | mapserv->resultlayer = NULL; |
4986 | 0 | } |
4987 | | |
4988 | 0 | if (mapserv->map->web.footer) |
4989 | 0 | return msReturnPage(mapserv, mapserv->map->web.footer, BROWSE, papszBuffer); |
4990 | | |
4991 | 0 | return MS_SUCCESS; |
4992 | 0 | } |
4993 | | |
4994 | 0 | int msReturnOpenLayersPage(mapservObj *mapserv) { |
4995 | 0 | int i; |
4996 | 0 | char *buffer = NULL, *layer = NULL; |
4997 | 0 | const char *tmpUrl = NULL; |
4998 | 0 | const char *openlayersUrl = olUrl; |
4999 | 0 | const char *openlayersCssUrl = olCssUrl; |
5000 | 0 | char *projection = NULL; |
5001 | 0 | char *format = NULL; |
5002 | | |
5003 | | /* 2 CGI parameters are used in the template. we need to transform them |
5004 | | * to be sure the case match during the template processing. We also |
5005 | | * need to search the SRS/CRS parameter to get the projection info. OGC |
5006 | | * services version >= 1.3.0 uses CRS rather than SRS */ |
5007 | 0 | for (i = 0; i < mapserv->request->NumParams; i++) { |
5008 | 0 | if ((strcasecmp(mapserv->request->ParamNames[i], "SRS") == 0) || |
5009 | 0 | (strcasecmp(mapserv->request->ParamNames[i], "CRS") == 0)) { |
5010 | 0 | projection = mapserv->request->ParamValues[i]; |
5011 | 0 | } else if (strcasecmp(mapserv->request->ParamNames[i], "LAYERS") == 0) { |
5012 | 0 | free(mapserv->request->ParamNames[i]); |
5013 | 0 | mapserv->request->ParamNames[i] = msStrdup("LAYERS"); |
5014 | 0 | } else if (strcasecmp(mapserv->request->ParamNames[i], "VERSION") == 0) { |
5015 | 0 | free(mapserv->request->ParamNames[i]); |
5016 | 0 | mapserv->request->ParamNames[i] = msStrdup("VERSION"); |
5017 | 0 | } |
5018 | 0 | } |
5019 | 0 | if (mapserv->map->outputformat->mimetype && |
5020 | 0 | *mapserv->map->outputformat->mimetype) { |
5021 | 0 | format = mapserv->map->outputformat->mimetype; |
5022 | 0 | } |
5023 | | |
5024 | | /* check if the environment variable or config MS_OPENLAYERS_JS_URL is set */ |
5025 | 0 | tmpUrl = msGetConfigOption(mapserv->map, "MS_OPENLAYERS_JS_URL"); |
5026 | 0 | if (tmpUrl == NULL) |
5027 | 0 | tmpUrl = CPLGetConfigOption("MS_OPENLAYERS_JS_URL", NULL); |
5028 | |
|
5029 | 0 | if (tmpUrl) |
5030 | 0 | openlayersUrl = tmpUrl; |
5031 | | |
5032 | | /* now do the same for the MS_OPENLAYERS_CSS_URL */ |
5033 | 0 | tmpUrl = msGetConfigOption(mapserv->map, "MS_OPENLAYERS_CSS_URL"); |
5034 | 0 | if (tmpUrl == NULL) |
5035 | 0 | tmpUrl = CPLGetConfigOption("MS_OPENLAYERS_CSS_URL", NULL); |
5036 | |
|
5037 | 0 | if (tmpUrl) |
5038 | 0 | openlayersCssUrl = tmpUrl; |
5039 | |
|
5040 | 0 | if (mapserv->Mode == BROWSE) { |
5041 | 0 | layer = processLine(mapserv, olLayerMapServerTag, NULL, BROWSE); |
5042 | 0 | } else |
5043 | 0 | layer = processLine(mapserv, olLayerWMSTag, NULL, BROWSE); |
5044 | |
|
5045 | 0 | buffer = processLine(mapserv, olTemplate, NULL, BROWSE); |
5046 | 0 | buffer = msReplaceSubstring(buffer, "[openlayers_js_url]", openlayersUrl); |
5047 | 0 | buffer = msReplaceSubstring(buffer, "[openlayers_css_url]", openlayersCssUrl); |
5048 | 0 | buffer = msReplaceSubstring(buffer, "[openlayers_layer]", layer); |
5049 | 0 | if (projection) |
5050 | 0 | buffer = msReplaceSubstring(buffer, "[openlayers_projection]", projection); |
5051 | 0 | if (format) |
5052 | 0 | buffer = msReplaceSubstring(buffer, "[openlayers_format]", format); |
5053 | 0 | else |
5054 | 0 | buffer = msReplaceSubstring(buffer, "[openlayers_format]", "image/png"); |
5055 | 0 | msIO_fwrite(buffer, strlen(buffer), 1, stdout); |
5056 | 0 | free(layer); |
5057 | 0 | free(buffer); |
5058 | |
|
5059 | 0 | return MS_SUCCESS; |
5060 | 0 | } |
5061 | | |
5062 | 0 | mapservObj *msAllocMapServObj() { |
5063 | 0 | mapservObj *mapserv = msSmallMalloc(sizeof(mapservObj)); |
5064 | |
|
5065 | 0 | mapserv->savemap = MS_FALSE; |
5066 | 0 | mapserv->savequery = MS_FALSE; /* should the query and/or map be saved */ |
5067 | |
|
5068 | 0 | mapserv->sendheaders = MS_TRUE; |
5069 | |
|
5070 | 0 | mapserv->request = msAllocCgiObj(); |
5071 | |
|
5072 | 0 | mapserv->map = NULL; |
5073 | |
|
5074 | 0 | mapserv->NumLayers = 0; /* number of layers specified by a user */ |
5075 | 0 | mapserv->MaxLayers = 0; /* allocated size of Layers[] array */ |
5076 | 0 | mapserv->Layers = NULL; |
5077 | |
|
5078 | 0 | mapserv->icon = NULL; |
5079 | |
|
5080 | 0 | mapserv->RawExt.minx = -1; |
5081 | 0 | mapserv->RawExt.miny = -1; |
5082 | 0 | mapserv->RawExt.maxx = -1; |
5083 | 0 | mapserv->RawExt.maxy = -1; |
5084 | |
|
5085 | 0 | mapserv->fZoom = 1; |
5086 | 0 | mapserv->Zoom = 1; /* default for browsing */ |
5087 | |
|
5088 | 0 | mapserv->resultlayer = NULL; |
5089 | |
|
5090 | 0 | mapserv->UseShapes = MS_FALSE; |
5091 | |
|
5092 | 0 | mapserv->mappnt.x = -1; |
5093 | 0 | mapserv->mappnt.y = -1; |
5094 | |
|
5095 | 0 | mapserv->ZoomDirection = |
5096 | 0 | 0; /* whether zooming in or out, default is pan or 0 */ |
5097 | |
|
5098 | 0 | mapserv->Mode = BROWSE; /* can be BROWSE, QUERY, etc. */ |
5099 | |
|
5100 | 0 | sprintf(mapserv->Id, "%ld%d", (long)time(NULL), (int)getpid()); |
5101 | |
|
5102 | 0 | mapserv->CoordSource = NONE; |
5103 | 0 | mapserv->ScaleDenom = 0; |
5104 | |
|
5105 | 0 | mapserv->ImgRows = -1; |
5106 | 0 | mapserv->ImgCols = -1; |
5107 | |
|
5108 | 0 | mapserv->ImgExt.minx = -1; |
5109 | 0 | mapserv->ImgExt.miny = -1; |
5110 | 0 | mapserv->ImgExt.maxx = -1; |
5111 | 0 | mapserv->ImgExt.maxy = -1; |
5112 | |
|
5113 | 0 | mapserv->ImgBox.minx = -1; |
5114 | 0 | mapserv->ImgBox.miny = -1; |
5115 | 0 | mapserv->ImgBox.maxx = -1; |
5116 | 0 | mapserv->ImgBox.maxy = -1; |
5117 | |
|
5118 | 0 | mapserv->RefPnt.x = -1; |
5119 | 0 | mapserv->RefPnt.y = -1; |
5120 | 0 | mapserv->ImgPnt.x = -1; |
5121 | 0 | mapserv->ImgPnt.y = -1; |
5122 | |
|
5123 | 0 | mapserv->Buffer = 0; |
5124 | | |
5125 | | /* |
5126 | | ** variables for multiple query results processing |
5127 | | */ |
5128 | 0 | mapserv->RN = 0; /* overall result number */ |
5129 | 0 | mapserv->LRN = 0; /* result number within a layer */ |
5130 | 0 | mapserv->NL = 0; /* total number of layers with results */ |
5131 | 0 | mapserv->NR = 0; /* total number or results */ |
5132 | 0 | mapserv->NLR = 0; /* number of results in a layer */ |
5133 | |
|
5134 | 0 | mapserv->SearchMap = |
5135 | 0 | MS_FALSE; /* apply pan/zoom BEFORE doing the query (e.g. query the output |
5136 | | image rather than the input image) */ |
5137 | |
|
5138 | 0 | mapserv->QueryFile = NULL; |
5139 | 0 | mapserv->QueryLayer = NULL; |
5140 | 0 | mapserv->SelectLayer = NULL; |
5141 | 0 | mapserv->QueryLayerIndex = -1; |
5142 | 0 | mapserv->SelectLayerIndex = -1; |
5143 | 0 | mapserv->QueryItem = NULL; |
5144 | 0 | mapserv->QueryString = NULL; |
5145 | 0 | mapserv->ShapeIndex = -1; |
5146 | 0 | mapserv->TileIndex = -1; |
5147 | 0 | mapserv->TileMode = TILE_GMAP; |
5148 | 0 | mapserv->TileCoords = NULL; |
5149 | 0 | mapserv->TileWidth = -1; |
5150 | 0 | mapserv->TileHeight = -1; |
5151 | 0 | mapserv->QueryCoordSource = NONE; |
5152 | 0 | mapserv->ZoomSize = 0; /* zoom absolute magnitude (i.e. > 0) */ |
5153 | |
|
5154 | 0 | mapserv->hittest = NULL; |
5155 | |
|
5156 | 0 | return mapserv; |
5157 | 0 | } |
5158 | | |
5159 | 0 | void msFreeMapServObj(mapservObj *mapserv) { |
5160 | 0 | int i; |
5161 | |
|
5162 | 0 | if (mapserv) { |
5163 | 0 | if (mapserv->map) { |
5164 | 0 | if (mapserv->hittest) { |
5165 | 0 | freeMapHitTests(mapserv->map, mapserv->hittest); |
5166 | 0 | free(mapserv->hittest); |
5167 | 0 | } |
5168 | 0 | msFreeMap(mapserv->map); |
5169 | 0 | mapserv->map = NULL; |
5170 | 0 | } |
5171 | |
|
5172 | 0 | if (mapserv->request) { |
5173 | 0 | msFreeCgiObj(mapserv->request); |
5174 | 0 | mapserv->request = NULL; |
5175 | 0 | } |
5176 | |
|
5177 | 0 | for (i = 0; i < mapserv->NumLayers; i++) |
5178 | 0 | msFree(mapserv->Layers[i]); |
5179 | 0 | msFree(mapserv->Layers); |
5180 | |
|
5181 | 0 | msFree(mapserv->icon); |
5182 | |
|
5183 | 0 | msFree(mapserv->QueryItem); |
5184 | 0 | msFree(mapserv->QueryString); |
5185 | 0 | msFree(mapserv->QueryLayer); |
5186 | 0 | msFree(mapserv->SelectLayer); |
5187 | 0 | msFree(mapserv->QueryFile); |
5188 | |
|
5189 | 0 | msFree(mapserv->TileCoords); |
5190 | |
|
5191 | 0 | msFree(mapserv); |
5192 | 0 | } |
5193 | 0 | } |
5194 | | |
5195 | | /* |
5196 | | ** Ensure there is at least one free entry in the Layers array. |
5197 | | ** |
5198 | | ** This function is safe to use for the initial allocation of the Layers[] |
5199 | | ** array as well (i.e. when MaxLayers==0 and Layers==NULL) |
5200 | | ** |
5201 | | ** Returns MS_SUCCESS/MS_FAILURE |
5202 | | */ |
5203 | 0 | int msGrowMapservLayers(mapservObj *mapserv) { |
5204 | | /* Do we need to increase the size of Layers[] by MS_LAYER_ALLOCSIZE? */ |
5205 | 0 | if (mapserv->NumLayers == mapserv->MaxLayers) { |
5206 | 0 | int i; |
5207 | |
|
5208 | 0 | if (mapserv->MaxLayers == 0) { |
5209 | | /* initial allocation of array */ |
5210 | 0 | mapserv->MaxLayers += MS_LAYER_ALLOCSIZE; |
5211 | 0 | mapserv->NumLayers = 0; |
5212 | 0 | mapserv->Layers = |
5213 | 0 | (char **)msSmallMalloc(mapserv->MaxLayers * sizeof(char *)); |
5214 | 0 | } else { |
5215 | | /* realloc existing array */ |
5216 | 0 | mapserv->MaxLayers += MS_LAYER_ALLOCSIZE; |
5217 | 0 | mapserv->Layers = (char **)msSmallRealloc( |
5218 | 0 | mapserv->Layers, mapserv->MaxLayers * sizeof(char *)); |
5219 | 0 | } |
5220 | |
|
5221 | 0 | if (mapserv->Layers == NULL) { |
5222 | 0 | msSetError(MS_MEMERR, "Failed to allocate memory for Layers array.", |
5223 | 0 | "msGrowMappservLayers()"); |
5224 | 0 | return MS_FAILURE; |
5225 | 0 | } |
5226 | | |
5227 | 0 | for (i = mapserv->NumLayers; i < mapserv->MaxLayers; i++) { |
5228 | 0 | mapserv->Layers[i] = NULL; |
5229 | 0 | } |
5230 | 0 | } |
5231 | | |
5232 | 0 | return MS_SUCCESS; |
5233 | 0 | } |
5234 | | |
5235 | | /* |
5236 | | ** Utility function to generate map, legend, scalebar and reference images. |
5237 | | ** |
5238 | | ** Parameters: |
5239 | | ** - mapserv: mapserv object (used to extract the map object). |
5240 | | ** - bQueryMap: if set to TRUE a query map will be created instead of a |
5241 | | *regular map. |
5242 | | ** - bReturnOnError: if set to TRUE, the function will return on the first |
5243 | | *error, else it will try to generate all the images. |
5244 | | */ |
5245 | 0 | int msGenerateImages(mapservObj *mapserv, int bQueryMap, int bReturnOnError) { |
5246 | 0 | char buffer[1024]; |
5247 | |
|
5248 | 0 | if (mapserv) { |
5249 | | |
5250 | | /* render the map OR query map */ |
5251 | 0 | if ((!bQueryMap && mapserv->map->status == MS_ON) || |
5252 | 0 | (bQueryMap && mapserv->map->querymap.status == MS_ON)) { |
5253 | 0 | imageObj *image = NULL; |
5254 | |
|
5255 | 0 | image = msDrawMap(mapserv->map, bQueryMap); |
5256 | 0 | if (image) { |
5257 | 0 | snprintf(buffer, sizeof(buffer), "%s%s%s.%s", |
5258 | 0 | mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, |
5259 | 0 | MS_IMAGE_EXTENSION(mapserv->map->outputformat)); |
5260 | |
|
5261 | 0 | if (msSaveImage(mapserv->map, image, buffer) != MS_SUCCESS && |
5262 | 0 | bReturnOnError) { |
5263 | 0 | msFreeImage(image); |
5264 | 0 | return MS_FAILURE; |
5265 | 0 | } |
5266 | 0 | msFreeImage(image); |
5267 | 0 | } else if (bReturnOnError) |
5268 | 0 | return MS_FAILURE; |
5269 | 0 | } |
5270 | | |
5271 | | /* render the legend */ |
5272 | 0 | if (mapserv->map->legend.status == MS_ON) { |
5273 | 0 | imageObj *image = NULL; |
5274 | 0 | image = msDrawLegend(mapserv->map, MS_FALSE, NULL); |
5275 | 0 | if (image) { |
5276 | 0 | snprintf(buffer, sizeof(buffer), "%s%sleg%s.%s", |
5277 | 0 | mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, |
5278 | 0 | MS_IMAGE_EXTENSION(mapserv->map->outputformat)); |
5279 | |
|
5280 | 0 | if (msSaveImage(mapserv->map, image, buffer) != MS_SUCCESS && |
5281 | 0 | bReturnOnError) { |
5282 | 0 | msFreeImage(image); |
5283 | 0 | return MS_FAILURE; |
5284 | 0 | } |
5285 | 0 | msFreeImage(image); |
5286 | 0 | } else if (bReturnOnError) |
5287 | 0 | return MS_FAILURE; |
5288 | 0 | } |
5289 | | |
5290 | | /* render the scalebar */ |
5291 | 0 | if (mapserv->map->scalebar.status == MS_ON) { |
5292 | 0 | imageObj *image = NULL; |
5293 | 0 | image = msDrawScalebar(mapserv->map); |
5294 | 0 | if (image) { |
5295 | 0 | snprintf(buffer, sizeof(buffer), "%s%ssb%s.%s", |
5296 | 0 | mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, |
5297 | 0 | MS_IMAGE_EXTENSION(mapserv->map->outputformat)); |
5298 | 0 | if (msSaveImage(mapserv->map, image, buffer) != MS_SUCCESS && |
5299 | 0 | bReturnOnError) { |
5300 | 0 | msFreeImage(image); |
5301 | 0 | return MS_FAILURE; |
5302 | 0 | } |
5303 | 0 | msFreeImage(image); |
5304 | 0 | } else if (bReturnOnError) |
5305 | 0 | return MS_FAILURE; |
5306 | 0 | } |
5307 | | |
5308 | | /* render the reference map */ |
5309 | 0 | if (mapserv->map->reference.status == MS_ON) { |
5310 | 0 | imageObj *image; |
5311 | 0 | image = msDrawReferenceMap(mapserv->map); |
5312 | 0 | if (image) { |
5313 | 0 | snprintf(buffer, sizeof(buffer), "%s%sref%s.%s", |
5314 | 0 | mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, |
5315 | 0 | MS_IMAGE_EXTENSION(mapserv->map->outputformat)); |
5316 | 0 | if (msSaveImage(mapserv->map, image, buffer) != MS_SUCCESS && |
5317 | 0 | bReturnOnError) { |
5318 | 0 | msFreeImage(image); |
5319 | 0 | return MS_FAILURE; |
5320 | 0 | } |
5321 | 0 | msFreeImage(image); |
5322 | 0 | } else if (bReturnOnError) |
5323 | 0 | return MS_FAILURE; |
5324 | 0 | } |
5325 | 0 | } |
5326 | | |
5327 | 0 | return MS_SUCCESS; |
5328 | 0 | } |
5329 | | |
5330 | | /* |
5331 | | ** Utility function to open a template file, process it and |
5332 | | ** and return into a buffer the processed template. Uses the |
5333 | | ** template file from the web object. Returns NULL if there is |
5334 | | ** an error. |
5335 | | */ |
5336 | | char *msProcessTemplate(mapObj *map, int bGenerateImages, char **names, |
5337 | 0 | char **values, int numentries) { |
5338 | 0 | char *pszBuffer = NULL; |
5339 | |
|
5340 | 0 | if (map) { |
5341 | | |
5342 | | /* Initialize object and set appropriate defaults. */ |
5343 | 0 | mapservObj *mapserv = NULL; |
5344 | 0 | mapserv = msAllocMapServObj(); |
5345 | |
|
5346 | 0 | mapserv->map = map; |
5347 | 0 | mapserv->Mode = BROWSE; |
5348 | |
|
5349 | 0 | if (names && values && numentries > 0) { |
5350 | 0 | msFreeCharArray(mapserv->request->ParamNames, |
5351 | 0 | mapserv->request->NumParams); |
5352 | 0 | msFreeCharArray(mapserv->request->ParamValues, |
5353 | 0 | mapserv->request->NumParams); |
5354 | 0 | mapserv->request->ParamNames = names; |
5355 | 0 | mapserv->request->ParamValues = values; |
5356 | 0 | mapserv->request->NumParams = numentries; |
5357 | 0 | } |
5358 | | |
5359 | | /* |
5360 | | ** ISSUE/TODO : some of the name/values should be extracted and |
5361 | | ** processed (ex imgext, layers, ...) as it is done in function |
5362 | | ** loadform. |
5363 | | */ |
5364 | |
|
5365 | 0 | if (bGenerateImages) |
5366 | 0 | msGenerateImages(mapserv, MS_FALSE, MS_FALSE); |
5367 | | |
5368 | | /* |
5369 | | ** Process the template. |
5370 | | ** |
5371 | | ** TODO : use web minscaledenom/maxscaledenom depending on the scale. |
5372 | | */ |
5373 | 0 | if (msReturnPage(mapserv, mapserv->map->web.template, BROWSE, &pszBuffer) != |
5374 | 0 | MS_SUCCESS) { |
5375 | 0 | msFree(pszBuffer); |
5376 | 0 | pszBuffer = NULL; |
5377 | 0 | } |
5378 | | |
5379 | | /* Don't free the map and names and values arrays since they were passed by |
5380 | | * reference. */ |
5381 | 0 | mapserv->map = NULL; |
5382 | 0 | mapserv->request->ParamNames = mapserv->request->ParamValues = NULL; |
5383 | 0 | mapserv->request->NumParams = 0; |
5384 | 0 | msFreeMapServObj(mapserv); |
5385 | 0 | } |
5386 | |
|
5387 | 0 | return pszBuffer; |
5388 | 0 | } |
5389 | | |
5390 | | /* |
5391 | | ** Utility method to process the legend template. |
5392 | | */ |
5393 | | char *msProcessLegendTemplate(mapObj *map, char **names, char **values, |
5394 | 0 | int numentries) { |
5395 | 0 | char *pszOutBuf = NULL; |
5396 | |
|
5397 | 0 | if (map && map->legend.template) { |
5398 | | |
5399 | | /* Initialize object and set appropriate defaults. */ |
5400 | 0 | mapservObj *mapserv = NULL; |
5401 | 0 | mapserv = msAllocMapServObj(); |
5402 | |
|
5403 | 0 | mapserv->map = map; |
5404 | 0 | mapserv->Mode = BROWSE; |
5405 | |
|
5406 | 0 | if (names && values && numentries > 0) { |
5407 | 0 | msFreeCharArray(mapserv->request->ParamNames, |
5408 | 0 | mapserv->request->NumParams); |
5409 | 0 | msFreeCharArray(mapserv->request->ParamValues, |
5410 | 0 | mapserv->request->NumParams); |
5411 | 0 | mapserv->request->ParamNames = names; |
5412 | 0 | mapserv->request->ParamValues = values; |
5413 | 0 | mapserv->request->NumParams = numentries; |
5414 | 0 | } |
5415 | |
|
5416 | 0 | pszOutBuf = generateLegendTemplate(mapserv); |
5417 | | |
5418 | | /* Don't free the map and names and values arrays since they were passed by |
5419 | | * reference. */ |
5420 | 0 | mapserv->map = NULL; |
5421 | 0 | mapserv->request->ParamNames = mapserv->request->ParamValues = NULL; |
5422 | 0 | mapserv->request->NumParams = 0; |
5423 | 0 | msFreeMapServObj(mapserv); |
5424 | 0 | } |
5425 | |
|
5426 | 0 | return pszOutBuf; |
5427 | 0 | } |
5428 | | |
5429 | | /* |
5430 | | ** Utility function that process a template file(s) used in the |
5431 | | ** query and return the processed template(s) in a buffer. |
5432 | | */ |
5433 | | char *msProcessQueryTemplate(mapObj *map, int bGenerateImages, char **names, |
5434 | 0 | char **values, int numentries) { |
5435 | 0 | char *pszBuffer = NULL; |
5436 | |
|
5437 | 0 | if (map) { |
5438 | | |
5439 | | /* Initialize object and set appropriate defaults. */ |
5440 | 0 | mapservObj *mapserv = NULL; |
5441 | 0 | mapserv = msAllocMapServObj(); |
5442 | |
|
5443 | 0 | mapserv->map = map; |
5444 | 0 | mapserv->Mode = QUERY; |
5445 | |
|
5446 | 0 | if (names && values && numentries > 0) { |
5447 | 0 | msFreeCharArray(mapserv->request->ParamNames, |
5448 | 0 | mapserv->request->NumParams); |
5449 | 0 | msFreeCharArray(mapserv->request->ParamValues, |
5450 | 0 | mapserv->request->NumParams); |
5451 | 0 | mapserv->request->ParamNames = names; |
5452 | 0 | mapserv->request->ParamValues = values; |
5453 | 0 | mapserv->request->NumParams = numentries; |
5454 | 0 | } |
5455 | |
|
5456 | 0 | if (bGenerateImages) |
5457 | 0 | msGenerateImages(mapserv, MS_TRUE, MS_FALSE); |
5458 | |
|
5459 | 0 | mapserv->sendheaders = MS_FALSE; |
5460 | 0 | IGNORE_RET_VAL(msReturnTemplateQuery(mapserv, mapserv->map->web.queryformat, |
5461 | 0 | &pszBuffer)); |
5462 | |
|
5463 | 0 | mapserv->map = NULL; |
5464 | 0 | mapserv->request->ParamNames = mapserv->request->ParamValues = NULL; |
5465 | 0 | mapserv->request->NumParams = 0; |
5466 | 0 | msFreeMapServObj(mapserv); |
5467 | 0 | } |
5468 | |
|
5469 | 0 | return pszBuffer; |
5470 | 0 | } |