Coverage Report

Created: 2025-06-13 06:18

/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
}