Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: c921a06a3e
Fetching contributors…

Cannot retrieve contributors at this time

4734 lines (3867 sloc) 163.307 kB
/******************************************************************************
* $id: maptemplate.c 7725 2008-06-21 15:56:58Z sdlime $
*
* Project: MapServer
* Purpose: Various template processing functions.
* Author: Steve Lime and the MapServer team.
*
******************************************************************************
* Copyright (c) 1996-2008 Regents of the University of Minnesota.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies of this Software or works derived from this Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "maptemplate.h"
#include "maphash.h"
#include "mapserver.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <ctype.h>
static char *olUrl = "http://www.mapserver.org/lib/OpenLayers-ms60.js";
static char *olTemplate = \
"<html>\n"
"<head>\n"
" <title>MapServer Simple Viewer</title>\n"
" <script type=\"text/javascript\" src=\"[openlayers_js_url]\"></script>\n"
" </head>\n"
" <body>\n"
" <div style=\"width:[mapwidth]; height:[mapheight]\" id=\"map\"></div>\n"
" <script defer=\"defer\" type=\"text/javascript\">\n"
" var map = new OpenLayers.Map('map',\n"
" {maxExtent: new OpenLayers.Bounds([minx],[miny],[maxx],[maxy]),\n"
" maxResolution: [cellsize]});\n"
" [openlayers_layer];\n"
" map.addLayer(mslayer);\n"
" map.zoomToMaxExtent();\n"
" </script>\n"
"</body>\n"
"</html>";
static char *olLayerMapServerTag = \
"var mslayer = new OpenLayers.Layer.MapServer( \"MapServer Layer\",\n"
" \"[mapserv_onlineresource]\",\n"
" {layers: '[layers]'},\n"
" {singleTile: \"true\", ratio:1} )";
static char *olLayerWMSTag = \
"var mslayer = new OpenLayers.Layer.WMS('MapServer Simple Viewer\',\n"
" '[mapserv_onlineresource]',\n"
" {layers: '[LAYERS]',\n"
" bbox: '[minx],[miny],[maxx],[maxy]',\n"
" width: [mapwidth], height: [mapheight], version: '[VERSION]', format:'[openlayers_format]'},"
" {singleTile: \"true\", ratio:1, projection: '[openlayers_projection]'});\n";
static char *processLine(mapservObj *mapserv, char *instr, FILE *stream, int mode);
static int isValidTemplate(FILE *stream, const char *filename)
{
char buffer[MS_BUFFER_LENGTH];
if(fgets(buffer, MS_BUFFER_LENGTH, stream) != NULL) {
if(!strcasestr(buffer, MS_TEMPLATE_MAGIC_STRING)) {
msSetError(MS_WEBERR, "Missing magic string, %s doesn't look like a MapServer template.", "isValidTemplate()", filename);
return MS_FALSE;
}
}
return MS_TRUE;
}
/*
* Redirect to (only use in CGI)
*
*/
int msRedirect(char *url)
{
msIO_setHeader("Status","302 Found");
msIO_setHeader("Uri",url);
msIO_setHeader("Location",url);
msIO_setHeader("Content-type","text/html");
msIO_sendHeaders();
return MS_SUCCESS;
}
/*
** Sets the map extent under a variety of scenarios.
*/
int setExtent(mapservObj *mapserv)
{
double cellx,celly,cellsize;
switch(mapserv->CoordSource) {
case FROMUSERBOX: /* user passed in a map extent */
break;
case FROMIMGBOX: /* fully interactive web, most likely with java front end */
cellx = MS_CELLSIZE(mapserv->ImgExt.minx, mapserv->ImgExt.maxx, mapserv->ImgCols);
celly = MS_CELLSIZE(mapserv->ImgExt.miny, mapserv->ImgExt.maxy, mapserv->ImgRows);
mapserv->map->extent.minx = MS_IMAGE2MAP_X(mapserv->ImgBox.minx, mapserv->ImgExt.minx, cellx);
mapserv->map->extent.maxx = MS_IMAGE2MAP_X(mapserv->ImgBox.maxx, mapserv->ImgExt.minx, cellx);
mapserv->map->extent.maxy = MS_IMAGE2MAP_Y(mapserv->ImgBox.miny, mapserv->ImgExt.maxy, celly); /* y's are flip flopped because img/map coordinate systems are */
mapserv->map->extent.miny = MS_IMAGE2MAP_Y(mapserv->ImgBox.maxy, mapserv->ImgExt.maxy, celly);
break;
case FROMIMGPNT:
cellx = MS_CELLSIZE(mapserv->ImgExt.minx, mapserv->ImgExt.maxx, mapserv->ImgCols);
celly = MS_CELLSIZE(mapserv->ImgExt.miny, mapserv->ImgExt.maxy, mapserv->ImgRows);
mapserv->mappnt.x = MS_IMAGE2MAP_X(mapserv->ImgPnt.x, mapserv->ImgExt.minx, cellx);
mapserv->mappnt.y = MS_IMAGE2MAP_Y(mapserv->ImgPnt.y, mapserv->ImgExt.maxy, celly);
mapserv->map->extent.minx = mapserv->mappnt.x - .5*((mapserv->ImgExt.maxx - mapserv->ImgExt.minx)/mapserv->fZoom); /* create an extent around that point */
mapserv->map->extent.miny = mapserv->mappnt.y - .5*((mapserv->ImgExt.maxy - mapserv->ImgExt.miny)/mapserv->fZoom);
mapserv->map->extent.maxx = mapserv->mappnt.x + .5*((mapserv->ImgExt.maxx - mapserv->ImgExt.minx)/mapserv->fZoom);
mapserv->map->extent.maxy = mapserv->mappnt.y + .5*((mapserv->ImgExt.maxy - mapserv->ImgExt.miny)/mapserv->fZoom);
break;
case FROMREFPNT:
cellx = MS_CELLSIZE(mapserv->map->reference.extent.minx, mapserv->map->reference.extent.maxx, mapserv->map->reference.width);
celly = MS_CELLSIZE(mapserv->map->reference.extent.miny, mapserv->map->reference.extent.maxy, mapserv->map->reference.height);
mapserv->mappnt.x = MS_IMAGE2MAP_X(mapserv->RefPnt.x, mapserv->map->reference.extent.minx, cellx);
mapserv->mappnt.y = MS_IMAGE2MAP_Y(mapserv->RefPnt.y, mapserv->map->reference.extent.maxy, celly);
mapserv->map->extent.minx = mapserv->mappnt.x - .5*(mapserv->ImgExt.maxx - mapserv->ImgExt.minx); /* create an extent around that point */
mapserv->map->extent.miny = mapserv->mappnt.y - .5*(mapserv->ImgExt.maxy - mapserv->ImgExt.miny);
mapserv->map->extent.maxx = mapserv->mappnt.x + .5*(mapserv->ImgExt.maxx - mapserv->ImgExt.minx);
mapserv->map->extent.maxy = mapserv->mappnt.y + .5*(mapserv->ImgExt.maxy - mapserv->ImgExt.miny);
break;
case FROMBUF:
mapserv->map->extent.minx = mapserv->mappnt.x - mapserv->Buffer; /* create an extent around that point, using the buffer */
mapserv->map->extent.miny = mapserv->mappnt.y - mapserv->Buffer;
mapserv->map->extent.maxx = mapserv->mappnt.x + mapserv->Buffer;
mapserv->map->extent.maxy = mapserv->mappnt.y + mapserv->Buffer;
break;
case FROMSCALE:
cellsize = (mapserv->ScaleDenom/mapserv->map->resolution)/msInchesPerUnit(mapserv->map->units,0); /* user supplied a point and a scale denominator */
mapserv->map->extent.minx = mapserv->mappnt.x - cellsize*(mapserv->map->width-1)/2.0;
mapserv->map->extent.miny = mapserv->mappnt.y - cellsize*(mapserv->map->height-1)/2.0;
mapserv->map->extent.maxx = mapserv->mappnt.x + cellsize*(mapserv->map->width-1)/2.0;
mapserv->map->extent.maxy = mapserv->mappnt.y + cellsize*(mapserv->map->height-1)/2.0;
break;
default: /* use the default in the mapfile if it exists */
if((mapserv->map->extent.minx == mapserv->map->extent.maxx) && (mapserv->map->extent.miny == mapserv->map->extent.maxy)) {
msSetError(MS_WEBERR, "No way to generate map extent.", "mapserv()");
return MS_FAILURE;
}
}
mapserv->RawExt = mapserv->map->extent; /* save unaltered extent */
return MS_SUCCESS;
}
int checkWebExtent(mapservObj *mapserv)
{
return MS_SUCCESS;
}
int checkWebScale(mapservObj *mapserv)
{
int status;
rectObj work_extent = mapserv->map->extent;
mapserv->map->cellsize = msAdjustExtent(&(work_extent), mapserv->map->width, mapserv->map->height); /* we do this cause we need a scale */
if((status = msCalculateScale(work_extent, mapserv->map->units, mapserv->map->width, mapserv->map->height, mapserv->map->resolution, &mapserv->map->scaledenom)) != MS_SUCCESS) return status;
if((mapserv->map->scaledenom < mapserv->map->web.minscaledenom) && (mapserv->map->web.minscaledenom > 0)) {
if(mapserv->map->web.mintemplate) { /* use the template provided */
if(TEMPLATE_TYPE(mapserv->map->web.mintemplate) == MS_FILE) {
if((status = msReturnPage(mapserv, mapserv->map->web.mintemplate, BROWSE, NULL)) != MS_SUCCESS) return status;
} else {
if((status = msReturnURL(mapserv, mapserv->map->web.mintemplate, BROWSE)) != MS_SUCCESS) return status;
}
} else { /* force zoom = 1 (i.e. pan) */
mapserv->fZoom = mapserv->Zoom = 1;
mapserv->ZoomDirection = 0;
mapserv->CoordSource = FROMSCALE;
mapserv->ScaleDenom = mapserv->map->web.minscaledenom;
mapserv->mappnt.x = (mapserv->map->extent.maxx + mapserv->map->extent.minx)/2; /* use center of bad extent */
mapserv->mappnt.y = (mapserv->map->extent.maxy + mapserv->map->extent.miny)/2;
setExtent(mapserv);
mapserv->map->cellsize = msAdjustExtent(&(mapserv->map->extent), mapserv->map->width, mapserv->map->height);
if((status = msCalculateScale(mapserv->map->extent, mapserv->map->units, mapserv->map->width, mapserv->map->height, mapserv->map->resolution, &mapserv->map->scaledenom)) != MS_SUCCESS) return status;
}
} else {
if((mapserv->map->scaledenom > mapserv->map->web.maxscaledenom) && (mapserv->map->web.maxscaledenom > 0)) {
if(mapserv->map->web.maxtemplate) { /* use the template provided */
if(TEMPLATE_TYPE(mapserv->map->web.maxtemplate) == MS_FILE) {
if((status = msReturnPage(mapserv, mapserv->map->web.maxtemplate, BROWSE, NULL)) != MS_SUCCESS) return status;
} else {
if((status = msReturnURL(mapserv, mapserv->map->web.maxtemplate, BROWSE)) != MS_SUCCESS) return status;
}
} else { /* force zoom = 1 (i.e. pan) */
mapserv->fZoom = mapserv->Zoom = 1;
mapserv->ZoomDirection = 0;
mapserv->CoordSource = FROMSCALE;
mapserv->ScaleDenom = mapserv->map->web.maxscaledenom;
mapserv->mappnt.x = (mapserv->map->extent.maxx + mapserv->map->extent.minx)/2; /* use center of bad extent */
mapserv->mappnt.y = (mapserv->map->extent.maxy + mapserv->map->extent.miny)/2;
setExtent(mapserv);
mapserv->map->cellsize = msAdjustExtent(&(mapserv->map->extent), mapserv->map->width, mapserv->map->height);
if((status = msCalculateScale(mapserv->map->extent, mapserv->map->units, mapserv->map->width, mapserv->map->height, mapserv->map->resolution, &mapserv->map->scaledenom)) != MS_SUCCESS) return status;
}
}
}
return MS_SUCCESS;
}
int msReturnTemplateQuery(mapservObj *mapserv, char *queryFormat, char **papszBuffer)
{
imageObj *img = NULL;
int i, status;
outputFormatObj *outputFormat=NULL;
mapObj *map = mapserv->map;
if(!queryFormat) {
msSetError(MS_WEBERR, "Return format/mime-type not specified.", "msReturnTemplateQuery()");
return MS_FAILURE;
}
msApplyDefaultOutputFormats(map);
i = msGetOutputFormatIndex(map, queryFormat); /* queryFormat can be a mime-type or name */
if(i >= 0) outputFormat = map->outputformatlist[i];
if(outputFormat) {
if( MS_RENDERER_PLUGIN(outputFormat) ) {
msInitializeRendererVTable(outputFormat);
}
if( MS_RENDERER_OGR(outputFormat) ) {
if( mapserv != NULL )
checkWebScale(mapserv);
status = msOGRWriteFromQuery(map, outputFormat, mapserv->sendheaders);
return status;
}
if( !MS_RENDERER_TEMPLATE(outputFormat) ) { /* got an image format, return the query results that way */
outputFormatObj *tempOutputFormat = map->outputformat; /* save format */
if( mapserv != NULL )
checkWebScale(mapserv);
map->outputformat = outputFormat; /* override what was given for IMAGETYPE */
img = msDrawMap(map, MS_TRUE);
if(!img) return MS_FAILURE;
map->outputformat = tempOutputFormat; /* restore format */
if(mapserv == NULL || mapserv->sendheaders) {
msIO_setHeader("Content-type", MS_IMAGE_MIME_TYPE(outputFormat));
msIO_sendHeaders();
}
status = msSaveImage(map, img, NULL);
msFreeImage(img);
return status;
}
}
/*
** At this point we know we have a template of some sort, either the new style that references a or the old
** style made up of external files slammed together. Either way we may have to compute a query map and other
** images. We only create support images IF the querymap has status=MS_ON.
*/
if(map->querymap.status && mapserv != NULL ) {
checkWebScale(mapserv);
if(msGenerateImages(mapserv, MS_TRUE, MS_TRUE) != MS_SUCCESS)
return MS_FAILURE;
}
if(outputFormat) {
const char *file = msGetOutputFormatOption( outputFormat, "FILE", NULL );
if(!file) {
msSetError(MS_WEBERR, "Template driver requires \"FILE\" format option be set.", "msReturnTemplateQuery()");
return MS_FAILURE;
}
if(mapserv == NULL || mapserv->sendheaders) {
const char *attachment = msGetOutputFormatOption( outputFormat, "ATTACHMENT", NULL );
if(attachment)
msIO_setHeader("Content-disposition","attachment; filename=%s", attachment);
msIO_setHeader("Content-type", outputFormat->mimetype);
msIO_sendHeaders();
}
if((status = msReturnPage(mapserv, (char *) file, BROWSE, papszBuffer)) != MS_SUCCESS)
return status;
} else {
if((status = msReturnNestedTemplateQuery(mapserv, queryFormat, papszBuffer)) != MS_SUCCESS)
return status;
}
return MS_SUCCESS;
}
/*
** Is a particular layer or group on, that is was it requested explicitly by the user.
*/
int isOn(mapservObj *mapserv, char *name, char *group)
{
int i;
for(i=0; i<mapserv->NumLayers; i++) {
if(name && strcmp(mapserv->Layers[i], name) == 0) return(MS_TRUE);
if(group && strcmp(mapserv->Layers[i], group) == 0) return(MS_TRUE);
}
return(MS_FALSE);
}
/************************************************************************/
/* int sortLayerByOrder(mapObj *map, char* pszOrder) */
/* */
/* sorth the displaying in ascending or descending order. */
/************************************************************************/
int sortLayerByOrder(mapObj *map, char* pszOrder)
{
int *panCurrentOrder = NULL;
int i = 0;
if(!map) {
msSetError(MS_WEBERR, "Invalid pointer.", "sortLayerByOrder()");
return MS_FAILURE;
}
/* ==================================================================== */
/* The flag "ascending" is in fact not useful since the */
/* default ordering is ascending. */
/* ==================================================================== */
/* -------------------------------------------------------------------- */
/* the map->layerorder should be set at this point in the */
/* sortLayerByMetadata. */
/* -------------------------------------------------------------------- */
if(map->layerorder) {
panCurrentOrder = (int*)msSmallMalloc(map->numlayers * sizeof(int));
for (i=0; i<map->numlayers ; i++)
panCurrentOrder[i] = map->layerorder[i];
if(strcasecmp(pszOrder, "DESCENDING") == 0) {
for (i=0; i<map->numlayers; i++)
map->layerorder[i] = panCurrentOrder[map->numlayers-1-i];
}
free(panCurrentOrder);
}
return MS_SUCCESS;
}
/*!
* This function set the map->layerorder
* index order by the metadata collumn name
*/
int sortLayerByMetadata(mapObj *map, char* pszMetadata)
{
int nLegendOrder1;
int nLegendOrder2;
char *pszLegendOrder1;
char *pszLegendOrder2;
int i, j;
int tmp;
if(!map) {
msSetError(MS_WEBERR, "Invalid pointer.", "sortLayerByMetadata()");
return MS_FAILURE;
}
/*
* Initiate to default order (Reverse mapfile order)
*/
if(map->layerorder) {
int *pnLayerOrder;
/* Backup the original layer order to be able to reverse it */
pnLayerOrder = (int*)msSmallMalloc(map->numlayers * sizeof(int));
for (i=0; i<map->numlayers ; i++)
pnLayerOrder[i] = map->layerorder[i];
/* Get a new layerorder array */
free(map->layerorder);
map->layerorder = (int*)msSmallMalloc(map->numlayers * sizeof(int));
/* Reverse the layerorder array */
for (i=0; i<map->numlayers ; i++)
map->layerorder[i] = pnLayerOrder[map->numlayers - i - 1];
free(pnLayerOrder);
} else {
map->layerorder = (int*)msSmallMalloc(map->numlayers * sizeof(int));
for (i=0; i<map->numlayers ; i++)
map->layerorder[i] = map->numlayers - i - 1;
}
if(!pszMetadata)
return MS_SUCCESS;
/*
* Bubble sort algo (not very efficient)
* should implement a kind of quick sort
* alog instead
*/
for (i=0; i<map->numlayers-1; i++) {
for (j=0; j<map->numlayers-1-i; j++) {
pszLegendOrder1 = msLookupHashTable(&(GET_LAYER(map, map->layerorder[j+1])->metadata), pszMetadata);
pszLegendOrder2 = msLookupHashTable(&(GET_LAYER(map, map->layerorder[j])->metadata), pszMetadata);
if(!pszLegendOrder1 || !pszLegendOrder2)
continue;
nLegendOrder1 = atoi(pszLegendOrder1);
nLegendOrder2 = atoi(pszLegendOrder2);
if(nLegendOrder1 < nLegendOrder2) { /* compare the two neighbors */
tmp = map->layerorder[j]; /* swap a[j] and a[j+1] */
map->layerorder[j] = map->layerorder[j+1];
map->layerorder[j+1] = tmp;
}
}
}
return MS_SUCCESS;
}
/*
** This function return a pointer
** at the begining of the first occurence
** of pszTag in pszInstr.
**
** Tag can be [TAG] or [TAG something]
*/
char *findTag(char *pszInstr, char *pszTag)
{
char *pszTag1, *pszStart=NULL;
char *pszTemp;
int done=MS_FALSE;
int length;
if(!pszInstr || !pszTag) {
msSetError(MS_WEBERR, "Invalid pointer.", "findTag()");
return NULL;
}
length = strlen(pszTag) + 1; /* adding [ character to the beginning */
pszTag1 = (char*) msSmallMalloc(length+1);
strcpy(pszTag1, "[");
strcat(pszTag1, pszTag);
pszTemp = pszInstr;
while(!done) {
pszStart = strstr(pszTemp, pszTag1);
if(pszStart == NULL)
done = MS_TRUE; /* tag not found */
else if((*(pszStart+length) == ']' || *(pszStart+length) == ' '))
done = MS_TRUE; /* valid tag */
else
pszTemp += length; /* skip ahead and start over */
}
free(pszTag1);
return pszStart;
}
/*
** This function return a pointer
** to the end of the tag in pszTag
**
** The end of a tag is the next
** non-quoted ']' character.
** Return NULL if not found.
*/
char *findTagEnd(const char *pszTag)
{
char *pszEnd = NULL,
*pszTmp = (char*)pszTag;
while (pszTmp != NULL) {
if (*pszTmp == '"')
pszTmp = strchr(pszTmp+1,'"');
if ((pszTmp == NULL) || (*pszTmp == ']')) {
pszEnd = pszTmp;
pszTmp = NULL;
} else
pszTmp++;
}
return pszEnd;
}
/*
** Return a hashtableobj from instr of all
** arguments. hashtable must be freed by caller.
*/
int getTagArgs(char* pszTag, char* pszInstr, hashTableObj **ppoHashTable)
{
char *pszStart, *pszEnd, *pszArgs;
int nLength;
char **papszArgs, **papszVarVal;
int nArgs, nDummy;
int i;
if(!pszTag || !pszInstr) {
msSetError(MS_WEBERR, "Invalid pointer.", "getTagArgs()");
return MS_FAILURE;
}
/* set position to the begining of tag */
pszStart = findTag(pszInstr, pszTag);
if(pszStart) {
/* find ending position */
pszEnd = findTagEnd(pszStart);
if(pszEnd) {
/* skip the tag name */
pszStart = pszStart + strlen(pszTag) + 1;
/* get length of all args */
nLength = pszEnd - pszStart;
if(nLength > 0) { /* is there arguments ? */
pszArgs = (char*)msSmallMalloc(nLength + 1);
strlcpy(pszArgs, pszStart, nLength+1);
if(!(*ppoHashTable))
*ppoHashTable = msCreateHashTable();
/* put all arguments seperate by space in a hash table */
papszArgs = msStringTokenize(pszArgs, " ", &nArgs, MS_TRUE);
/* msReturnTemplateQuerycheck all argument if they have values */
for (i=0; i<nArgs; i++) {
if(strlen(papszArgs[i]) == 0) continue;
if(strchr(papszArgs[i], '=')) {
papszVarVal = msStringTokenize(papszArgs[i], "=", &nDummy, MS_FALSE);
msInsertHashTable(*ppoHashTable, papszVarVal[0],
papszVarVal[1]);
free(papszVarVal[0]);
free(papszVarVal[1]);
free(papszVarVal);
} else /* no value specified. set it to 1 */
msInsertHashTable(*ppoHashTable, papszArgs[i], "1");
free(papszArgs[i]);
}
free(papszArgs);
free(pszArgs);
}
}
}
return MS_SUCCESS;
}
/*
** Return a substring from instr between [tag] and [/tag]
** char * returned must be freed by caller.
** pszNextInstr will be a pointer at the end of the
** first occurence found.
*/
int getInlineTag(char *pszTag, char *pszInstr, char **pszResult)
{
char *pszStart, *pszEnd=NULL, *pszEndTag, *pszPatIn, *pszPatOut=NULL, *pszTmp;
int nInst=0;
int nLength;
*pszResult = NULL;
if(!pszInstr || !pszTag) {
msSetError(MS_WEBERR, "Invalid pointer.", "getInlineTag()");
return MS_FAILURE;
}
pszEndTag = (char*)msSmallMalloc(strlen(pszTag) + 3);
strcpy(pszEndTag, "[/");
strcat(pszEndTag, pszTag);
/* find start tag */
pszPatIn = findTag(pszInstr, pszTag);
pszPatOut = strstr(pszInstr, pszEndTag);
pszStart = pszPatIn;
pszTmp = pszInstr;
if(pszPatIn) {
do {
if(pszPatIn && pszPatIn < pszPatOut) {
nInst++;
pszTmp = pszPatIn;
}
if(pszPatOut && ((pszPatIn == NULL) || pszPatOut < pszPatIn)) {
pszEnd = pszPatOut;
nInst--;
pszTmp = pszPatOut;
}
pszPatIn = findTag(pszTmp+1, pszTag);
pszPatOut = strstr(pszTmp+1, pszEndTag);
} while (pszTmp != NULL && nInst > 0);
}
if(pszStart && pszEnd) {
/* find end of start tag */
pszStart = strchr(pszStart, ']');
if(pszStart) {
pszStart++;
nLength = pszEnd - pszStart;
if(nLength > 0) {
*pszResult = (char*)msSmallMalloc(nLength + 1);
/* copy string beetween start and end tag */
strlcpy(*pszResult, pszStart, nLength+1);
(*pszResult)[nLength] = '\0';
}
} else {
msSetError(MS_WEBERR, "Malformed [%s] tag.", "getInlineTag()", pszTag);
return MS_FAILURE;
}
}
msFree(pszEndTag);
return MS_SUCCESS;
}
/*!
* this function process all if tag in pszInstr.
* this function return a modified pszInstr.
* ht mus contain all variables needed by the function
* to interpret if expression.
*
* If bLastPass is true then all tests for 'null' values will be
* considered true if the corresponding value is not set.
*/
int processIfTag(char **pszInstr, hashTableObj *ht, int bLastPass)
{
/* char *pszNextInstr = pszInstr; */
char *pszStart, *pszEnd=NULL;
char *pszName, *pszValue, *pszOperator, *pszThen=NULL, *pszHTValue;
char *pszIfTag;
char *pszPatIn=NULL, *pszPatOut=NULL, *pszTmp;
int nInst = 0;
int bEmpty = 0;
int nLength;
hashTableObj *ifArgs=NULL;
if(!*pszInstr) {
msSetError(MS_WEBERR, "Invalid pointer.", "processIfTag()");
return MS_FAILURE;
}
/* find the if start tag */
pszStart = findTag(*pszInstr, "if");
while (pszStart) {
pszPatIn = findTag(pszStart, "if");
pszPatOut = strstr(pszStart, "[/if]");
pszTmp = pszPatIn;
do {
if(pszPatIn && pszPatIn < pszPatOut) {
nInst++;
pszTmp = pszPatIn;
}
if(pszPatOut && ((pszPatIn == NULL) || pszPatOut < pszPatIn)) {
pszEnd = pszPatOut;
nInst--;
pszTmp = pszPatOut;
}
pszPatIn = findTag(pszTmp+1, "if");
pszPatOut = strstr(pszTmp+1, "[/if]");
} while (pszTmp != NULL && nInst > 0);
/* get the then string (if expression is true) */
if(getInlineTag("if", pszStart, &pszThen) != MS_SUCCESS) {
msSetError(MS_WEBERR, "Malformed then if tag.", "processIfTag()");
return MS_FAILURE;
}
/* retrieve if tag args */
if(getTagArgs("if", pszStart, &ifArgs) != MS_SUCCESS) {
msSetError(MS_WEBERR, "Malformed args if tag.", "processIfTag()");
return MS_FAILURE;
}
pszName = msLookupHashTable(ifArgs, "name");
pszValue = msLookupHashTable(ifArgs, "value");
pszOperator = msLookupHashTable(ifArgs, "oper");
if(pszOperator == NULL) /* Default operator if not set is "eq" */
pszOperator = "eq";
bEmpty = 0;
if(pszName) {
/* build the complete if tag ([if all_args]then string[/if]) */
/* to replace if by then string if expression is true */
/* or by a white space if not. */
nLength = pszEnd - pszStart;
pszIfTag = (char*)msSmallMalloc(nLength + 6);
strlcpy(pszIfTag, pszStart, nLength+1);
pszIfTag[nLength] = '\0';
strcat(pszIfTag, "[/if]");
pszHTValue = msLookupHashTable(ht, pszName);
if(strcmp(pszOperator, "neq") == 0) {
if(pszValue && pszHTValue && strcasecmp(pszValue, pszHTValue) != 0) {
*pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen);
} else if(pszHTValue) {
*pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, "");
bEmpty = 1;
}
} else if(strcmp(pszOperator, "eq") == 0) {
if(pszValue && pszHTValue && strcasecmp(pszValue, pszHTValue) == 0) {
*pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen);
} else if(pszHTValue) {
*pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, "");
bEmpty = 1;
}
} else if(strcmp(pszOperator, "isnull") == 0) {
if(pszHTValue != NULL) {
/* We met a non-null value... condition is false */
*pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, "");
bEmpty = 1;
} else if(bLastPass) {
/* On last pass, if value is still null then condition is true */
*pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen);
}
} else if(strcmp(pszOperator, "isset") == 0) {
if(pszHTValue != NULL) {
/* Found a non-null value... condition is true */
*pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen);
} else if(bLastPass) {
/* On last pass, if value still not set then condition is false */
*pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, "");
bEmpty = 1;
}
} else {
msSetError(MS_WEBERR, "Unsupported operator (%s) in if tag.", "processIfTag()", pszOperator);
return MS_FAILURE;
}
if(pszIfTag)
free(pszIfTag);
pszIfTag = NULL;
}
if(pszThen)
free (pszThen);
pszThen=NULL;
msFreeHashTable(ifArgs);
ifArgs=NULL;
/* find the if start tag */
if(bEmpty)
pszStart = findTag(pszStart, "if");
else
pszStart = findTag(pszStart + 1, "if");
}
return MS_SUCCESS;
}
/* Helper function to return the text before the supplied string2 in string1. */
static char *getPreTagText(const char *string1, const char *string2)
{
int n;
char *result, *tmpstr;
if((tmpstr = strstr(string1, string2)) == NULL) return msStrdup(""); /* return an empty string */
n = strlen(string1) - strlen(tmpstr);
result = (char *) msSmallMalloc(n + 1);
strlcpy(result, string1, n+1);
return result;
}
/* Helper function to retunr the text after the supplied string2 in string1. */
static char *getPostTagText(const char *string1, const char *string2)
{
char *tmpstr;
if((tmpstr = strstr(string1, string2)) == NULL) return msStrdup(""); /* return an empty string */
tmpstr += strlen(string2); /* skip string2 */
return msStrdup(tmpstr);
}
/*
** Function to process a [feature ...] tag. This tag can *only* be found within
** a [resultset ...][/resultset] block.
*/
static int processFeatureTag(mapservObj *mapserv, char **line, layerObj *layer)
{
char *preTag, *postTag; /* text before and after the tag */
char *argValue;
char *tag, *tagInstance, *tagStart;
hashTableObj *tagArgs=NULL;
int limit=-1;
char *trimLast=NULL;
int i, j, status;
if(!*line) {
msSetError(MS_WEBERR, "Invalid line pointer.", "processFeatureTag()");
return(MS_FAILURE);
}
tagStart = findTag(*line, "feature");
if(!tagStart) return(MS_SUCCESS); /* OK, just return; */
/* check for any tag arguments */
if(getTagArgs("feature", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE);
if(tagArgs) {
argValue = msLookupHashTable(tagArgs, "limit");
if(argValue) limit = atoi(argValue);
argValue = msLookupHashTable(tagArgs, "trimlast");
if(argValue) trimLast = argValue;
}
if(strstr(*line, "[/feature]") == NULL) { /* we know the closing tag must be here, if not throw an error */
msSetError(MS_WEBERR, "[feature] tag found without closing [/feature].", "processFeatureTag()");
return(MS_FAILURE);
}
if(getInlineTag("feature", *line, &tag) != MS_SUCCESS) {
msSetError(MS_WEBERR, "Malformed feature tag.", "processFeatureTag()");
return MS_FAILURE;
}
preTag = getPreTagText(*line, "[feature");
postTag = getPostTagText(*line, "[/feature]");
/* start rebuilding **line */
free(*line);
*line = preTag;
/* we know the layer has query results or we wouldn't be in this code */
#if 0
status = msLayerOpen(layer); /* open the layer */
if(status != MS_SUCCESS) return status;
status = msLayerGetItems(layer); /* retrieve all the item names */
if(status != MS_SUCCESS) return status;
#endif
if(layer->numjoins > 0) { /* initialize necessary JOINs here */
for(j=0; j<layer->numjoins; j++) {
status = msJoinConnect(layer, &(layer->joins[j]));
if(status != MS_SUCCESS) return status;
}
}
mapserv->LRN = 1; /* layer result counter */
mapserv->resultlayer = layer;
msInitShape(&(mapserv->resultshape));
if(limit == -1) /* return all */
limit = layer->resultcache->numresults;
else
limit = MS_MIN(limit, layer->resultcache->numresults);
for(i=0; i<limit; i++) {
status = msLayerGetShape(layer, &(mapserv->resultshape), &(layer->resultcache->results[i]));
if(status != MS_SUCCESS) return status;
mapserv->resultshape.classindex = msShapeGetClass(layer, layer->map, &mapserv->resultshape, NULL, -1);
if(layer->class[mapserv->resultshape.classindex]->numlabels > 0)
msShapeGetAnnotation(layer, &mapserv->resultshape); // RFC 77 TODO: check return value
/* prepare any necessary JOINs here (one-to-one only) */
if(layer->numjoins > 0) {
for(j=0; j<layer->numjoins; j++) {
if(layer->joins[j].type == MS_JOIN_ONE_TO_ONE) {
msJoinPrepare(&(layer->joins[j]), &(mapserv->resultshape));
msJoinNext(&(layer->joins[j])); /* fetch the first row */
}
}
}
/*
** if necessary trim a few characters off the end of the tag
*/
if(trimLast && (i == limit-1)) {
char *ptr;
if((ptr = strrstr(tag, trimLast)) != NULL)
*ptr = '\0';
}
/* process the tag */
tagInstance = processLine(mapserv, tag, NULL, QUERY); /* do substitutions */
*line = msStringConcatenate(*line, tagInstance); /* grow the line */
free(tagInstance);
msFreeShape(&(mapserv->resultshape)); /* init too */
mapserv->RN++; /* increment counters */
mapserv->LRN++;
}
/* msLayerClose(layer); */
mapserv->resultlayer = NULL; /* necessary? */
*line = msStringConcatenate(*line, postTag);
/*
** clean up
*/
free(postTag);
free(tag);
return(MS_SUCCESS);
}
/*
** Function to process a [resultset ...] tag.
*/
static int processResultSetTag(mapservObj *mapserv, char **line, FILE *stream)
{
char lineBuffer[MS_BUFFER_LENGTH];
int foundTagEnd;
char *preTag, *postTag; /* text before and after the tag */
char *tag, *tagStart;
hashTableObj *tagArgs=NULL;
char *layerName=NULL;
char *nodata=NULL;
int layerIndex=-1;
layerObj *lp;
if(!*line) {
msSetError(MS_WEBERR, "Invalid line pointer.", "processResultSetTag()");
return(MS_FAILURE);
}
tagStart = findTag(*line, "resultset");
if(!tagStart) return(MS_SUCCESS); /* OK, just return; */
while (tagStart) {
/* initialize the tag arguments */
layerName = NULL;
/* check for any tag arguments */
if(getTagArgs("resultset", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE);
if(tagArgs) {
layerName = msLookupHashTable(tagArgs, "layer");
nodata = msLookupHashTable(tagArgs, "nodata");
}
if(!layerName) {
msSetError(MS_WEBERR, "[resultset] tag missing required 'layer' argument.", "processResultSetTag()");
return(MS_FAILURE);
}
layerIndex = msGetLayerIndex(mapserv->map, layerName);
if(layerIndex>=mapserv->map->numlayers || layerIndex<0) {
msSetError(MS_MISCERR, "Layer named '%s' does not exist.", "processResultSetTag()", layerName);
return MS_FAILURE;
}
lp = GET_LAYER(mapserv->map, layerIndex);
if(strstr(*line, "[/resultset]") == NULL) { /* read ahead */
if(!stream) {
msSetError(MS_WEBERR, "Invalid file pointer.", "processResultSetTag()");
return(MS_FAILURE);
}
foundTagEnd = MS_FALSE;
while(!foundTagEnd) {
if(fgets(lineBuffer, MS_BUFFER_LENGTH, stream) != NULL) {
*line = msStringConcatenate(*line, lineBuffer);
if(strstr(*line, "[/resultset]") != NULL)
foundTagEnd = MS_TRUE;
} else
break; /* ran out of file */
}
if(foundTagEnd == MS_FALSE) {
msSetError(MS_WEBERR, "[resultset] tag found without closing [/resultset].", "processResultSetTag()");
return(MS_FAILURE);
}
}
if(getInlineTag("resultset", *line, &tag) != MS_SUCCESS) {
msSetError(MS_WEBERR, "Malformed resultset tag.", "processResultSetTag()");
return MS_FAILURE;
}
preTag = getPreTagText(*line, "[resultset"); /* TODO: need to handle tags in these */
postTag = getPostTagText(*line, "[/resultset]");
/* start rebuilding **line */
free(*line);
*line = preTag;
if(lp->resultcache && lp->resultcache->numresults > 0) {
/* probably will need a while-loop here to handle multiple instances of [feature ...] tags */
if(processFeatureTag(mapserv, &tag, lp) != MS_SUCCESS)
return(MS_FAILURE); /* TODO: how to handle */
*line = msStringConcatenate(*line, tag);
} else if(nodata) {
*line = msStringConcatenate(*line, nodata);
}
*line = msStringConcatenate(*line, postTag);
/* clean up */
msFreeHashTable(tagArgs);
tagArgs=NULL;
free(postTag);
free(tag);
tagStart = findTag(*line, "resultset");
}
return(MS_SUCCESS);
}
/*
** Function process a [include src="..."] tag.
**
** TODO's:
** - allow URLs
*/
static int processIncludeTag(mapservObj *mapserv, char **line, FILE *stream, int mode)
{
char *tag, *tagStart, *tagEnd;
hashTableObj *tagArgs=NULL;
int tagOffset, tagLength;
char *content=NULL, *processedContent=NULL, *src=NULL;
FILE *includeStream;
char buffer[MS_BUFFER_LENGTH], path[MS_MAXPATHLEN];
if(!*line) {
msSetError(MS_WEBERR, "Invalid line pointer.", "processIncludeTag()");
return(MS_FAILURE);
}
tagStart = findTag(*line, "include");
/* It is OK to have no include tags, just return. */
if( !tagStart ) return MS_SUCCESS;
while( tagStart ) {
tagOffset = tagStart - *line;
/* check for any tag arguments */
if(getTagArgs("include", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE);
if(tagArgs) {
src = msLookupHashTable(tagArgs, "src");
}
if(!src) return(MS_SUCCESS); /* don't process the tag, could be something else so return MS_SUCCESS */
if((includeStream = fopen(msBuildPath(path, mapserv->map->mappath, src), "r")) == NULL) {
msSetError(MS_IOERR, src, "processIncludeTag()");
return MS_FAILURE;
}
if(isValidTemplate(includeStream, src) != MS_TRUE) {
fclose(includeStream);
return MS_FAILURE;
}
while(fgets(buffer, MS_BUFFER_LENGTH, includeStream) != NULL)
content = msStringConcatenate(content, buffer);
/* done with included file handle */
fclose(includeStream);
/* find the end of the tag */
tagEnd = findTagEnd(tagStart);
tagEnd++;
/* build the complete tag so we can do substitution */
tagLength = tagEnd - tagStart;
tag = (char *) msSmallMalloc(tagLength + 1);
strlcpy(tag, tagStart, tagLength+1);
/* process any other tags in the content */
processedContent = processLine(mapserv, content, stream, mode);
/* do the replacement */
*line = msReplaceSubstring(*line, tag, processedContent);
/* clean up */
free(tag);
tag = NULL;
msFreeHashTable(tagArgs);
tagArgs=NULL;
free(content);
free(processedContent);
if((*line)[tagOffset] != '\0')
tagStart = findTag(*line+tagOffset+1, "include");
else
tagStart = NULL;
}
return(MS_SUCCESS);
}
/*
** Function to process an [item ...] tag: line contains the tag, shape holds the attributes.
*/
enum ITEM_ESCAPING {ESCAPE_HTML, ESCAPE_URL, ESCAPE_NONE};
static int processItemTag(layerObj *layer, char **line, shapeObj *shape)
{
int i, j;
char *tag, *tagStart, *tagEnd;
hashTableObj *tagArgs=NULL;
int tagOffset, tagLength;
char *encodedTagValue=NULL, *tagValue=NULL;
char *argValue=NULL;
char *name=NULL, *pattern=NULL;
char *format=NULL, *nullFormat=NULL;
int precision;
int uc, lc, commify;
int escape;
if(!*line) {
msSetError(MS_WEBERR, "Invalid line pointer.", "processItemTag()");
return(MS_FAILURE);
}
tagStart = findTag(*line, "item");
if(!tagStart) return(MS_SUCCESS); /* OK, just return; */
while (tagStart) {
format = "$value"; /* initialize the tag arguments */
nullFormat = "";
precision=-1;
name = pattern = NULL;
uc = lc = commify = MS_FALSE;
escape=ESCAPE_HTML;
tagOffset = tagStart - *line;
/* check for any tag arguments */
if(getTagArgs("item", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE);
if(tagArgs) {
argValue = msLookupHashTable(tagArgs, "name");
if(argValue) name = argValue;
argValue = msLookupHashTable(tagArgs, "pattern");
if(argValue) pattern = argValue;
argValue = msLookupHashTable(tagArgs, "precision");
if(argValue) precision = atoi(argValue);
argValue = msLookupHashTable(tagArgs, "format");
if(argValue) format = argValue;
argValue = msLookupHashTable(tagArgs, "nullformat");
if(argValue) nullFormat = argValue;
argValue = msLookupHashTable(tagArgs, "uc");
if(argValue && strcasecmp(argValue, "true") == 0) uc = MS_TRUE;
argValue = msLookupHashTable(tagArgs, "lc");
if(argValue && strcasecmp(argValue, "true") == 0) lc = MS_TRUE;
argValue = msLookupHashTable(tagArgs, "commify");
if(argValue && strcasecmp(argValue, "true") == 0) commify = MS_TRUE;
argValue = msLookupHashTable(tagArgs, "escape");
if(argValue && strcasecmp(argValue, "url") == 0) escape = ESCAPE_URL;
else if(argValue && strcasecmp(argValue, "none") == 0) escape = ESCAPE_NONE;
/* TODO: deal with sub strings */
}
if(!name) {
msSetError(MS_WEBERR, "Item tag contains no name attribute.", "processItemTag()");
return(MS_FAILURE);
}
for(i=0; i<layer->numitems; i++)
if(strcasecmp(name, layer->items[i]) == 0) break;
if(i == layer->numitems) {
msSetError(MS_WEBERR, "Item name (%s) not found in layer item list.", "processItemTag()", name);
return(MS_FAILURE);
}
/*
** now we know which item so build the tagValue
*/
if(shape->values[i] && strlen(shape->values[i]) > 0) {
char *itemValue=NULL;
/* set tag text depending on pattern (if necessary), nullFormat can contain $value (#3637) */
if(pattern && msEvalRegex(pattern, shape->values[i]) != MS_TRUE)
tagValue = msStrdup(nullFormat);
else
tagValue = msStrdup(format);
if(precision != -1) {
char numberFormat[16];
itemValue = (char *) msSmallMalloc(64); /* plenty big */
snprintf(numberFormat, sizeof(numberFormat), "%%.%dlf", precision);
snprintf(itemValue, 64, numberFormat, atof(shape->values[i]));
} else
itemValue = msStrdup(shape->values[i]);
if(commify == MS_TRUE)
itemValue = msCommifyString(itemValue);
/* apply other effects */
if(uc == MS_TRUE)
for(j=0; j<strlen(itemValue); j++) itemValue[j] = toupper(itemValue[j]);
if(lc == MS_TRUE)
for(j=0; j<strlen(itemValue); j++) itemValue[j] = tolower(itemValue[j]);
tagValue = msReplaceSubstring(tagValue, "$value", itemValue);
msFree(itemValue);
if(!tagValue) {
msSetError(MS_WEBERR, "Error applying item format.", "processItemTag()");
return(MS_FAILURE); /* todo leaking... */
}
} else {
tagValue = msStrdup(nullFormat); /* attribute value is NULL or empty */
}
/* find the end of the tag */
tagEnd = findTagEnd(tagStart);
tagEnd++;
/* build the complete tag so we can do substitution */
tagLength = tagEnd - tagStart;
tag = (char *) msSmallMalloc(tagLength + 1);
strlcpy(tag, tagStart, tagLength+1);
/* do the replacement */
switch(escape) {
case ESCAPE_HTML:
encodedTagValue = msEncodeHTMLEntities(tagValue);
*line = msReplaceSubstring(*line, tag, encodedTagValue);
break;
case ESCAPE_URL:
encodedTagValue = msEncodeUrl(tagValue);
*line = msReplaceSubstring(*line, tag, encodedTagValue);
break;
case ESCAPE_NONE:
*line = msReplaceSubstring(*line, tag, tagValue);
break;
default:
break;
}
/* clean up */
free(tag);
tag = NULL;
msFreeHashTable(tagArgs);
tagArgs=NULL;
msFree(tagValue);
tagValue=NULL;
msFree(encodedTagValue);
encodedTagValue=NULL;
tagStart = findTag(*line, "item");
}
return(MS_SUCCESS);
}
/*
** Function process any number of MapServer extent tags (e.g. shpext, mapext, etc...).
*/
static int processExtentTag(mapservObj *mapserv, char **line, char *name, rectObj *extent, projectionObj *rectProj)
{
char *argValue;
char *tag, *tagStart, *tagEnd;
hashTableObj *tagArgs=NULL;
int tagOffset, tagLength;
char *encodedTagValue=NULL, *tagValue=NULL;
rectObj tempExtent;
double xExpand, yExpand;
char number[64]; /* holds a single number in the extent */
char numberFormat[16];
char *format;
int precision;
int escape;
char *projectionString=NULL;
if(!*line) {
msSetError(MS_WEBERR, "Invalid line pointer.", "processExtentTag()");
return(MS_FAILURE);
}
tagStart = findTag(*line, name); /* this supports any extent */
/* It is OK to have no include tags, just return. */
if(!tagStart) return MS_SUCCESS;
/* hack to handle tags like 'mapext_esc' easily */
if(strstr(name, "_esc")) escape = ESCAPE_URL;
while(tagStart) {
xExpand = yExpand = 0; /* set tag argument defaults */
precision = -1;
format = "$minx $miny $maxx $maxy";
if(strstr(name, "_esc"))
escape = ESCAPE_URL;
else
escape = ESCAPE_HTML;
projectionString = NULL;
tagOffset = tagStart - *line;
/* check for any tag arguments */
if(getTagArgs(name, tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE);
if(tagArgs) {
argValue = msLookupHashTable(tagArgs, "expand");
if(argValue) {
if(strchr(argValue, '%') != NULL) {
float f;
sscanf(argValue, "%f%%", &f);
xExpand = ((f/100.0)*(extent->maxx-extent->minx))/2;
yExpand = ((f/100.0)*(extent->maxy-extent->miny))/2;
} else {
xExpand = atof(argValue);
yExpand = xExpand;
}
}
argValue = msLookupHashTable(tagArgs, "escape");
if(argValue && strcasecmp(argValue, "url") == 0) escape = ESCAPE_URL;
else if(argValue && strcasecmp(argValue, "none") == 0) escape = ESCAPE_NONE;
argValue = msLookupHashTable(tagArgs, "format");
if(argValue) format = argValue;
argValue = msLookupHashTable(tagArgs, "precision");
if(argValue) precision = atoi(argValue);
argValue = msLookupHashTable(tagArgs, "proj");
if(argValue) projectionString = argValue;
}
tempExtent.minx = extent->minx - xExpand;
tempExtent.miny = extent->miny - yExpand;
tempExtent.maxx = extent->maxx + xExpand;
tempExtent.maxy = extent->maxy + yExpand;
/* no big deal to convert from file to image coordinates, but what are the image parameters */
if(rectProj && projectionString && strcasecmp(projectionString,"image") == 0) {
precision = 0;
/* if necessary, project the shape to match the map */
if(msProjectionsDiffer(rectProj, &(mapserv->map->projection)))
msProjectRect(rectProj, &mapserv->map->projection, &tempExtent);
/* convert tempExtent to image coordinates based on the map extent and cellsize */
tempExtent.minx = MS_MAP2IMAGE_X(tempExtent.minx, mapserv->map->extent.minx, mapserv->map->cellsize);
tempExtent.miny = MS_MAP2IMAGE_Y(tempExtent.miny, mapserv->map->extent.maxy, mapserv->map->cellsize);
tempExtent.maxx = MS_MAP2IMAGE_X(tempExtent.minx, mapserv->map->extent.minx, mapserv->map->cellsize);
tempExtent.maxy = MS_MAP2IMAGE_Y(tempExtent.miny, mapserv->map->extent.maxy, mapserv->map->cellsize);
} else if(rectProj && projectionString) {
projectionObj projection;
msInitProjection(&projection);
if(MS_SUCCESS != msLoadProjectionString(&projection, projectionString)) return MS_FAILURE;
if(msProjectionsDiffer(rectProj, &projection))
msProjectRect(rectProj, &projection, &tempExtent);
}
tagValue = msStrdup(format);
if(precision != -1)
snprintf(numberFormat, sizeof(numberFormat), "%%.%dlf", precision);
else
snprintf(numberFormat, sizeof(numberFormat), "%%f");
snprintf(number, sizeof(number), numberFormat, tempExtent.minx);
tagValue = msReplaceSubstring(tagValue, "$minx", number);
snprintf(number, sizeof(number), numberFormat, tempExtent.miny);
tagValue = msReplaceSubstring(tagValue, "$miny", number);
snprintf(number, sizeof(number), numberFormat, tempExtent.maxx);
tagValue = msReplaceSubstring(tagValue, "$maxx", number);
snprintf(number, sizeof(number), numberFormat, tempExtent.maxy);
tagValue = msReplaceSubstring(tagValue, "$maxy", number);
/* find the end of the tag */
tagEnd = findTagEnd(tagStart);
tagEnd++;
/* build the complete tag so we can do substitution */
tagLength = tagEnd - tagStart;
tag = (char *) msSmallMalloc(tagLength + 1);
strlcpy(tag, tagStart, tagLength+1);
/* do the replacement */
switch(escape) {
case ESCAPE_HTML:
encodedTagValue = msEncodeHTMLEntities(tagValue);
*line = msReplaceSubstring(*line, tag, encodedTagValue);
break;
case ESCAPE_URL:
encodedTagValue = msEncodeUrl(tagValue);
*line = msReplaceSubstring(*line, tag, encodedTagValue);
break;
case ESCAPE_NONE:
*line = msReplaceSubstring(*line, tag, tagValue);
break;
default:
break;
}
/* clean up */
free(tag);
tag = NULL;
msFreeHashTable(tagArgs);
tagArgs=NULL;
msFree(tagValue);
tagValue=NULL;
msFree(encodedTagValue);
encodedTagValue=NULL;
if((*line)[tagOffset] != '\0')
tagStart = findTag(*line+tagOffset+1, name);
else
tagStart = NULL;
}
return(MS_SUCCESS);
}
// RFC 77 TODO: Need to validate these changes with Assefa...
static int processShplabelTag(layerObj *layer, char **line, shapeObj *origshape)
{
char *tag, *tagStart, *tagEnd;
char *tagValue=NULL;
hashTableObj *tagArgs=NULL;
int tagOffset, tagLength;
char *format;
char *argValue=NULL;
char *projectionString=NULL;
shapeObj tShape;
int precision=0;
int clip_to_map=MS_TRUE;
int use_label_settings=MS_FALSE;
double cellsize=0;
int labelposvalid = MS_FALSE;
pointObj labelPos;
int i,status;
char number[64]; /* holds a single number in the extent */
char numberFormat[16];
shapeObj *shape = NULL;
if(!*line) {
msSetError(MS_WEBERR, "Invalid line pointer.", "processShplabelTag()");
return(MS_FAILURE);
}
if(msCheckParentPointer(layer->map,"map") == MS_FAILURE)
return MS_FAILURE;
tagStart = findTag(*line, "shplabel");
/* It is OK to have no shplabel tags, just return. */
if(!tagStart)
return MS_SUCCESS;
if(!origshape || origshape->numlines <= 0) { /* I suppose we need to make sure the part has vertices (need shape checker?) */
msSetError(MS_WEBERR, "Null or empty shape.", "processShplabelTag()");
return(MS_FAILURE);
}
while(tagStart) {
if(shape) msFreeShape(shape);
shape = (shapeObj *) msSmallMalloc(sizeof(shapeObj));
msInitShape(shape);
msCopyShape(origshape, shape);
projectionString = NULL;
format = "$x,$y";
tagOffset = tagStart - *line;
if(getTagArgs("shplabel", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE);
if(tagArgs) {
argValue = msLookupHashTable(tagArgs, "format");
if(argValue) format = argValue;
argValue = msLookupHashTable(tagArgs, "precision");
if(argValue) precision = atoi(argValue);
argValue = msLookupHashTable(tagArgs, "proj");
if(argValue) projectionString = argValue;
argValue = msLookupHashTable(tagArgs, "clip_to_map");
if(argValue) {
if(strcasecmp(argValue,"false") == 0) clip_to_map = MS_FALSE;
}
argValue = msLookupHashTable(tagArgs, "use_label_settings");
if(argValue) {
if(strcasecmp(argValue,"true") == 0) use_label_settings = MS_TRUE;
}
}
labelPos.x = -1;
labelPos.y = -1;
msInitShape(&tShape);
tShape.type = MS_SHAPE_LINE;
tShape.line = (lineObj *) msSmallMalloc(sizeof(lineObj));
tShape.numlines = 1;
tShape.line[0].point = NULL; /* initialize the line */
tShape.line[0].numpoints = 0;
if(layer->map->cellsize <= 0)
cellsize = MS_MAX(MS_CELLSIZE(layer->map->extent.minx, layer->map->extent.maxx, layer->map->width), MS_CELLSIZE(layer->map->extent.miny, layer->map->extent.maxy, layer->map->height));
else
cellsize = layer->map->cellsize ;
if(shape->type == MS_SHAPE_POINT) {
labelposvalid = MS_FALSE;
if(shape->numlines > 0 && shape->line[0].numpoints > 0) {
labelposvalid = MS_TRUE;
labelPos = shape->line[0].point[0];
if(layer->transform == MS_TRUE) {
if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection)))
msProjectShape(&layer->projection, &layer->map->projection, shape);
labelPos = shape->line[0].point[0];
labelPos.x = MS_MAP2IMAGE_X(labelPos.x, layer->map->extent.minx, cellsize);
labelPos.y = MS_MAP2IMAGE_Y(labelPos.y, layer->map->extent.maxy, cellsize);
}
}
} else if(shape->type == MS_SHAPE_LINE) {
pointObj **annopoints = NULL;
double **angles = NULL, **lengths = NULL;
int numpoints = 1;
labelposvalid = MS_FALSE;
if(layer->transform == MS_TRUE) {
if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection)))
msProjectShape(&layer->projection, &layer->map->projection, shape);
if(clip_to_map)
msClipPolylineRect(shape, layer->map->extent);
msTransformShapeToPixelRound(shape, layer->map->extent, cellsize);
} else
msOffsetShapeRelativeTo(shape, layer);
if(shape->numlines > 0) {
annopoints = msPolylineLabelPoint(shape, -1, 0, &angles, &lengths, &numpoints, MS_FALSE);
if(numpoints > 0) {
/* convert to geo */
labelPos.x = annopoints[0]->x;
labelPos.y = annopoints[0]->y;
labelposvalid = MS_TRUE;
for(i=0; i<numpoints; i++) {
if(annopoints[i]) msFree(annopoints[i]);
if(angles[i]) msFree(angles[i]);
if(lengths[i]) msFree(lengths[i]);
}
msFree(angles);
msFree(annopoints);
msFree(lengths);
}
}
} else if (shape->type == MS_SHAPE_POLYGON) {
labelposvalid = MS_FALSE;
if(layer->transform == MS_TRUE) {
if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection)))
msProjectShape(&layer->projection, &layer->map->projection, shape);
if(clip_to_map)
msClipPolygonRect(shape, layer->map->extent);
msTransformShapeToPixelRound(shape, layer->map->extent, cellsize);
} else
msOffsetShapeRelativeTo(shape, layer);
if(shape->numlines > 0) {
if(msPolygonLabelPoint(shape, &labelPos, -1) == MS_SUCCESS) {
if(labelPos.x == -1 && labelPos.y == -1)
labelposvalid = MS_FALSE;
else
labelposvalid = MS_TRUE;
}
}
}
if(labelposvalid == MS_TRUE) {
pointObj p1;
pointObj p2;
int label_offset_x, label_offset_y;
labelObj *label=NULL;
rectObj r;
shapeObj poly;
double tmp;
msInitShape(&poly);
p1.x =labelPos.x;
p1.y =labelPos.y;
p2.x =labelPos.x;
p2.y =labelPos.y;
if(use_label_settings == MS_TRUE) {
/* RFC 77: classes (and shapes) can have more than 1 piece of annotation, here we only use the first (index=0) */
if(shape->classindex >= 0 && layer->class[shape->classindex]->numlabels > 0) {
label = layer->class[shape->classindex]->labels[0];
if(msGetLabelSize(layer->map, label, label->annotext, label->size, &r, NULL) == MS_SUCCESS) {
label_offset_x = (int)(label->offsetx*layer->scalefactor);
label_offset_y = (int)(label->offsety*layer->scalefactor);
p1 = get_metrics(&labelPos, label->position, r, label_offset_x, label_offset_y, label->angle, 0, &poly);
/* should we use the point returned from get_metrics?. From few test done, It seems
to return the UL corner of the text. For now use the bounds.minx/miny */
p1.x = poly.bounds.minx;
p1.y = poly.bounds.miny;
p2.x = poly.bounds.maxx;
p2.y = poly.bounds.maxy;
}
}
}
/* y's are flipped because it is in image coordinate systems */
p1.x = MS_IMAGE2MAP_X(p1.x, layer->map->extent.minx, cellsize);
tmp = p1.y;
p1.y = MS_IMAGE2MAP_Y(p2.y, layer->map->extent.maxy, cellsize);
p2.x = MS_IMAGE2MAP_X(p2.x, layer->map->extent.minx, cellsize);
p2.y = MS_IMAGE2MAP_Y(tmp, layer->map->extent.maxy, cellsize);
if(layer->transform == MS_TRUE) {
if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) {
msProjectPoint(&layer->map->projection, &layer->projection, &p1);
msProjectPoint(&layer->map->projection, &layer->projection, &p2);
}
}
msAddPointToLine(&(tShape.line[0]), &p1);
msAddPointToLine(&(tShape.line[0]), &p2);
} else
tShape.numlines = 0;
if(projectionString && strcasecmp(projectionString,"image") == 0) {
precision = 0;
/* if necessary, project the shape to match the map */
if(msProjectionsDiffer(&(layer->projection), &(layer->map->projection)))
msProjectShape(&layer->projection, &layer->map->projection, &tShape);
msClipPolylineRect(&tShape, layer->map->extent);
msTransformShapeToPixelRound(&tShape, layer->map->extent, layer->map->cellsize);
} else if(projectionString) {
projectionObj projection;
msInitProjection(&projection);
status = msLoadProjectionString(&projection, projectionString);
if(status != MS_SUCCESS) return MS_FAILURE;
if(msProjectionsDiffer(&(layer->projection), &projection))
msProjectShape(&layer->projection, &projection, &tShape);
}
/* find the end of the tag */
tagEnd = findTagEnd(tagStart);
tagEnd++;
/* build the complete tag so we can do substitution */
tagLength = tagEnd - tagStart;
tag = (char *) msSmallMalloc(tagLength + 1);
strlcpy(tag, tagStart, tagLength+1);
/* do the replacement */
tagValue = msStrdup(format);
if(precision > 0)
snprintf(numberFormat, sizeof(numberFormat), "%%.%dlf", precision);
else
snprintf(numberFormat, sizeof(numberFormat), "%%f");
if(tShape.numlines > 0) {
if(strcasestr(tagValue, "$x") != 0) {
snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[0].x);
tagValue = msReplaceSubstring(tagValue, "$x", number);
}
if(strcasestr(tagValue, "$y") != 0) {
snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[0].y);
tagValue = msReplaceSubstring(tagValue, "$y", number);
}
if(strcasestr(tagValue, "$minx") != 0) {
snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[0].x);
tagValue = msReplaceSubstring(tagValue, "$minx", number);
}
if(strcasestr(tagValue, "$miny") != 0) {
snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[0].y);
tagValue = msReplaceSubstring(tagValue, "$miny", number);
}
if(strcasestr(tagValue, "$maxx") != 0) {
snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[1].x);
tagValue = msReplaceSubstring(tagValue, "$maxx", number);
}
if(strcasestr(tagValue, "$maxy") != 0) {
snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[1].y);
tagValue = msReplaceSubstring(tagValue, "$maxy", number);
}
}
/* find the end of the tag */
tagEnd = findTagEnd(tagStart);
tagEnd++;
/* build the complete tag so we can do substitution */
tagLength = tagEnd - tagStart;
tag = (char *) msSmallMalloc(tagLength + 1);
strlcpy(tag, tagStart, tagLength+1);
*line = msReplaceSubstring(*line, tag, tagValue);
/* clean up */
msFreeShape(&tShape);
free(tag);
tag = NULL;
msFreeHashTable(tagArgs);
tagArgs=NULL;
msFree(tagValue);
tagValue=NULL;
if((*line)[tagOffset] != '\0')
tagStart = findTag(*line+tagOffset+1, "shplabel");
else
tagStart = NULL;
}
if(shape)
msFreeShape(shape);
return(MS_SUCCESS);
}
/*
** Function to process a [date ...] tag
*/
static int processDateTag(char **line)
{
struct tm *datetime;
time_t t;
int result;
char *tag=NULL, *tagStart, *tagEnd;
hashTableObj *tagArgs=NULL;
int tagOffset, tagLength;
#define DATE_BUFLEN 1024
char datestr[DATE_BUFLEN];
char *argValue=NULL;
char *format, *tz; /* tag parameters */
if(!*line) {
msSetError(MS_WEBERR, "Invalid line pointer.", "processDateTag()");
return(MS_FAILURE);
}
tagStart = findTag(*line, "date");
/* It is OK to have no date tags, just return. */
if( !tagStart )
return MS_SUCCESS;
while (tagStart) {
/* set tag params to defaults */
format = DEFAULT_DATE_FORMAT;
tz = "";
tagOffset = tagStart - *line;
/* check for any tag arguments */
if(getTagArgs("date", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE);
if(tagArgs) {
argValue = msLookupHashTable(tagArgs, "format");
if(argValue) format = argValue;
argValue = msLookupHashTable(tagArgs, "tz");
if(argValue) tz = argValue;
}
t = time(NULL);
if( strncasecmp( tz, "gmt", 4 ) == 0 ) {
datetime = gmtime(&t);
} else {
datetime = localtime(&t);
}
result = strftime(datestr, DATE_BUFLEN, format, datetime);
/* Only do the replacement if the date was successfully written */
if( result > 0 ) {
/* find the end of the tag */
tagEnd = findTagEnd(tagStart);
tagEnd++;
/* build the complete tag so we can do substitution */
tagLength = tagEnd - tagStart;
tag = (char *) msSmallMalloc(tagLength + 1);
strlcpy(tag, tagStart, tagLength+1);
/* do the replacement */
*line = msReplaceSubstring(*line, tag, datestr);
}
/* clean up */
msFree(tag);
tag = NULL;
msFreeHashTable(tagArgs);
tagArgs=NULL;
if((*line)[tagOffset] != '\0')
tagStart = findTag(*line+tagOffset+1, "shpxy");
else
tagStart = NULL;
}
return(MS_SUCCESS);
}
/*
** Function to process a [shpxy ...] tag: line contains the tag, shape holds the coordinates.
**
** TODO's:
** - May need to change attribute names.
** - Need generalization routines (not here, but in mapprimative.c).
** - Try to avoid all the realloc calls.
*/
static int processShpxyTag(layerObj *layer, char **line, shapeObj *shape)
{
int i,j,p;
int status;
char *tag, *tagStart, *tagEnd;
hashTableObj *tagArgs=NULL;
int tagOffset, tagLength;
char *argValue=NULL;
char *pointFormat1=NULL, *pointFormat2=NULL;
int pointFormatLength;
/*
** Pointers to static strings, naming convention is:
** char 1/2 - x=x, y=y, c=coordinate, p=part, s=shape, ir=inner ring, or=outer ring
** last char - h=header, f=footer, s=seperator
*/
char *xh, *xf, *yh, *yf;
char *cs;
char *ph, *pf, *ps;
char *sh, *sf;
char *irh, *irf; /* inner ring: necessary for complex polygons */
char *orh, *orf; /* outer ring */
int centroid;
int precision;
double scale_x, scale_y;
double buffer;
int bufferUnits;
char *projectionString=NULL;
shapeObj tShape;
char *coords=NULL, point[128];
if(!*line) {
msSetError(MS_WEBERR, "Invalid line pointer.", "processShpxyTag()");
return(MS_FAILURE);
}
if( msCheckParentPointer(layer->map,"map")==MS_FAILURE )
return MS_FAILURE;
tagStart = findTag(*line, "shpxy");
/* It is OK to have no shpxy tags, just return. */
if( !tagStart )
return MS_SUCCESS;
if(!shape || shape->numlines <= 0) { /* I suppose we need to make sure the part has vertices (need shape checker?) */
msSetError(MS_WEBERR, "Null or empty shape.", "processShpxyTag()");
return(MS_FAILURE);
}
while (tagStart) {
xh = yh = yf = ph = pf = sh = sf = ""; /* initialize the tag arguments */
xf= ",";
irh = irf = orh = orf = "";
ps = cs = " ";
centroid = MS_FALSE;
precision = 0;
scale_x = scale_y = 1.0;
buffer = 0;
bufferUnits = -1;
projectionString = NULL;
tagOffset = tagStart - *line;
/* check for any tag arguments */
if(getTagArgs("shpxy", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE);
if(tagArgs) {
argValue = msLookupHashTable(tagArgs, "xh");
if(argValue) xh = argValue;
argValue = msLookupHashTable(tagArgs, "xf");
if(argValue) xf = argValue;
argValue = msLookupHashTable(tagArgs, "yh");
if(argValue) yh = argValue;
argValue = msLookupHashTable(tagArgs, "yf");
if(argValue) yf = argValue;
argValue = msLookupHashTable(tagArgs, "cs");
if(argValue) cs = argValue;
argValue = msLookupHashTable(tagArgs, "irh");
if(argValue) irh = argValue;
argValue = msLookupHashTable(tagArgs, "irf");
if(argValue) irf = argValue;
argValue = msLookupHashTable(tagArgs, "orh");
if(argValue) orh = argValue;
argValue = msLookupHashTable(tagArgs, "orf");
if(argValue) orf = argValue;
argValue = msLookupHashTable(tagArgs, "ph");
if(argValue) ph = argValue;
argValue = msLookupHashTable(tagArgs, "pf");
if(argValue) pf = argValue;
argValue = msLookupHashTable(tagArgs, "ps");
if(argValue) ps = argValue;
argValue = msLookupHashTable(tagArgs, "sh");
if(argValue) sh = argValue;
argValue = msLookupHashTable(tagArgs, "sf");
if(argValue) sf = argValue;
argValue = msLookupHashTable(tagArgs, "buffer");
if(argValue) {
buffer = atof(argValue);
if(strstr(argValue, "px")) bufferUnits = MS_PIXELS; /* may support others at some point */
}
argValue = msLookupHashTable(tagArgs, "precision");
if(argValue) precision = atoi(argValue);
argValue = msLookupHashTable(tagArgs, "scale");
if(argValue) {
scale_x = atof(argValue);
scale_y = scale_x;
}
argValue = msLookupHashTable(tagArgs, "scale_x");
if(argValue) scale_x = atof(argValue);
argValue = msLookupHashTable(tagArgs, "scale_y");
if(argValue) scale_y = atof(argValue);
argValue = msLookupHashTable(tagArgs, "centroid");
if(argValue)
if(strcasecmp(argValue,"true") == 0) centroid = MS_TRUE;
argValue = msLookupHashTable(tagArgs, "proj");
if(argValue) projectionString = argValue;
}
/* build the per point format strings (version 1 contains the coordinate seperator, version 2 doesn't) */
pointFormatLength = strlen("xh") + strlen("xf") + strlen("yh") + strlen("yf") + strlen("cs") + 10 + 1;
pointFormat1 = (char *) msSmallMalloc(pointFormatLength);
snprintf(pointFormat1, pointFormatLength, "%s%%.%dlf%s%s%%.%dlf%s%s", xh, precision, xf, yh, precision, yf, cs);
pointFormat2 = (char *) msSmallMalloc(pointFormatLength);
snprintf(pointFormat2, pointFormatLength, "%s%%.%dlf%s%s%%.%dlf%s", xh, precision, xf, yh, precision, yf);
/* make a copy of the original shape or compute a centroid if necessary */
msInitShape(&tShape);
if(centroid == MS_TRUE) {
pointObj p;
p.x = (shape->bounds.minx + shape->bounds.maxx)/2;
p.y = (shape->bounds.miny + shape->bounds.maxy)/2;
tShape.type = MS_SHAPE_POINT;
tShape.line = (lineObj *) msSmallMalloc(sizeof(lineObj));
tShape.numlines = 1;
tShape.line[0].point = NULL; /* initialize the line */
tShape.line[0].numpoints = 0;
msAddPointToLine(&(tShape.line[0]), &p);
}
#ifdef USE_GEOS
else if(buffer != 0 && bufferUnits != MS_PIXELS) {
shapeObj *bufferShape=NULL;
bufferShape = msGEOSBuffer(shape, buffer);
if(!bufferShape) return(MS_FAILURE); /* buffer failed */
msCopyShape(bufferShape, &tShape);
msFreeShape(bufferShape);
}
#endif
else {
status = msCopyShape(shape, &tShape);
if(status != 0) return(MS_FAILURE); /* copy failed */
}
/* no big deal to convert from file to image coordinates, but what are the image parameters */
if(projectionString && strcasecmp(projectionString,"image") == 0) {
precision = 0;
/* if necessary, project the shape to match the map */
if(msProjectionsDiffer(&(layer->projection), &(layer->map->projection)))
msProjectShape(&layer->projection, &layer->map->projection, &tShape);
switch(tShape.type) {
case(MS_SHAPE_POINT):
/* at this point we only convert the first point of the first shape */
tShape.line[0].point[0].x = MS_MAP2IMAGE_X(tShape.line[0].point[0].x, layer->map->extent.minx, layer->map->cellsize);
tShape.line[0].point[0].y = MS_MAP2IMAGE_Y(tShape.line[0].point[0].y, layer->map->extent.maxy, layer->map->cellsize);
break;
case(MS_SHAPE_LINE):
msClipPolylineRect(&tShape, layer->map->extent);
break;
case(MS_SHAPE_POLYGON):
msClipPolygonRect(&tShape, layer->map->extent);
break;
default:
/* TO DO: need an error message here */
return(MS_FAILURE);
break;
}
msTransformShapeToPixelRound(&tShape, layer->map->extent, layer->map->cellsize);
#ifdef USE_GEOS
if(buffer != 0 && bufferUnits == MS_PIXELS) {
shapeObj *bufferShape=NULL;
bufferShape = msGEOSBuffer(&tShape, buffer);
if(!bufferShape) {
if(!msIsDegenerateShape(&tShape)) /* If shape is degenerate this is expected. */
return(MS_FAILURE); /* buffer failed */
} else {
msFreeShape(&tShape); /* avoid memory leak */
msCopyShape(bufferShape, &tShape);
msFreeShape(bufferShape);
}
}
#endif
} else if(projectionString) {
projectionObj projection;
msInitProjection(&projection);
status = msLoadProjectionString(&projection, projectionString);
if(status != MS_SUCCESS) return MS_FAILURE;
if(msProjectionsDiffer(&(layer->projection), &projection))
msProjectShape(&layer->projection, &projection, &tShape);
}
/* TODO: add thinning support here */
/*
** build the coordinate string
*/
if(strlen(sh) > 0) coords = msStringConcatenate(coords, sh);
/* do we need to handle inner/outer rings */
if(tShape.type == MS_SHAPE_POLYGON && strlen(orh) > 0 && strlen(irh) > 0) {
int *outers;
int firstPart; /* to keep track of inserting part separators before each part after the first */
outers = msGetOuterList( &tShape );
firstPart = 1;
/* loop over rings looking for outers*/
for(i=0; i<tShape.numlines; i++) {
int *inners;
if( outers[i] ) {
/* this is an outer ring */
if((!firstPart) && (strlen(ps) > 0)) coords = msStringConcatenate(coords, ps);
firstPart = 0;
if(strlen(ph) > 0) coords = msStringConcatenate(coords, ph);
coords = msStringConcatenate(coords, orh);
for(p=0; p<tShape.line[i].numpoints-1; p++) {
snprintf(point, sizeof(point), pointFormat1, scale_x*tShape.line[i].point[p].x, scale_y*tShape.line[i].point[p].y);
coords = msStringConcatenate(coords, point);
}
snprintf(point, sizeof(point), pointFormat2, scale_x*tShape.line[i].point[p].x, scale_y*tShape.line[i].point[p].y);
coords = msStringConcatenate(coords, point);
coords = msStringConcatenate(coords, orf);
inners = msGetInnerList(&tShape, i, outers);
/* loop over rings looking for inners to this outer */
for(j=0; j<tShape.numlines; j++) {
if( inners[j] ) {
/* j is an inner ring of i */
coords = msStringConcatenate(coords, irh);
for(p=0; p<tShape.line[j].numpoints-1; p++) {
snprintf(point, sizeof(point), pointFormat1, scale_x*tShape.line[j].point[p].x, scale_y*tShape.line[j].point[p].y);
coords = msStringConcatenate(coords, point);
}
snprintf(point, sizeof(point), pointFormat2, scale_x*tShape.line[j].point[p].x, scale_y*tShape.line[j].point[p].y);
coords = msStringConcatenate(coords, irf);
}
}
free( inners );
if(strlen(pf) > 0) coords = msStringConcatenate(coords, pf);
}
} /* end of loop over outer rings */
free( outers );
} else { /* output without ring formatting */
for(i=0; i<tShape.numlines; i++) { /* e.g. part */
/* skip degenerate parts, really should only happen with pixel output */
if((tShape.type == MS_SHAPE_LINE && tShape.line[i].numpoints < 2) ||
(tShape.type == MS_SHAPE_POLYGON && tShape.line[i].numpoints < 3))
continue;
if(strlen(ph) > 0) coords = msStringConcatenate(coords, ph);
for(p=0; p<tShape.line[i].numpoints-1; p++) {
snprintf(point, sizeof(point), pointFormat1, scale_x*tShape.line[i].point[p].x, scale_y*tShape.line[i].point[p].y);
coords = msStringConcatenate(coords, point);
}
snprintf(point, sizeof(point), pointFormat2, scale_x*tShape.line[i].point[p].x, scale_y*tShape.line[i].point[p].y);
coords = msStringConcatenate(coords, point);
if(strlen(pf) > 0) coords = msStringConcatenate(coords, pf);
if((i < tShape.numlines-1) && (strlen(ps) > 0)) coords = msStringConcatenate(coords, ps);
}
}
if(strlen(sf) > 0) coords = msStringConcatenate(coords, sf);
msFreeShape(&tShape);
/* find the end of the tag */
tagEnd = findTagEnd(tagStart);
tagEnd++;
/* build the complete tag so we can do substitution */
tagLength = tagEnd - tagStart;
tag = (char *) msSmallMalloc(tagLength + 1);
strlcpy(tag, tagStart, tagLength+1);
/* do the replacement */
*line = msReplaceSubstring(*line, tag, coords);
/* clean up */
free(tag);
tag = NULL;
msFreeHashTable(tagArgs);
tagArgs=NULL;
free(pointFormat1);
pointFormat1 = NULL;
free(pointFormat2);
pointFormat2 = NULL;
free(coords);
coords = NULL;
if((*line)[tagOffset] != '\0')
tagStart = findTag(*line+tagOffset+1, "shpxy");
else
tagStart = NULL;
}
return(MS_SUCCESS);
}
/*!
* this function process all metadata
* in pszInstr. ht mus contain all corresponding
* metadata value.
*
* this function return a modified pszInstr
*/
int processMetadata(char** pszInstr, hashTableObj *ht)
{
/* char *pszNextInstr = pszInstr; */
char *pszEnd, *pszStart;
char *pszMetadataTag;
char *pszHashName;
char *pszHashValue;
int nLength, nOffset;
hashTableObj *metadataArgs = NULL;
if(!*pszInstr) {
msSetError(MS_WEBERR, "Invalid pointer.", "processMetadata()");
return MS_FAILURE;
}
/* set position to the begining of metadata tag */
pszStart = findTag(*pszInstr, "metadata");
while (pszStart) {
/* get metadata args */
if(getTagArgs("metadata", pszStart, &metadataArgs) != MS_SUCCESS)
return MS_FAILURE;
pszHashName = msLookupHashTable(metadataArgs, "name");
pszHashValue = msLookupHashTable(ht, pszHashName);
nOffset = pszStart - *pszInstr;
if(pszHashName && pszHashValue) {
/* set position to the end of metadata start tag */
pszEnd = strchr(pszStart, ']');
pszEnd++;
/* build the complete metadata tag ([metadata all_args]) */
/* to replace it by the corresponding value from ht */
nLength = pszEnd - pszStart;
pszMetadataTag = (char*)msSmallMalloc(nLength + 1);
strlcpy(pszMetadataTag, pszStart, nLength+1);
*pszInstr = msReplaceSubstring(*pszInstr, pszMetadataTag, pszHashValue);
free(pszMetadataTag);
pszMetadataTag=NULL;
}
msFreeHashTable(metadataArgs);
metadataArgs=NULL;
/* set position to the begining of the next metadata tag */
if((*pszInstr)[nOffset] != '\0')
pszStart = findTag(*pszInstr+nOffset+1, "metadata");
else
pszStart = NULL;
}
return MS_SUCCESS;
}
/*!
* this function process all icon tag
* from pszInstr.
*
* This func return a modified pszInstr.
*/
int processIcon(mapObj *map, int nIdxLayer, int nIdxClass, char** pszInstr, char* pszPrefix)
{
int nWidth, nHeight, nLen;
char szImgFname[1024], *pszFullImgFname=NULL, *pszImgTag;
char szPath[MS_MAXPATHLEN];
hashTableObj *myHashTable=NULL;
FILE *fIcon;
if(!map ||
nIdxLayer > map->numlayers ||
nIdxLayer < 0 ) {
msSetError(MS_WEBERR, "Invalid pointer.", "processIcon()");
return MS_FAILURE;
}
/* find the begining of tag */
pszImgTag = strstr(*pszInstr, "[leg_icon");
while (pszImgTag) {
int i;
char szStyleCode[512] = "";
classObj *thisClass=NULL;
/* It's okay to have no classes... we'll generate an empty icon in this case */
if(nIdxClass >= 0 && nIdxClass < GET_LAYER(map, nIdxLayer)->numclasses)
thisClass = GET_LAYER(map, nIdxLayer)->class[nIdxClass];
if(getTagArgs("leg_icon", pszImgTag, &myHashTable) != MS_SUCCESS)
return MS_FAILURE;
/* if no specified width or height, set them to map default */
if(!msLookupHashTable(myHashTable, "width") || !msLookupHashTable(myHashTable, "height")) {
nWidth = map->legend.keysizex;
nHeight= map->legend.keysizey;
} else {
nWidth = atoi(msLookupHashTable(myHashTable, "width"));
nHeight = atoi(msLookupHashTable(myHashTable, "height"));
}
/* Create a unique and predictable filename to cache the legend icons.
* Include some key parameters from the first 2 styles
*/
for(i=0; i<2 && thisClass && i<thisClass->numstyles; i++) {
styleObj *style;
char *pszSymbolNameHash = NULL;
style = thisClass->styles[i];
if(style->symbolname)
pszSymbolNameHash = msHashString(style->symbolname);
snprintf(szStyleCode+strlen(szStyleCode), 255,
"s%d_%x_%x_%x_%d_%s_%g",
i, MS_COLOR_GETRGB(style->color), MS_COLOR_GETRGB(style->backgroundcolor), MS_COLOR_GETRGB(style->outlinecolor),
style->symbol, pszSymbolNameHash?pszSymbolNameHash:"",
style->angle);
msFree(pszSymbolNameHash);
}
snprintf(szImgFname, sizeof(szImgFname), "%s_%d_%d_%d_%d_%s.%s%c",
pszPrefix, nIdxLayer, nIdxClass, nWidth, nHeight,
szStyleCode, MS_IMAGE_EXTENSION(map->outputformat),'\0');
pszFullImgFname = msStrdup(msBuildPath3(szPath, map->mappath,
map->web.imagepath, szImgFname));
/* check if icon already exist in cache */
if((fIcon = fopen(pszFullImgFname, "r")) != NULL) {
/* File already exists. No need to generate it again */
fclose(fIcon);
} else {
/* Create an image corresponding to the current class */
imageObj *img=NULL;
if(thisClass == NULL) {
/* Nonexistent class. Create an empty image */
img = msCreateLegendIcon(map, NULL, NULL, nWidth, nHeight);
} else {
img = msCreateLegendIcon(map, GET_LAYER(map, nIdxLayer),
thisClass, nWidth, nHeight);
}
if(!img) {
if(myHashTable)
msFreeHashTable(myHashTable);
msSetError(MS_GDERR, "Error while creating GD image.", "processIcon()");
return MS_FAILURE;
}
/* save it with a unique file name */
if(msSaveImage(map, img, pszFullImgFname) != MS_SUCCESS) {
if(myHashTable)
msFreeHashTable(myHashTable);
msFreeImage(img);
msSetError(MS_IOERR, "Error saving GD image to disk (%s).", "processIcon()", pszFullImgFname);
msFree(pszFullImgFname);
return MS_FAILURE;
}
msFreeImage(img);
}
msFree(pszFullImgFname);
pszFullImgFname = NULL;
nLen = (strchr(pszImgTag, ']') + 1) - pszImgTag;
if(nLen > 0) {
char *pszTag;
/* rebuid image tag ([leg_class_img all_args]) */
/* to replace it by the image url */
pszTag = (char*)msSmallMalloc(nLen + 1);
strlcpy(pszTag, pszImgTag, nLen+1);
pszFullImgFname = (char*)msSmallMalloc(strlen(map->web.imageurl) + strlen(szImgFname) + 1);
strcpy(pszFullImgFname, map->web.imageurl);
strcat(pszFullImgFname, szImgFname);
*pszInstr = msReplaceSubstring(*pszInstr, pszTag, pszFullImgFname);
msFree(pszFullImgFname);
pszFullImgFname = NULL;
msFree(pszTag);
/* find the begining of tag */
pszImgTag = strstr(*pszInstr, "[leg_icon");
} else {
pszImgTag = NULL;
}
if(myHashTable) {
msFreeHashTable(myHashTable);
myHashTable = NULL;
}
}
return MS_SUCCESS;
}
/*!
* Replace all tags from group template
* with correct value.
*
* this function return a buffer containing
* the template with correct values.
*
* buffer must be freed by caller.
*/
int generateGroupTemplate(char* pszGroupTemplate, mapObj *map, char* pszGroupName, hashTableObj *oGroupArgs, char **pszTemp, char* pszPrefix)
{
hashTableObj *myHashTable;
char pszStatus[3];
char *pszClassImg;
char *pszOptFlag = NULL;
int i, j;
int nOptFlag = 15;
int bShowGroup;
*pszTemp = NULL;
if(!pszGroupName || !pszGroupTemplate) {
msSetError(MS_WEBERR, "Invalid pointer.", "generateGroupTemplate()");
return MS_FAILURE;
}
/*
* Get the opt_flag is any.
*/
if(oGroupArgs)
pszOptFlag = msLookupHashTable(oGroupArgs, "opt_flag");
if(pszOptFlag)
nOptFlag = atoi(pszOptFlag);
/*
* Check all layers, if one in the group
* should be visible, print the group.
* (Check for opt_flag)
*/
bShowGroup = 0;
for (j=0; j<map->numlayers; j++) {
if(GET_LAYER(map, map->layerorder[j])->group &&
strcmp(GET_LAYER(map, map->layerorder[j])->group, pszGroupName) == 0) {
/* dont display layer is off. */
if( (nOptFlag & 2) == 0 &&
GET_LAYER(map, map->layerorder[j])->status == MS_OFF )
bShowGroup = 0;
else
bShowGroup = 1;
/* dont display layer is query. */
if( (nOptFlag & 4) == 0 &&
GET_LAYER(map, map->layerorder[j])->type == MS_LAYER_QUERY )
bShowGroup = 0;
/* dont display layer is annotation. */
if( (nOptFlag & 8) == 0 &&
GET_LAYER(map, map->layerorder[j])->type == MS_LAYER_ANNOTATION )
bShowGroup = 0;
/* dont display layer if out of scale. */
if((nOptFlag & 1) == 0) {
if(map->scaledenom > 0) {
if((GET_LAYER(map, map->layerorder[j])->maxscaledenom > 0) &&
(map->scaledenom > GET_LAYER(map, map->layerorder[j])->maxscaledenom))
bShowGroup = 0;
if((GET_LAYER(map, map->layerorder[j])->minscaledenom > 0) &&
(map->scaledenom <= GET_LAYER(map, map->layerorder[j])->minscaledenom))
bShowGroup = 0;
}
}
/* The group contains one visible layer */
/* Draw the group */
if( bShowGroup )
break;
}
}
if( ! bShowGroup )
return MS_SUCCESS;
/*
* Work from a copy
*/
*pszTemp = (char*)msSmallMalloc(strlen(pszGroupTemplate) + 1);
strcpy(*pszTemp, pszGroupTemplate);
/*
* Change group tags
*/
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_group_name]", pszGroupName);
/*
* Create a hash table that contain info
* on current layer
*/
myHashTable = msCreateHashTable();
/*
* Check for the first layer
* that belong to this group.
* Get his status and check for if.
*/
for (j=0; j<map->numlayers; j++) {
if(GET_LAYER(map, map->layerorder[j])->group && strcmp(GET_LAYER(map, map->layerorder[j])->group, pszGroupName) == 0) {
snprintf(pszStatus, sizeof(pszStatus), "%d", GET_LAYER(map, map->layerorder[j])->status);
msInsertHashTable(myHashTable, "layer_status", pszStatus);
msInsertHashTable(myHashTable, "layer_visible", msLayerIsVisible(map, GET_LAYER(map, map->layerorder[j]))?"1":"0" );
msInsertHashTable(myHashTable, "layer_queryable", msIsLayerQueryable(GET_LAYER(map, map->layerorder[j]))?"1":"0" );
msInsertHashTable(myHashTable, "group_name", pszGroupName);
if(processIfTag(pszTemp, myHashTable, MS_FALSE) != MS_SUCCESS)
return MS_FAILURE;
if(processIfTag(pszTemp, &(GET_LAYER(map, map->layerorder[j])->metadata), MS_FALSE) != MS_SUCCESS)
return MS_FAILURE;
if(processMetadata(pszTemp, &GET_LAYER(map, map->layerorder[j])->metadata) != MS_SUCCESS)
return MS_FAILURE;
break;
}
}
msFreeHashTable(myHashTable);
/*
* Process all metadata tags
* only web object is accessible
*/
if(processMetadata(pszTemp, &(map->web.metadata)) != MS_SUCCESS)
return MS_FAILURE;
/*
* check for if tag
*/
if(processIfTag(pszTemp, &(map->web.metadata), MS_TRUE) != MS_SUCCESS)
return MS_FAILURE;
/*
* Check if leg_icon tag exist
* if so display the first layer first class icon
*/
pszClassImg = strstr(*pszTemp, "[leg_icon");
if(pszClassImg) {
/* find first layer of this group */
for (i=0; i<map->numlayers; i++)
if(GET_LAYER(map, map->layerorder[i])->group && strcmp(GET_LAYER(map, map->layerorder[i])->group, pszGroupName) == 0)
processIcon(map, map->layerorder[i], 0, pszTemp, pszPrefix);
}
return MS_SUCCESS;
}
/*!
* Replace all tags from layer template
* with correct value.
*
* this function return a buffer containing
* the template with correct values.
*
* buffer must be freed by caller.
*/
int generateLayerTemplate(char *pszLayerTemplate, mapObj *map, int nIdxLayer, hashTableObj *oLayerArgs, char **pszTemp, char* pszPrefix)
{
hashTableObj *myHashTable;
char szStatus[10];
char szType[10];
int nOptFlag=0;
char *pszOptFlag = NULL;
char *pszClassImg;
char szTmpstr[128]; /* easily big enough for the couple of instances we need */
*pszTemp = NULL;
if(!pszLayerTemplate ||
!map ||
nIdxLayer > map->numlayers ||
nIdxLayer < 0 ) {
msSetError(MS_WEBERR, "Invalid pointer.", "generateLayerTemplate()");
return MS_FAILURE;
}
if(oLayerArgs)
pszOptFlag = msLookupHashTable(oLayerArgs, "opt_flag");
if(pszOptFlag)
nOptFlag = atoi(pszOptFlag);
/* don't display deleted layers */
if(GET_LAYER(map, nIdxLayer)->status == MS_DELETE)
return MS_SUCCESS;
/* dont display layer is off. */
/* check this if Opt flag is not set */
if((nOptFlag & 2) == 0 && GET_LAYER(map, nIdxLayer)->status == MS_OFF)
return MS_SUCCESS;
/* dont display layer is query. */
/* check this if Opt flag is not set */
if((nOptFlag & 4) == 0 && GET_LAYER(map, nIdxLayer)->type == MS_LAYER_QUERY)
return MS_SUCCESS;
/* dont display layer is annotation. */
/* check this if Opt flag is not set */
if((nOptFlag & 8) == 0 && GET_LAYER(map, nIdxLayer)->type == MS_LAYER_ANNOTATION)
return MS_SUCCESS;
/* dont display layer if out of scale. */
/* check this if Opt flag is not set */
if((nOptFlag & 1) == 0) {
if(map->scaledenom > 0) {
if((GET_LAYER(map, nIdxLayer)->maxscaledenom > 0) && (map->scaledenom > GET_LAYER(map, nIdxLayer)->maxscaledenom))
return MS_SUCCESS;
if((GET_LAYER(map, nIdxLayer)->minscaledenom > 0) && (map->scaledenom <= GET_LAYER(map, nIdxLayer)->minscaledenom))
return MS_SUCCESS;
}
}
/*
* Work from a copy
*/
*pszTemp = msStrdup(pszLayerTemplate);
/*
* Change layer tags
*/
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_name]", GET_LAYER(map, nIdxLayer)->name);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_group]", GET_LAYER(map, nIdxLayer)->group);
snprintf(szTmpstr, sizeof(szTmpstr), "%d", nIdxLayer);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_index]", szTmpstr);
snprintf(szTmpstr, sizeof(szTmpstr), "%g", GET_LAYER(map, nIdxLayer)->minscaledenom);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_minscale]", szTmpstr);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_minscaledenom]", szTmpstr);
snprintf(szTmpstr, sizeof(szTmpstr), "%g", GET_LAYER(map, nIdxLayer)->maxscaledenom);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_maxscale]", szTmpstr);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_maxscaledenom]", szTmpstr);
/*
* Create a hash table that contain info
* on current layer
*/
myHashTable = msCreateHashTable();
/*
* for now, only status and type is required by template
*/
snprintf(szStatus, sizeof(szStatus), "%d", GET_LAYER(map, nIdxLayer)->status);
msInsertHashTable(myHashTable, "layer_status", szStatus);
snprintf(szType, sizeof(szType), "%d", GET_LAYER(map, nIdxLayer)->type);
msInsertHashTable(myHashTable, "layer_type", szType);
msInsertHashTable(myHashTable, "layer_name", (GET_LAYER(map, nIdxLayer)->name)? GET_LAYER(map, nIdxLayer)->name : "");
msInsertHashTable(myHashTable, "layer_group", (GET_LAYER(map, nIdxLayer)->group)? GET_LAYER(map, nIdxLayer)->group : "");
msInsertHashTable(myHashTable, "layer_visible", msLayerIsVisible(map, GET_LAYER(map, nIdxLayer))?"1":"0" );
msInsertHashTable(myHashTable, "layer_queryable", msIsLayerQueryable(GET_LAYER(map, nIdxLayer))?"1":"0" );
if(processIfTag(pszTemp, myHashTable, MS_FALSE) != MS_SUCCESS)
return MS_FAILURE;
if(processIfTag(pszTemp, &(GET_LAYER(map, nIdxLayer)->metadata), MS_FALSE) != MS_SUCCESS)
return MS_FAILURE;
if(processIfTag(pszTemp, &(map->web.metadata), MS_TRUE) != MS_SUCCESS)
return MS_FAILURE;
msFreeHashTable(myHashTable);
/*
* Check if leg_icon tag exist
* if so display the first class icon
*/
pszClassImg = strstr(*pszTemp, "[leg_icon");
if(pszClassImg) {
processIcon(map, nIdxLayer, 0, pszTemp, pszPrefix);
}
/* process all metadata tags
* only current layer and web object
* metaddata are accessible
*/
if(processMetadata(pszTemp, &GET_LAYER(map, nIdxLayer)->metadata) != MS_SUCCESS)
return MS_FAILURE;
if(processMetadata(pszTemp, &(map->web.metadata)) != MS_SUCCESS)
return MS_FAILURE;
return MS_SUCCESS;
}
/*!
* Replace all tags from class template
* with correct value.
*
* this function return a buffer containing
* the template with correct values.
*
* buffer must be freed by caller.
*/
int generateClassTemplate(char* pszClassTemplate, mapObj *map, int nIdxLayer, int nIdxClass, hashTableObj *oClassArgs, char **pszTemp, char* pszPrefix)
{
hashTableObj *myHashTable;
char szStatus[10];
char szType[10];
char *pszClassImg;
int nOptFlag=0;
char *pszOptFlag = NULL;
char szTmpstr[128]; /* easily big enough for the couple of instances we need */
*pszTemp = NULL;
if(!pszClassTemplate ||
!map ||
nIdxLayer > map->numlayers ||
nIdxLayer < 0 ||
nIdxClass > GET_LAYER(map, nIdxLayer)->numclasses ||
nIdxClass < 0) {
msSetError(MS_WEBERR, "Invalid pointer.", "generateClassTemplate()");
return MS_FAILURE;
}
if(oClassArgs)
pszOptFlag = msLookupHashTable(oClassArgs, "Opt_flag");
if(pszOptFlag)
nOptFlag = atoi(pszOptFlag);
/* don't display deleted layers */
if(GET_LAYER(map, nIdxLayer)->status == MS_DELETE)
return MS_SUCCESS;
/* dont display class if layer is off. */
/* check this if Opt flag is not set */
if((nOptFlag & 2) == 0 && GET_LAYER(map, nIdxLayer)->status == MS_OFF)
return MS_SUCCESS;
/* dont display class if layer is query. */
/* check this if Opt flag is not set */
if((nOptFlag & 4) == 0 && GET_LAYER(map, nIdxLayer)->type == MS_LAYER_QUERY)
return MS_SUCCESS;
/* dont display class if layer is annotation. */
/* check this if Opt flag is not set */
if((nOptFlag & 8) == 0 && GET_LAYER(map, nIdxLayer)->type == MS_LAYER_ANNOTATION)
return MS_SUCCESS;
/* dont display layer if out of scale. */
/* check this if Opt flag is not set */
if((nOptFlag & 1) == 0) {
if(map->scaledenom > 0) {
if((GET_LAYER(map, nIdxLayer)->maxscaledenom > 0) && (map->scaledenom > GET_LAYER(map, nIdxLayer)->maxscaledenom))
return MS_SUCCESS;
if((GET_LAYER(map, nIdxLayer)->minscaledenom > 0) && (map->scaledenom <= GET_LAYER(map, nIdxLayer)->minscaledenom))
return MS_SUCCESS;
}
}
/*
* Work from a copy
*/
*pszTemp = (char*)msSmallMalloc(strlen(pszClassTemplate) + 1);
strcpy(*pszTemp, pszClassTemplate);
/*
* Change class tags
*/
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_name]", GET_LAYER(map, nIdxLayer)->class[nIdxClass]->name);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_title]", GET_LAYER(map, nIdxLayer)->class[nIdxClass]->title);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_name]", GET_LAYER(map, nIdxLayer)->name);
snprintf(szTmpstr, sizeof(szTmpstr), "%d", nIdxClass);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_index]", szTmpstr);
snprintf(szTmpstr, sizeof(szTmpstr), "%g", GET_LAYER(map, nIdxLayer)->class[nIdxClass]->minscaledenom);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_minscale]", szTmpstr);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_minscaledenom]", szTmpstr);
snprintf(szTmpstr, sizeof(szTmpstr), "%g", GET_LAYER(map, nIdxLayer)->class[nIdxClass]->maxscaledenom);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_maxscale]", szTmpstr);
*pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_maxscaledenom]", szTmpstr);
/*
* Create a hash table that contain info
* on current layer
*/
myHashTable = msCreateHashTable();
/*
* for now, only status, type, name and group are required by template
*/
snprintf(szStatus, sizeof(szStatus), "%d", GET_LAYER(map, nIdxLayer)->status);
msInsertHashTable(myHashTable, "layer_status", szStatus);
snprintf(szType, sizeof(szType), "%d", GET_LAYER(map, nIdxLayer)->type);
msInsertHashTable(myHashTable, "layer_type", szType);
msInsertHashTable(myHashTable, "layer_name",
(GET_LAYER(map, nIdxLayer)->name)? GET_LAYER(map, nIdxLayer)->name : "");
msInsertHashTable(myHashTable, "layer_group",
(GET_LAYER(map, nIdxLayer)->group)? GET_LAYER(map, nIdxLayer)->group : "");
msInsertHashTable(myHashTable, "layer_visible", msLayerIsVisible(map, GET_LAYER(map, nIdxLayer))?"1":"0" );
msInsertHashTable(myHashTable, "layer_queryable", msIsLayerQueryable(GET_LAYER(map, nIdxLayer))?"1":"0" );
msInsertHashTable(myHashTable, "class_name",
(GET_LAYER(map, nIdxLayer)->class[nIdxClass]->name)? GET_LAYER(map, nIdxLayer)->class[nIdxClass]->name : "");
if(processIfTag(pszTemp, myHashTable, MS_FALSE) != MS_SUCCESS)
return MS_FAILURE;
if(processIfTag(pszTemp, &(GET_LAYER(map, nIdxLayer)->metadata), MS_FALSE) != MS_SUCCESS)
return MS_FAILURE;
if(processIfTag(pszTemp, &(map->web.metadata), MS_TRUE) != MS_SUCCESS)
return MS_FAILURE;
msFreeHashTable(myHashTable);
/*
* Check if leg_icon tag exist
*/
pszClassImg = strstr(*pszTemp, "[leg_icon");
if(pszClassImg) {
processIcon(map, nIdxLayer, nIdxClass, pszTemp, pszPrefix);
}
/* process all metadata tags
* only current layer and web object
* metaddata are accessible
*/
if(processMetadata(pszTemp, &GET_LAYER(map, nIdxLayer)->metadata) != MS_SUCCESS)
return MS_FAILURE;
if(processMetadata(pszTemp, &(map->web.metadata)) != MS_SUCCESS)
return MS_FAILURE;
return MS_SUCCESS;
}
char *generateLegendTemplate(mapservObj *mapserv)
{
FILE *stream;
char *file = NULL;
int length;
char *pszResult = NULL;
char *legGroupHtml = NULL;
char *legLayerHtml = NULL;
char *legClassHtml = NULL;
char *legLayerHtmlCopy = NULL;
char *legClassHtmlCopy = NULL;
char *legGroupHtmlCopy = NULL;
char *legHeaderHtml = NULL;
char *legFooterHtml = NULL;
char *pszPrefix = NULL;
char *pszMapFname = NULL;
struct stat tmpStat;
char *pszOrderMetadata = NULL;
char *pszOrder = NULL;
int i,j,k;
char **papszGroups = NULL;
int nGroupNames = 0;
int nLegendOrder = 0;
char *pszOrderValue;
hashTableObj *groupArgs = NULL;
hashTableObj *layerArgs = NULL;
hashTableObj *classArgs = NULL;
ms_regex_t re; /* compiled regular expression to be matched */
int *panCurrentDrawingOrder = NULL;
char szPath[MS_MAXPATHLEN];
if(ms_regcomp(&re, MS_TEMPLATE_EXPR, MS_REG_EXTENDED|MS_REG_NOSUB|MS_REG_ICASE) != 0) {
msSetError(MS_IOERR, "Error regcomp.", "generateLegendTemplate()");
return NULL;
}
if(ms_regexec(&re, mapserv->map->legend.template, 0, NULL, 0) != 0) { /* no match */
msSetError(MS_IOERR, "Invalid template file name.", "generateLegendTemplate()");
ms_regfree(&re);
return NULL;
}
ms_regfree(&re);
/* -------------------------------------------------------------------- */
/* Save the current drawing order. The drawing order is reset */
/* at the end of the function. */
/* -------------------------------------------------------------------- */
if(mapserv && mapserv->map && mapserv->map->numlayers > 0) {
panCurrentDrawingOrder =
(int *)msSmallMalloc(sizeof(int)*mapserv->map->numlayers);
for (i=0; i<mapserv->map->numlayers; i++) {
if(mapserv->map->layerorder)
panCurrentDrawingOrder[i] = mapserv->map->layerorder[i];
else
panCurrentDrawingOrder[i] = i;
}
}
/*
* build prefix filename
* for legend icon creation
*/
for(i=0; i<mapserv->request->NumParams; i++) /* find the mapfile parameter first */
if(strcasecmp(mapserv->request->ParamNames[i], "map") == 0) break;
if(i == mapserv->request->NumParams) {
if( getenv("MS_MAPFILE"))
pszMapFname = msStringConcatenate(pszMapFname, getenv("MS_MAPFILE"));
} else {
if(getenv(mapserv->request->ParamValues[i])) /* an environment references the actual file to use */
pszMapFname = msStringConcatenate(pszMapFname, getenv(mapserv->request->ParamValues[i]));
else
pszMapFname = msStringConcatenate(pszMapFname, mapserv->request->ParamValues[i]);
}
if(pszMapFname) {
if(stat(pszMapFname, &tmpStat) != -1) {
int nLen;
nLen = (mapserv->map->name?strlen(mapserv->map->name):0) + 50;
pszPrefix = (char*)msSmallMalloc((nLen+1) * sizeof(char));
snprintf(pszPrefix, nLen, "%s_%ld_%ld",
mapserv->map->name,
(long) tmpStat.st_size,
(long) tmpStat.st_mtime);
pszPrefix[nLen] = '\0';
}
free(pszMapFname);
pszMapFname = NULL;
} else {
/* -------------------------------------------------------------------- */
/* map file name may not be avaible when the template functions */
/* are called from mapscript. Use the time stamp as prefix. */
/* -------------------------------------------------------------------- */
char pszTime[20];
snprintf(pszTime, sizeof(pszTime), "%ld", (long)time(NULL));
pszPrefix = msStringConcatenate(pszPrefix, pszTime);
}
/* open template */
if((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, mapserv->map->legend.template), "r")) == NULL) {
msSetError(MS_IOERR, "Error while opening template file.", "generateLegendTemplate()");
return NULL;
}
fseek(stream, 0, SEEK_END);
length = ftell(stream);
rewind(stream);
file = (char*)msSmallMalloc(length + 1);
if(!file) {
msSetError(MS_IOERR, "Error while allocating memory for template file.", "generateLegendTemplate()");
fclose(stream);
return NULL;
}
/*
* Read all the template file
*/
fread(file, length, 1, stream);
/* Disabled for now due to Windows issue, see ticket #3814
if( 1 != fread(file, length, 1, stream)) {
msSetError(MS_IOERR, "Error while reading template file.", "generateLegendTemplate()");
free(file);
fclose(stream);
return NULL;
}
*/
file[length] = '\0';
if(msValidateContexts(mapserv->map) != MS_SUCCESS) return NULL; /* make sure there are no recursive REQUIRES or LABELREQUIRES expressions */
/*
* Seperate header/footer, groups, layers and class
*/
getInlineTag("leg_header_html", file, &legHeaderHtml);
getInlineTag("leg_footer_html", file, &legFooterHtml);
getInlineTag("leg_group_html", file, &legGroupHtml);
getInlineTag("leg_layer_html", file, &legLayerHtml);
getInlineTag("leg_class_html", file, &legClassHtml);
/*
* Retrieve arguments of all three parts
*/
if(legGroupHtml)
if(getTagArgs("leg_group_html", file, &groupArgs) != MS_SUCCESS)
return NULL;
if(legLayerHtml)
if(getTagArgs("leg_layer_html", file, &layerArgs) != MS_SUCCESS)
return NULL;
if(legClassHtml)
if(getTagArgs("leg_class_html", file, &classArgs) != MS_SUCCESS)
return NULL;
mapserv->map->cellsize = msAdjustExtent(&(mapserv->map->extent),
mapserv->map->width,
mapserv->map->height);
if(msCalculateScale(mapserv->map->extent, mapserv->map->units,
mapserv->map->width, mapserv->map->height,
mapserv->map->resolution, &mapserv->map->scaledenom) != MS_SUCCESS)
return(NULL);
/* start with the header if present */
if(legHeaderHtml) pszResult = msStringConcatenate(pszResult, legHeaderHtml);
/********************************************************************/
/*
* order layers if order_metadata args is set
* If not, keep default order
*/
pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata");
if(sortLayerByMetadata(mapserv->map, pszOrderMetadata) != MS_SUCCESS)
goto error;
/* -------------------------------------------------------------------- */
/* if the order tag is set to ascending or descending, the */
/* current order will be changed to correspond to that. */
/* -------------------------------------------------------------------- */
pszOrder = msLookupHashTable(layerArgs, "order");
if(pszOrder && ((strcasecmp(pszOrder, "ASCENDING") == 0) ||
(strcasecmp(pszOrder, "DESCENDING") == 0))) {
if(sortLayerByOrder(mapserv->map, pszOrder) != MS_SUCCESS)
goto error;
}
if(legGroupHtml) {
/* retrieve group names */
papszGroups = msGetAllGroupNames(mapserv->map, &nGroupNames);
for (i=0; i<nGroupNames; i++) {
/* process group tags */
if(generateGroupTemplate(legGroupHtml, mapserv->map, papszGroups[i], groupArgs, &legGroupHtmlCopy, pszPrefix) != MS_SUCCESS) {
if(pszResult)
free(pszResult);
pszResult=NULL;
goto error;
}
/* concatenate it to final result */
pszResult = msStringConcatenate(pszResult, legGroupHtmlCopy);
/*
if(!pszResult)
{
if(pszResult)
free(pszResult);
pszResult=NULL;
goto error;
}
*/
if(legGroupHtmlCopy) {
free(legGroupHtmlCopy);
legGroupHtmlCopy = NULL;
}
/* for all layers in group */
if(legLayerHtml) {
for (j=0; j<mapserv->map->numlayers; j++) {
/*
* if order_metadata is set and the order
* value is less than 0, dont display it
*/
pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata");
if(pszOrderMetadata) {
pszOrderValue = msLookupHashTable(&(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->metadata), pszOrderMetadata);
if(pszOrderValue) {
nLegendOrder = atoi(pszOrderValue);
if(nLegendOrder < 0)
continue;
}
}
if(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group && strcmp(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group, papszGroups[i]) == 0) {
/* process all layer tags */
if(generateLayerTemplate(legLayerHtml, mapserv->map, mapserv->map->layerorder[j], layerArgs, &legLayerHtmlCopy, pszPrefix) != MS_SUCCESS) {
if(pszResult)
free(pszResult);
pszResult=NULL;
goto error;
}
/* concatenate to final result */
pszResult = msStringConcatenate(pszResult, legLayerHtmlCopy);
if(legLayerHtmlCopy) {
free(legLayerHtmlCopy);
legLayerHtmlCopy = NULL;
}
/* for all classes in layer */
if(legClassHtml) {
for (k=0; k<GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->numclasses; k++) {
/* process all class tags */
if(!GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->class[k]->name)
continue;
if(generateClassTemplate(legClassHtml, mapserv->map, mapserv->map->layerorder[j], k, classArgs, &legClassHtmlCopy, pszPrefix) != MS_SUCCESS) {
if(pszResult)
free(pszResult);
pszResult=NULL;
goto error;
}
/* concatenate to final result */
pszResult = msStringConcatenate(pszResult, legClassHtmlCopy);
if(legClassHtmlCopy) {
free(legClassHtmlCopy);
legClassHtmlCopy = NULL;
}
}
}
}
}
} else if(legClassHtml) { /* no layer template specified but class and group template */
for (j=0; j<mapserv->map->numlayers; j++) {
/*
* if order_metadata is set and the order
* value is less than 0, dont display it
*/
pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata");
if(pszOrderMetadata) {
pszOrderValue = msLookupHashTable(&(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->metadata), pszOrderMetadata);
if(pszOrderValue) {
nLegendOrder = atoi(pszOrderValue);
if(nLegendOrder < 0)
continue;
}
}
if(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group && strcmp(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group, papszGroups[i]) == 0) {
/* for all classes in layer */
if(legClassHtml) {
for (k=0; k<GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->numclasses; k++) {
/* process all class tags */
if(!GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->class[k]->name)
continue;
if(generateClassTemplate(legClassHtml, mapserv->map, mapserv->map->layerorder[j], k, classArgs, &legClassHtmlCopy, pszPrefix) != MS_SUCCESS) {
if(pszResult)
free(pszResult);
pszResult=NULL;
goto error;
}
/* concatenate to final result */
pszResult = msStringConcatenate(pszResult, legClassHtmlCopy);
if(legClassHtmlCopy) {
free(legClassHtmlCopy);
legClassHtmlCopy = NULL;
}
}
}
}
}
}
}
} else {
/* if no group template specified */
if(legLayerHtml) {
for (j=0; j<mapserv->map->numlayers; j++) {
/*
* if order_metadata is set and the order
* value is less than 0, dont display it
*/
pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata");
if(pszOrderMetadata) {
pszOrderValue = msLookupHashTable(&(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->metadata), pszOrderMetadata);
if(pszOrderValue) {
nLegendOrder = atoi(pszOrderValue);
if(nLegendOrder < 0)
continue;
} else
nLegendOrder=0;
}
/* process a layer tags */
if(generateLayerTemplate(legLayerHtml, mapserv->map, mapserv->map->layerorder[j], layerArgs, &legLayerHtmlCopy, pszPrefix) != MS_SUCCESS) {
if(pszResult)
free(pszResult);
pszResult=NULL;
goto error;
}
/* concatenate to final result */
pszResult = msStringConcatenate(pszResult, legLayerHtmlCopy);
if(legLayerHtmlCopy) {
free(legLayerHtmlCopy);
legLayerHtmlCopy = NULL;
}
/* for all classes in layer */
if(legClassHtml) {
for (k=0; k<GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->numclasses; k++) {
/* process all class tags */
if(!GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->class[k]->name)
continue;
if(generateClassTemplate(legClassHtml, mapserv->map, mapserv->map->layerorder[j], k, classArgs, &legClassHtmlCopy, pszPrefix) != MS_SUCCESS) {
if(pszResult)
free(pszResult);
pszResult=NULL;
goto error;
}
/* concatenate to final result */
pszResult = msStringConcatenate(pszResult, legClassHtmlCopy);
if(legClassHtmlCopy) {
free(legClassHtmlCopy);
legClassHtmlCopy = NULL;
}
}
}
}
} else { /* if no group and layer template specified */
if(legClassHtml) {
for (j=0; j<mapserv->map->numlayers; j++) {
/*
* if order_metadata is set and the order
* value is less than 0, dont display it
*/
pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata");
if(pszOrderMetadata) {
pszOrderValue = msLookupHashTable(&(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->metadata), pszOrderMetadata);
if(pszOrderValue) {
nLegendOrder = atoi(pszOrderValue);
if(nLegendOrder < 0)
continue;
}
}
for (k=0; k<GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->numclasses; k++) {
if(!GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->class[k]->name)
continue;
if(generateClassTemplate(legClassHtml, mapserv->map, mapserv->map->layerorder[j], k, classArgs, &legClassHtmlCopy, pszPrefix) != MS_SUCCESS) {
if(pszResult)
free(pszResult);
pszResult=NULL;
goto error;
}
pszResult = msStringConcatenate(pszResult, legClassHtmlCopy);
if(legClassHtmlCopy) {
free(legClassHtmlCopy);
legClassHtmlCopy = NULL;
}
}
}
}
}
}
/* finish with the footer if present */
if(legFooterHtml) pszResult = msStringConcatenate(pszResult, legFooterHtml);
/*
* if we reach this point, that mean no error was generated.
* So check if template is null and initialize it to <space>.
*/
if(pszResult == NULL) {
pszResult = msStringConcatenate(pszResult, " ");
}
/********************************************************************/
error:
if(papszGroups) {
for (i=0; i<nGroupNames; i++)
msFree(papszGroups[i]);
msFree(papszGroups);
}
msFreeHashTable(groupArgs);
msFreeHashTable(layerArgs);
msFreeHashTable(classArgs);
msFree(file);
msFree(legGroupHtmlCopy);
msFree(legLayerHtmlCopy);
msFree(legClassHtmlCopy);
msFree(legHeaderHtml);
msFree(legFooterHtml);
msFree(legGroupHtml);
msFree(legLayerHtml);
msFree(legClassHtml);
msFree(pszPrefix);
fclose(stream);
/* -------------------------------------------------------------------- */
/* Reset the layerdrawing order. */
/* -------------------------------------------------------------------- */
if(panCurrentDrawingOrder && mapserv->map->layerorder) {
for (i=0; i<mapserv->map->numlayers; i++)
mapserv->map->layerorder[i] = panCurrentDrawingOrder[i];
free(panCurrentDrawingOrder);
}
return pszResult;
}
char *processOneToManyJoin(mapservObj* mapserv, joinObj *join)
{
int records=MS_FALSE;
FILE *stream=NULL;
char *outbuf;
char line[MS_BUFFER_LENGTH], *tmpline;
char szPath[MS_MAXPATHLEN];
if((outbuf = msStrdup("")) == NULL) return(NULL); /* empty at first */
msJoinPrepare(join, &(mapserv->resultshape)); /* execute the join */
while(msJoinNext(join) == MS_SUCCESS) {
/* First time through, deal with the header (if necessary) and open the main template. We only */
/* want to do this if there are joined records. */
if(records == MS_FALSE) {
if(join->header != NULL) {
if((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, join->header), "r")) == NULL) {
msSetError(MS_IOERR, "Error while opening join header file %s.", "processOneToManyJoin()", join->header);
return(NULL);
}
if(isValidTemplate(stream, join->header) != MS_TRUE) {
fclose(stream);
return NULL;
}
/* echo file to the output buffer, no substitutions */
while(fgets(line, MS_BUFFER_LENGTH, stream) != NULL) outbuf = msStringConcatenate(outbuf, line);
fclose(stream);
}
if((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, join->template), "r")) == NULL) {
msSetError(MS_IOERR, "Error while opening join template file %s.", "processOneToManyJoin()", join->template);
return(NULL);
}
if(isValidTemplate(stream, join->template) != MS_TRUE) {
fclose(stream);
return NULL;
}
records = MS_TRUE;
}
while(fgets(line, MS_BUFFER_LENGTH, stream) != NULL) { /* now on to the end of the template */
if(strchr(line, '[') != NULL) {
tmpline = processLine(mapserv, line, NULL, QUERY); /* no multiline tags are allowed in a join */
if(!tmpline) return NULL;
outbuf = msStringConcatenate(outbuf, tmpline);
free(tmpline);
} else /* no subs, just echo */
outbuf = msStringConcatenate(outbuf, line);
}
rewind(stream);
fgets(line, MS_BUFFER_LENGTH, stream); /* skip the first line since it's the magic string */
} /* next record */
if(records==MS_TRUE && join->footer) {
if((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, join->footer), "r")) == NULL) {
msSetError(MS_IOERR, "Error while opening join footer file %s.", "processOneToManyJoin()", join->footer);
return(NULL);
}
if(isValidTemplate(stream, join->footer) != MS_TRUE) {
fclose(stream);
return NULL;
}
/* echo file to the output buffer, no substitutions */
while(fgets(line, MS_BUFFER_LENGTH, stream) != NULL) outbuf = msStringConcatenate(outbuf, line);
fclose(stream);
}
/* clear any data associated with the join */
msFreeCharArray(join->values, join->numitems);
join->values = NULL;
return(outbuf);
}
/*
** Process a single line in the template. A few tags (e.g. [resultset]...[/resultset]) can be multi-line so
** we pass the filehandle to look ahead if necessary.
*/
static char *processLine(mapservObj *mapserv, char *instr, FILE *stream, int mode)
{
int i, j;
#define PROCESSLINE_BUFLEN 5120
char repstr[PROCESSLINE_BUFLEN], substr[PROCESSLINE_BUFLEN], *outstr; /* repstr = replace string, substr = sub string */
struct hashObj *tp=NULL;
char *encodedstr;
#ifdef USE_PROJ
rectObj llextent;
pointObj llpoint;
#endif
outstr = msStrdup(instr); /* work from a copy */
if(strstr(outstr, "[version]")) outstr = msReplaceSubstring(outstr, "[version]", msGetVersion());
snprintf(repstr, PROCESSLINE_BUFLEN, "%s%s%s.%s", mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat));
outstr = msReplaceSubstring(outstr, "[img]", repstr);
snprintf(repstr, PROCESSLINE_BUFLEN, "%s%sref%s.%s", mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat));
outstr = msReplaceSubstring(outstr, "[ref]", repstr);
if(strstr(outstr, "[errmsg")) {
char *errmsg = msGetErrorString(";");
if(!errmsg) errmsg = msStrdup("Error message buffer is empty."); /* should never happen, but just in case... */
outstr = msReplaceSubstring(outstr, "[errmsg]", errmsg);
encodedstr = msEncodeUrl(errmsg);
outstr = msReplaceSubstring(outstr, "[errmsg_esc]", encodedstr);
free(errmsg);
free(encodedstr);
}
if(strstr(outstr, "[legend]")) {
/* if there's a template legend specified, use it */
if(mapserv->map->legend.template) {
char *legendTemplate;
legendTemplate = generateLegendTemplate(mapserv);
if(legendTemplate) {
outstr = msReplaceSubstring(outstr, "[legend]", legendTemplate);
free(legendTemplate);
} else /* error already generated by (generateLegendTemplate()) */
return NULL;
} else { /* if not display gif image with all legend icon */
snprintf(repstr, PROCESSLINE_BUFLEN, "%s%sleg%s.%s", mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat));
outstr = msReplaceSubstring(outstr, "[legend]", repstr);
}
}
snprintf(repstr, PROCESSLINE_BUFLEN, "%s%ssb%s.%s", mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat));
outstr = msReplaceSubstring(outstr, "[scalebar]", repstr);
if(mapserv->savequery) {
snprintf(repstr, PROCESSLINE_BUFLEN, "%s%s%s%s", mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, MS_QUERY_EXTENSION);
outstr = msReplaceSubstring(outstr, "[queryfile]", repstr);
}
if(mapserv->savemap) {
snprintf(repstr, PROCESSLINE_BUFLEN, "%s%s%s.map", mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id);
outstr = msReplaceSubstring(outstr, "[map]", repstr);
}
#if defined(USE_WMS_SVR) || defined (USE_WFS_SVR) || defined (USE_WCS_SVR) || defined(USE_SOS_SVR) || defined(USE_WMS_LYR) || defined(USE_WFS_LYR)
outstr = msReplaceSubstring(outstr, "[mapserv_onlineresource]",
msOWSGetOnlineResource(mapserv->map, "O", "onlineresource", mapserv->request));
#else
outstr = msReplaceSubstring(outstr, "[mapserv_onlineresource]",
msBuildOnlineResource(mapserv->map, mapserv->request));
#endif
if(getenv("HTTP_HOST")) {
snprintf(repstr, PROCESSLINE_BUFLEN, "%s", getenv("HTTP_HOST"));
outstr = msReplaceSubstring(outstr, "[host]", repstr);
}
if(getenv("SERVER_PORT")) {
snprintf(repstr, PROCESSLINE_BUFLEN, "%s", getenv("SERVER_PORT"));
outstr = msReplaceSubstring(outstr, "[port]", repstr);
}
snprintf(repstr, PROCESSLINE_BUFLEN, "%s", mapserv->Id);
outstr = msReplaceSubstring(outstr, "[id]", repstr);
repstr[0] = '\0'; /* Layer list for a "POST" request */
for(i=0; i<mapserv->NumLayers; i++) {
strlcat(repstr, mapserv->Layers[i], sizeof(repstr));
strlcat(repstr, " ", sizeof(repstr));
}
msStringTrimBlanks(repstr);
outstr = msReplaceSubstring(outstr, "[layers]", repstr);
encodedstr = msEncodeUrl(repstr);
outstr = msReplaceSubstring(outstr, "[layers_esc]", encodedstr);
free(encodedstr);
strcpy(repstr, ""); /* list of ALL layers that can be toggled */
repstr[0] = '\0';
for(i=0; i<mapserv->map->numlayers; i++) {
if(GET_LAYER(mapserv->map, i)->status != MS_DEFAULT && GET_LAYER(mapserv->map, i)->name != NULL) {
strlcat(repstr, GET_LAYER(mapserv->map, i)->name, sizeof(repstr));
strlcat(repstr, " ", sizeof(repstr));
}
}
msStringTrimBlanks(repstr);
outstr = msReplaceSubstring(outstr, "[toggle_layers]", repstr);
encodedstr = msEncodeUrl(repstr);
outstr = msReplaceSubstring(outstr, "[toggle_layers_esc]", encodedstr);
free(encodedstr);
for(i=0; i<mapserv->map->numlayers; i++) { /* Set form widgets (i.e. checkboxes, radio and select lists), note that default layers don't show up here */
if(isOn(mapserv, GET_LAYER(mapserv->map, i)->name, GET_LAYER(mapserv->map, i)->group) == MS_TRUE) {
if(GET_LAYER(mapserv->map, i)->group) {
snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", GET_LAYER(mapserv->map, i)->group);
outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\"");
snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", GET_LAYER(mapserv->map, i)->group);
outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\"");
}
if(GET_LAYER(mapserv->map, i)->name) {
snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", GET_LAYER(mapserv->map, i)->name);
outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\"");
snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", GET_LAYER(mapserv->map, i)->name);
outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\"");
}
} else {
if(GET_LAYER(mapserv->map, i)->group) {
snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", GET_LAYER(mapserv->map, i)->group);
outstr = msReplaceSubstring(outstr, substr, "");
snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", GET_LAYER(mapserv->map, i)->group);
outstr = msReplaceSubstring(outstr, substr, "");
}
if(GET_LAYER(mapserv->map, i)->name) {
snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", GET_LAYER(mapserv->map, i)->name);
outstr = msReplaceSubstring(outstr, substr, "");
snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", GET_LAYER(mapserv->map, i)->name);
outstr = msReplaceSubstring(outstr, substr, "");
}
}
}
for(i=-1; i<=1; i++) { /* make zoom direction persistant */
if(mapserv->ZoomDirection == i) {
snprintf(substr, sizeof(substr), "[zoomdir_%d_select]", i);
outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\"");
snprintf(substr, sizeof(substr), "[zoomdir_%d_check]", i);
outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\"");
} else {
snprintf(substr, sizeof(substr), "[zoomdir_%d_select]", i);
outstr = msReplaceSubstring(outstr, substr, "");
snprintf(substr, sizeof(substr), "[zoomdir_%d_check]", i);
outstr = msReplaceSubstring(outstr, substr, "");
}
}
for(i=MINZOOM; i<=MAXZOOM; i++) { /* make zoom persistant */
if(mapserv->Zoom == i) {
snprintf(substr, sizeof(substr), "[zoom_%d_select]", i);
outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\"");
snprintf(substr, sizeof(substr), "[zoom_%d_check]", i);
outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\"");
} else {
snprintf(substr, sizeof(substr), "[zoom_%d_select]", i);
outstr = msReplaceSubstring(outstr, substr, "");
snprintf(substr, sizeof(substr), "[zoom_%d_check]", i);
outstr = msReplaceSubstring(outstr, substr, "");
}
}
/* allow web object metadata access in template */
/*
* reworked by SG to use HashTable methods
*/
if(&(mapserv->map->web.metadata) && strstr(outstr, "web_")) {
for (j=0; j<MS_HASHSIZE; j++) {
if(mapserv->map->web.metadata.items[j] != NULL) {
for(tp=mapserv->map->web.metadata.items[j]; tp!=NULL; tp=tp->next) {
snprintf(substr, PROCESSLINE_BUFLEN, "[web_%s]", tp->key);
outstr = msReplaceSubstring(outstr, substr, tp->data);
snprintf(substr, PROCESSLINE_BUFLEN, "[web_%s_esc]", tp->key);
encodedstr = msEncodeUrl(tp->data);
outstr = msReplaceSubstring(outstr, substr, encodedstr);
free(encodedstr);
}
}
}
}
/* allow layer metadata access in template */
for(i=0; i<mapserv->map->numlayers; i++) {
if(&(GET_LAYER(mapserv->map, i)->metadata) && GET_LAYER(mapserv->map, i)->name && strstr(outstr, GET_LAYER(mapserv->map, i)->name)) {
for(j=0; j<MS_HASHSIZE; j++) {
if(GET_LAYER(mapserv->map, i)->metadata.items[j] != NULL) {
for(tp=GET_LAYER(mapserv->map, i)->metadata.items[j]; tp!=NULL; tp=tp->next) {
snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s]", GET_LAYER(mapserv->map, i)->name, tp->key);
if(GET_LAYER(mapserv->map, i)->status == MS_ON)
outstr = msReplaceSubstring(outstr, substr, tp->data);
else
outstr = msReplaceSubstring(outstr, substr, "");
snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s_esc]", GET_LAYER(mapserv->map, i)->name, tp->key);
if(GET_LAYER(mapserv->map, i)->status == MS_ON) {
encodedstr = msEncodeUrl(tp->data);
outstr = msReplaceSubstring(outstr, substr, encodedstr);
free(encodedstr);
} else
outstr = msReplaceSubstring(outstr, substr, "");
}
}
}
}