/****************************************************************************** * $Id$ * * Project: MapServer * Purpose: OpenGIS Web Mapping Service support implementation. * Author: Steve Lime and the MapServer team. * ****************************************************************************** * Copyright (c) 1996-2005 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. *****************************************************************************/ #define _GNU_SOURCE #include "mapserver.h" #include "maperror.h" #include "mapgml.h" #include #include "maptemplate.h" #include "mapogcsld.h" #include "mapogcfilter.h" #include "maptime.h" #include "mapproject.h" #include #include #include #ifdef WIN32 #include #endif MS_CVSID("$Id$") /* ================================================================== * WMS Server stuff. * ================================================================== */ #ifdef USE_WMS_SVR #ifdef USE_OGR int ogrEnabled = 1; #else int ogrEnabled = 0; #endif /* USE_OGR */ /* ** msWMSException() ** ** Report current MapServer error in requested format. */ int msWMSException(mapObj *map, int nVersion, const char *exception_code, char *wms_exception_format) { const char *encoding; char *schemalocation = NULL; /* Default to WMS 1.3.0 exceptions if version not set yet */ if (nVersion <= 0) nVersion = OWS_1_3_0; /* get scheam location */ schemalocation = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) ); encoding = msOWSLookupMetadata(&(map->web.metadata), "MO", "encoding"); /* Establish default exception format depending on VERSION */ if (wms_exception_format == NULL) { if (nVersion <= OWS_1_0_0) wms_exception_format = "INIMAGE"; /* WMS 1.0.0 */ else if (nVersion <= OWS_1_0_7) wms_exception_format = "SE_XML"; /* WMS 1.0.1 to 1.0.7 */ else if (nVersion <= OWS_1_1_1) wms_exception_format = "application/vnd.ogc.se_xml"; /* WMS 1.1.0 and later */ else wms_exception_format = "text/xml"; } if (strcasecmp(wms_exception_format, "INIMAGE") == 0 || strcasecmp(wms_exception_format, "BLANK") == 0 || strcasecmp(wms_exception_format, "application/vnd.ogc.se_inimage")== 0 || strcasecmp(wms_exception_format, "application/vnd.ogc.se_blank") == 0) { int blank = 0; if (strcasecmp(wms_exception_format, "BLANK") == 0 || strcasecmp(wms_exception_format, "application/vnd.ogc.se_blank") == 0) { blank = 1; } msWriteErrorImage(map, NULL, blank); } else if (strcasecmp(wms_exception_format, "WMS_XML") == 0) /* Only in V1.0.0 */ { if (encoding) msIO_setHeader("Content-type","text/xml; charset=%s", encoding); else msIO_setHeader("Content-type","text/xml"); msIO_sendHeaders(); msIO_printf("\n"); msWriteErrorXML(stdout); msIO_printf("\n"); } else /* XML error, the default: SE_XML (1.0.1 to 1.0.7) */ /* or application/vnd.ogc.se_xml (1.1.0 and later) */ { if (nVersion <= OWS_1_0_7) { /* In V1.0.1 to 1.0.7, the MIME type was text/xml */ if (encoding) msIO_setHeader("Content-type","text/xml; charset=%s", encoding); else msIO_setHeader("Content-type","text/xml"); msIO_sendHeaders(); msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "encoding", OWS_NOERR, "\n", "ISO-8859-1"); msIO_printf("\n"); msIO_printf("\n"); } else if (nVersion <= OWS_1_1_0) { /* In V1.1.0 and later, we have OGC-specific MIME types */ /* we cannot return anything else than application/vnd.ogc.se_xml here. */ if (encoding) msIO_setHeader("Content-type","application/vnd.ogc.se_xml; charset=%s", encoding); else msIO_setHeader("Content-type","application/vnd.ogc.se_xml"); msIO_sendHeaders(); msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "encoding", OWS_NOERR, "\n", "ISO-8859-1"); msIO_printf("\n",schemalocation); msIO_printf("\n"); } else if (nVersion <= OWS_1_1_1)/* 1.1.1 */ { if (encoding) msIO_setHeader("Content-type","application/vnd.ogc.se_xml; charset=%s", encoding); else msIO_setHeader("Content-type","application/vnd.ogc.se_xml"); msIO_sendHeaders(); msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "encoding", OWS_NOERR, "\n", "ISO-8859-1"); msIO_printf("\n", schemalocation); msIO_printf("\n"); } else /*1.3.0*/ { if (strcasecmp(wms_exception_format, "application/vnd.ogc.se_xml") == 0) { if (encoding) msIO_setHeader("Content-type","application/vnd.ogc.se_xml; charset=%s", encoding); else msIO_setHeader("Content-type","application/vnd.ogc.se_xml"); } else { if (encoding) msIO_setHeader("Content-type","text/xml; charset=%s", encoding); else msIO_setHeader("Content-type","text/xml"); } msIO_sendHeaders(); msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "encoding", OWS_NOERR, "\n", "ISO-8859-1"); msIO_printf("\n", schemalocation); } if (exception_code) msIO_printf("\n", exception_code); else msIO_printf("\n"); msWriteErrorXML(stdout); msIO_printf("\n"); msIO_printf("\n"); free(schemalocation); } return MS_FAILURE; /* so that we can call 'return msWMSException();' anywhere */ } void msWMSSetTimePattern(const char *timepatternstring, char *timestring) { char *time = NULL; char **atimes, **tokens = NULL; int numtimes, ntmp, i = 0; char *tmpstr = NULL; if (timepatternstring && timestring) { /* parse the time parameter to extract a distinct time. */ /* time value can be dicrete times (eg 2004-09-21), */ /* multiple times (2004-09-21, 2004-09-22, ...) */ /* and range(s) (2004-09-21/2004-09-25, 2004-09-27/2004-09-29) */ if (strstr(timestring, ",") == NULL && strstr(timestring, "/") == NULL) /* discrete time */ { time = msStrdup(timestring); } else { atimes = msStringSplit (timestring, ',', &numtimes); if (numtimes >=1 && atimes) { tokens = msStringSplit(atimes[0], '/', &ntmp); if (ntmp == 2 && tokens) /* range */ { time = msStrdup(tokens[0]); } else /* multiple times */ { time = msStrdup(atimes[0]); } msFreeCharArray(tokens, ntmp); msFreeCharArray(atimes, numtimes); } } /* get the pattern to use */ if (time) { tokens = msStringSplit(timepatternstring, ',', &ntmp); if (tokens && ntmp >= 1) { for (i=0; i 0) { msStringTrimBlanks(tokens[i]); tmpstr = msStringTrimLeft(tokens[i]); if (msTimeMatchPattern(time, tmpstr) == MS_TRUE) { msSetLimitedPattersToUse(tmpstr); break; } } } msFreeCharArray(tokens, ntmp); } free(time); } } } /* ** Apply the TIME parameter to layers that are time aware */ int msWMSApplyTime(mapObj *map, int version, char *time, char *wms_exception_format) { int i=0; layerObj *lp = NULL; const char *timeextent, *timefield, *timedefault, *timpattern = NULL; if (map) { for (i=0; inumlayers; i++) { lp = (GET_LAYER(map, i)); if (lp->status != MS_ON && lp->status != MS_DEFAULT) continue; /* check if the layer is time aware */ timeextent = msOWSLookupMetadata(&(lp->metadata), "MO", "timeextent"); timefield = msOWSLookupMetadata(&(lp->metadata), "MO", "timeitem"); timedefault = msOWSLookupMetadata(&(lp->metadata), "MO", "timedefault"); if (timeextent && timefield) { /* check to see if the time value is given. If not */ /* use default time. If default time is not available */ /* send an exception */ if (time == NULL || strlen(time) <=0) { if (timedefault == NULL) { msSetError(MS_WMSERR, "No Time value was given, and no default time value defined.", "msWMSApplyTime"); return msWMSException(map, version, "MissingDimensionValue", wms_exception_format); } else { if (msValidateTimeValue((char *)timedefault, timeextent) == MS_FALSE) { msSetError(MS_WMSERR, "No Time value was given, and the default time value %s is invalid or outside the time extent defined %s", "msWMSApplyTime", timedefault, timeextent); /* return MS_FALSE; */ return msWMSException(map, version, "InvalidDimensionValue", wms_exception_format); } msLayerSetTimeFilter(lp, timedefault, timefield); } } else { /* check if given time is in the range */ if (msValidateTimeValue(time, timeextent) == MS_FALSE) { if (timedefault == NULL) { msSetError(MS_WMSERR, "Time value(s) %s given is invalid or outside the time extent defined (%s).", "msWMSApplyTime", time, timeextent); /* return MS_FALSE; */ return msWMSException(map, version, "InvalidDimensionValue", wms_exception_format); } else { if (msValidateTimeValue((char *)timedefault, timeextent) == MS_FALSE) { msSetError(MS_WMSERR, "Time value(s) %s given is invalid or outside the time extent defined (%s), and default time set is invalid (%s)", "msWMSApplyTime", time, timeextent, timedefault); /* return MS_FALSE; */ return msWMSException(map, version, "InvalidDimensionValue", wms_exception_format); } else msLayerSetTimeFilter(lp, timedefault, timefield); } } else { /* build the time string */ msLayerSetTimeFilter(lp, time, timefield); timeextent= NULL; } } } } /* check to see if there is a list of possible patterns defined */ /* if it is the case, use it to set the time pattern to use */ /* for the request */ timpattern = msOWSLookupMetadata(&(map->web.metadata), "MO", "timeformat"); if (timpattern && time && strlen(time) > 0) msWMSSetTimePattern(timpattern, time); } return MS_SUCCESS; } /* ** msWMSPrepareNestedGroups() ** ** purpose: Parse WMS_LAYER_GROUP settings into arrays ** ** params: ** - nestedGroups: This array holds the arrays of groups that have been set ** through the WMS_LAYER_GROUP metadata ** - numNestedGroups: This array holds the number of groups set in ** WMS_LAYER_GROUP for each layer ** - isUsedInNestedGroup: This array indicates if the layer is used as group ** as set through the WMS_LAYER_GROUP metadata */ void msWMSPrepareNestedGroups(mapObj* map, int nVersion, char*** nestedGroups, int* numNestedGroups, int* isUsedInNestedGroup) { int i, j, k; const char* groups; char* errorMsg; for (i = 0; i < map->numlayers; i++) { nestedGroups[i] = NULL; /* default */ numNestedGroups[i] = 0; /* default */ isUsedInNestedGroup[i] = 0; /* default */ groups = msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "MO", "layer_group"); if ((groups != NULL) && (strlen(groups) != 0)) { if (GET_LAYER(map, i)->group != NULL && strlen(GET_LAYER(map, i)->group) != 0) { errorMsg = "It is not allowed to set both the GROUP and WMS_LAYER_GROUP for a layer"; msSetError(MS_WMSERR, errorMsg, "msWMSPrepareNestedGroups()", NULL); msIO_fprintf(stdout, "\n", errorMsg); /* cannot return exception at this point because we are already writing to stdout */ } else { if (groups[0] != '/') { errorMsg = "The WMS_LAYER_GROUP metadata does not start with a '/'"; msSetError(MS_WMSERR, errorMsg, "msWMSPrepareNestedGroups()", NULL); msIO_fprintf(stdout, "\n", errorMsg); /* cannot return exception at this point because we are already writing to stdout */ } else { /* split into subgroups. Start at adres + 1 because the first '/' would cause an extra emtpy group */ nestedGroups[i] = msStringSplit(groups + 1, '/', &numNestedGroups[i]); /* */ for (j = 0; j < map->numlayers; j++) { if (isUsedInNestedGroup[j]) continue; for (k=0; kname && strcasecmp(GET_LAYER(map, j)->name, nestedGroups[i][k]) == 0 ) { isUsedInNestedGroup[j] = 1; break; } } } } } } } } /* ** Validate that a given dimension is inside the extents defined */ int msWMSValidateDimensionValue(char *value, const char *dimensionextent, int forcecharcter) { char **extents=NULL, **ranges=NULL, **onerange=NULL; int numextents; char **aextentvalues = NULL; int nextentvalues=0; pointObj *aextentranges=NULL; int nextentranges=0; int isextentavalue = MS_FALSE, isextentarange=MS_FALSE; int i,j, ntmp; char **uservalues=NULL; int numuservalues=0; char *stmp = NULL; int ischaracter = MS_FALSE; float minval, maxval,currentval,mincurrentval,maxcurrentval, mincurrentrange, maxcurrentrange; int uservaluevalid= MS_FALSE; if (forcecharcter) ischaracter = MS_TRUE; if (!value || !dimensionextent) return MS_FALSE; /*for the value, we support descrete values (2005) */ /* multiple values (abc, def, ...) */ /* and range(s) (1000/2000, 3000/5000) */ /** we do not support resolution*/ /* -------------------------------------------------------------------- */ /* parse the extent first. */ /* -------------------------------------------------------------------- */ extents = msStringSplit (dimensionextent, ',', &numextents); if (numextents == 1) { if (strstr(dimensionextent, "/") == NULL) { /*single value*/ isextentavalue = MS_TRUE; nextentvalues = 1; aextentvalues = (char **)msSmallMalloc(sizeof(char *)); msStringTrim(extents[0]); aextentvalues[0] = msStrdup(dimensionextent); if (!forcecharcter) ischaracter= !FLTIsNumeric((char *)dimensionextent); } else { ntmp = -1; ranges = msStringSplit (dimensionextent, '/', &ntmp); if(ranges && (ntmp == 2 || ntmp == 3)) { /*single range*/ isextentarange = MS_TRUE; aextentranges = msSmallMalloc(sizeof(pointObj)); nextentranges=1; aextentranges[0].x = atof(ranges[0]); aextentranges[0].y = atof(ranges[1]); /*ranges should be numeric*/ ischaracter = MS_FALSE; } if (ranges && ntmp > 0) { msFreeCharArray(ranges, ntmp); ranges = NULL; } } } else if (numextents > 1) /*check if it is muliple values or mutliple ranges*/ { if (strstr(dimensionextent, "/") == NULL) { /*multiple values*/ isextentavalue = MS_TRUE; aextentvalues = (char **)msSmallMalloc(sizeof(char *)*numextents); for (i=0; i 0 ) { msFreeCharArray(onerange, ntmp); onerange = NULL; } } if (!isvalidextent) { msFree(aextentranges); nextentranges = 0; isextentarange = MS_FALSE; } } } if (numextents > 0) { msFreeCharArray(extents, numextents); extents = NULL; } /* make sure that we got a valid extent*/ if (!isextentavalue && !isextentarange) { return MS_FALSE; } /*for the extent of the dimesion, we support single value, or list of mulitiple values comma separated, a single range or multipe ranges */ uservalues = msStringSplit (value, ',', &numuservalues); uservaluevalid = MS_FALSE; if (numuservalues == 1) { /*user iput=single*/ /*is it descret or range*/ ranges = msStringSplit(uservalues[0], '/', &ntmp); if (ntmp == 1) /*discrete*/ { if (isextentavalue) { /*single user value, single/multiple values extent*/ for (i=0; i= minval && currentval <= maxval) { uservaluevalid= MS_TRUE; break; } } } } else if (ntmp == 2 || ntmp == 3) /*range*/ { /*user input=single range. In this case the extents must be of a range type.*/ mincurrentval = atof(ranges[0]); maxcurrentval = atof(ranges[1]); if (isextentarange) { for (i=0; i= maxcurrentval && minval <= maxval) { uservaluevalid= MS_TRUE; break; } } } } if (ranges && ntmp > 0) msFreeCharArray(ranges, ntmp); } else if (numuservalues > 1) /*user input=multiple*/ { if (strstr(value, "/") == NULL) { /*user input=multiple value*/ int valueisvalid = MS_FALSE; for (i=0; i= currentval && minval <= maxval) { valueisvalid = MS_TRUE; break; } } if (!valueisvalid) break; } } uservaluevalid = valueisvalid; } else /*user input multiple ranges*/ { int valueisvalid = MS_TRUE; for (i=0; i=mincurrentrange && maxcurrentval <= maxcurrentrange && mincurrentval <= maxcurrentval) { break; } } if (j == nextentranges) { valueisvalid = MS_FALSE; break; } } } else { valueisvalid = MS_FALSE; } if (onerange && ntmp > 0) msFreeCharArray(onerange, ntmp); } uservaluevalid = valueisvalid; } } if(uservalues && numuservalues > 0) msFreeCharArray(uservalues, numuservalues); if (aextentvalues && nextentvalues > 0) { for (i=0; i 0) { msFree(aextentranges); } if(uservaluevalid) return MS_TRUE; return MS_FALSE; } int msWMSApplyDimensionLayer(layerObj *lp, const char *item, char *value, int forcecharcter) { int result = MS_FALSE; char *pszExpression=NULL; if (lp && item && value) { /*for the value, we support descrete values (2005) */ /* multiple values (abc, def, ...) */ /* and range(s) (1000/2000, 3000/5000) */ pszExpression = FLTGetExpressionForValuesRanges(lp, (char *)item, value, forcecharcter); if (pszExpression) { if(FLTApplyExpressionToLayer(lp, pszExpression)) result = MS_TRUE; msFree(pszExpression); } } return result; } int msWMSApplyDimension(layerObj *lp, int version, char *dimensionname, char *value, char *wms_exception_format) { char *dimensionitemname=NULL, *dimensionextentname=NULL, *dimensiontypename=NULL; char *dimensionunitname=NULL, *dimensiondefaultname=NULL; const char *dimensionitem, *dimensionextent, *dimensiontype, *dimensionunit, *dimensiondefault; int forcecharcter; int result = MS_FALSE; char *dimension = NULL, *currentvalue=NULL; if (lp && dimensionname && value) { /*check if the dimension name passes starts with dim_. All dimensions should start with dim_, except elevation*/ if (strncasecmp(dimensionname, "dim_", 4) == 0) dimension = msStrdup(dimensionname+4); else dimension = msStrdup(dimensionname); /*if value is empty and a default is defined, use it*/ if (strlen(value) > 0) currentvalue = msStrdup(value); else { dimensiondefaultname = msStrdup(dimension); dimensiondefaultname = msStringConcatenate(dimensiondefaultname, "_default"); dimensiondefault = msOWSLookupMetadata(&(lp->metadata), "M", dimensiondefaultname); if (dimensiondefault && strlen(dimensiondefault) > 0) currentvalue = msStrdup(dimensiondefault); } /*check if the manadatory metada related to the dimension are set*/ dimensionitemname = msStrdup(dimension); dimensionitemname = msStringConcatenate(dimensionitemname, "_item"); dimensionitem = msOWSLookupMetadata(&(lp->metadata), "M", dimensionitemname); dimensionextentname = msStrdup(dimension); dimensionextentname = msStringConcatenate(dimensionextentname, "_extent"); dimensionextent = msOWSLookupMetadata(&(lp->metadata), "M", dimensionextentname); dimensionunitname = msStrdup(dimension); dimensionunitname = msStringConcatenate(dimensionunitname, "_units"); dimensionunit = msOWSLookupMetadata(&(lp->metadata), "M", dimensionunitname); /*if the server want to force the type to character*/ dimensiontypename = msStrdup(dimension); dimensiontypename = msStringConcatenate(dimensiontypename, "_type"); dimensiontype = msOWSLookupMetadata(&(lp->metadata), "M", dimensiontypename); forcecharcter = MS_FALSE; if (dimensiontype && strcasecmp(dimensiontype, "Character") == 0) forcecharcter = MS_TRUE; if (dimensionitem && dimensionextent && dimensionunit && currentvalue) { if(msWMSValidateDimensionValue(currentvalue, dimensionextent, forcecharcter)) { result = msWMSApplyDimensionLayer(lp, dimensionitem, currentvalue, forcecharcter); } else { msSetError(MS_WMSERR, "Dimension %s with a value of %s is invalid or outside the extents defined", "msWMSApplyDimension", dimension, currentvalue); result = MS_FALSE; } } else msSetError(MS_WMSERR, "Dimension %s : invalid settings. Make sure that item, units and extent are set.", "msWMSApplyDimension", dimension, currentvalue); msFree(dimensionitemname); msFree(dimensionextentname); msFree(dimensiontypename); msFree(dimensionunitname); msFree(dimensiondefaultname); msFree(dimension); msFree(currentvalue); } return result; } /* ** */ int msWMSLoadGetMapParams(mapObj *map, int nVersion, char **names, char **values, int numentries, char *wms_exception_format, const char *wms_request, owsRequestObj *ows_request) { int i, adjust_extent = MS_FALSE, nonsquare_enabled = MS_FALSE; int iUnits = -1; int nLayerOrder = 0; int transparent = MS_NOOVERRIDE; outputFormatObj *format = NULL; int validlayers = 0; char *styles = NULL; int numlayers = 0; char **layers = NULL; int layerfound =0; int invalidlayers = 0; char epsgbuf[100]; char srsbuffer[100]; int epsgvalid = MS_FALSE; const char *projstring; int timerequest = 0; char *stime = NULL; char **tokens=NULL; int n,j; int srsfound = 0; int bboxfound = 0; int formatfound = 0; int widthfound = 0; int heightfound = 0; char *request = NULL; int status = 0; const char *layerlimit = NULL; char *bboxrequest=NULL; const char *sldenabled=NULL; char *sld_url=NULL, *sld_body=NULL; epsgbuf[0]='\0'; srsbuffer[0]='\0'; /* Some of the getMap parameters are actually required depending on the */ /* request, but for now we assume all are optional and the map file */ /* defaults will apply. */ msAdjustExtent(&(map->extent), map->width, map->height); /* Check for SLDs first. If SLD is available LAYERS and STYLES parameters are non mandatory */ for(i=0; map && iweb.metadata), "MO", "sld_enabled"); if (sldenabled == NULL) sldenabled = "true"; if (ogrEnabled == 0) { msSetError(MS_WMSERR, "OGR support is not available.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } else { if (strcasecmp(sldenabled, "true") == 0) { if (strcasecmp(names[i], "SLD") == 0) { sld_url = values[i]; } if (strcasecmp(names[i], "SLD_BODY") == 0) { sld_body = values[i]; } } } } } for(i=0; map && inumlayers * sizeof(int)); MS_CHECK_ALLOC(layerOrder, map->numlayers * sizeof(int), MS_FAILURE) layers = msStringSplit(values[i], ',', &numlayers); if (layers==NULL || strlen(values[i]) <=0 || numlayers < 1) { numlayers = 0; if (sld_url == NULL && sld_body == NULL) { msSetError(MS_WMSERR, "At least one layer name required in LAYERS.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } } if (nVersion >= OWS_1_3_0) { layerlimit = msOWSLookupMetadata(&(map->web.metadata), "MO", "layerlimit"); if(layerlimit) { if (numlayers > atoi(layerlimit)) { msSetError(MS_WMSERR, "Number of layers requested exceeds LayerLimit.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } } } for (iLayer=0; iLayer < map->numlayers; iLayer++) { map->layerorder[iLayer] = iLayer; layerOrder[iLayer] = 0; } for(j=0; jnumlayers; j++) { /* Keep only layers with status=DEFAULT by default */ /* Layer with status DEFAULT is drawn first. */ if (GET_LAYER(map, j)->status != MS_DEFAULT) GET_LAYER(map, j)->status = MS_OFF; else { map->layerorder[nLayerOrder++] = j; layerOrder[j] = 1; } } nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); for (k=0; knumlayers; j++) { /* Turn on selected layers only. */ if ( ((GET_LAYER(map, j)->name && strcasecmp(GET_LAYER(map, j)->name, layers[k]) == 0) || (map->name && strcasecmp(map->name, layers[k]) == 0) || (GET_LAYER(map, j)->group && strcasecmp(GET_LAYER(map, j)->group, layers[k]) == 0) || ((numNestedGroups[j] >0) && msStringInArray(layers[k], nestedGroups[j], numNestedGroups[j]))) && ((msIntegerInArray(GET_LAYER(map, j)->index, ows_request->enabled_layers, ows_request->numlayers))) ) { if (GET_LAYER(map, j)->status != MS_DEFAULT) { if (layerOrder[j] == 0) { map->layerorder[nLayerOrder++] = j; layerOrder[j] = 1; GET_LAYER(map, j)->status = MS_ON; } } validlayers++; layerfound = 1; } } if (layerfound == 0 && numlayers>0) invalidlayers++; } /* free the stuff used for nested layers */ for (k = 0; k < map->numlayers; k++) { if (numNestedGroups[k] > 0) { msFreeCharArray(nestedGroups[k], numNestedGroups[k]); } } free(nestedGroups); free(numNestedGroups); free(isUsedInNestedGroup); /* set all layers with status off at end of array */ for (j=0; jnumlayers; j++) { if (GET_LAYER(map, j)->status == MS_OFF) if (layerOrder[j] == 0) map->layerorder[nLayerOrder++] = j; } free(layerOrder); msFreeCharArray(layers, numlayers); } else if (strcasecmp(names[i], "STYLES") == 0) { styles = values[i]; } else if ((strcasecmp(names[i], "SRS") == 0 && nVersion < OWS_1_3_0) || (strcasecmp(names[i], "CRS") == 0 && nVersion >= OWS_1_3_0)) { srsfound = 1; /* SRS is in format "EPSG:epsg_id" or "AUTO:proj_id,unit_id,lon0,lat0" */ if (strncasecmp(values[i], "EPSG:", 5) == 0) { /* SRS=EPSG:xxxx */ /* don't need to copy init=xxx since the srsbudder is only used with msLoadProjection and that does alreay the job */ /* snprintf(srsbuffer, 100, "init=epsg:%.20s", values[i]+5); */ snprintf(srsbuffer, sizeof(srsbuffer), "EPSG:%.20s",values[i]+5); snprintf(epsgbuf, sizeof(epsgbuf), "EPSG:%.20s",values[i]+5); /* This test was to correct a request by the OCG cite 1.3.0 test sending CRS=ESPG:4326, Bug:*/ if (nVersion >= OWS_1_3_0) { if (srsbuffer[strlen(srsbuffer)-1] == ',') srsbuffer[strlen(srsbuffer)-1] = '\0'; if (epsgbuf[strlen(epsgbuf)-1] == ',') epsgbuf[strlen(epsgbuf)-1] = '\0'; } /* we need to wait until all params are read before */ /* loding the projection into the map. This will help */ /* insure that the passes srs is valid for all layers. */ /* if (msLoadProjectionString(&(map->projection), buffer) != 0) return msWMSException(map, nVersion, NULL); iUnits = GetMapserverUnitUsingProj(&(map->projection)); if (iUnits != -1) map->units = iUnits; */ } else if (strncasecmp(values[i], "AUTO:", 5) == 0 && nVersion < OWS_1_3_0) { snprintf(srsbuffer, sizeof(srsbuffer), "%s", values[i]); /* SRS=AUTO:proj_id,unit_id,lon0,lat0 */ /* if (msLoadProjectionString(&(map->projection), values[i]) != 0) return msWMSException(map, nVersion, NULL); iUnits = GetMapserverUnitUsingProj(&(map->projection)); if (iUnits != -1) map->units = iUnits; */ } else if (nVersion >= OWS_1_3_0 && (strncasecmp(values[i], "AUTO2:", 6) == 0 || strncasecmp(values[i], "CRS:", 4) == 0)) { snprintf(srsbuffer, sizeof(srsbuffer), "%s", values[i]); } else { if (nVersion >= OWS_1_3_0) { msSetError(MS_WMSERR, "Unsupported CRS namespace (only EPSG, AUTO2, CRS currently supported).", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "InvalidCRS", wms_exception_format); } else { msSetError(MS_WMSERR, "Unsupported SRS namespace (only EPSG and AUTO currently supported).", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "InvalidSRS", wms_exception_format); } } } else if (strcasecmp(names[i], "BBOX") == 0) { char **tokens; int n; bboxfound = 1; tokens = msStringSplit(values[i], ',', &n); if (tokens==NULL || n != 4) { msSetError(MS_WMSERR, "Wrong number of arguments for BBOX.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } bboxrequest = values[i]; /*for wms 1.3.0 we will do the validation of the bbox after all parameters are read to account for the axes order*/ if (nVersion < OWS_1_3_0) { map->extent.minx = atof(tokens[0]); map->extent.miny = atof(tokens[1]); map->extent.maxx = atof(tokens[2]); map->extent.maxy = atof(tokens[3]); msFreeCharArray(tokens, n); /* validate bbox values */ if ( map->extent.minx >= map->extent.maxx || map->extent.miny >= map->extent.maxy) { msSetError(MS_WMSERR, "Invalid values for BBOX.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } adjust_extent = MS_TRUE; } } else if (strcasecmp(names[i], "WIDTH") == 0) { widthfound = 1; map->width = atoi(values[i]); } else if (strcasecmp(names[i], "HEIGHT") == 0) { heightfound = 1; map->height = atoi(values[i]); } else if (strcasecmp(names[i], "FORMAT") == 0) { const char *format_list = NULL; formatfound = 1; if (strcasecmp(values[i], "application/openlayers")!=0) { /*check to see if a predefined list is given*/ format_list = msOWSLookupMetadata(&(map->web.metadata), "M","getmap_formatlist"); if (format_list) { format = msOwsIsOutputFormatValid(map, values[i], &(map->web.metadata), "M", "getmap_formatlist"); if (format == NULL && strcasecmp(values[i], "application/openlayers")!=0) { msSetError(MS_IMGERR, "Unsupported output format (%s).", "msWMSLoadGetMapParams()", values[i] ); return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); } } else { format = msSelectOutputFormat( map, values[i] ); if( format == NULL || (strncasecmp(format->driver, "GD/", 3) != 0 && strncasecmp(format->driver, "GDAL/", 5) != 0 && strncasecmp(format->driver, "AGG/", 4) != 0 && strncasecmp(format->driver, "CAIRO/", 6) != 0 && strncasecmp(format->driver, "OGL/", 4) != 0 && strncasecmp(format->driver, "KML", 3) != 0 && strncasecmp(format->driver, "KMZ", 3) != 0)) { msSetError(MS_IMGERR, "Unsupported output format (%s).", "msWMSLoadGetMapParams()", values[i] ); return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); } } } msFree( map->imagetype ); map->imagetype = msStrdup(values[i]); } else if (strcasecmp(names[i], "TRANSPARENT") == 0) { transparent = (strcasecmp(values[i], "TRUE") == 0); } else if (strcasecmp(names[i], "BGCOLOR") == 0) { long c; c = strtol(values[i], NULL, 16); map->imagecolor.red = (c/0x10000)&0xff; map->imagecolor.green = (c/0x100)&0xff; map->imagecolor.blue = c&0xff; } /* value of time can be empty. We should look for a default value */ /* see function msWMSApplyTime */ else if (strcasecmp(names[i], "TIME") == 0)/* && values[i]) */ { stime = values[i]; timerequest = 1; } /* Vendor-specific ANGLE param (for map rotation), added in ticket #3332, * also supported by GeoServer */ else if (strcasecmp(names[i], "ANGLE") == 0) { msMapSetRotation(map, atof(values[i])); } } /*validate the exception format WMS 1.3.0 section 7.3.3.11*/ if (nVersion >= OWS_1_3_0 && wms_exception_format != NULL) { if (strcasecmp(wms_exception_format, "INIMAGE") != 0 && strcasecmp(wms_exception_format, "BLANK") != 0 && strcasecmp(wms_exception_format, "XML") != 0) { msSetError(MS_WMSERR, "Invalid format %s for the EXCEPTIONS parameter.", "msWMSLoadGetMapParams()", wms_exception_format); return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); } } if (bboxfound && bboxrequest && nVersion >= OWS_1_3_0) { char **tokens; int n; rectObj rect; projectionObj proj; tokens = msStringSplit(bboxrequest, ',', &n); /*we have already validated that the request format when reding the request parameters*/ rect.minx = atof(tokens[0]); rect.miny = atof(tokens[1]); rect.maxx = atof(tokens[2]); rect.maxy = atof(tokens[3]); msFreeCharArray(tokens, n); /*try to adjust the axes if necessary*/ if (strlen(srsbuffer) > 1) { msInitProjection(&proj); if (msLoadProjectionStringEPSG(&proj, (char *)srsbuffer) == 0) { msAxisNormalizePoints( &proj, 1, &rect.minx, &rect.miny ); msAxisNormalizePoints( &proj, 1, &rect.maxx, &rect.maxy ); } msFreeProjection( &proj ); } /*if the CRS is AUTO2:auto_crs_id,factor,lon0,lat0, we need to grab the factor patameter and use it with the bbox*/ if (strlen(srsbuffer) > 1 && strncasecmp(srsbuffer, "AUTO2:", 6) == 0) { char **args; int numargs; double factor; args = msStringSplit(srsbuffer, ',', &numargs); if (numargs == 4) { factor = atof(args[1]); if (factor > 0 && factor != 1.0) { rect.minx = rect.minx*factor; rect.miny = rect.miny*factor; rect.maxx = rect.maxx*factor; rect.maxx = rect.maxy*factor; } } msFreeCharArray(args, numargs); } map->extent.minx = rect.minx; map->extent.miny = rect.miny; map->extent.maxx = rect.maxx; map->extent.maxy = rect.maxy; /* validate bbox values */ if ( map->extent.minx >= map->extent.maxx || map->extent.miny >= map->extent.maxy) { msSetError(MS_WMSERR, "Invalid values for BBOX.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } adjust_extent = MS_TRUE; } /* ** If any select layers have a default time, we will apply the default ** time value even if no TIME request was in the url. */ if( !timerequest && map ) { for (i=0; inumlayers && !timerequest; i++) { layerObj *lp = NULL; lp = (GET_LAYER(map, i)); if (lp->status != MS_ON && lp->status != MS_DEFAULT) continue; if( msOWSLookupMetadata(&(lp->metadata), "MO", "timedefault") ) timerequest = 1; } } /* ** Apply time filters if available in the request. */ if (timerequest) { if (msWMSApplyTime(map, nVersion, stime, wms_exception_format) == MS_FAILURE) { return MS_FAILURE;/* msWMSException(map, nVersion, "InvalidTimeRequest"); */ } } /* ** Check/apply wms dimensions ** all dimension requests shoul start with dim_xxxx, except time and elevation. */ for (i=0; inumlayers; i++) { layerObj *lp = NULL; const char *dimensionlist = NULL; char **tokens; int ntokens=0,k; lp = (GET_LAYER(map, i)); if (lp->status != MS_ON && lp->status != MS_DEFAULT) continue; dimensionlist = msOWSLookupMetadata(&(lp->metadata), "M", "dimensionlist"); /* if (!dimensionlist) dimensionlist = msOWSLookupMetadata(&(map->web.metadata), "M", "dimensionlist"); */ if (dimensionlist) { tokens = msStringSplit(dimensionlist, ',', &ntokens); if (tokens && ntokens > 0) { char *dimensionname=NULL; char *stmp = NULL; for (j=0; jmap, nVersion, "InvalidDimensionValue", wms_exception_format); } break; } msFree(dimensionname); } } msFreeCharArray(tokens, ntokens); } } } /* ** Apply the selected output format (if one was selected), and override ** the transparency if needed. */ if( format != NULL ) msApplyOutputFormat( &(map->outputformat), format, transparent, MS_NOOVERRIDE, MS_NOOVERRIDE ); /* Validate all layers given. ** If an invalid layer is sent, return an exception. */ if (validlayers == 0 || invalidlayers > 0) { if (invalidlayers > 0) { msSetError(MS_WMSERR, "Invalid layer(s) given in the LAYERS parameter.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); } if (validlayers == 0 && sld_url == NULL && sld_body == NULL) { msSetError(MS_WMSERR, "Missing required parameter LAYERS", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); } } /* validate srs value: When the SRS parameter in a GetMap request contains a ** SRS that is valid for some, but not all of the layers being requested, ** then the server shall throw a Service Exception (code = "InvalidSRS"). ** Validate first against epsg in the map and if no matching srs is found ** validate all layers requested. */ if (epsgbuf != NULL && strlen(epsgbuf) > 1) { epsgvalid = MS_FALSE; projstring = msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "MO", MS_FALSE); if (projstring) { tokens = msStringSplit(projstring, ' ', &n); if (tokens && n > 0) { for(i=0; inumlayers; i++) { epsgvalid = MS_FALSE; if (GET_LAYER(map, i)->status == MS_ON) { projstring = msOWSGetEPSGProj(&(GET_LAYER(map, i)->projection), &(GET_LAYER(map, i)->metadata), "MO", MS_FALSE); if (projstring) { tokens = msStringSplit(projstring, ' ', &n); if (tokens && n > 0) { for(j=0; j= OWS_1_3_0) { msSetError(MS_WMSERR, "Invalid CRS given : CRS must be valid for all requested layers.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "InvalidSRS", wms_exception_format); } else { msSetError(MS_WMSERR, "Invalid SRS given : SRS must be valid for all requested layers.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "InvalidSRS", wms_exception_format); } } } } } } /* Validate requested image size. */ if(map->width > map->maxsize || map->height > map->maxsize || map->width < 1 || map->height < 1) { msSetError(MS_WMSERR, "Image size out of range, WIDTH and HEIGHT must be between 1 and %d pixels.", "msWMSLoadGetMapParams()", map->maxsize); /* Restore valid default values in case errors INIMAGE are used */ map->width = 400; map->height= 300; return msWMSException(map, nVersion, NULL, wms_exception_format); } /* Check whether requested BBOX and width/height result in non-square pixels */ nonsquare_enabled = msTestConfigOption( map, "MS_NONSQUARE", MS_FALSE ); if (!nonsquare_enabled) { double dx, dy, reqy; dx = MS_ABS(map->extent.maxx - map->extent.minx); dy = MS_ABS(map->extent.maxy - map->extent.miny); reqy = ((double)map->width) * dy / dx; /* Allow up to 1 pixel of error on the width/height ratios. */ /* If more than 1 pixel then enable non-square pixels */ if ( MS_ABS((reqy - (double)map->height)) > 1.0 ) { if (map->debug) msDebug("msWMSLoadGetMapParams(): enabling non-square pixels.\n"); msSetConfigOption(map, "MS_NONSQUARE", "YES"); nonsquare_enabled = MS_TRUE; } } /* If the requested SRS is different from the default mapfile projection, or ** if a BBOX resulting in non-square pixels is requested then ** copy the original mapfile's projection to any layer that doesn't already ** have a projection. This will prevent problems when users forget to ** explicitly set a projection on all layers in a WMS mapfile. */ if ((srsbuffer != NULL && strlen(srsbuffer) > 1) || nonsquare_enabled) { projectionObj newProj; if (map->projection.numargs <= 0) { if (nVersion >= OWS_1_3_0) { msSetError(MS_WMSERR, "Cannot set new CRS on a map that doesn't " "have any projection set. Please make sure your mapfile " "has a projection defined at the top level.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "InvalidCRS", wms_exception_format); } else { msSetError(MS_WMSERR, "Cannot set new SRS on a map that doesn't " "have any projection set. Please make sure your mapfile " "has a projection defined at the top level.", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "InvalidSRS", wms_exception_format); } } msInitProjection(&newProj); if (srsbuffer != NULL && strlen(srsbuffer) > 1) { int nTmp; if (nVersion >= OWS_1_3_0) nTmp = msLoadProjectionStringEPSG(&newProj, srsbuffer); else nTmp = msLoadProjectionString(&newProj, srsbuffer); if (nTmp != 0) { msFreeProjection(&newProj); return msWMSException(map, nVersion, NULL, wms_exception_format); } } if (nonsquare_enabled || msProjectionsDiffer(&(map->projection), &newProj)) { char *original_srs = NULL; for(i=0; inumlayers; i++) { if (GET_LAYER(map, i)->projection.numargs <= 0 && GET_LAYER(map, i)->status != MS_OFF && GET_LAYER(map, i)->transform == MS_TRUE) { /* This layer is turned on and needs a projection */ /* Fetch main map projection string only now that we need it */ if (original_srs == NULL) original_srs = msGetProjectionString(&(map->projection)); if (msLoadProjectionString(&(GET_LAYER(map, i)->projection), original_srs) != 0) { msFreeProjection(&newProj); return msWMSException(map, nVersion, NULL, wms_exception_format); } GET_LAYER(map, i)->project = MS_TRUE; } } msFree(original_srs); } msFreeProjection(&newProj); } /* apply the srs to the map file. This is only done after validating */ /* that the srs given as parameter is valid for all layers */ if (srsbuffer != NULL && strlen(srsbuffer) > 1) { int nTmp; msFreeProjection(&map->projection); msInitProjection(&map->projection); if (nVersion >= OWS_1_3_0) nTmp = msLoadProjectionStringEPSG(&(map->projection), srsbuffer); else nTmp = msLoadProjectionString(&(map->projection), srsbuffer); if (nTmp != 0) return msWMSException(map, nVersion, NULL, wms_exception_format); iUnits = GetMapserverUnitUsingProj(&(map->projection)); if (iUnits != -1) map->units = iUnits; } if (sld_url || sld_body) { int nLayersBefore, nLayerAfter; char request_tmp[32]; char *pszLayerNames = NULL; nLayersBefore = map->numlayers; /* -------------------------------------------------------------------- */ /* if LAYERS parameter was not given, set all layers to off */ /* -------------------------------------------------------------------- */ if (validlayers == 0) /*no LAYERS parameter is give*/ { for(j=0; jnumlayers; j++) { if (GET_LAYER(map, j)->status != MS_DEFAULT) GET_LAYER(map, j)->status = MS_OFF; } } /*apply sld if defined. This is done here so that bbox and srs are already applied*/ if (sld_url) { if ((status = msSLDApplySLDURL(map, sld_url, -1, NULL, &pszLayerNames)) != MS_SUCCESS) return msWMSException(map, nVersion, NULL, wms_exception_format); } else if (sld_body) { if ((status =msSLDApplySLD(map, sld_body, -1, NULL, &pszLayerNames)) != MS_SUCCESS) return msWMSException(map, nVersion, NULL, wms_exception_format); } /* -------------------------------------------------------------------- */ /* SLD and styles can use the same layer multiple times. If */ /* that is the case we duplicate the layer for drawing */ /* purpose. We need to reset the ows request enable settings (#1602)*/ /* -------------------------------------------------------------------- */ nLayerAfter=map->numlayers; if (nLayersBefore != nLayerAfter) { strlcpy(request_tmp, "GetMap", sizeof(request_tmp)); msOWSRequestLayersEnabled(map, "M", request_tmp, ows_request); } /* -------------------------------------------------------------------- */ /* We need to take into account where the LAYERS parameter was */ /* not given (the LAYERS is option when an SLD is given). In */ /* this particular case, we need to turn on the layers */ /* identified the SLD (#1166). */ /* */ /* -------------------------------------------------------------------- */ if (validlayers == 0) { if (pszLayerNames) { char **tokens; int ntokens=0; tokens = msStringSplit(pszLayerNames, ',', &ntokens); if (ntokens >0) { for (i=0; inumlayers; j++) { if ( ((GET_LAYER(map, j)->name && strcasecmp(GET_LAYER(map, j)->name, tokens[i]) == 0) || (map->name && strcasecmp(map->name, tokens[i]) == 0) || (GET_LAYER(map, j)->group && strcasecmp(GET_LAYER(map, j)->group, tokens[i]) == 0)) && ((msIntegerInArray(GET_LAYER(map, j)->index, ows_request->enabled_layers, ows_request->numlayers))) ) { if (GET_LAYER(map, j)->status != MS_DEFAULT) GET_LAYER(map, j)->status = MS_ON; } } } } } } msFree(pszLayerNames); } /* Validate Styles : ** MapServer advertize styles through th group setting in a class object. ** If no styles are set MapServer expects to have empty values ** for the styles parameter (...&STYLES=&...) Or for multiple Styles/Layers, ** we could have ...&STYLES=,,,. If that is not the ** case, we generate an exception. */ if(styles && strlen(styles) > 0) { char **tokens; int n=0, i=0, k=0, l=0,m=0; char **layers=NULL; int numlayers =0; layerObj *lp = NULL; tokens = msStringSplit(styles, ',' ,&n); for (i=0; i 0 && strcasecmp(tokens[i],"default") != 0) { if (layers == NULL) { int bLayerInserted = MS_FALSE; char request_tmp[32]; for(j=0; j0) { for (m=0; mvtable) msInitializeVirtualTable(psTmpLayer); /*make the name unique*/ snprintf(tmpId, sizeof(tmpId), "%lx_%x_%d",(long)time(NULL),(int)getpid(), map->numlayers); if (psTmpLayer->name) msFree(psTmpLayer->name); psTmpLayer->name = strdup(tmpId); msFree(layers[l]); layers[l] = strdup(tmpId); msInsertLayer(map, psTmpLayer, -1); bLayerInserted =MS_TRUE; } } } } if (bLayerInserted) { strlcpy(request_tmp, "GetMap", sizeof(request_tmp)); msOWSRequestLayersEnabled(map, "M", request_tmp, ows_request); } } if (layers && numlayers == n) { for (j=0; jnumlayers; j++) { if ((GET_LAYER(map, j)->name && strcasecmp(GET_LAYER(map, j)->name, layers[i]) == 0) || (map->name && strcasecmp(map->name, layers[i]) == 0) || (GET_LAYER(map, j)->group && strcasecmp(GET_LAYER(map, j)->group, layers[i]) == 0)) { lp = GET_LAYER(map, j); for (k=0; knumclasses; k++) { if (lp->class[k]->group && strcasecmp(lp->class[k]->group, tokens[i]) == 0) { if (lp->classgroup) msFree(lp->classgroup); lp->classgroup = msStrdup( tokens[i]); break; } } if (k == lp->numclasses) { msSetError(MS_WMSERR, "Style (%s) not defined on layer.", "msWMSLoadGetMapParams()", tokens[i]); msFreeCharArray(tokens, n); msFreeCharArray(layers, numlayers); return msWMSException(map, nVersion, "StyleNotDefined", wms_exception_format); } } } } else { msSetError(MS_WMSERR, "Invalid style (%s). Mapserver is expecting an empty string for the STYLES : STYLES= or STYLES=,,, or using keyword default STYLES=default,default, ...", "msWMSLoadGetMapParams()", styles); if (tokens && n > 0) msFreeCharArray(tokens, n); if (layers && numlayers > 0) msFreeCharArray(layers, numlayers); return msWMSException(map, nVersion, "StyleNotDefined", wms_exception_format); } } } if (tokens && n > 0) msFreeCharArray(tokens, n); } /* ** WMS extents are edge to edge while MapServer extents are center of ** pixel to center of pixel. Here we try to adjust the WMS extents ** in by half a pixel. We wait till here because we want to ensure we ** are doing this in terms of the correct WIDTH and HEIGHT. */ if( adjust_extent ) { double dx, dy; dx = (map->extent.maxx - map->extent.minx) / map->width; map->extent.minx += dx*0.5; map->extent.maxx -= dx*0.5; dy = (map->extent.maxy - map->extent.miny) / map->height; map->extent.miny += dy*0.5; map->extent.maxy -= dy*0.5; } if (request && strcasecmp(request, "DescribeLayer") != 0) { if (srsfound == 0) { if ( nVersion >= OWS_1_3_0) msSetError(MS_WMSERR, "Missing required parameter CRS", "msWMSLoadGetMapParams()"); else msSetError(MS_WMSERR, "Missing required parameter SRS", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); } if (bboxfound == 0) { msSetError(MS_WMSERR, "Missing required parameter BBOX", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); } if (formatfound == 0 && (strcasecmp(request, "GetMap") == 0 || strcasecmp(request, "map") == 0)) { msSetError(MS_WMSERR, "Missing required parameter FORMAT", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); } if (widthfound == 0) { msSetError(MS_WMSERR, "Missing required parameter WIDTH", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); } if (heightfound == 0) { msSetError(MS_WMSERR, "Missing required parameter HEIGHT", "msWMSLoadGetMapParams()"); return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); } } return MS_SUCCESS; } /* ** */ static void msWMSPrintRequestCap(int nVersion, const char *request, const char *script_url, const char *formats, ...) { va_list argp; const char *fmt; char *encoded; msIO_printf(" <%s>\n", request); /* We expect to receive a NULL-terminated args list of formats */ va_start(argp, formats); fmt = formats; while(fmt != NULL) { /* Special case for early WMS with subelements in Format (bug 908) */ if( nVersion <= OWS_1_0_7 ) { encoded = msStrdup( fmt ); } /* otherwise we HTML code special characters */ else { encoded = msEncodeHTMLEntities(fmt); } msIO_printf(" %s\n", encoded); msFree(encoded); fmt = va_arg(argp, const char *); } va_end(argp); msIO_printf(" \n"); msIO_printf(" \n"); /* The URL should already be HTML encoded. */ if (nVersion == OWS_1_0_0) { msIO_printf(" \n", script_url); msIO_printf(" \n", script_url); } else { msIO_printf(" \n", script_url); msIO_printf(" \n", script_url); } msIO_printf(" \n"); msIO_printf(" \n"); msIO_printf(" \n", request); } void msWMSPrintAttribution(FILE *stream, const char *tabspace, hashTableObj *metadata, const char *namespaces) { const char *title, *onlineres, *logourl; char * pszEncodedValue=NULL; if (stream && metadata) { title = msOWSLookupMetadata(metadata, "MO", "attribution_title"); onlineres = msOWSLookupMetadata(metadata, "MO", "attribution_onlineresource"); logourl = msOWSLookupMetadata(metadata, "MO", "attribution_logourl_width"); if (title || onlineres || logourl) { msIO_printf("%s\n",tabspace); if (title) { pszEncodedValue = msEncodeHTMLEntities(title); msIO_fprintf(stream, "%s%s%s\n", tabspace, tabspace, pszEncodedValue); free(pszEncodedValue); } if (onlineres) { pszEncodedValue = msEncodeHTMLEntities(onlineres); msIO_fprintf(stream, "%s%s\n", tabspace, tabspace, pszEncodedValue); free(pszEncodedValue); } if (logourl) { msOWSPrintURLType(stream, metadata, "MO","attribution_logourl", OWS_NOERR, NULL, "LogoURL", NULL, " width=\"%s\"", " height=\"%s\"", ">\n %s\n" " ", MS_FALSE, MS_TRUE, MS_TRUE, MS_TRUE, MS_TRUE, NULL, NULL, NULL, NULL, NULL, " "); } msIO_printf("%s\n", tabspace); } } } /* ** msWMSPrintScaleHint() ** ** Print a Min/MaxScaleDenominator tag for the layer if applicable. ** used for WMS >=1.3.0 */ void msWMSPrintScaleDenominator(const char *tabspace, double minscaledenom, double maxscaledenom) { if (minscaledenom > 0) msIO_printf("%s%g\n", tabspace, minscaledenom); if (maxscaledenom > 0) msIO_printf("%s%g\n", tabspace, maxscaledenom); } /* ** msWMSPrintScaleHint() ** ** Print a ScaleHint tag for this layer if applicable. ** ** (see WMS 1.1.0 sect. 7.1.5.4) The WMS defines the scalehint values as ** the ground distance in meters of the southwest to northeast diagonal of ** the central pixel of a map. ScaleHint values are the min and max ** recommended values of that diagonal. */ void msWMSPrintScaleHint(const char *tabspace, double minscaledenom, double maxscaledenom, double resolution) { double scalehintmin=0.0, scalehintmax=0.0, diag; diag = sqrt(2.0); if (minscaledenom > 0) scalehintmin = diag*(minscaledenom/resolution)/msInchesPerUnit(MS_METERS,0); if (maxscaledenom > 0) scalehintmax = diag*(maxscaledenom/resolution)/msInchesPerUnit(MS_METERS,0); if (scalehintmin > 0.0 || scalehintmax > 0.0) { msIO_printf("%s\n", tabspace, scalehintmin, scalehintmax); if (scalehintmax == 0.0) msIO_printf("%s\n", tabspace); } } /* ** msWMSPrintAuthorityURL() ** ** Print an AuthorityURL tag if applicable. */ void msWMSPrintAuthorityURL(FILE *stream, const char *tabspace, hashTableObj *metadata, const char *namespaces) { const char *pszWmsAuthorityName; const char *pszWMSAuthorityHref; char *pszTemplateName=NULL, *pszTemplateHref=NULL; if (stream && metadata) { pszWmsAuthorityName = msOWSLookupMetadata(metadata, namespaces, "authorityurl_name"); pszWMSAuthorityHref = msOWSLookupMetadata(metadata, namespaces, "authorityurl_href"); /* AuthorityURL only makes sense if you have *both* the name and url */ if( pszWmsAuthorityName && pszWMSAuthorityHref ) { pszTemplateName = msStringConcatenate(msStrdup(tabspace), "\n"); msOWSPrintEncodeMetadata(stream, metadata, namespaces, "authorityurl_name", OWS_NOERR, pszTemplateName, NULL); pszTemplateHref = msStringConcatenate(msStrdup(tabspace), " \n"); msOWSPrintEncodeMetadata(stream, metadata, namespaces, "authorityurl_href", OWS_NOERR, pszTemplateHref, NULL); msIO_printf("%s\n", tabspace); } else if ( pszWmsAuthorityName || pszWMSAuthorityHref ) { msIO_printf("%s\n", tabspace); } } msFree(pszTemplateName); msFree(pszTemplateHref); } /* ** msWMSPrintIdentifier() ** ** Print an Identifier tag if applicable. */ void msWMSPrintIdentifier(FILE *stream, const char *tabspace, hashTableObj *metadata, const char *namespaces) { const char *pszWMSIdentifierAuthority; const char *pszWMSIdentifierValue; char *pszTemplate=NULL; if (stream && metadata) { pszWMSIdentifierAuthority = msOWSLookupMetadata(metadata, namespaces, "identifier_authority"); pszWMSIdentifierValue = msOWSLookupMetadata(metadata, namespaces, "identifier_value"); /* Identifier only makes sense if you have *both* the authority and value */ if( pszWMSIdentifierAuthority && pszWMSIdentifierValue ) { pszTemplate = msStringConcatenate(msStrdup(tabspace), ""); msOWSPrintEncodeMetadata(stream, metadata, namespaces, "identifier_authority", OWS_NOERR, pszTemplate, NULL); msOWSPrintEncodeMetadata(stream, metadata, namespaces, "identifier_value", OWS_NOERR, "%s\n", NULL); } else if ( pszWMSIdentifierAuthority || pszWMSIdentifierValue ) { msIO_printf("%s\n", tabspace); } } msFree(pszTemplate); } /* ** msWMSPrintKeywordlist() ** ** Print a Keywordlist tag if applicable. */ void msWMSPrintKeywordlist(FILE *stream, const char *tabspace, const char *name, hashTableObj *metadata, const char *namespaces, int nVersion) { char newname[28]; /* max. rootlayer_keywordlist_items */ char vocname[33]; /* max. rootlayer_keywordlist_vocabulary */ const char *vocabularylist; /* to be read from metadata */ char **tokens = NULL; /* splitted vocabularylist */ char *pszName=NULL, /* key to lookup keywords with vocabulary */ *pszTemplate1=NULL, /* templates for msOWSPrintEncodeMetadataList*/ *pszTemplate2=NULL; int i, sName, sTemplate, ntokens = 0; newname[0]='\0'; vocname[0]='\0'; snprintf(newname, sizeof(newname), "%s_items", name); snprintf(vocname, sizeof(vocname), "%s_vocabulary", name); if (nVersion == OWS_1_0_0) { /* in V 1.0.0 */ /* The 1.0.0 spec doesn't specify which delimiter to use so let's use spaces */ pszTemplate1 = msStringConcatenate(msStrdup(tabspace), ""); pszTemplate2 = msStringConcatenate(msStrdup(tabspace), "\n"); msOWSPrintEncodeMetadataList(stream, metadata, namespaces, name, pszTemplate1, pszTemplate2, "%s ", NULL); } else if ( msOWSLookupMetadata(metadata, namespaces, name) || msOWSLookupMetadata(metadata, namespaces, newname) || msOWSLookupMetadata(metadata, namespaces, vocname) ) { /* ... in V1.0.6+ */ msIO_printf("%s\n", tabspace); pszTemplate1 = msStringConcatenate(msStrdup(tabspace), " %s\n"); /* print old styled ..._keywordlist */ msOWSPrintEncodeMetadataList(stream, metadata, namespaces, name, NULL, NULL, pszTemplate1, NULL); /* print new styled ..._keywordlist_items */ msOWSPrintEncodeMetadataList(stream, metadata, namespaces, newname, NULL, NULL, pszTemplate1, NULL); /* find out if there's a vocabulary list set */ vocabularylist = msOWSLookupMetadata(metadata, namespaces, vocname); if ( vocabularylist ) { tokens = msStringSplit(vocabularylist, ',', &ntokens); if ( tokens && ntokens > 0 ) { /* In order to do malloc only once, the length of the metadata*/ /* key to lookup is calculated from "rootlayer_keywordlist" */ /* plus "_items" plus the length of all vocabulary items */ /* concatenate. */ /* The same is done with template string used for printing the*/ /* keyword list. Here the string is tabspace + " %s\n" */ sName = 22 + 6 + strlen(vocabularylist) +1; pszName = (char*)msSmallMalloc(sName); sTemplate = strlen(tabspace)+4+21+strlen(vocabularylist)+17+1; pszTemplate2 = (char*)msSmallMalloc(sTemplate); for (i=0; i%s\n", tabspace, tokens[i], "%s"); msOWSPrintEncodeMetadataList(stream, metadata, namespaces, pszName, NULL, NULL, pszTemplate2, NULL); } msFree(pszName); } msFreeCharArray(tokens, ntokens); } msIO_printf("%s\n", tabspace); } msFree(pszTemplate1); msFree(pszTemplate2); } /* ** msDumpLayer() */ int msDumpLayer(mapObj *map, layerObj *lp, int nVersion, const char *script_url_encoded, const char *indent, const char *validated_language, int grouplayer) { rectObj ext; const char *value; const char *pszWmsTimeExtent, *pszWmsTimeDefault= NULL, *pszStyle=NULL; const char *pszLegendURL=NULL; char *pszMetadataName=NULL, *mimetype=NULL; char **classgroups = NULL; int iclassgroups=0 ,j=0; char szVersionBuf[OWS_VERSION_MAXLEN]; size_t bufferSize = 0; const char *pszDimensionlist=NULL; /* if the layer status is set to MS_DEFAULT, output a warning */ if (lp->status == MS_DEFAULT) msIO_fprintf(stdout, "\n"); if (nVersion <= OWS_1_0_7) { msIO_printf("%s \n", indent, msIsLayerQueryable(lp)); } else { /* 1.1.0 and later: opaque and cascaded are new. */ int cascaded=0, opaque=0; if ((value = msOWSLookupMetadata(&(lp->metadata), "MO", "opaque")) != NULL) opaque = atoi(value); if (lp->connectiontype == MS_WMS) cascaded = 1; msIO_printf("%s \n", indent, msIsLayerQueryable(lp), opaque, cascaded); } if (lp->name && strlen(lp->name) > 0 && (msIsXMLTagValid(lp->name) == MS_FALSE || isdigit(lp->name[0]))) msIO_fprintf(stdout, "\n", lp->name); msOWSPrintEncodeParam(stdout, "LAYER.NAME", lp->name, OWS_NOERR, " %s\n", NULL); /* the majority of this section is dependent on appropriately named metadata in the LAYER object */ msOWSPrintEncodeMetadata2(stdout, &(lp->metadata), "MO", "title", OWS_WARN, " %s\n", lp->name, validated_language); msOWSPrintEncodeMetadata2(stdout, &(lp->metadata), "MO", "abstract", OWS_NOERR, " %s\n", NULL, validated_language); msWMSPrintKeywordlist(stdout, " ", "keywordlist", &(lp->metadata), "MO", nVersion); if (msOWSGetEPSGProj(&(map->projection),&(map->web.metadata), "MO", MS_FALSE) == NULL) { /* If map has no proj then every layer MUST have one or produce a warning */ if (nVersion > OWS_1_1_0) { /* starting 1.1.1 SRS are given in individual tags */ if (nVersion >= OWS_1_3_0) msOWSPrintEncodeParamList(stdout, "(at least one of) " "MAP.PROJECTION, LAYER.PROJECTION " "or wms_srs metadata", msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "MO", MS_FALSE), OWS_WARN, ' ', NULL, NULL, " %s\n", NULL); else msOWSPrintEncodeParamList(stdout, "(at least one of) " "MAP.PROJECTION, LAYER.PROJECTION " "or wms_srs metadata", msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "MO", MS_FALSE), OWS_WARN, ' ', NULL, NULL, " %s\n", NULL); } else msOWSPrintEncodeParam(stdout, "(at least one of) MAP.PROJECTION, " "LAYER.PROJECTION or wms_srs metadata", msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "MO", MS_FALSE), OWS_WARN, " %s\n", NULL); } else { /* No warning required in this case since there's at least a map proj. */ if (nVersion > OWS_1_1_0) { /* starting 1.1.1 SRS are given in individual tags */ if (nVersion >= OWS_1_3_0) msOWSPrintEncodeParamList(stdout, "(at least one of) " "MAP.PROJECTION, LAYER.PROJECTION " "or wms_srs metadata", msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "MO", MS_FALSE), OWS_NOERR, ' ', NULL, NULL, " %s\n", NULL); else msOWSPrintEncodeParamList(stdout, "(at least one of) " "MAP.PROJECTION, LAYER.PROJECTION " "or wms_srs metadata", msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "MO", MS_FALSE), OWS_NOERR, ' ', NULL, NULL, " %s\n", NULL); } else msOWSPrintEncodeParam(stdout, " LAYER.PROJECTION (or wms_srs metadata)", msOWSGetEPSGProj(&(lp->projection), &(lp->metadata),"MO",MS_FALSE), OWS_NOERR, " %s\n", NULL); } /* If layer has no proj set then use map->proj for bounding box. */ if (msOWSGetLayerExtent(map, lp, "MO", &ext) == MS_SUCCESS) { if(lp->projection.numargs > 0) { if (nVersion >= OWS_1_3_0) msOWSPrintEX_GeographicBoundingBox(stdout, " ", &(ext), &(lp->projection)); else msOWSPrintLatLonBoundingBox(stdout, " ", &(ext), &(lp->projection), NULL, OWS_WMS); msOWSPrintBoundingBox( stdout," ", &(ext), &(lp->projection), &(lp->metadata), &(map->web.metadata), "MO", nVersion ); } else { if (nVersion >= OWS_1_3_0) msOWSPrintEX_GeographicBoundingBox(stdout, " ", &(ext), &(map->projection)); else msOWSPrintLatLonBoundingBox(stdout, " ", &(ext), &(map->projection), NULL, OWS_WMS); msOWSPrintBoundingBox(stdout," ", &(ext), &(map->projection), &(lp->metadata), &(map->web.metadata), "MO", nVersion ); } } else { if (nVersion >= OWS_1_3_0) msIO_printf(" \n"); else msIO_printf(" \n"); } /* time support */ pszWmsTimeExtent = msOWSLookupMetadata(&(lp->metadata), "MO", "timeextent"); if (pszWmsTimeExtent) { pszWmsTimeDefault = msOWSLookupMetadata(&(lp->metadata), "MO", "timedefault"); if (nVersion >= OWS_1_3_0) { if (pszWmsTimeDefault) msIO_fprintf(stdout, " %s\n",pszWmsTimeDefault, pszWmsTimeExtent); else msIO_fprintf(stdout, " %s\n",pszWmsTimeExtent); } else { msIO_fprintf(stdout, " \n"); if (pszWmsTimeDefault) msIO_fprintf(stdout, " %s\n",pszWmsTimeDefault, pszWmsTimeExtent); else msIO_fprintf(stdout, " %s\n",pszWmsTimeExtent); } } /*dimensions support: elevation + other user defined dimensions*/ pszDimensionlist = msOWSLookupMetadata(&(lp->metadata), "M", "dimensionlist"); if (pszDimensionlist) { char **tokens = NULL; int ntokens = 0; char *pszDimension=NULL, *pszDimensionItemName=NULL, *pszDimensionExtentName=NULL, *pszDimensionUnitName=NULL, *pszDimensionDefaultName=NULL; const char *pszDimensionItem=NULL, *pszDimensionExtent=NULL, *pszDimensionUnit=NULL, *pszDimensionDefault=NULL; int i; tokens = msStringSplit(pszDimensionlist, ',', &ntokens); if (tokens && ntokens > 0) { for (i=0; imetadata), "M", pszDimensionItemName); pszDimensionExtentName = msStrdup(pszDimension); pszDimensionExtentName = msStringConcatenate(pszDimensionExtentName, "_extent"); pszDimensionExtent = msOWSLookupMetadata(&(lp->metadata), "M", pszDimensionExtentName); pszDimensionUnitName = msStrdup(pszDimension); pszDimensionUnitName = msStringConcatenate(pszDimensionUnitName, "_units"); pszDimensionUnit = msOWSLookupMetadata(&(lp->metadata), "M", pszDimensionUnitName); pszDimensionDefaultName = msStrdup(pszDimension); pszDimensionDefaultName = msStringConcatenate(pszDimensionDefaultName, "_default"); pszDimensionDefault = msOWSLookupMetadata(&(lp->metadata), "M", pszDimensionDefaultName); if (pszDimensionItem && pszDimensionExtent && pszDimensionUnit) { if (nVersion >= OWS_1_3_0) { if(pszDimensionDefault && strlen(pszDimensionDefault) > 0) msIO_fprintf(stdout, " %s\n", pszDimension, pszDimensionUnit, pszDimensionDefault, pszDimensionExtent); else msIO_fprintf(stdout, " %s\n", pszDimension, pszDimensionUnit, pszDimensionExtent); } else { msIO_fprintf(stdout, " \n", pszDimension, pszDimensionUnit); if(pszDimensionDefault && strlen(pszDimensionDefault) > 0) msIO_fprintf(stdout, " %s\n", pszDimension, pszDimensionDefault, pszDimensionExtent); else msIO_fprintf(stdout, " %s\n", pszDimension, pszDimensionExtent); } } msFree(pszDimension); msFree(pszDimensionItemName); msFree(pszDimensionUnitName); msFree(pszDimensionDefaultName); } msFreeCharArray(tokens, ntokens); } } if (nVersion >= OWS_1_0_7) { msWMSPrintAttribution(stdout, " ", &(lp->metadata), "MO"); } /* AuthorityURL support and Identifier support, only available >= WMS 1.1.0 */ if(nVersion >= OWS_1_1_0) { msWMSPrintAuthorityURL(stdout, " ", &(lp->metadata), "MO"); msWMSPrintIdentifier(stdout, " ", &(lp->metadata), "MO"); } if(nVersion >= OWS_1_1_0) msOWSPrintURLType(stdout, &(lp->metadata), "MO", "metadataurl", OWS_NOERR, NULL, "MetadataURL", " type=\"%s\"", NULL, NULL, ">\n %s\n ", MS_TRUE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, NULL, NULL, NULL, NULL, NULL, " "); if(nVersion < OWS_1_1_0) msOWSPrintEncodeMetadata(stdout, &(lp->metadata), "MO", "dataurl_href", OWS_NOERR, " %s\n", NULL); else msOWSPrintURLType(stdout, &(lp->metadata), "MO", "dataurl", OWS_NOERR, NULL, "DataURL", NULL, NULL, NULL, ">\n %s\n ", MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, NULL, NULL, NULL, NULL, NULL, " "); /* The LegendURL reside in a style. The Web Map Context spec already */ /* included the support on this in mapserver. However, it is not in the */ /* wms_legendurl_... metadatas it's in the styles metadata, */ /* In wms_style__lengendurl_... metadata. So we have to detect */ /* the current style before reading it. Also in the Style block, we need */ /* a Title and a name. Title is derived from wms_style_\n"); } else if(nVersion >= OWS_1_1_0) { if (pszLegendURL) { /* First, print the style block */ msIO_fprintf(stdout, " \n"); } else { if (script_url_encoded) { if (lp->connectiontype != MS_WMS && lp->connectiontype != MS_WFS && lp->connectiontype != MS_UNUSED_1 && lp->numclasses > 0) { char width[10], height[10]; char *legendurl = NULL; size_t bufferSize = 0; int classnameset = 0, i=0; for (i=0; inumclasses; i++) { if (lp->class[i]->name && strlen(lp->class[i]->name) > 0) { classnameset = 1; break; } } if (classnameset) { int size_x=0, size_y=0; int layer_index[1]; layer_index[0] = lp->index; if (msLegendCalcSize(map, 1, &size_x, &size_y, layer_index, 1) == MS_SUCCESS) { snprintf(width, sizeof(width), "%d", size_x); snprintf(height, sizeof(height), "%d", size_y); bufferSize = strlen(script_url_encoded)+300; legendurl = (char*)msSmallMalloc(bufferSize); #ifdef USE_GD_PNG mimetype = msEncodeHTMLEntities("image/png"); #endif #ifdef USE_GD_GIF if (!mimetype) mimetype = msEncodeHTMLEntities("image/gif"); #endif #ifdef USE_GD_JPEG if (!mimetype) mimetype = msEncodeHTMLEntities("image/jpeg"); #endif if (!mimetype) mimetype = msEncodeHTMLEntities(MS_IMAGE_MIME_TYPE(map->outputformat)); /* -------------------------------------------------------------------- */ /* check if the group parameters for the classes are set. We */ /* should then publish the deffrent class groups as diffrent styles.*/ /* -------------------------------------------------------------------- */ iclassgroups = 0; classgroups = NULL; for (i=0; inumclasses; i++) { if (lp->class[i]->name && lp->class[i]->group) { if (!classgroups) { classgroups = (char **)msSmallMalloc(sizeof(char *)); classgroups[iclassgroups++]= msStrdup(lp->class[i]->group); } else { for (j=0; jclass[i]->group) == 0) break; } if (j == iclassgroups) { iclassgroups++; classgroups = (char **)msSmallRealloc(classgroups, sizeof(char *)*iclassgroups); classgroups[iclassgroups-1]= msStrdup(lp->class[i]->group); } } } } if (classgroups == NULL) { classgroups = (char **)msSmallMalloc(sizeof(char *)); classgroups[0]= msStrdup("default"); iclassgroups = 1; } for (i=0; iname); if (nVersion >= OWS_1_3_0) snprintf(legendurl, bufferSize, "%sversion=%s&service=WMS&request=GetLegendGraphic&sld_version=1.1.0&layer=%s&format=%s&STYLE=%s", script_url_encoded,msOWSGetVersionString(nVersion, szVersionBuf),name_encoded, mimetype, classgroups[i]); else snprintf(legendurl, bufferSize, "%sversion=%s&service=WMS&request=GetLegendGraphic&layer=%s&format=%s&STYLE=%s", script_url_encoded,msOWSGetVersionString(nVersion, szVersionBuf),name_encoded, mimetype, classgroups[i]); msFree(name_encoded); msIO_fprintf(stdout, " \n"); } msFree(legendurl); for (i=0; iminscaledenom, lp->maxscaledenom, map->resolution); else msWMSPrintScaleDenominator(" ", lp->minscaledenom, lp->maxscaledenom); if ( grouplayer == MS_FALSE ) msIO_printf("%s \n", indent); return MS_SUCCESS; } /* * msWMSIsSubGroup */ int msWMSIsSubGroup(char** currentGroups, int currentLevel, char** otherGroups, int numOtherGroups) { int i; /* no match if otherGroups[] has less levels than currentLevel */ if (numOtherGroups <= currentLevel) { return MS_FALSE; } /* compare all groups below the current level */ for (i = 0; i <= currentLevel; i++) { if (strcmp(currentGroups[i], otherGroups[i]) != 0) { return MS_FALSE; /* if one of these is not equal it is not a sub group */ } } return MS_TRUE; } /*********************************************************************************** * msWMSPrintNestedGroups() * * * * purpose: Writes the layers to the capabilities that have the * * "WMS_LAYER_GROUP" metadata set. * * * * params: * * -map: The main map object * * -nVersion: OGC WMS version * * -pabLayerProcessed: boolean array indicating which layers have been dealt with. * * -index: the index of the current layer. * * -level: the level of depth in the group tree (root = 0) * * -nestedGroups: This array holds the arrays of groups that have * * been set through the WMS_LAYER_GROUP metadata * * -numNestedGroups: This array holds the number of nested groups for each layer * ***********************************************************************************/ void msWMSPrintNestedGroups(mapObj* map, int nVersion, char* pabLayerProcessed, int index, int level, char*** nestedGroups, int* numNestedGroups, int* isUsedInNestedGroup, const char *script_url_encoded, const char *validated_language) { int i, j; char *indent = NULL; indent = msStrdup(""); for (i = 0; i < level; i++) { indent = msStringConcatenate(indent, " "); } if (numNestedGroups[index] <= level) /* no more subgroups */ { if ((!pabLayerProcessed[index]) && (!isUsedInNestedGroup[index])) { /* we are at the deepest level of the group branchings, so add layer now. */ msDumpLayer(map, GET_LAYER(map, index), nVersion, script_url_encoded, indent, validated_language, MS_FALSE); pabLayerProcessed[index] = 1; /* done */ } } else /* not yet there, we have to deal with this group and possible subgroups and layers. */ { for (j = 0; j < map->numlayers; j++) { if ( GET_LAYER(map, j)->name && strcasecmp(GET_LAYER(map, j)->name, nestedGroups[index][level]) == 0 ) { break; } } /* Beginning of a new group... enclose the group in a layer block */ if ( j < map->numlayers ) { if (!pabLayerProcessed[j]) { msDumpLayer(map, GET_LAYER(map, j), nVersion, script_url_encoded, indent, validated_language, MS_TRUE); pabLayerProcessed[j] = 1; /* done */ } } else { msIO_printf("%s \n", indent); msIO_printf("%s %s\n", indent, nestedGroups[index][level]); } /* Look for one group deeper in the current layer */ if (!pabLayerProcessed[index]) { msWMSPrintNestedGroups(map, nVersion, pabLayerProcessed, index, level + 1, nestedGroups, numNestedGroups, isUsedInNestedGroup, script_url_encoded, validated_language); } /* look for subgroups in other layers. */ for (j = index + 1; j < map->numlayers; j++) { if (msWMSIsSubGroup(nestedGroups[index], level, nestedGroups[j], numNestedGroups[j])) { if (!pabLayerProcessed[j]) { msWMSPrintNestedGroups(map, nVersion, pabLayerProcessed, j, level + 1, nestedGroups, numNestedGroups, isUsedInNestedGroup, script_url_encoded, validated_language); } } else { /* TODO: if we would sort all layers on "WMS_LAYER_GROUP" beforehand */ /* we could break out of this loop at this point, which would increase */ /* performance. */ } } /* Close group layer block */ msIO_printf("%s \n", indent); } msFree(indent); } /* msWMSPrintNestedGroups */ /* ** msWMSGetCapabilities() */ int msWMSGetCapabilities(mapObj *map, int nVersion, cgiRequestObj *req, owsRequestObj *ows_request, const char *requested_updatesequence, char *wms_exception_format, const char *requested_language) { char *dtd_url = NULL; char *script_url=NULL, *script_url_encoded=NULL; char szVersionBuf[OWS_VERSION_MAXLEN]; char *schemalocation = NULL; const char *updatesequence=NULL; const char *sldenabled=NULL; const char *encoding; const char *layerlimit=NULL; char *pszTmp=NULL; int i; const char *format_list=NULL; char **tokens = NULL; int numtokens = 0; char *validated_language = NULL; updatesequence = msOWSLookupMetadata(&(map->web.metadata), "MO", "updatesequence"); sldenabled = msOWSLookupMetadata(&(map->web.metadata), "MO", "sld_enabled"); encoding = msOWSLookupMetadata(&(map->web.metadata), "MO", "encoding"); if (sldenabled == NULL) sldenabled = "true"; if (requested_updatesequence != NULL) { i = msOWSNegotiateUpdateSequence(requested_updatesequence, updatesequence); if (i == 0) { /* current */ msSetError(MS_WMSERR, "UPDATESEQUENCE parameter (%s) is equal to server (%s)", "msWMSGetCapabilities()", requested_updatesequence, updatesequence); return msWMSException(map, nVersion, "CurrentUpdateSequence", wms_exception_format); } if (i > 0) { /* invalid */ msSetError(MS_WMSERR, "UPDATESEQUENCE parameter (%s) is higher than server (%s)", "msWMSGetCapabilities()", requested_updatesequence, updatesequence); return msWMSException(map, nVersion, "InvalidUpdateSequence", wms_exception_format); } } schemalocation = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) ); if (nVersion < 0) nVersion = OWS_1_3_0; /* Default to 1.3.0 */ /* Decide which version we're going to return. */ if (nVersion < OWS_1_0_7) { nVersion = OWS_1_0_0; dtd_url = msStrdup(schemalocation); dtd_url = msStringConcatenate(dtd_url, "/wms/1.0.0/capabilities_1_0_0.dtd"); } else if (nVersion < OWS_1_1_0) { nVersion = OWS_1_0_7; dtd_url = msStrdup(schemalocation); dtd_url = msStringConcatenate(dtd_url, "/wms/1.0.7/capabilities_1_0_7.dtd"); } else if (nVersion < OWS_1_1_1) { nVersion = OWS_1_1_0; dtd_url = msStrdup(schemalocation); dtd_url = msStringConcatenate(dtd_url, "/wms/1.1.0/capabilities_1_1_0.dtd"); } else if (nVersion < OWS_1_3_0) { nVersion = OWS_1_1_1; dtd_url = msStrdup(schemalocation); /* this exception was added to accomadote the OGC test suite (Bug 1576)*/ if (strcasecmp(schemalocation, OWS_DEFAULT_SCHEMAS_LOCATION) == 0) dtd_url = msStringConcatenate(dtd_url, "/wms/1.1.1/WMS_MS_Capabilities.dtd"); else dtd_url = msStringConcatenate(dtd_url, "/wms/1.1.1/capabilities_1_1_1.dtd"); } else nVersion = OWS_1_3_0; /* This function owns validated_language, so remember to free it later*/ validated_language = msOWSGetLanguageFromList(map, "MO", requested_language); if (validated_language != NULL) { for(i=0; inumlayers; i++) { layerObj *layer = GET_LAYER(map, i); if(layer->data) layer->data = msCaseReplaceSubstring(layer->data, "%language%", validated_language); if(layer->connection) layer->connection = msCaseReplaceSubstring(layer->connection, "%language%", validated_language); } } /* We need this server's onlineresource. */ /* Default to use the value of the "onlineresource" metadata, and if not */ /* set then build it: "http://$(SERVER_NAME):$(SERVER_PORT)$(SCRIPT_NAME)?" */ /* the returned string should be freed once we're done with it. */ if ((script_url=msOWSGetOnlineResource2(map, "MO", "onlineresource", req, validated_language)) == NULL || (script_url_encoded = msEncodeHTMLEntities(script_url)) == NULL) { msFree(validated_language); return msWMSException(map, nVersion, NULL, wms_exception_format); } if (nVersion <= OWS_1_0_7 || nVersion >= OWS_1_3_0) /* 1.0.0 to 1.0.7 and >=1.3.0*/ if (encoding) msIO_setHeader("Content-type","text/xml; charset=%s", encoding); else msIO_setHeader("Content-type","text/xml"); else /* 1.1.0 and later */ if (encoding) msIO_setHeader("Content-type","application/vnd.ogc.se_xml; charset=%s", encoding); else msIO_setHeader("Content-type","application/vnd.ogc.se_xml"); msIO_sendHeaders(); msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "encoding", OWS_NOERR, "\n", "ISO-8859-1"); /*TODO review wms1.3.0*/ if ( nVersion < OWS_1_3_0) { msIO_printf("\n"); msIO_printf(" ]> \n\n"); } updatesequence = msOWSLookupMetadata(&(map->web.metadata), "MO", "updatesequence"); if ( nVersion >= OWS_1_3_0) msIO_printf("web.metadata), "MO", "inspire_capabilities") ) { msIO_printf(" xmlns:inspire_common=\"http://inspire.ec.europa.eu/schemas/common/1.0\"" " xmlns:inspire_vs=\"http://inspire.ec.europa.eu/schemas/inspire_vs/1.0\"" ); } msIO_printf(" xsi:schemaLocation=\"http://www.opengis.net/wms %s/wms/%s/capabilities_1_3_0.xsd " " http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd ", msOWSGetSchemasLocation(map), msOWSGetVersionString(nVersion, szVersionBuf)); if ( msOWSLookupMetadata(&(map->web.metadata), "MO", "inspire_capabilities") ) { msIO_printf(" http://inspire.ec.europa.eu/schemas/inspire_vs/1.0 " " http://inspire.ec.europa.eu/schemas/inspire_vs/1.0/inspire_vs.xsd"); } msIO_printf(" http://mapserver.gis.umn.edu/mapserver %sservice=WMS&version=1.3.0&request=GetSchemaExtension\"", script_url_encoded); } msIO_printf(">\n"); /* Report MapServer Version Information */ msIO_printf("\n\n\n", msGetVersion()); /* WMS definition */ msIO_printf("\n"); /* Service name is defined by the spec and changed at v1.0.0 */ if (nVersion <= OWS_1_0_7) msIO_printf(" GetMap\n"); /* v 1.0.0 to 1.0.7 */ else if (nVersion > OWS_1_0_7 && nVersion < OWS_1_3_0) msIO_printf(" OGC:WMS\n"); /* v 1.1.0 to 1.1.1*/ else msIO_printf(" WMS\n"); /* v 1.3.0+ */ /* the majority of this section is dependent on appropriately named metadata in the WEB object */ msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "title", OWS_WARN, " %s\n", map->name, validated_language); msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "abstract", OWS_NOERR, " %s\n", NULL, validated_language); msWMSPrintKeywordlist(stdout, " ", "keywordlist", &(map->web.metadata), "MO", nVersion); /* Service/onlineresource */ /* Defaults to same as request onlineresource if wms_service_onlineresource */ /* is not set. */ if (nVersion== OWS_1_0_0) msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "service_onlineresource", OWS_NOERR, " %s\n", script_url_encoded); else msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "service_onlineresource", OWS_NOERR, " \n", script_url_encoded); /* contact information is a required element in 1.0.7 but the */ /* sub-elements such as ContactPersonPrimary, etc. are not! */ /* In 1.1.0, ContactInformation becomes optional. */ msOWSPrintContactInfo(stdout, " ", nVersion, &(map->web.metadata), "MO"); msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "fees", OWS_NOERR, " %s\n", NULL); msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "accessconstraints", OWS_NOERR, " %s\n", NULL); if (nVersion >= OWS_1_3_0) { layerlimit = msOWSLookupMetadata(&(map->web.metadata), "MO", "layerlimit"); if (layerlimit) { msIO_printf(" %s\n", layerlimit); } msIO_printf(" %d\n", map->maxsize); msIO_printf(" %d\n", map->maxsize); } msIO_printf("\n\n"); /* WMS capabilities definitions */ msIO_printf("\n"); msIO_printf(" \n"); if (nVersion <= OWS_1_0_7) { /* WMS 1.0.0 to 1.0.7 - We don't try to use outputformats list here for now */ if (msOWSRequestIsEnabled(map, NULL, "M", "GetMap", MS_FALSE)) msWMSPrintRequestCap(nVersion, "Map", script_url_encoded, "" #ifdef USE_GD_GIF "" #endif #ifdef USE_GD_PNG "" #endif #ifdef USE_GD_JPEG "" #endif "" , NULL); if (msOWSRequestIsEnabled(map, NULL, "M", "GetCapabilities", MS_FALSE)) msWMSPrintRequestCap(nVersion, "Capabilities", script_url_encoded, "", NULL); if (msOWSRequestIsEnabled(map, NULL, "M", "GetFeatureInfo", MS_FALSE)) msWMSPrintRequestCap(nVersion, "FeatureInfo", script_url_encoded, "", NULL); } else { char *mime_list[20]; int mime_count = 0; int max_mime = 20; /* WMS 1.1.0 and later */ /* Note changes to the request names, their ordering, and to the formats */ if (msOWSRequestIsEnabled(map, NULL, "M", "GetCapabilities", MS_FALSE)) { if (nVersion >= OWS_1_3_0) msWMSPrintRequestCap(nVersion, "GetCapabilities", script_url_encoded, "text/xml", NULL); else msWMSPrintRequestCap(nVersion, "GetCapabilities", script_url_encoded, "application/vnd.ogc.wms_xml", NULL); } msGetOutputFormatMimeListWMS(map,mime_list,sizeof(mime_list)/sizeof(char*)); if (msOWSRequestIsEnabled(map, NULL, "M", "GetMap", MS_FALSE)) msWMSPrintRequestCap(nVersion, "GetMap", script_url_encoded, mime_list[0], mime_list[1], mime_list[2], mime_list[3], mime_list[4], mime_list[5], mime_list[6], mime_list[7], mime_list[8], mime_list[9], mime_list[10], mime_list[11], mime_list[12], mime_list[13], mime_list[14], mime_list[15], mime_list[16], mime_list[17], mime_list[18], mime_list[19], NULL ); format_list = msOWSLookupMetadata(&(map->web.metadata), "M", "getfeatureinfo_formatlist"); /*feature_info_mime_type depricated for MapServer 6.0*/ if (!format_list) format_list = msOWSLookupMetadata(&(map->web.metadata), "MO", "feature_info_mime_type"); if (format_list && strlen(format_list) > 0) { tokens = msStringSplit(format_list, ',', &numtokens); if (tokens && numtokens > 0) { mime_count = 0; for(i=0; i < numtokens; i++ ) { msStringTrim(tokens[i]); /*text plain and gml do not need to be a format and accepted by default*/ /*can not really validate since the old way of using template with wei->header, layer->template ... should be kept*/ if (strlen(tokens[i]) > 0 && mime_count0) { if (mime_count0) msFreeCharArray(tokens, numtokens); } else { if (msOWSRequestIsEnabled(map, NULL, "M", "GetFeatureInfo", MS_FALSE)) msWMSPrintRequestCap(nVersion, "GetFeatureInfo", script_url_encoded, "text/plain", "application/vnd.ogc.gml", NULL); } if (strcasecmp(sldenabled, "true") == 0) { if (msOWSRequestIsEnabled(map, NULL, "M", "DescribeLayer", MS_FALSE)) { if (nVersion == OWS_1_3_0) msWMSPrintRequestCap(nVersion, "sld:DescribeLayer", script_url_encoded, "text/xml", NULL); else msWMSPrintRequestCap(nVersion, "DescribeLayer", script_url_encoded, "text/xml", NULL); } msGetOutputFormatMimeListImg(map,mime_list,sizeof(mime_list)/sizeof(char*)); if (nVersion >= OWS_1_1_1) { if (nVersion == OWS_1_3_0) { if (msOWSRequestIsEnabled(map, NULL, "M", "GetLegendGraphic", MS_FALSE)) msWMSPrintRequestCap(nVersion, "sld:GetLegendGraphic", script_url_encoded, mime_list[0], mime_list[1], mime_list[2], mime_list[3], mime_list[4], mime_list[5], mime_list[6], mime_list[7], mime_list[8], mime_list[9], mime_list[10], mime_list[11], mime_list[12], mime_list[13], mime_list[14], mime_list[15], mime_list[16], mime_list[17], mime_list[18], mime_list[19], NULL ); if (msOWSRequestIsEnabled(map, NULL, "M", "GetStyles", MS_FALSE)) msWMSPrintRequestCap(nVersion, "ms:GetStyles", script_url_encoded, "text/xml", NULL); } else { if (msOWSRequestIsEnabled(map, NULL, "M", "GetLegendGraphic", MS_FALSE)) msWMSPrintRequestCap(nVersion, "GetLegendGraphic", script_url_encoded, mime_list[0], mime_list[1], mime_list[2], mime_list[3], mime_list[4], mime_list[5], mime_list[6], mime_list[7], mime_list[8], mime_list[9], mime_list[10], mime_list[11], mime_list[12], mime_list[13], mime_list[14], mime_list[15], mime_list[16], mime_list[17], mime_list[18], mime_list[19], NULL ); if (msOWSRequestIsEnabled(map, NULL, "M", "GetStyles", MS_FALSE)) msWMSPrintRequestCap(nVersion, "GetStyles", script_url_encoded, "text/xml", NULL); } } } } msIO_printf(" \n"); msIO_printf(" \n"); if (nVersion <= OWS_1_0_7) msIO_printf(" \n"); else if (nVersion <= OWS_1_1_1) { msIO_printf(" application/vnd.ogc.se_xml\n"); msIO_printf(" application/vnd.ogc.se_inimage\n"); msIO_printf(" application/vnd.ogc.se_blank\n"); } else /*>=1.3.0*/ { msIO_printf(" XML\n"); msIO_printf(" INIMAGE\n"); msIO_printf(" BLANK\n"); } msIO_printf(" \n"); if (nVersion != OWS_1_3_0) msIO_printf(" \n"); /* nothing yet */ /* SLD support */ if (strcasecmp(sldenabled, "true") == 0) { if (nVersion >= OWS_1_0_7) { if (nVersion >= OWS_1_3_0) msIO_printf(" \n"); else msIO_printf(" \n"); } } /* INSPIRE extended capabilities */ if (nVersion >= OWS_1_3_0 && msOWSLookupMetadata(&(map->web.metadata), "MO", "inspire_capabilities") ) { msOWSPrintInspireCommonExtendedCapabilities(stdout, map, "MO", OWS_WARN, "inspire_vs:ExtendedCapabilities", validated_language, OWS_WMS); } /* Top-level layer with map extents and SRS, encloses all map layers */ /* Output only if at least one layers is enabled. */ if (ows_request->numlayers == 0) { msIO_fprintf(stdout, " \n"); } else { msIO_printf(" \n"); /* Layer Name is optional but title is mandatory. */ if (map->name && strlen(map->name) > 0 && (msIsXMLTagValid(map->name) == MS_FALSE || isdigit(map->name[0]))) msIO_fprintf(stdout, "\n", map->name); msOWSPrintEncodeParam(stdout, "MAP.NAME", map->name, OWS_NOERR, " %s\n", NULL); if (msOWSLookupMetadataWithLanguage(&(map->web.metadata), "MO", "rootlayer_title", validated_language)) msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "rootlayer_title", OWS_WARN, " %s\n", map->name, validated_language); else msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "title", OWS_WARN, " %s\n", map->name, validated_language); if (msOWSLookupMetadataWithLanguage(&(map->web.metadata), "MO", "rootlayer_abstract", validated_language)) msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "rootlayer_abstract", OWS_NOERR, " %s\n", map->name, validated_language); else msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "abstract", OWS_NOERR, " %s\n", map->name, validated_language); if (msOWSLookupMetadata(&(map->web.metadata), "MO", "rootlayer_keywordlist") || msOWSLookupMetadata(&(map->web.metadata), "MO", "rootlayer_keywordlist_vocabulary")) pszTmp = msStrdup("rootlayer_keywordlist"); else pszTmp = msStrdup("keywordlist"); msWMSPrintKeywordlist(stdout, " ", pszTmp, &(map->web.metadata), "MO", nVersion); msFree(pszTmp); /* According to normative comments in the 1.0.7 DTD, the root layer's SRS tag */ /* is REQUIRED. It also suggests that we use an empty SRS element if there */ /* is no common SRS. */ if (nVersion > OWS_1_1_0) { /* starting 1.1.1 SRS are given in individual tags */ if (nVersion >= OWS_1_3_0) msOWSPrintEncodeParamList(stdout, "(at least one of) " "MAP.PROJECTION, LAYER.PROJECTION " "or wms_srs metadata", msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "MO", MS_FALSE), OWS_WARN, ' ', NULL, NULL, " %s\n", ""); else msOWSPrintEncodeParamList(stdout, "(at least one of) " "MAP.PROJECTION, LAYER.PROJECTION " "or wms_srs metadata", msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "MO", MS_FALSE), OWS_WARN, ' ', NULL, NULL, " %s\n", ""); } else /* If map has no proj then every layer MUST have one or produce a warning */ msOWSPrintEncodeParam(stdout, "MAP.PROJECTION (or wms_srs metadata)", msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "MO", MS_FALSE), OWS_WARN, " %s\n", ""); if (nVersion >= OWS_1_3_0) msOWSPrintEX_GeographicBoundingBox(stdout, " ", &(map->extent), &(map->projection)); else msOWSPrintLatLonBoundingBox(stdout, " ", &(map->extent), &(map->projection), NULL, OWS_WMS); msOWSPrintBoundingBox( stdout, " ", &(map->extent), &(map->projection), NULL, &(map->web.metadata), "MO", nVersion); if (nVersion >= OWS_1_0_7) { msWMSPrintAttribution(stdout, " ", &(map->web.metadata), "MO"); } /* AuthorityURL support and Identifier support, only available >= WMS 1.1.0 */ if(nVersion >= OWS_1_1_0) { msWMSPrintAuthorityURL(stdout, " ", &(map->web.metadata), "MO"); msWMSPrintIdentifier(stdout, " ", &(map->web.metadata), "MO"); } /* MetadataURL */ if(nVersion >= OWS_1_1_0) msOWSPrintURLType(stdout, &(map->web.metadata), "MO", "metadataurl", OWS_NOERR, NULL, "MetadataURL", " type=\"%s\"", NULL, NULL, ">\n %s\n ", MS_TRUE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, NULL, NULL, NULL, NULL, NULL, " "); /* DataURL */ if(nVersion < OWS_1_1_0) msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "dataurl_href", OWS_NOERR, " %s\n", NULL); else msOWSPrintURLType(stdout, &(map->web.metadata), "MO", "dataurl", OWS_NOERR, NULL, "DataURL", NULL, NULL, NULL, ">\n %s\n ", MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, NULL, NULL, NULL, NULL, NULL, " "); if (nVersion < OWS_1_3_0) msWMSPrintScaleHint(" ", map->web.minscaledenom, map->web.maxscaledenom, map->resolution); else msWMSPrintScaleDenominator(" ", map->web.minscaledenom, map->web.maxscaledenom); if (map->name && strlen(map->name) > 0 && msOWSLookupMetadata(&(map->web.metadata), "MO", "inspire_capabilities") ) { char *pszEncodedName = NULL; const char *styleName = NULL; char *pszEncodedStyleName = NULL; const char *legendURL = NULL; pszEncodedName = msEncodeHTMLEntities(map->name); styleName = msOWSLookupMetadata(&(map->web.metadata), "MO", "style_name"); if (styleName == NULL) styleName = "default"; pszEncodedStyleName = msEncodeHTMLEntities(styleName); msIO_fprintf(stdout, " \n"); msFree(pszEncodedName); msFree(pszEncodedStyleName); } /* */ /* Dump list of layers organized by groups. Layers with no group are listed */ /* individually, at the same level as the groups in the layer hierarchy */ /* */ if (map->numlayers) { int i, j; char *pabLayerProcessed = NULL; char ***nestedGroups = NULL; int *numNestedGroups = NULL; int *isUsedInNestedGroup = NULL; /* We'll use this array of booleans to track which layer/group have been */ /* processed already */ pabLayerProcessed = (char *)msSmallCalloc(map->numlayers, sizeof(char*)); nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); for(i=0; inumlayers; i++) { layerObj *lp; lp = (GET_LAYER(map, i)); if (pabLayerProcessed[i] || (lp->status == MS_DELETE) || (!msIntegerInArray(lp->index, ows_request->enabled_layers, ows_request->numlayers))) continue; /* Layer is hidden or has already been handled */ if (numNestedGroups[i] > 0) { /* Has nested groups. */ msWMSPrintNestedGroups(map, nVersion, pabLayerProcessed, i, 0, nestedGroups, numNestedGroups, isUsedInNestedGroup, script_url_encoded, validated_language); } else if (lp->group == NULL || strlen(lp->group) == 0) { /* Don't dump layer if it is used in wms_group_layer. */ if (!isUsedInNestedGroup[i]) { /* This layer is not part of a group... dump it directly */ msDumpLayer(map, lp, nVersion, script_url_encoded, "", validated_language, MS_FALSE); pabLayerProcessed[i] = 1; } } else { /* Beginning of a new group... enclose the group in a layer block */ msIO_printf(" \n"); /* Layer Name is optional but title is mandatory. */ if (lp->group && strlen(lp->group) > 0 && (msIsXMLTagValid(lp->group) == MS_FALSE || isdigit(lp->group[0]))) msIO_fprintf(stdout, "\n", lp->group); msOWSPrintEncodeParam(stdout, "GROUP.NAME", lp->group, OWS_NOERR, " %s\n", NULL); msOWSPrintGroupMetadata2(stdout, map, lp->group, "MO", "GROUP_TITLE", OWS_WARN, " %s\n", lp->group, validated_language); msOWSPrintGroupMetadata2(stdout, map, lp->group, "MO", "GROUP_ABSTRACT", OWS_NOERR, " %s\n", lp->group, validated_language); /*build a getlegendgraphicurl*/ if( script_url_encoded) { if (lp->group && strlen(lp->group) > 0) { char *pszEncodedName = NULL; const char *styleName = NULL; char *pszEncodedStyleName = NULL; const char *legendURL = NULL; pszEncodedName = msEncodeHTMLEntities(lp->group); styleName = msOWSLookupMetadata(&(lp->metadata), "MO", "group_style_name"); if (styleName == NULL) styleName = "default"; pszEncodedStyleName = msEncodeHTMLEntities(styleName); msIO_fprintf(stdout, " \n"); msFree(pszEncodedName); msFree(pszEncodedStyleName); } } /* Dump all layers for this group */ for(j=i; jnumlayers; j++) { if (!pabLayerProcessed[j] && GET_LAYER(map, j)->group && strcmp(lp->group, GET_LAYER(map, j)->group) == 0 && msIntegerInArray(GET_LAYER(map, j)->index, ows_request->enabled_layers, ows_request->numlayers)) { msDumpLayer(map, (GET_LAYER(map, j)), nVersion, script_url_encoded, " ", validated_language, MS_FALSE); pabLayerProcessed[j] = 1; } } /* Close group layer block */ msIO_printf(" \n"); } } free(pabLayerProcessed); /* free the stuff used for nested layers */ for (i = 0; i < map->numlayers; i++) { if (numNestedGroups[i] > 0) { msFreeCharArray(nestedGroups[i], numNestedGroups[i]); } } free(nestedGroups); free(numNestedGroups); free(isUsedInNestedGroup); } msIO_printf(" \n"); } msIO_printf("\n"); if ( nVersion >= OWS_1_3_0) msIO_printf("\n"); else msIO_printf("\n"); msFree(validated_language); free(script_url); free(script_url_encoded); free(dtd_url); free(schemalocation); return(MS_SUCCESS); } /* * This function look for params that can be used * by mapserv when generating template. */ int msTranslateWMS2Mapserv(char **names, char **values, int *numentries) { int i=0; int tmpNumentries = *numentries;; for (i=0; i<*numentries; i++) { if (strcasecmp("X", names[i]) == 0) { values[tmpNumentries] = msStrdup(values[i]); names[tmpNumentries] = msStrdup("img.x"); tmpNumentries++; } else if (strcasecmp("Y", names[i]) == 0) { values[tmpNumentries] = msStrdup(values[i]); names[tmpNumentries] = msStrdup("img.y"); tmpNumentries++; } else if (strcasecmp("LAYERS", names[i]) == 0) { char **layers; int tok; int j; layers = msStringSplit(values[i], ',', &tok); for (j=0; j 0) || (strcasecmp(names[i], "SLD_BODY") == 0 && values[i] && strlen(values[i]) > 0)) { sldrequested = MS_TRUE; break; } } if (sldrequested) { for (i=0; inumlayers; i++) { if (msLookupHashTable(&(GET_LAYER(map, i)->metadata), "tmp_wms_sld_query")) { sldspatialfilter = MS_TRUE; break; } } } /* turn off layer if WMS GetMap is not enabled */ for (i=0; inumlayers; i++) if (!msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) GET_LAYER(map, i)->status = MS_OFF; if (sldrequested && sldspatialfilter) { /* set the quermap style so that only selected features will be retruned */ map->querymap.status = MS_ON; map->querymap.style = MS_SELECTED; img = msPrepareImage(map, MS_TRUE); /* compute layer scale factors now */ for(i=0;inumlayers; i++) { if(GET_LAYER(map, i)->sizeunits != MS_PIXELS) GET_LAYER(map, i)->scalefactor = (msInchesPerUnit(GET_LAYER(map, i)->sizeunits,0)/msInchesPerUnit(map->units,0)) / map->cellsize; else if(GET_LAYER(map, i)->symbolscaledenom > 0 && map->scaledenom > 0) GET_LAYER(map, i)->scalefactor = GET_LAYER(map, i)->symbolscaledenom/map->scaledenom; else GET_LAYER(map, i)->scalefactor = 1; } for (i=0; inumlayers; i++) { if (msLookupHashTable(&(GET_LAYER(map, i)->metadata), "tmp_wms_sld_query") && (GET_LAYER(map, i)->type == MS_LAYER_POINT || GET_LAYER(map, i)->type == MS_LAYER_LINE || GET_LAYER(map, i)->type == MS_LAYER_POLYGON || GET_LAYER(map, i)->type == MS_LAYER_ANNOTATION || GET_LAYER(map, i)->type == MS_LAYER_TILEINDEX)) { /* make sure that there is a resultcache. If not just ignore */ /* the layer */ if (GET_LAYER(map, i)->resultcache) msDrawQueryLayer(map, GET_LAYER(map, i), img); } else msDrawLayer(map, GET_LAYER(map, i), img); } } else img = msDrawMap(map, MS_FALSE); if (img == NULL) return msWMSException(map, nVersion, NULL, wms_exception_format); /* Set the HTTP Cache-control headers if they are defined in the map object */ if( (http_max_age = msOWSLookupMetadata(&(map->web.metadata), "MO", "http_max_age")) ) { msIO_setHeader("Cache-Control","max-age=%s", http_max_age); } if (strcasecmp(map->imagetype, "application/openlayers")!=0) { msIO_setHeader("Content-type",MS_IMAGE_MIME_TYPE(map->outputformat)); msIO_sendHeaders(); if (msSaveImage(map, img, NULL) != MS_SUCCESS) return msWMSException(map, nVersion, NULL, wms_exception_format); msFreeImage(img); } return(MS_SUCCESS); } int msDumpResult(mapObj *map, int bFormatHtml, int nVersion, char *wms_exception_format) { int numresults=0; int i; for(i=0; inumlayers; i++) { int j, k, *itemvisible; char **incitems=NULL; int numincitems=0; char **excitems=NULL; int numexcitems=0; const char *value; layerObj *lp; lp = (GET_LAYER(map, i)); if(lp->status != MS_ON || lp->resultcache==NULL || lp->resultcache->numresults == 0) continue; /* if(msLayerOpen(lp) != MS_SUCCESS || msLayerGetItems(lp) != MS_SUCCESS) return msWMSException(map, nVersion, NULL); */ /* Use metadata to control which fields to output. We use the same * metadata names as for GML: * wms/ows_include_items: comma delimited list or keyword 'all' * wms/ows_exclude_items: comma delimited list (all items are excluded by default) */ /* get a list of items that should be excluded in output */ if((value = msOWSLookupMetadata(&(lp->metadata), "MO", "include_items")) != NULL) incitems = msStringSplit(value, ',', &numincitems); /* get a list of items that should be excluded in output */ if((value = msOWSLookupMetadata(&(lp->metadata), "MO", "exclude_items")) != NULL) excitems = msStringSplit(value, ',', &numexcitems); itemvisible = (int*)msSmallMalloc(lp->numitems*sizeof(int)); for(k=0; knumitems; k++) { int l; itemvisible[k] = MS_FALSE; /* check visibility, included items first... */ if(numincitems == 1 && strcasecmp("all", incitems[0]) == 0) { itemvisible[k] = MS_TRUE; } else { for(l=0; litems[k], incitems[l]) == 0) itemvisible[k] = MS_TRUE; } } /* ...and now excluded items */ for(l=0; litems[k], excitems[l]) == 0) itemvisible[k] = MS_FALSE; } } msFreeCharArray(incitems, numincitems); msFreeCharArray(excitems, numexcitems); /* Output selected shapes for this layer */ msIO_printf("\nLayer '%s'\n", lp->name); for(j=0; jresultcache->numresults; j++) { shapeObj shape; msInitShape(&shape); if (msLayerGetShape(lp, &shape, &(lp->resultcache->results[j])) != MS_SUCCESS) { msFree(itemvisible); return msWMSException(map, nVersion, NULL, wms_exception_format); } msIO_printf(" Feature %ld: \n", lp->resultcache->results[j].shapeindex); for(k=0; knumitems; k++) { if (itemvisible[k]) msIO_printf(" %s = '%s'\n", lp->items[k], shape.values[k]); } msFreeShape(&shape); numresults++; } msFree(itemvisible); /* msLayerClose(lp); */ } return numresults; } /* ** msWMSFeatureInfo() */ int msWMSFeatureInfo(mapObj *map, int nVersion, char **names, char **values, int numentries, char *wms_exception_format, owsRequestObj *ows_request) { int i, feature_count=1, numlayers_found=0; pointObj point = {-1.0, -1.0}; const char *info_format="MIME"; double cellx, celly; errorObj *ms_error = msGetErrorObj(); int query_status=MS_NOERR; const char *encoding; int query_layer = 0; const char *format_list=NULL; int valid_format=MS_FALSE; int format_found = MS_FALSE; int use_bbox = MS_FALSE; int wms_layer = MS_FALSE; const char *wms_connection = NULL; int numOWSLayers = 0; char ***nestedGroups = NULL; int *numNestedGroups = NULL; int *isUsedInNestedGroup = NULL; encoding = msOWSLookupMetadata(&(map->web.metadata), "MO", "encoding"); nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); for(i=0; map && inumlayers; j++) { /* Force all layers OFF by default */ GET_LAYER(map, j)->status = MS_OFF; for(k=0; kname && strcasecmp(GET_LAYER(map, j)->name, layers[k]) == 0) || (map->name && strcasecmp(map->name, layers[k]) == 0) || (GET_LAYER(map, j)->group && strcasecmp(GET_LAYER(map, j)->group, layers[k]) == 0) || ((numNestedGroups[j] >0) && msStringInArray(layers[k], nestedGroups[j], numNestedGroups[j]))) && (msIntegerInArray(GET_LAYER(map, j)->index, ows_request->enabled_layers, ows_request->numlayers)) ) { if (GET_LAYER(map, j)->connectiontype == MS_WMS) { wms_layer = MS_TRUE; wms_connection = GET_LAYER(map, j)->connection; } /* Don't turn on layers that are not queryable but have sublayers. */ if ((msIsLayerQueryable(GET_LAYER(map, j))) || isUsedInNestedGroup[j] == 0) { numlayers_found++; GET_LAYER(map, j)->status = MS_ON; } } } } msFreeCharArray(layers, numlayers); } else if (strcasecmp(names[i], "INFO_FORMAT") == 0) { if (values[i] && strlen(values[i]) > 0) { info_format = values[i]; format_found = MS_TRUE; } } else if (strcasecmp(names[i], "FEATURE_COUNT") == 0) feature_count = atoi(values[i]); else if(strcasecmp(names[i], "X") == 0 || strcasecmp(names[i], "I") == 0) point.x = atof(values[i]); else if (strcasecmp(names[i], "Y") == 0 || strcasecmp(names[i], "J") == 0) point.y = atof(values[i]); else if (strcasecmp(names[i], "RADIUS") == 0) { /* RADIUS in pixels. */ /* This is not part of the spec, but some servers such as cubeserv */ /* support it as a vendor-specific feature. */ /* It's easy for MapServer to handle this so let's do it! */ /* Special RADIUS value that changes the query into a bbox query */ /* based on the bbox in the request parameters. */ if( strcasecmp(values[i], "BBOX") == 0) { use_bbox = MS_TRUE; } else { int j; for(j=0; jnumlayers; j++) { GET_LAYER(map, j)->tolerance = atoi(values[i]); GET_LAYER(map, j)->toleranceunits = MS_PIXELS; } } } } /* free the stuff used for nested layers */ for (i = 0; i < map->numlayers; i++) { if (numNestedGroups[i] > 0) { msFreeCharArray(nestedGroups[i], numNestedGroups[i]); } } free(nestedGroups); free(numNestedGroups); free(isUsedInNestedGroup); if(numlayers_found == 0) { if (query_layer) { msSetError(MS_WMSERR, "Layer(s) specified in QUERY_LAYERS parameter is not offered by the service instance.", "msWMSFeatureInfo()"); return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); } else { msSetError(MS_WMSERR, "Required QUERY_LAYERS parameter missing for getFeatureInfo.", "msWMSFeatureInfo()"); return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); } } /*make sure to initialize the map scale so that layers that are scale dependent are resepected for the query*/ msCalculateScale(map->extent,map->units,map->width,map->height, map->resolution, &map->scaledenom); /* -------------------------------------------------------------------- */ /* check if all layers selected are queryable. If not send an */ /* exception. */ /* -------------------------------------------------------------------- */ /* If a layer of type WMS was found... all layers have to be of that type and with the same connection */ for (i=0; inumlayers; i++) { if (GET_LAYER(map, i)->status == MS_ON) { if (!msIsLayerQueryable(GET_LAYER(map, i))) { msSetError(MS_WMSERR, "Requested layer(s) are not queryable.", "msWMSFeatureInfo()"); return msWMSException(map, nVersion, "LayerNotQueryable", wms_exception_format); } else if (wms_layer == MS_TRUE) { if ( (GET_LAYER(map, i)->connectiontype != MS_WMS) || (strcasecmp(wms_connection, GET_LAYER(map, i)->connection) != 0) ) { msSetError(MS_WMSERR, "Requested WMS layer(s) are not queryable: type or connection differ", "msWMSFeatureInfo()"); return msWMSException(map, nVersion, "LayerNotQueryable", wms_exception_format); } ++numOWSLayers; } } } /* It's a valid Cascading WMS GetFeatureInfo request */ if (wms_layer) return msWMSLayerExecuteRequest(map, numOWSLayers, point.x, point.y, feature_count, info_format, WMS_GETFEATUREINFO); if( use_bbox == MS_FALSE ) { if(point.x == -1.0 || point.y == -1.0) { if (nVersion >= OWS_1_3_0) msSetError(MS_WMSERR, "Required I/J parameters missing for getFeatureInfo.", "msWMSFeatureInfo()"); else msSetError(MS_WMSERR, "Required X/Y parameters missing for getFeatureInfo.", "msWMSFeatureInfo()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } /*wms1.3.0: check if the points are valid*/ if (nVersion >= OWS_1_3_0) { if (point.x > map->width || point.y > map->height) { msSetError(MS_WMSERR, "Invalid I/J values", "msWMSFeatureInfo()"); return msWMSException(map, nVersion, "InvalidPoint", wms_exception_format); } } /* Perform the actual query */ cellx = MS_CELLSIZE(map->extent.minx, map->extent.maxx, map->width); /* note: don't adjust extent, WMS assumes incoming extent is correct */ celly = MS_CELLSIZE(map->extent.miny, map->extent.maxy, map->height); point.x = MS_IMAGE2MAP_X(point.x, map->extent.minx, cellx); point.y = MS_IMAGE2MAP_Y(point.y, map->extent.maxy, celly); /* WMS 1.3.0 states that feature_count is *per layer*. * Its value is a positive integer, if omitted then the default is 1 */ if (feature_count < 1) feature_count = 1; map->query.type = MS_QUERY_BY_POINT; map->query.mode = (feature_count==1?MS_QUERY_SINGLE:MS_QUERY_MULTIPLE); map->query.layer = -1; map->query.point = point; map->query.buffer = 0; map->query.maxresults = feature_count; if(msQueryByPoint(map) != MS_SUCCESS) if((query_status=ms_error->code) != MS_NOTFOUND) return msWMSException(map, nVersion, NULL, wms_exception_format); } else { /* use_bbox == MS_TRUE */ map->query.type = MS_QUERY_BY_RECT; map->query.mode = MS_QUERY_MULTIPLE; map->query.layer = -1; map->query.rect = map->extent; map->query.buffer = 0; map->query.maxresults = feature_count; if(msQueryByRect(map) != MS_SUCCESS) if((query_status=ms_error->code) != MS_NOTFOUND) return msWMSException(map, nVersion, NULL, wms_exception_format); } /*validate the INFO_FORMAT*/ valid_format = MS_FALSE; format_list = msOWSLookupMetadata(&(map->web.metadata), "M", "getfeatureinfo_formatlist"); /*feature_info_mime_type depricated for MapServer 6.0*/ if (!format_list) format_list = msOWSLookupMetadata(&(map->web.metadata), "MO", "feature_info_mime_type"); if (format_list) { /*can not really validate if it is a valid output format since old way of using template with web->header/footer and layer templates need to still be supported. We can only validate if it was part of the format list*/ if (strcasestr(format_list, info_format)) valid_format = MS_TRUE; } /*check to see if the format passed is text/plain or GML and if is defined in the formatlist. If that is the case, It is a valid format*/ if (strcasecmp(info_format, "MIME") == 0 || strcasecmp(info_format, "text/plain") == 0 || strncasecmp(info_format, "GML", 3) == 0 || strcasecmp(info_format, "application/vnd.ogc.gml") == 0) valid_format = MS_TRUE; /*last case: if the info_format is not part of the request, it defaults to MIME*/ if (!valid_format && format_found == MS_FALSE) valid_format =MS_TRUE; if (!valid_format) { msSetError(MS_WMSERR, "Unsupported INFO_FORMAT value (%s).", "msWMSFeatureInfo()", info_format); if (nVersion >= OWS_1_3_0) return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); else return msWMSException(map, nVersion, NULL, wms_exception_format); } /* Generate response */ if (strcasecmp(info_format, "MIME") == 0 || strcasecmp(info_format, "text/plain") == 0) { /* MIME response... we're free to use any valid MIME type */ int numresults = 0; if (encoding) msIO_setHeader("Content-type","text/plain; charset=%s", encoding); else msIO_setHeader("Content-type","text/plain"); msIO_sendHeaders(); msIO_printf("GetFeatureInfo results:\n"); numresults = msDumpResult(map, 0, nVersion, wms_exception_format); if (numresults == 0) msIO_printf("\n Search returned no results.\n"); } else if (strncasecmp(info_format, "GML", 3) == 0 || /* accept GML.1 or GML */ strcasecmp(info_format, "application/vnd.ogc.gml") == 0) { if (nVersion <= OWS_1_0_7) /* 1.0.0 to 1.0.7 */ if (encoding) msIO_setHeader("Content-type","text/xml; charset=%s", encoding); else msIO_setHeader("Content-type","text/xml"); else /* 1.1.0 and later */ if (encoding) msIO_setHeader("Content-type","application/vnd.ogc.gml; charset=%s", encoding); else msIO_setHeader("Content-type","application/vnd.ogc.gml"); msIO_sendHeaders(); msGMLWriteQuery(map, NULL, "MGO"); /* default is stdout */ } else { mapservObj *msObj; msObj = msAllocMapServObj(); /* Translate some vars from WMS to mapserv */ msTranslateWMS2Mapserv(names, values, &numentries); msObj->map = map; msFreeCharArray(msObj->request->ParamNames, msObj->request->NumParams); msFreeCharArray(msObj->request->ParamValues, msObj->request->NumParams); msObj->request->ParamNames = names; msObj->request->ParamValues = values; msObj->Mode = QUERY; msObj->request->NumParams = numentries; msObj->mappnt.x = point.x; msObj->mappnt.y = point.y; if (query_status == MS_NOTFOUND && msObj->map->web.empty) { if(msReturnURL(msObj, msObj->map->web.empty, BROWSE) != MS_SUCCESS) return msWMSException(map, nVersion, NULL, wms_exception_format); } else if (msReturnTemplateQuery(msObj, (char *)info_format, NULL) != MS_SUCCESS) return msWMSException(map, nVersion, NULL, wms_exception_format); /* We don't want to free the map, and param names/values since they */ /* belong to the caller, set them to NULL before freeing the mapservObj */ msObj->map = NULL; msObj->request->ParamNames = NULL; msObj->request->ParamValues = NULL; msObj->request->NumParams = 0; msFreeMapServObj(msObj); } return(MS_SUCCESS); } /* ** msWMSDescribeLayer() */ int msWMSDescribeLayer(mapObj *map, int nVersion, char **names, char **values, int numentries, char *wms_exception_format) { int i = 0; char **layers = NULL; int numlayers = 0; int j, k; layerObj *lp = NULL; const char *pszOnlineResMapWFS = NULL, *pszOnlineResLyrWFS = NULL; const char *pszOnlineResMapWCS = NULL, *pszOnlineResLyrWCS = NULL; char *pszOnlineResEncoded=NULL, *pszLayerName=NULL; char *schemalocation = NULL; char *version = NULL; char *sld_version = NULL; const char *encoding; char ***nestedGroups = NULL; int *numNestedGroups = NULL; int *isUsedInNestedGroup = NULL; encoding = msOWSLookupMetadata(&(map->web.metadata), "MO", "encoding"); for(i=0; map && i= OWS_1_3_0 && sld_version == NULL) { msSetError(MS_WMSERR, "Missing required parameter SLD_VERSION", "DescribeLayer()"); return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); } if (nVersion >= OWS_1_3_0 && strcasecmp(sld_version, "1.1.0") != 0) { msSetError(MS_WMSERR, "SLD_VERSION must be 1.1.0", "DescribeLayer()"); return msWMSException(map, nVersion, "InvalidParameterValue", wms_exception_format); } if (encoding) msIO_setHeader("Content-type","text/xml; charset=%s", encoding); else msIO_setHeader("Content-type","text/xml"); msIO_sendHeaders(); msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "encoding", OWS_NOERR, "\n", "ISO-8859-1"); schemalocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); if (nVersion < OWS_1_3_0) { msIO_printf("\n", schemalocation); msIO_printf("\n", version); } else { msIO_printf("\n", schemalocation); msIO_printf("%s\n",sld_version); } free(schemalocation); /* check if map-level metadata wfs(wcs)_onlineresource is available */ pszOnlineResMapWFS = msOWSLookupMetadata(&(map->web.metadata), "FO", "onlineresource"); if (pszOnlineResMapWFS && strlen(pszOnlineResMapWFS) == 0) pszOnlineResMapWFS = NULL; pszOnlineResMapWCS = msOWSLookupMetadata(&(map->web.metadata), "CO", "onlineresource"); if (pszOnlineResMapWCS && strlen(pszOnlineResMapWCS) == 0) pszOnlineResMapWCS = NULL; nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); for(j=0; jnumlayers; k++) { lp = GET_LAYER(map, k); if ((map->name && strcasecmp(map->name, layers[j]) == 0) || (lp->name && strcasecmp(lp->name, layers[j]) == 0) || (lp->group && strcasecmp(lp->group, layers[j]) == 0) || ((numNestedGroups[k] >0) && msStringInArray(layers[j], nestedGroups[k], numNestedGroups[k]))) { /* Look for a WFS onlineresouce at the layer level and then at * the map level. */ pszOnlineResLyrWFS = msOWSLookupMetadata(&(lp->metadata), "FO", "onlineresource"); pszOnlineResLyrWCS = msOWSLookupMetadata(&(lp->metadata), "CO", "onlineresource"); if (pszOnlineResLyrWFS == NULL || strlen(pszOnlineResLyrWFS) == 0) pszOnlineResLyrWFS = pszOnlineResMapWFS; if (pszOnlineResLyrWCS == NULL || strlen(pszOnlineResLyrWCS) == 0) pszOnlineResLyrWCS = pszOnlineResMapWCS; if (pszOnlineResLyrWFS && (lp->type == MS_LAYER_POINT || lp->type == MS_LAYER_LINE || lp->type == MS_LAYER_POLYGON) ) { pszOnlineResEncoded = msEncodeHTMLEntities(pszOnlineResLyrWFS); pszLayerName = msEncodeHTMLEntities(lp->name); if (nVersion < OWS_1_3_0) { msIO_printf("\n", pszLayerName, pszOnlineResEncoded, pszOnlineResEncoded); msIO_printf("\n", pszLayerName); msIO_printf("\n"); } else /*wms 1.3.0*/ { msIO_printf(" \n"); msIO_printf(" wfs\n"); msIO_printf(" \n", pszOnlineResEncoded); msIO_printf(" \n"); msIO_printf(" %s\n",pszLayerName); msIO_printf(" \n"); msIO_printf(" \n"); } msFree(pszOnlineResEncoded); msFree(pszLayerName); } else if (pszOnlineResLyrWCS && lp->type == MS_LAYER_RASTER && lp->connectiontype != MS_WMS) { pszOnlineResEncoded = msEncodeHTMLEntities(pszOnlineResLyrWCS); pszLayerName = msEncodeHTMLEntities(lp->name); if (nVersion < OWS_1_3_0) { msIO_printf("\n", pszLayerName, pszOnlineResEncoded); msIO_printf("\n", pszLayerName); msIO_printf("\n"); msFree(pszOnlineResEncoded); msFree(pszLayerName); } else { msIO_printf(" \n"); msIO_printf(" wcs\n"); msIO_printf(" \n", pszOnlineResEncoded); msIO_printf(" \n"); msIO_printf(" %s\n",pszLayerName); msIO_printf(" \n"); msIO_printf(" \n"); } } else { char *pszLayerName; pszLayerName = msEncodeHTMLEntities(lp->name); if (nVersion < OWS_1_3_0) msIO_printf("\n", pszLayerName); else /*wms 1.3.0*/ { msIO_printf(" \n"); /*need to have a owstype for the DescribeLayer to be valid*/ if (lp->type == MS_LAYER_RASTER && lp->connectiontype != MS_WMS) msIO_printf(" wcs\n"); else msIO_printf(" wfs\n"); msIO_printf(" \n"); msIO_printf(" \n"); if (lp->type == MS_LAYER_RASTER && lp->connectiontype != MS_WMS) msIO_printf(" %s\n",pszLayerName); else msIO_printf(" %s\n",pszLayerName); msIO_printf(" \n"); msIO_printf(" \n"); } msFree(pszLayerName); } /* break; */ } } } if (nVersion < OWS_1_3_0) msIO_printf("\n"); else msIO_printf("\n"); if (layers) msFreeCharArray(layers, numlayers); /* free the stuff used for nested layers */ for (i = 0; i < map->numlayers; i++) { if (numNestedGroups[i] > 0) { msFreeCharArray(nestedGroups[i], numNestedGroups[i]); } } free(nestedGroups); free(numNestedGroups); free(isUsedInNestedGroup); return(MS_SUCCESS); } /* ** msWMSGetLegendGraphic() */ int msWMSLegendGraphic(mapObj *map, int nVersion, char **names, char **values, int numentries, char *wms_exception_format, owsRequestObj *ows_request) { char *pszLayer = NULL; char *pszFormat = NULL; char *psRule = NULL; char *psScale = NULL; int iLayerIndex = -1; outputFormatObj *psFormat = NULL; imageObj *img=NULL; int j, i = 0; int nWidth = -1, nHeight =-1; char *pszStyle = NULL; char *sld_version = NULL; int wms_layer = MS_FALSE; const char *sldenabled = NULL; const char *format_list = NULL; layerObj *lp; int nLayers =0; char ***nestedGroups = NULL; int *numNestedGroups = NULL; int *isUsedInNestedGroup = NULL; sldenabled = msOWSLookupMetadata(&(map->web.metadata), "MO", "sld_enabled"); if (sldenabled == NULL) sldenabled = "true"; for(i=0; map && i 0 && strcasecmp(sldenabled, "true") == 0) msSLDApplySLDURL(map, values[i], -1, NULL, NULL); else if (strcasecmp(names[i], "SLD_BODY") == 0 && values[i] && strlen(values[i]) > 0 && strcasecmp(sldenabled, "true") == 0) msSLDApplySLD(map, values[i], -1, NULL, NULL); else if (strcasecmp(names[i], "RULE") == 0) psRule = values[i]; else if (strcasecmp(names[i], "SCALE") == 0) psScale = values[i]; else if (strcasecmp(names[i], "STYLE") == 0) pszStyle = values[i]; #endif /* -------------------------------------------------------------------- */ /* SLD support: */ /* - because the request parameter "sld_version" is required in */ /* in WMS 1.3.0, it will be set regardless of OGR support. */ /* -------------------------------------------------------------------- */ else if(strcasecmp(names[i], "SLD_VERSION") == 0) sld_version = values[i]; } if (!pszLayer) { msSetError(MS_WMSERR, "Mandatory LAYER parameter missing in GetLegendGraphic request.", "msWMSGetLegendGraphic()"); return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); } if (!pszFormat) { msSetError(MS_WMSERR, "Mandatory FORMAT parameter missing in GetLegendGraphic request.", "msWMSGetLegendGraphic()"); return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); } if (nVersion >= OWS_1_3_0 && sld_version == NULL) { msSetError(MS_WMSERR, "Missing required parameter SLD_VERSION", "GetLegendGraphic()"); return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); } if (nVersion >= OWS_1_3_0 && strcasecmp(sld_version, "1.1.0") != 0) { msSetError(MS_WMSERR, "SLD_VERSION must be 1.1.0", "GetLegendGraphic()"); return msWMSException(map, nVersion, "InvalidParameterValue", wms_exception_format); } nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); /* check if layer name is valid. we check for layer's and group's name */ /* as well as wms_layer_group names */ for (i=0; inumlayers; i++) { lp = GET_LAYER(map, i); if ( ((map->name && strcasecmp(map->name, pszLayer) == 0) || (lp->name && strcasecmp(lp->name, pszLayer) == 0) || (lp->group && strcasecmp(lp->group, pszLayer) == 0) || ((numNestedGroups[i] >0) && (msStringInArray(pszLayer, nestedGroups[i], numNestedGroups[i]))) ) && (msIntegerInArray(lp->index, ows_request->enabled_layers, ows_request->numlayers)) ) { nLayers++; lp->status = MS_ON; iLayerIndex = i; if (GET_LAYER(map, i)->connectiontype == MS_WMS) { /* we do not cascade a wms layer if it contains at least * one class with the property name set */ wms_layer = MS_TRUE; for (j=0; jnumclasses; j++) { if (lp->class[j]->name != NULL && strlen(lp->class[j]->name)>0) { wms_layer = MS_FALSE; break; } } } } else lp->status = MS_OFF; } /* free the stuff used for nested layers */ for (i = 0; i < map->numlayers; i++) { if (numNestedGroups[i] > 0) { msFreeCharArray(nestedGroups[i], numNestedGroups[i]); } } free(nestedGroups); free(numNestedGroups); free(isUsedInNestedGroup); if (nLayers == 0) { msSetError(MS_WMSERR, "Invalid layer given in the LAYER parameter.", "msWMSGetLegendGraphic()"); return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); } /* validate format */ /*check to see if a predefined list is given*/ format_list = msOWSLookupMetadata(&(map->web.metadata), "M","getlegendgraphic_formatlist"); if (format_list) { psFormat = msOwsIsOutputFormatValid(map, pszFormat, &(map->web.metadata), "M", "getlegendgraphic_formatlist"); if (psFormat == NULL) { msSetError(MS_IMGERR, "Unsupported output format (%s).", "msWMSGetLegendGraphic()", pszFormat); return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); } } else { psFormat = msSelectOutputFormat( map, pszFormat); if( psFormat == NULL || ! MS_RENDERER_PLUGIN(psFormat) ) /* msDrawLegend and msCreateLegendIcon both switch the alpha channel to gd ** after creation, so they can be called here without going through ** the msAlphaGD2AGG functions */ { msSetError(MS_IMGERR, "Unsupported output format (%s).", "msWMSGetLegendGraphic()", pszFormat); return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); } } msApplyOutputFormat(&(map->outputformat), psFormat, MS_NOOVERRIDE, MS_NOOVERRIDE, MS_NOOVERRIDE ); /* It's a valid Cascading WMS GetLegendGraphic request */ if (wms_layer) return msWMSLayerExecuteRequest(map, 1, 0, 0, 0, NULL, WMS_GETLEGENDGRAPHIC); /*if STYLE is set, check if it is a valid style (valid = at least one of the classes have a the group value equals to the style */ /*style is only validated when there is only one layer #3411*/ if (nLayers == 1 && pszStyle && strlen(pszStyle) > 0 && strcasecmp(pszStyle, "default") != 0) { for (i=0; inumclasses; i++) { if (GET_LAYER(map, iLayerIndex)->class[i]->group && strcasecmp(GET_LAYER(map, iLayerIndex)->class[i]->group, pszStyle) == 0) break; } if (i == GET_LAYER(map, iLayerIndex)->numclasses) { msSetError(MS_WMSERR, "style used in the STYLE parameter is not defined on the layer.", "msWMSGetLegendGraphic()"); return msWMSException(map, nVersion, "StyleNotDefined", wms_exception_format); } else { if (GET_LAYER(map, iLayerIndex)->classgroup) msFree(GET_LAYER(map, iLayerIndex)->classgroup); GET_LAYER(map, iLayerIndex)->classgroup = msStrdup(pszStyle); } } if ( psRule == NULL || nLayers > 1) { /* if SCALE was provided in request, calculate an extent and use a default width and height */ if ( psScale != NULL ) { double center_y, scale, cellsize; scale = atof(psScale); map->width = 600; map->height = 600; center_y = 0.0; cellsize = (scale/map->resolution)/msInchesPerUnit(map->units, center_y); map->extent.minx = 0.0 - cellsize*map->width/2.0; map->extent.miny = 0.0 - cellsize*map->height/2.0; map->extent.maxx = 0.0 + cellsize*map->width/2.0; map->extent.maxy = 0.0 + cellsize*map->height/2.0; img = msDrawLegend(map, MS_FALSE); } else { /* Scale-independent legend */ img = msDrawLegend(map, MS_TRUE); } } else { /* RULE was specified. Get the class corresponding to the RULE */ /* (RULE = class->name) */ for (i=0; inumclasses; i++) { if (GET_LAYER(map, iLayerIndex)->classgroup && (GET_LAYER(map, iLayerIndex)->class[i]->group == NULL || strcasecmp(GET_LAYER(map, iLayerIndex)->class[i]->group, GET_LAYER(map, iLayerIndex)->classgroup) != 0)) continue; if (GET_LAYER(map, iLayerIndex)->class[i]->name && strlen(GET_LAYER(map, iLayerIndex)->class[i]->name) > 0 && strcasecmp(GET_LAYER(map, iLayerIndex)->class[i]->name,psRule) == 0) break; } if (i < GET_LAYER(map, iLayerIndex)->numclasses) { /* set the map legend parameters */ if (nWidth < 0) { if (map->legend.keysizex > 0) nWidth = map->legend.keysizex; else nWidth = 20; /* default values : this in not defined in the specs */ } if (nHeight < 0) { if (map->legend.keysizey > 0) nHeight = map->legend.keysizey; else nHeight = 20; } img = msCreateLegendIcon(map, GET_LAYER(map, iLayerIndex), GET_LAYER(map, iLayerIndex)->class[i], nWidth, nHeight); } if (img == NULL) { msSetError(MS_IMGERR, "Unavailable RULE (%s).", "msWMSGetLegendGraphic()", psRule); return msWMSException(map, nVersion, "InvalidRule", wms_exception_format); } } if (img == NULL) return msWMSException(map, nVersion, NULL, wms_exception_format); msIO_setHeader("Content-type",MS_IMAGE_MIME_TYPE(map->outputformat)); msIO_sendHeaders(); if (msSaveImage(map, img, NULL) != MS_SUCCESS) return msWMSException(map, nVersion, NULL, wms_exception_format); msFreeImage(img); return(MS_SUCCESS); } /* ** msWMSGetStyles() : return an SLD document for all layers that ** have a status set to on or default. */ int msWMSGetStyles(mapObj *map, int nVersion, char **names, char **values, int numentries, char *wms_exception_format) { int i,j,k; int validlayer = 0; int numlayers = 0; char **layers = NULL; char *sld = NULL; const char *encoding; char ***nestedGroups = NULL; int *numNestedGroups = NULL; int *isUsedInNestedGroup = NULL; encoding = msOWSLookupMetadata(&(map->web.metadata), "MO", "encoding"); nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); for(i=0; map && inumlayers; j++) GET_LAYER(map, j)->status = MS_OFF; for (k=0; knumlayers; j++) { if ((map->name && strcasecmp(map->name, layers[k]) == 0) || (GET_LAYER(map, j)->name && strcasecmp(GET_LAYER(map, j)->name, layers[k]) == 0) || (GET_LAYER(map, j)->group && strcasecmp(GET_LAYER(map, j)->group, layers[k]) == 0) || ((numNestedGroups[j] >0) && msStringInArray(layers[k], nestedGroups[j], numNestedGroups[j])) ) { GET_LAYER(map, j)->status = MS_ON; validlayer =1; } } } msFreeCharArray(layers, numlayers); } } /* free the stuff used for nested layers */ for (i = 0; i < map->numlayers; i++) { if (numNestedGroups[i] > 0) { msFreeCharArray(nestedGroups[i], numNestedGroups[i]); } } free(nestedGroups); free(numNestedGroups); free(isUsedInNestedGroup); /* validate all layers given. If an invalid layer is sent, return an exception. */ if (validlayer == 0) { msSetError(MS_WMSERR, "Invalid layer(s) given in the LAYERS parameter.", "msWMSGetStyles()"); return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); } if (nVersion <= OWS_1_1_1) { if (encoding) msIO_setHeader("Content-type","application/vnd.ogc.sld+xml; charset=%s", encoding); else msIO_setHeader("Content-type","application/vnd.ogc.sld+xml"); msIO_sendHeaders(); sld = msSLDGenerateSLD(map, -1, "1.0.0"); } else { /*for wms 1.3.0 generate a 1.1 sld*/ if (encoding) msIO_setHeader("Content-type","text/xml; charset=%s", encoding); else msIO_setHeader("Content-type","text/xml"); msIO_sendHeaders(); sld = msSLDGenerateSLD(map, -1, "1.1.0"); } if (sld) { msIO_printf("%s\n", sld); free(sld); } return(MS_SUCCESS); } int msWMSGetSchemaExtension(mapObj *map) { char *schemalocation = NULL; const char *encoding; schemalocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); encoding = msOWSLookupMetadata(&(map->web.metadata), "MO", "encoding"); if (encoding) msIO_setHeader("Content-type","text/xml; charset=%s", encoding); else msIO_setHeader("Content-type","text/xml"); msIO_sendHeaders(); msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "encoding", OWS_NOERR, "\n", "ISO-8859-1"); msIO_printf("\n"); msIO_printf(" \n", schemalocation); msIO_printf(" \n"); msIO_printf(""); free(schemalocation); return(MS_SUCCESS); } #endif /* USE_WMS_SVR */ /* ** msWMSDispatch() is the entry point for WMS requests. ** - If this is a valid request then it is processed and MS_SUCCESS is returned ** on success, or MS_FAILURE on failure. ** - If this does not appear to be a valid WMS request then MS_DONE ** is returned and MapServer is expected to process this as a regular ** MapServer request. */ int msWMSDispatch(mapObj *map, cgiRequestObj *req, owsRequestObj *ows_request, int force_wms_mode) { #ifdef USE_WMS_SVR int i, status, nVersion=OWS_VERSION_NOTSET; const char *version=NULL, *request=NULL, *service=NULL, *format=NULL, *updatesequence=NULL, *language=NULL; const char * encoding; char *wms_exception_format = NULL; char *validated_language = NULL; encoding = msOWSLookupMetadata(&(map->web.metadata), "MO", "encoding"); /* ** Process Params common to all requests */ /* VERSION (WMTVER in 1.0.0) and REQUEST must be present in a valid request */ for(i=0; iNumParams; i++) { if(strcasecmp(req->ParamNames[i], "VERSION") == 0) version = req->ParamValues[i]; else if (strcasecmp(req->ParamNames[i], "WMTVER") == 0 && version == NULL) version = req->ParamValues[i]; else if (strcasecmp(req->ParamNames[i], "UPDATESEQUENCE") == 0) updatesequence = req->ParamValues[i]; else if (strcasecmp(req->ParamNames[i], "REQUEST") == 0) request = req->ParamValues[i]; else if (strcasecmp(req->ParamNames[i], "EXCEPTIONS") == 0) wms_exception_format = req->ParamValues[i]; else if (strcasecmp(req->ParamNames[i], "SERVICE") == 0) service = req->ParamValues[i]; else if (strcasecmp(req->ParamNames[i], "FORMAT") == 0) format = req->ParamValues[i]; else if (strcasecmp(req->ParamNames[i], "LANGUAGE") == 0 && msOWSLookupMetadata(&(map->web.metadata), "MO", "inspire_capabilities")) language = req->ParamValues[i]; } /* If SERVICE is specified then it MUST be "WMS" */ if (service != NULL && strcasecmp(service, "WMS") != 0) return MS_DONE; /* Not a WMS request */ nVersion = msOWSParseVersionString(version); if (nVersion == OWS_VERSION_BADFORMAT) { /* Invalid version format. msSetError() has been called by * msOWSParseVersionString() and we return the error as an exception */ return msWMSException(map, OWS_VERSION_NOTSET, NULL, wms_exception_format); } /* ** GetCapbilities request needs the service parametr defined as WMS: see section 7.1.3.2 wms 1.1.1 specs for decsription. */ if (request && service == NULL && (strcasecmp(request, "capabilities") == 0 || strcasecmp(request, "GetCapabilities") == 0) && (nVersion >= OWS_1_0_7 || nVersion == OWS_VERSION_NOTSET)) { if (force_wms_mode) { msSetError(MS_WMSERR, "Required SERVICE parameter missing.", "msWMSDispatch"); return msWMSException(map, nVersion, "ServiceNotDefined", wms_exception_format); } else return MS_DONE; } /* ** Dispatch request... we should probably do some validation on VERSION here ** vs the versions we actually support. */ if (request && (strcasecmp(request, "capabilities") == 0 || strcasecmp(request, "GetCapabilities") == 0) ) { const char *enable_request; int globally_enabled, disabled = MS_FALSE; if (nVersion == OWS_VERSION_NOTSET) { version = msOWSLookupMetadata(&(map->web.metadata), "M", "getcapabilities_version"); if (version) nVersion = msOWSParseVersionString(version); else nVersion = OWS_1_3_0;/* VERSION is optional with getCapabilities only */ } if ((status = msOWSMakeAllLayersUnique(map)) != MS_SUCCESS) return msWMSException(map, nVersion, NULL, wms_exception_format); msOWSRequestLayersEnabled(map, "M", "GetCapabilities", ows_request); enable_request = msOWSLookupMetadata(&map->web.metadata, "OM", "enable_request"); globally_enabled = msOWSParseRequestMetadata(enable_request, "GetCapabilities", &disabled); if (ows_request->numlayers == 0 && !globally_enabled) { msSetError(MS_WMSERR, "WMS request not enabled. Check wms/ows_enable_request settings.", "msWMSGetCapabilities()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } return msWMSGetCapabilities(map, nVersion, req, ows_request, updatesequence, wms_exception_format, language); } else if (request && (strcasecmp(request, "context") == 0 || strcasecmp(request, "GetContext") == 0) ) { /* Return a context document with all layers in this mapfile * This is not a standard WMS request. * __TODO__ The real implementation should actually return only context * info for selected layers in the LAYERS parameter. */ const char *getcontext_enabled; getcontext_enabled = msOWSLookupMetadata(&(map->web.metadata), "MO", "getcontext_enabled"); if (nVersion != OWS_VERSION_NOTSET) { /* VERSION, if specified, is Map Context version, not WMS version */ /* Pass it via wms_context_version metadata */ char szVersion[OWS_VERSION_MAXLEN]; msInsertHashTable(&(map->web.metadata), "wms_context_version", msOWSGetVersionString(nVersion, szVersion)); } /* Now set version to 1.1.1 for error handling purposes */ nVersion = OWS_1_1_1; if (getcontext_enabled==NULL || atoi(getcontext_enabled) == 0) { msSetError(MS_WMSERR, "GetContext not enabled on this server.", "msWMSDispatch()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } if ((status = msOWSMakeAllLayersUnique(map)) != MS_SUCCESS) return msWMSException(map, nVersion, NULL, wms_exception_format); if (encoding) msIO_setHeader("Content-type","text/xml; charset=%s", encoding); else msIO_setHeader("Content-type","text/xml"); msIO_sendHeaders(); if ( msWriteMapContext(map, stdout) != MS_SUCCESS ) return msWMSException(map, nVersion, NULL, wms_exception_format); /* Request completed */ return MS_SUCCESS; } else if (request && strcasecmp(request, "GetMap") == 0 && format && strcasecmp(format, "image/txt") == 0) { /* Until someone adds full support for ASCII graphics this should do. ;) */ if (encoding) msIO_setHeader("Content-type","text/plain; charset=%s", encoding); else msIO_setHeader("Content-type","text/plain"); msIO_sendHeaders(); msIO_printf(".\n ,,ggddY\"\"\"Ybbgg,,\n ,agd888b,_ " "\"Y8, ___'\"\"Ybga,\n ,gdP\"\"88888888baa,.\"\"8b \"" "888g,\n ,dP\" ]888888888P' \"Y '888Yb,\n ,dP\"" " ,88888888P\" db, \"8P\"\"Yb,\n ,8\" ,8888" "88888b, d8888a \"8,\n ,8' d88888888888,88P\"" "' a, '8,\n,8' 88888888888888PP\" \"\" " " '8,\nd' I88888888888P\" 'b\n8" " '8\"88P\"\"Y8P' 8\n8 " " Y 8[ _ \" 8\n8 \"Y8d8" "b \"Y a 8\n8 '\"\"8d, __" " 8\nY, '\"8bd888b, " " ,P\n'8, ,d8888888baaa ,8'\n '8" ", 888888888888' ,8'\n '8a " " \"8888888888I a8'\n 'Yba 'Y88" "88888P' adP'\n \"Yba '888888P' adY\"" "\n '\"Yba, d8888P\" ,adP\"' \n '\"" "Y8baa, ,d888P,ad8P\"' \n ''\"\"YYba8888P\"" "\"''\n"); return MS_SUCCESS; } /* If SERVICE, VERSION and REQUEST not included than this isn't a WMS req*/ if (service == NULL && nVersion == OWS_VERSION_NOTSET && request==NULL) return MS_DONE; /* Not a WMS request */ /* VERSION *and* REQUEST required by both getMap and getFeatureInfo */ if (nVersion == OWS_VERSION_NOTSET) { msSetError(MS_WMSERR, "Incomplete WMS request: VERSION parameter missing", "msWMSDispatch()"); return msWMSException(map, OWS_VERSION_NOTSET, NULL, wms_exception_format); } /*check if the version is one of the supported vcersions*/ if (nVersion != OWS_1_0_0 && nVersion != OWS_1_0_6 && nVersion != OWS_1_0_7 && nVersion != OWS_1_1_0 && nVersion != OWS_1_1_1 && nVersion != OWS_1_3_0) { msSetError(MS_WMSERR, "Invalid WMS version: VERSION %s is not supported. Supported versions are 1.0.0, 1.0.6, 1.0.7, 1.1.0, 1.1.1, 1.3.0", "msWMSDispatch()", version); return msWMSException(map, OWS_VERSION_NOTSET, NULL, wms_exception_format); } if (request==NULL) { msSetError(MS_WMSERR, "Incomplete WMS request: REQUEST parameter missing", "msWMSDispatch()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } /* hack !? The function can return MS_DONE ... be sure it's a wms request * before checking the enabled layers */ if ( (strcasecmp(request, "GetStyles") == 0) || (strcasecmp(request, "GetLegendGraphic") == 0) || (strcasecmp(request, "GetSchemaExtension") == 0) || (strcasecmp(request, "map") == 0 || strcasecmp(request, "GetMap") == 0) || (strcasecmp(request, "feature_info") == 0 || strcasecmp(request, "GetFeatureInfo") == 0) || (strcasecmp(request, "DescribeLayer") == 0) ) { char request_tmp[32]; if (strcasecmp(request, "map") == 0) strlcpy(request_tmp, "GetMap", sizeof(request_tmp)); else if (strcasecmp(request, "feature_info") == 0) strlcpy(request_tmp, "GetFeatureInfo", sizeof(request_tmp)); else strlcpy(request_tmp, request, sizeof(request_tmp)); msOWSRequestLayersEnabled(map, "M", request_tmp, ows_request); if (ows_request->numlayers == 0) { msSetError(MS_WMSERR, "WMS request not enabled. Check wms/ows_enable_request settings.", "msWMSDispatch()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } } if ((status = msOWSMakeAllLayersUnique(map)) != MS_SUCCESS) return msWMSException(map, nVersion, NULL, wms_exception_format); if (strcasecmp(request, "GetLegendGraphic") == 0) return msWMSLegendGraphic(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, wms_exception_format, ows_request); if (strcasecmp(request, "GetStyles") == 0) return msWMSGetStyles(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, wms_exception_format); else if (request && strcasecmp(request, "GetSchemaExtension") == 0) return msWMSGetSchemaExtension(map); /* getMap parameters are used by both getMap and getFeatureInfo */ if (strcasecmp(request, "map") == 0 || strcasecmp(request, "GetMap") == 0 || strcasecmp(request, "feature_info") == 0 || strcasecmp(request, "GetFeatureInfo") == 0 || strcasecmp(request, "DescribeLayer") == 0) { status = msWMSLoadGetMapParams(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, wms_exception_format, request, ows_request); if (status != MS_SUCCESS) return status; } /* This function owns validated_language, so remember to free it later*/ validated_language = msOWSGetLanguageFromList(map, "MO", language); if (validated_language != NULL) { for(i=0; inumlayers; i++) { layerObj *layer = GET_LAYER(map, i); if(layer->data) layer->data = msCaseReplaceSubstring(layer->data, "%language%", validated_language); if(layer->connection) layer->connection = msCaseReplaceSubstring(layer->connection, "%language%", validated_language); } } msFree(validated_language); if (strcasecmp(request, "map") == 0 || strcasecmp(request, "GetMap") == 0) return msWMSGetMap(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, wms_exception_format, ows_request); else if (strcasecmp(request, "feature_info") == 0 || strcasecmp(request, "GetFeatureInfo") == 0) return msWMSFeatureInfo(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, wms_exception_format, ows_request); else if (strcasecmp(request, "DescribeLayer") == 0) { return msWMSDescribeLayer(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, wms_exception_format); } /* Hummmm... incomplete or unsupported WMS request */ if (service != NULL && strcasecmp(service, "WMS") == 0) { msSetError(MS_WMSERR, "Incomplete or unsupported WMS request", "msWMSDispatch()"); return msWMSException(map, nVersion, NULL, wms_exception_format); } else return MS_DONE; /* Not a WMS request */ #else msSetError(MS_WMSERR, "WMS server support is not available.", "msWMSDispatch()"); return(MS_FAILURE); #endif }