This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch experimental in repository mapserver.
commit b22943a2e4276668e6e627c850c135be08082b45 Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Tue Jul 7 21:38:01 2015 +0200 Imported Upstream version 7.0.0~beta2 --- CMakeLists.txt | 4 +- GD-COPYING | 50 ---- fontcache.c | 4 +- mapdraw.c | 93 ++++---- mapgeos.c | 1 + maplegend.c | 18 ++ mapmssql2008.c | 541 +++++++++++++++++++++++++++++++++++++++++--- mapogcfilter.c | 3 +- mapogcfiltercommon.c | 208 ++++++++--------- mapows.c | 29 +++ mappluginlayer.c | 7 + maprasterquery.c | 6 +- maprendering.c | 65 +++++- mapscript/php/map.c | 2 +- mapserver.h | 3 +- mapshape.c | 2 +- mapsymbol.c | 3 + mapwcs20.c | 12 +- mapwfslayer.c | 2 - mapwms.c | 48 +++- scripts/vagrant/packages.sh | 2 +- 21 files changed, 824 insertions(+), 279 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 006910b..8a6ca68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,9 +16,9 @@ include(CheckCSourceCompiles) set (MapServer_VERSION_MAJOR 7) -set (MapServer_VERSION_MINOR 1) +set (MapServer_VERSION_MINOR 0) set (MapServer_VERSION_REVISION 0) -set (MapServer_VERSION_SUFFIX "") +set (MapServer_VERSION_SUFFIX "-beta2") set(TARGET_VERSION_MAJOR ${MapServer_VERSION_MAJOR}) set(TARGET_VERSION_MINOR ${MapServer_VERSION_MINOR}) diff --git a/GD-COPYING b/GD-COPYING deleted file mode 100644 index 3e6ccc9..0000000 --- a/GD-COPYING +++ /dev/null @@ -1,50 +0,0 @@ - - Portions copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002 by Cold Spring Harbor Laboratory. Funded under Grant - P41-RR02188 by the National Institutes of Health. - - Portions copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 by - Boutell.Com, Inc. - - Portions relating to GD2 format copyright 1999, 2000, 2001, 2002 - Philip Warner. - - Portions relating to PNG copyright 1999, 2000, 2001, 2002 Greg - Roelofs. - - Portions relating to gdttf.c copyright 1999, 2000, 2001, 2002 John - Ellson (ell...@lucent.com). - - Portions relating to gdft.c copyright 2001, 2002 John Ellson - (ell...@lucent.com). - - Portions relating to JPEG and to color quantization copyright 2000, - 2001, 2002, Doug Becker and copyright (C) 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, Thomas G. Lane. This software is - based in part on the work of the Independent JPEG Group. See the - file README-JPEG.TXT for more information. - - Portions relating to WBMP copyright 2000, 2001, 2002 Maurice - Szmurlo and Johan Van den Brande. - - Permission has been granted to copy, distribute and modify gd in - any context without fee, including a commercial application, - provided that this notice is present in user-accessible supporting - documentation. - - This does not affect your ownership of the derived work itself, and - the intent is to assure proper credit for the authors of gd, not to - interfere with your productive use of gd. If you have questions, - ask. "Derived works" includes all programs that utilize the - library. Credit must be given in user-accessible documentation. - - This software is provided "AS IS." The copyright holders disclaim - all warranties, either express or implied, including but not - limited to implied warranties of merchantability and fitness for a - particular purpose, with respect to this code and accompanying - documentation. - - Although their code does not appear in gd, the authors wish to thank - David Koblas, David Rowley, and Hutchison Avenue Software Corporation - for their prior contributions. - diff --git a/fontcache.c b/fontcache.c index 4a12a13..e43eafe 100644 --- a/fontcache.c +++ b/fontcache.c @@ -86,6 +86,7 @@ void msFreeFontCache(ft_cache *c) { } #endif FT_Done_Face(cur_face->face); + free(cur_face->font); UT_HASH_DEL(c->face_cache,cur_face); free(cur_face); } @@ -227,9 +228,10 @@ face_element* msGetFontFace(char *key, fontSetObj *fontset) { FT_Select_Charmap(fc->face, FT_ENCODING_APPLE_ROMAN); /* the previous calls may have failed, we ignore as there's nothing much left to do */ } - fc->font = key; + fc->font = msStrdup(key); UT_HASH_ADD_KEYPTR(hh,cache->face_cache,fc->font, strlen(key), fc); } + return fc; } diff --git a/mapdraw.c b/mapdraw.c index 5da1edb..1221b90 100644 --- a/mapdraw.c +++ b/mapdraw.c @@ -328,6 +328,8 @@ imageObj *msDrawMap(mapObj *map, int querymap) for(i=0; i<map->numlayers; i++) { if(map->layerorder[i] != -1) { + char *force_draw_label_cache = NULL; + lp = (GET_LAYER(map, map->layerorder[i])); if(lp->postlabelcache) /* wait to draw */ @@ -389,6 +391,27 @@ imageObj *msDrawMap(mapObj *map, int querymap) (endtime.tv_sec+endtime.tv_usec/1.0e6)- (starttime.tv_sec+starttime.tv_usec/1.0e6) ); } + + /* Flush layer cache in-between layers if requested by PROCESSING directive*/ + force_draw_label_cache = msLayerGetProcessingKey(lp, "FORCE_DRAW_LABEL_CACHE"); + if (force_draw_label_cache && + strncasecmp(force_draw_label_cache,"FLUSH",5)==0) { + if(map->debug >= MS_DEBUGLEVEL_V) + msDebug("msDrawMap(): PROCESSING FORCE_DRAW_LABEL_CACHE=FLUSH found.\n"); + if(msDrawLabelCache(map, image) != MS_SUCCESS) { + msFreeImage(image); +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + if (pasOWSReqInfo) { + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + } +#endif /* USE_WMS_LYR || USE_WFS_LYR */ + return(NULL); + } + msFreeLabelCache(&(map->labelcache)); + msInitLabelCache(&(map->labelcache)); + } /* PROCESSING FORCE_DRAW_LABEL_CACHE */ + } } @@ -431,8 +454,6 @@ imageObj *msDrawMap(mapObj *map, int querymap) } } - if(map->debug >= MS_DEBUGLEVEL_TUNING) msGettimeofday(&starttime, NULL); - if(msDrawLabelCache(map, image) != MS_SUCCESS) { msFreeImage(image); #if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) @@ -444,12 +465,6 @@ imageObj *msDrawMap(mapObj *map, int querymap) return(NULL); } - if(map->debug >= MS_DEBUGLEVEL_TUNING) { - msGettimeofday(&endtime, NULL); - msDebug("msDrawMap(): Drawing Label Cache, %.3fs\n", - (endtime.tv_sec+endtime.tv_usec/1.0e6)- - (starttime.tv_sec+starttime.tv_usec/1.0e6) ); - } for(i=0; i<map->numlayers; i++) { /* for each layer, check for postlabelcache layers */ @@ -1007,7 +1022,6 @@ int msDrawVectorLayer(mapObj *map, layerObj *layer, imageObj *image) if (cache) { styleObj *pStyle = layer->class[shape.classindex]->styles[0]; - colorObj tmp; if (pStyle->outlinewidth > 0) { /* * RFC 49 implementation @@ -1017,17 +1031,7 @@ int msDrawVectorLayer(mapObj *map, layerObj *layer, imageObj *image) * - draw the shape (the outline) in the first pass of the * caching mechanism */ - - /* adapt width (must take scalefactor into account) */ - pStyle->width += (pStyle->outlinewidth / (layer->scalefactor/image->resolutionfactor)) * 2; - pStyle->minwidth += pStyle->outlinewidth * 2; - pStyle->maxwidth += pStyle->outlinewidth * 2; - pStyle->size += (pStyle->outlinewidth/layer->scalefactor*(map->resolution/map->defresolution)); - - /*swap color and outlinecolor*/ - tmp = pStyle->color; - pStyle->color = pStyle->outlinecolor; - pStyle->outlinecolor = tmp; + msOutlineRenderingPrepareStyle(pStyle, map, layer, image); } status = msDrawShape(map, layer, &shape, image, 0, drawmode|MS_DRAWMODE_SINGLESTYLE); /* draw a single style */ if (pStyle->outlinewidth > 0) { @@ -1036,17 +1040,7 @@ int msDrawVectorLayer(mapObj *map, layerObj *layer, imageObj *image) * original state, so the line fill will be drawn in the * second pass of the caching mechanism */ - - /* reset widths to original state */ - pStyle->width -= (pStyle->outlinewidth / (layer->scalefactor/image->resolutionfactor)) * 2; - pStyle->minwidth -= pStyle->outlinewidth * 2; - pStyle->maxwidth -= pStyle->outlinewidth * 2; - pStyle->size -= (pStyle->outlinewidth/layer->scalefactor*(map->resolution/map->defresolution)); - - /*reswap colors to original state*/ - tmp = pStyle->color; - pStyle->color = pStyle->outlinecolor; - pStyle->outlinecolor = tmp; + msOutlineRenderingRestoreStyle(pStyle, map, layer, image); } } @@ -1107,7 +1101,6 @@ int msDrawVectorLayer(mapObj *map, layerObj *layer, imageObj *image) } } else if(s>0) { if (pStyle->outlinewidth > 0 && MS_VALID_COLOR(pStyle->outlinecolor)) { - colorObj tmp; /* * RFC 49 implementation * if an outlinewidth is used: @@ -1116,17 +1109,7 @@ int msDrawVectorLayer(mapObj *map, layerObj *layer, imageObj *image) * - draw the shape (the outline) in the first pass of the * caching mechanism */ - - /* adapt width (must take scalefactor into account) */ - pStyle->width += (pStyle->outlinewidth / (layer->scalefactor/image->resolutionfactor)) * 2; - pStyle->minwidth += pStyle->outlinewidth * 2; - pStyle->maxwidth += pStyle->outlinewidth * 2; - pStyle->size += (pStyle->outlinewidth/layer->scalefactor*(map->resolution/map->defresolution)); - - /*swap color and outlinecolor*/ - tmp = pStyle->color; - pStyle->color = pStyle->outlinecolor; - pStyle->outlinecolor = tmp; + msOutlineRenderingPrepareStyle(pStyle, map, layer, image); if(UNLIKELY(MS_FAILURE == msDrawLineSymbol(map, image, ¤t->shape, pStyle, layer->scalefactor))) { return MS_FAILURE; } @@ -1135,17 +1118,7 @@ int msDrawVectorLayer(mapObj *map, layerObj *layer, imageObj *image) * original state, so the line fill will be drawn in the * second pass of the caching mechanism */ - - /* reset widths to original state */ - pStyle->width -= (pStyle->outlinewidth / (layer->scalefactor/image->resolutionfactor)) * 2; - pStyle->minwidth -= pStyle->outlinewidth * 2; - pStyle->maxwidth -= pStyle->outlinewidth * 2; - pStyle->size -= (pStyle->outlinewidth/layer->scalefactor*(map->resolution/map->defresolution)); - - /*reswap colors to original state*/ - tmp = pStyle->color; - pStyle->color = pStyle->outlinecolor; - pStyle->outlinecolor = tmp; + msOutlineRenderingRestoreStyle(pStyle, map, layer, image); } /* draw a valid line, i.e. one with a color defined or of type pixmap*/ if(MS_VALID_COLOR(pStyle->color) || @@ -2680,6 +2653,9 @@ void copyLabelBounds(label_bounds *dst, label_bounds *src) { int msDrawLabelCache(mapObj *map, imageObj *image) { int nReturnVal = MS_SUCCESS; + struct mstimeval starttime, endtime; + + if(map->debug >= MS_DEBUGLEVEL_TUNING) msGettimeofday(&starttime, NULL); if(image) { if(MS_RENDERER_PLUGIN(image->format)) { @@ -3139,10 +3115,17 @@ int msDrawLabelCache(mapObj *map, imageObj *image) } #endif - return MS_SUCCESS; /* necessary? */ + nReturnVal = MS_SUCCESS; /* necessary? */ } } + if(map->debug >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&endtime, NULL); + msDebug("msDrawMap(): Drawing Label Cache, %.3fs\n", + (endtime.tv_sec+endtime.tv_usec/1.0e6)- + (starttime.tv_sec+starttime.tv_usec/1.0e6) ); + } + return nReturnVal; } diff --git a/mapgeos.c b/mapgeos.c index 08c9b64..b8f25f0 100644 --- a/mapgeos.c +++ b/mapgeos.c @@ -720,6 +720,7 @@ void msGEOSFreeGeometry(shapeObj *shape) g = (GEOSGeom) shape->geometry; GEOSGeom_destroy_r(handle,g); + shape->geometry = NULL; #else msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSFreeGEOSGeom()"); return; diff --git a/maplegend.c b/maplegend.c index 7986b33..a8dd733 100644 --- a/maplegend.c +++ b/maplegend.c @@ -218,10 +218,28 @@ int msDrawLegendIcon(mapObj *map, layerObj *lp, classObj *theclass, if (theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_NONE || theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT || theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOLY) { + if (theclass->styles[i]->outlinewidth > 0) { + /* Swap the style contents to render the outline first, + * and then restore the style to render the interior of the line + */ + msOutlineRenderingPrepareStyle(theclass->styles[i], map, lp, image); + ret = msDrawLineSymbol(map, image_draw, &zigzag, theclass->styles[i], lp->scalefactor * image_draw->resolutionfactor); + msOutlineRenderingRestoreStyle(theclass->styles[i], map, lp, image); + if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; + } ret = msDrawLineSymbol(map, image_draw, &zigzag, theclass->styles[i], lp->scalefactor * image_draw->resolutionfactor); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; } else { + if (theclass->styles[i]->outlinewidth > 0) { + /* Swap the style contents to render the outline first, + * and then restore the style to render the interior of the line + */ + msOutlineRenderingPrepareStyle(theclass->styles[i], map, lp, image); + ret = msDrawTransformedShape(map, image_draw, &zigzag, theclass->styles[i], lp->scalefactor * image_draw->resolutionfactor); + msOutlineRenderingRestoreStyle(theclass->styles[i], map, lp, image); + if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; + } ret = msDrawTransformedShape(map, image_draw, &zigzag, theclass->styles[i], lp->scalefactor * image_draw->resolutionfactor); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; } diff --git a/mapmssql2008.c b/mapmssql2008.c index b1b74d2..cea2026 100644 --- a/mapmssql2008.c +++ b/mapmssql2008.c @@ -49,7 +49,55 @@ #include <string.h> #include <ctype.h> /* tolower() */ +/* SqlGeometry serialization format +Simple Point (SerializationProps & IsSinglePoint) + [SRID][0x01][SerializationProps][Point][z][m] + +Simple Line Segment (SerializationProps & IsSingleLineSegment) + [SRID][0x01][SerializationProps][Point1][Point2][z1][z2][m1][m2] + +Complex Geometries + [SRID][0x01][SerializationProps][NumPoints][Point1]..[PointN][z1]..[zN][m1]..[mN] + [NumFigures][Figure]..[Figure][NumShapes][Shape]..[Shape] + +SRID + Spatial Reference Id (4 bytes) + +SerializationProps (bitmask) 1 byte + 0x01 = HasZValues + 0x02 = HasMValues + 0x04 = IsValid + 0x08 = IsSinglePoint + 0x10 = IsSingleLineSegment + 0x20 = IsWholeGlobe + +Point (2-4)x8 bytes, size depends on SerializationProps & HasZValues & HasMValues + [x][y] - SqlGeometry + [latitude][longitude] - SqlGeography + +Figure + [FigureAttribute][PointOffset] + +FigureAttribute (1 byte) + 0x00 = Interior Ring + 0x01 = Stroke + 0x02 = Exterior Ring + +Shape + [ParentFigureOffset][FigureOffset][ShapeType] + +ShapeType (1 byte) + 0x00 = Unknown + 0x01 = Point + 0x02 = LineString + 0x03 = Polygon + 0x04 = MultiPoint + 0x05 = MultiLineString + 0x06 = MultiPolygon + 0x07 = GeometryCollection + +*/ /* Native geometry parser macros */ @@ -118,6 +166,7 @@ typedef struct msGeometryParserInfo_t { int nPointSize; int nPointPos; int nNumPoints; + int nNumPointsRead; /* figure array */ int nFigurePos; int nNumFigures; @@ -156,6 +205,7 @@ typedef struct ms_MSSQL2008_layer_info_t { msODBCconn * conn; /* Connection to db */ msGeometryParserInfo gpi; /* struct for the geometry parser */ int geometry_format; /* Geometry format to be retrieved from the database */ + tokenListNodeObjPtr current_node; /* filter expression translation */ } msMSSQL2008LayerInfo; #define SQL_COLUMN_NAME_MAX_LENGTH 128 @@ -170,7 +220,7 @@ typedef struct ms_MSSQL2008_layer_info_t { "mapmssql2008.c - version of 2007/7/1.\n" /* Native geometry parser code */ -void ReadPoint(msGeometryParserInfo* gpi, pointObj* p, int iPoint, int iOrder) +void ReadPoint(msGeometryParserInfo* gpi, pointObj* p, int iPoint) { if (gpi->nColType == MSSQLCOLTYPE_GEOGRAPHY) { p->x = ReadY(iPoint); @@ -180,7 +230,7 @@ void ReadPoint(msGeometryParserInfo* gpi, pointObj* p, int iPoint, int iOrder) p->y = ReadY(iPoint); } /* calculate bounds */ - if (iOrder == 0) { + if (gpi->nNumPointsRead++ == 0) { gpi->minx = gpi->maxx = p->x; gpi->miny = gpi->maxy = p->y; } else { @@ -202,6 +252,8 @@ int ParseSqlGeometry(msMSSQL2008LayerInfo* layerinfo, shapeObj *shape) { msGeometryParserInfo* gpi = &layerinfo->gpi; + gpi->nNumPointsRead = 0; + if (gpi->nLen < 10) { msDebug("ParseSqlGeometry NOT_ENOUGH_DATA\n"); return NOT_ENOUGH_DATA; @@ -239,7 +291,7 @@ int ParseSqlGeometry(msMSSQL2008LayerInfo* layerinfo, shapeObj *shape) shape->line[0].numpoints = 1; gpi->nPointPos = 6; - ReadPoint(gpi, &shape->line[0].point[0], 0, 0); + ReadPoint(gpi, &shape->line[0].point[0], 0); } else if ( gpi->chProps & SP_ISSINGLELINESEGMENT ) { // single line segment with 2 points gpi->nNumPoints = 2; @@ -255,8 +307,8 @@ int ParseSqlGeometry(msMSSQL2008LayerInfo* layerinfo, shapeObj *shape) shape->line[0].numpoints = 2; gpi->nPointPos = 6; - ReadPoint(gpi, &shape->line[0].point[0], 0, 0); - ReadPoint(gpi, &shape->line[0].point[1], 1, 1); + ReadPoint(gpi, &shape->line[0].point[0], 0); + ReadPoint(gpi, &shape->line[0].point[1], 1); } else { int iShape, iFigure; // complex geometries @@ -335,7 +387,7 @@ int ParseSqlGeometry(msMSSQL2008LayerInfo* layerinfo, shapeObj *shape) i = 0; while (iPoint < iNextPoint) { - ReadPoint(gpi, &shape->line[iFigure].point[i], iPoint, i); + ReadPoint(gpi, &shape->line[iFigure].point[i], iPoint); ++iPoint; ++i; } @@ -758,6 +810,28 @@ int msMSSQL2008LayerInitItemInfo(layerObj *layer) return MS_SUCCESS; } +/* Get the layer extent as specified in the mapfile or a largest area */ +/* covering all features */ +int msMSSQL2008LayerGetExtent(layerObj *layer, rectObj *extent) +{ + if(layer->debug) { + msDebug("msMSSQL2008LayerGetExtent called\n"); + } + + if (layer->extent.minx == -1.0 && layer->extent.miny == -1.0 && + layer->extent.maxx == -1.0 && layer->extent.maxy == -1.0) { + extent->minx = extent->miny = -1.0 * FLT_MAX; + extent->maxx = extent->maxy = FLT_MAX; + } else { + extent->minx = layer->extent.minx; + extent->miny = layer->extent.miny; + extent->maxx = layer->extent.maxx; + extent->maxy = layer->extent.maxy; + } + + return MS_SUCCESS; +} + /* Prepare and execute the SQL statement for this layer */ static int prepare_database(layerObj *layer, rectObj rect, char **query_string) { @@ -908,13 +982,19 @@ static int prepare_database(layerObj *layer, rectObj rect, char **query_string) msMSSQL2008LayerGetExtent(layer, &extent); if (rect.minx <= extent.minx && rect.miny <= extent.miny && rect.maxx >= extent.maxx && rect.maxy >= extent.maxy) { /* no spatial filter used */ - if(msLayerGetProcessingKey(layer, "NATIVE_FILTER") == NULL) { + if ( layer->filter.native_string ) { + snprintf(query_string_temp, sizeof(query_string_temp), "SELECT %s from %s WHERE (%s)", columns_wanted, data_source, layer->filter.native_string ); + } + else if(msLayerGetProcessingKey(layer, "NATIVE_FILTER") == NULL) { snprintf(query_string_temp, sizeof(query_string_temp), "SELECT %s from %s", columns_wanted, data_source ); } else { snprintf(query_string_temp, sizeof(query_string_temp), "SELECT %s from %s WHERE (%s)", columns_wanted, data_source, msLayerGetProcessingKey(layer, "NATIVE_FILTER")); } } else { - if(msLayerGetProcessingKey(layer, "NATIVE_FILTER") == NULL) { + if ( layer->filter.native_string ) { + snprintf(query_string_temp, sizeof(query_string_temp), "SELECT %s from %s WHERE (%s) and %s.STIntersects(%s) = 1 ", columns_wanted, data_source, layer->filter.native_string, layerinfo->geom_column, box3d ); + } + else if(msLayerGetProcessingKey(layer, "NATIVE_FILTER") == NULL) { snprintf(query_string_temp, sizeof(query_string_temp), "SELECT %s from %s WHERE %s.STIntersects(%s) = 1 ", columns_wanted, data_source, layerinfo->geom_column, box3d ); } else { snprintf(query_string_temp, sizeof(query_string_temp), "SELECT %s from %s WHERE (%s) and %s.STIntersects(%s) = 1 ", columns_wanted, data_source, msLayerGetProcessingKey(layer, "NATIVE_FILTER"), layerinfo->geom_column, box3d ); @@ -1900,28 +1980,6 @@ int msMSSQL2008LayerGetItems(layerObj *layer) return msMSSQL2008LayerInitItemInfo(layer); } -/* Get the layer extent as specified in the mapfile or a largest area */ -/* covering all features */ -int msMSSQL2008LayerGetExtent(layerObj *layer, rectObj *extent) -{ - if(layer->debug) { - msDebug("msMSSQL2008LayerGetExtent called\n"); - } - - if (layer->extent.minx == -1.0 && layer->extent.miny == -1.0 && - layer->extent.maxx == -1.0 && layer->extent.maxy == -1.0) { - extent->minx = extent->miny = -1.0 * FLT_MAX; - extent->maxx = extent->maxy = FLT_MAX; - } else { - extent->minx = layer->extent.minx; - extent->miny = layer->extent.miny; - extent->maxx = layer->extent.maxx; - extent->maxy = layer->extent.maxy; - } - - return MS_SUCCESS; -} - /* Get primary key column of table */ int msMSSQL2008LayerRetrievePK(layerObj *layer, char **urid_name, char* table_name, int debug) { @@ -2141,6 +2199,399 @@ static int msMSSQL2008LayerParseData(layerObj *layer, char **geom_column_name, c return MS_SUCCESS; } +char *msMSSQL2008LayerEscapePropertyName(layerObj *layer, const char* pszString) +{ + char* pszEscapedStr=NULL; + int i, j = 0; + + if (pszString && strlen(pszString) > 0) { + int nLength = strlen(pszString); + + pszEscapedStr = (char*) msSmallMalloc( 1 + nLength + 1 + 1); + pszEscapedStr[j++] = '['; + + for (i=0; i<nLength; i++) + pszEscapedStr[j++] = pszString[i]; + + pszEscapedStr[j++] = ']'; + pszEscapedStr[j++] = 0; + } + return pszEscapedStr; +} + +char *msMSSQL2008LayerEscapeSQLParam(layerObj *layer, const char *pszString) +{ + char *pszEscapedStr=NULL; + if (pszString) { + int nSrcLen; + char c; + int i=0, j=0; + nSrcLen = (int)strlen(pszString); + pszEscapedStr = (char*) msSmallMalloc( 2 * nSrcLen + 1); + for(i = 0, j = 0; i < nSrcLen; i++) { + c = pszString[i]; + if (c == '\'') { + pszEscapedStr[j++] = '\''; + pszEscapedStr[j++] = '\''; + } else + pszEscapedStr[j++] = c; + } + pszEscapedStr[j] = 0; + } + return pszEscapedStr; +} + +int process_node(layerObj* layer, expressionObj *filter) +{ + char *snippet = NULL; + char *strtmpl = NULL; + char *stresc = NULL; + msMSSQL2008LayerInfo *layerinfo = (msMSSQL2008LayerInfo *) layer->layerinfo; + + if (!layerinfo->current_node) + { + msSetError(MS_MISCERR, "Unecpected end of expression", "msMSSQL2008LayerTranslateFilter()"); + return 0; + } + + switch(layerinfo->current_node->token) { + case '(': + filter->native_string = msStringConcatenate(filter->native_string, "("); + /* process subexpression */ + layerinfo->current_node = layerinfo->current_node->next; + while (layerinfo->current_node != NULL) { + if (!process_node(layer, filter)) + return 0; + if (!layerinfo->current_node) + break; + if (layerinfo->current_node->token == ')') + break; + layerinfo->current_node = layerinfo->current_node->next; + } + break; + case ')': + filter->native_string = msStringConcatenate(filter->native_string, ")"); + break; + /* literal tokens */ + case MS_TOKEN_LITERAL_BOOLEAN: + case MS_TOKEN_LITERAL_NUMBER: + strtmpl = "%lf"; + snippet = (char *) msSmallMalloc(strlen(strtmpl) + 16); + sprintf(snippet, strtmpl, layerinfo->current_node->tokenval.dblval); + filter->native_string = msStringConcatenate(filter->native_string, snippet); + msFree(snippet); + break; + case MS_TOKEN_LITERAL_STRING: + strtmpl = "'%s'"; + stresc = msMSSQL2008LayerEscapeSQLParam(layer, layerinfo->current_node->tokenval.strval); + snippet = (char *) msSmallMalloc(strlen(strtmpl) + strlen(stresc)); + sprintf(snippet, strtmpl, stresc); + filter->native_string = msStringConcatenate(filter->native_string, snippet); + msFree(snippet); + msFree(stresc); + break; + case MS_TOKEN_LITERAL_TIME: + { + char buffer[30]; + if(strftime(buffer,30,"'%Y-%m-%d %H:%M:%S'",&layerinfo->current_node->tokenval.tmval) == 0) { + msSetError(MS_MISCERR, "Invalid time literal in expression", "msMSSQL2008LayerTranslateFilter()"); + return 0; + } + filter->native_string = msStringConcatenate(filter->native_string, buffer); + } + break; + case MS_TOKEN_LITERAL_SHAPE: + if (strcasecmp(layerinfo->geom_column_type, "geography") == 0) + filter->native_string = msStringConcatenate(filter->native_string, "geography::STGeomFromText('"); + else + filter->native_string = msStringConcatenate(filter->native_string, "geometry::STGeomFromText('"); + filter->native_string = msStringConcatenate(filter->native_string, msShapeToWKT(layerinfo->current_node->tokenval.shpval)); + filter->native_string = msStringConcatenate(filter->native_string, "'"); + if(layerinfo->user_srid && strcmp(layerinfo->user_srid, "") != 0) { + filter->native_string = msStringConcatenate(filter->native_string, ", "); + filter->native_string = msStringConcatenate(filter->native_string, layerinfo->user_srid); + } + filter->native_string = msStringConcatenate(filter->native_string, ")"); + break; + case MS_TOKEN_BINDING_TIME: + case MS_TOKEN_BINDING_DOUBLE: + case MS_TOKEN_BINDING_INTEGER: + case MS_TOKEN_BINDING_STRING: + strtmpl = "%s"; + stresc = msMSSQL2008LayerEscapePropertyName(layer, layerinfo->current_node->tokenval.bindval.item); + snippet = (char *) msSmallMalloc(strlen(strtmpl) + strlen(stresc)); + sprintf(snippet, strtmpl, stresc); + filter->native_string = msStringConcatenate(filter->native_string, snippet); + msFree(snippet); + msFree(stresc); + break; + case MS_TOKEN_BINDING_SHAPE: + filter->native_string = msStringConcatenate(filter->native_string, layerinfo->geom_column); + break; + case MS_TOKEN_BINDING_MAP_CELLSIZE: + strtmpl = "%lf"; + snippet = (char *) msSmallMalloc(strlen(strtmpl) + 16); + sprintf(snippet, strtmpl, layer->map->cellsize); + filter->native_string = msStringConcatenate(filter->native_string, snippet); + msFree(snippet); + break; + + /* comparisons */ + case MS_TOKEN_COMPARISON_IN: + filter->native_string = msStringConcatenate(filter->native_string, " IN "); + break; + case MS_TOKEN_COMPARISON_LIKE: + filter->native_string = msStringConcatenate(filter->native_string, " LIKE "); + break; + case MS_TOKEN_COMPARISON_EQ: + filter->native_string = msStringConcatenate(filter->native_string, " = "); + break; + case MS_TOKEN_COMPARISON_NE: + filter->native_string = msStringConcatenate(filter->native_string, " != "); + break; + case MS_TOKEN_COMPARISON_GT: + filter->native_string = msStringConcatenate(filter->native_string, " > "); + break; + case MS_TOKEN_COMPARISON_GE: + filter->native_string = msStringConcatenate(filter->native_string, " >= "); + break; + case MS_TOKEN_COMPARISON_LT: + filter->native_string = msStringConcatenate(filter->native_string, " < "); + break; + case MS_TOKEN_COMPARISON_LE: + filter->native_string = msStringConcatenate(filter->native_string, " <= "); + break; + + /* logical ops */ + case MS_TOKEN_LOGICAL_AND: + filter->native_string = msStringConcatenate(filter->native_string, " AND "); + break; + case MS_TOKEN_LOGICAL_OR: + filter->native_string = msStringConcatenate(filter->native_string, " OR "); + break; + case MS_TOKEN_LOGICAL_NOT: + filter->native_string = msStringConcatenate(filter->native_string, " NOT "); + break; + + /* spatial comparison tokens */ + case MS_TOKEN_COMPARISON_INTERSECTS: + filter->native_string = msStringConcatenate(filter->native_string, ".STIntersects("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")=1"); + break; + + case MS_TOKEN_COMPARISON_DISJOINT: + filter->native_string = msStringConcatenate(filter->native_string, ".STDisjoint("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")=1"); + break; + + case MS_TOKEN_COMPARISON_TOUCHES: + filter->native_string = msStringConcatenate(filter->native_string, ".STTouches("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")=1"); + break; + + case MS_TOKEN_COMPARISON_OVERLAPS: + filter->native_string = msStringConcatenate(filter->native_string, ".STOverlaps("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")=1"); + break; + + case MS_TOKEN_COMPARISON_CROSSES: + filter->native_string = msStringConcatenate(filter->native_string, ".STCrosses("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")=1"); + break; + + case MS_TOKEN_COMPARISON_WITHIN: + filter->native_string = msStringConcatenate(filter->native_string, ".STWithin("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")=1"); + break; + + case MS_TOKEN_COMPARISON_CONTAINS: + filter->native_string = msStringConcatenate(filter->native_string, ".STContains("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")=1"); + break; + + case MS_TOKEN_COMPARISON_EQUALS: + filter->native_string = msStringConcatenate(filter->native_string, ".STEquals("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")=1"); + break; + + case MS_TOKEN_COMPARISON_BEYOND: + msSetError(MS_MISCERR, "Beyond operator is unsupported.", "msMSSQL2008LayerTranslateFilter()"); + return 0; + + case MS_TOKEN_COMPARISON_DWITHIN: + msSetError(MS_MISCERR, "DWithin operator is unsupported.", "msMSSQL2008LayerTranslateFilter()"); + return 0; + + /* spatial functions */ + case MS_TOKEN_FUNCTION_AREA: + filter->native_string = msStringConcatenate(filter->native_string, ".STArea("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")"); + break; + + case MS_TOKEN_FUNCTION_BUFFER: + filter->native_string = msStringConcatenate(filter->native_string, ".STBuffer("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")"); + break; + + case MS_TOKEN_FUNCTION_DIFFERENCE: + filter->native_string = msStringConcatenate(filter->native_string, ".STDifference("); + layerinfo->current_node = layerinfo->current_node->next; + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")"); + break; + + case MS_TOKEN_FUNCTION_FROMTEXT: + if (strcasecmp(layerinfo->geom_column_type, "geography") == 0) + filter->native_string = msStringConcatenate(filter->native_string, "geography::STGeomFromText"); + else + filter->native_string = msStringConcatenate(filter->native_string, "geometry::STGeomFromText"); + break; + + case MS_TOKEN_FUNCTION_LENGTH: + filter->native_string = msStringConcatenate(filter->native_string, "len"); + break; + + case MS_TOKEN_FUNCTION_ROUND: + filter->native_string = msStringConcatenate(filter->native_string, "round"); + break; + + case MS_TOKEN_FUNCTION_TOSTRING: + break; + + case MS_TOKEN_FUNCTION_COMMIFY: + break; + + case MS_TOKEN_FUNCTION_SIMPLIFY: + filter->native_string = msStringConcatenate(filter->native_string, ".Reduce"); + break; + case MS_TOKEN_FUNCTION_SIMPLIFYPT: + break; + case MS_TOKEN_FUNCTION_GENERALIZE: + filter->native_string = msStringConcatenate(filter->native_string, ".Reduce"); + break; + + default: + msSetError(MS_MISCERR, "Translation to native SQL failed.","msMSSQL2008LayerTranslateFilter()"); + if (layer->debug) { + msDebug("Token not caught, exiting: Token is %i\n", layerinfo->current_node->token); + } + return 0; + } + return 1; +} + +/* Translate filter expression to native msssql filter */ +int msMSSQL2008LayerTranslateFilter(layerObj *layer, expressionObj *filter, char *filteritem) +{ + char *snippet = NULL; + char *strtmpl = NULL; + char *stresc = NULL; + msMSSQL2008LayerInfo *layerinfo = (msMSSQL2008LayerInfo *) layer->layerinfo; + + if(!filter->string) return MS_SUCCESS; + + msFree(filter->native_string); + filter->native_string = NULL; + + if(filter->type == MS_STRING && filter->string && filteritem) { /* item/value pair */ + stresc = msMSSQL2008LayerEscapePropertyName(layer, filteritem); + if(filter->flags & MS_EXP_INSENSITIVE) { + filter->native_string = msStringConcatenate(filter->native_string, "upper("); + filter->native_string = msStringConcatenate(filter->native_string, stresc); + filter->native_string = msStringConcatenate(filter->native_string, ") = upper("); + } else { + filter->native_string = msStringConcatenate(filter->native_string, stresc); + filter->native_string = msStringConcatenate(filter->native_string, " = "); + } + msFree(stresc); + + strtmpl = "'%s'"; /* don't have a type for the righthand literal so assume it's a string and we quote */ + snippet = (char *) msSmallMalloc(strlen(strtmpl) + strlen(filter->string)); + sprintf(snippet, strtmpl, filter->string); // TODO: escape filter->string + filter->native_string = msStringConcatenate(filter->native_string, snippet); + free(snippet); + + if(filter->flags & MS_EXP_INSENSITIVE) + filter->native_string = msStringConcatenate(filter->native_string, ")"); + + } else if(filter->type == MS_REGEX && filter->string && filteritem) { /* item/regex pair */ + /* NOTE: regex is not supported by MSSQL natively. We should install it in CLR UDF + according to https://msdn.microsoft.com/en-us/magazine/cc163473.aspx*/ + filter->native_string = msStringConcatenate(filter->native_string, "dbo.RegexMatch("); + if(filter->flags & MS_EXP_INSENSITIVE) { + filter->native_string = msStringConcatenate(filter->native_string, "'(?i)"); + } + filter->native_string = msStrdup(filteritem); + filter->native_string = msStringConcatenate(filter->native_string, ", "); + strtmpl = "'%s'"; + snippet = (char *) msSmallMalloc(strlen(strtmpl) + strlen(filter->string)); + sprintf(snippet, strtmpl, filter->string); // TODO: escape filter->string + filter->native_string = msStringConcatenate(filter->native_string, snippet); + + filter->native_string = msStringConcatenate(filter->native_string, "')"); + free(snippet); + } else if(filter->type == MS_EXPRESSION) { + + if(layer->debug >= 2) + msDebug("msMSSQL2008LayerTranslateFilter. String: %s.\n", filter->string); + + if(!filter->tokens) { + if(layer->debug >= 2) + msDebug("msMSSQL2008LayerTranslateFilter. There are tokens to process... \n"); + return MS_SUCCESS; + } + + /* start processing nodes */ + layerinfo->current_node = filter->tokens; + while (layerinfo->current_node != NULL) { + if (!process_node(layer, filter)) + { + msFree(filter->native_string); + filter->native_string = 0; + return MS_FAILURE; + } + + if (!layerinfo->current_node) + break; + + layerinfo->current_node = layerinfo->current_node->next; + } + } + + return MS_SUCCESS; +} + #else /* prototypes if MSSQL2008 isnt supposed to be compiled */ @@ -2210,6 +2661,24 @@ int msMSSQL2008LayerGetItems(layerObj *layer) return MS_FAILURE; } +int msMSSQL2008LayerTranslateFilter(layerObj *layer, expressionObj *filter, char *filteritem) +{ + msSetError(MS_QUERYERR, "msMSSQL2008LayerTranslateFilter called but unimplemented!(mapserver not compiled with MSSQL2008 support)", "msMSSQL2008LayerTranslateFilter()"); + return MS_FAILURE; +} + +char *msMSSQL2008LayerEscapeSQLParam(layerObj *layer, const char *pszString) +{ + msSetError(MS_QUERYERR, "msMSSQL2008EscapeSQLParam called but unimplemented!(mapserver not compiled with MSSQL2008 support)", "msMSSQL2008LayerEscapeSQLParam()"); + return NULL; +} + +char *msMSSQL2008LayerEscapePropertyName(layerObj *layer, const char *pszString) +{ + msSetError(MS_QUERYERR, "msMSSQL2008LayerEscapePropertyName called but unimplemented!(mapserver not compiled with MSSQL2008 support)", "msMSSQL2008LayerEscapePropertyName()"); + return NULL; +} + /* end above's #ifdef USE_MSSQL2008 */ #endif @@ -2220,7 +2689,9 @@ MS_DLL_EXPORT int PluginInitializeVirtualTable(layerVTableObj* vtable, layerObj assert(layer != NULL); assert(vtable != NULL); - /* vtable->LayerTranslateFilter, use default - need to add this... */ + vtable->LayerTranslateFilter = msMSSQL2008LayerTranslateFilter; + vtable->LayerEscapeSQLParam = msMSSQL2008LayerEscapeSQLParam; + vtable->LayerEscapePropertyName = msMSSQL2008LayerEscapePropertyName; vtable->LayerInitItemInfo = msMSSQL2008LayerInitItemInfo; vtable->LayerFreeItemInfo = msMSSQL2008LayerFreeItemInfo; @@ -2240,7 +2711,7 @@ MS_DLL_EXPORT int PluginInitializeVirtualTable(layerVTableObj* vtable, layerObj /* vtable->LayerGetAutoStyle, not supported for this layer */ vtable->LayerCloseConnection = msMSSQL2008LayerClose; - vtable->LayerSetTimeFilter = msLayerMakePlainTimeFilter; + vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter; /* vtable->LayerCreateItems, use default */ /* vtable->LayerGetNumFeatures, use default */ /* layer->vtable->LayerGetAutoProjection, use defaut*/ @@ -2256,6 +2727,10 @@ msMSSQL2008LayerInitializeVirtualTable(layerObj *layer) assert(layer != NULL); assert(layer->vtable != NULL); + layer->vtable->LayerTranslateFilter = msMSSQL2008LayerTranslateFilter; + layer->vtable->LayerEscapeSQLParam = msMSSQL2008LayerEscapeSQLParam; + layer->vtable->LayerEscapePropertyName = msMSSQL2008LayerEscapePropertyName; + layer->vtable->LayerInitItemInfo = msMSSQL2008LayerInitItemInfo; layer->vtable->LayerFreeItemInfo = msMSSQL2008LayerFreeItemInfo; layer->vtable->LayerOpen = msMSSQL2008LayerOpen; @@ -2274,7 +2749,7 @@ msMSSQL2008LayerInitializeVirtualTable(layerObj *layer) /* layer->vtable->LayerGetAutoStyle, not supported for this layer */ layer->vtable->LayerCloseConnection = msMSSQL2008LayerClose; - layer->vtable->LayerSetTimeFilter = msLayerMakePlainTimeFilter; + layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter; /* layer->vtable->LayerCreateItems, use default */ /* layer->vtable->LayerGetNumFeatures, use default */ diff --git a/mapogcfilter.c b/mapogcfilter.c index aa6cc94..3d4bab8 100644 --- a/mapogcfilter.c +++ b/mapogcfilter.c @@ -66,7 +66,8 @@ int FLTIsNumeric(const char *pszValue) return MS_TRUE; #else char * p; - if (strtod(pszValue, &p) != 0 || *p == '\0') return MS_TRUE; + strtod(pszValue, &p); + if ( p != pszValue && *p == '\0') return MS_TRUE; #endif } diff --git a/mapogcfiltercommon.c b/mapogcfiltercommon.c index 11f9ff7..a77b3e3 100644 --- a/mapogcfiltercommon.c +++ b/mapogcfiltercommon.c @@ -51,9 +51,7 @@ char *FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode) int nLength=0, i=0, iTmp=0; - - if (!psFilterNode || !psFilterNode->pOther || !psFilterNode->psLeftNode || - !psFilterNode->psRightNode || !psFilterNode->psRightNode->pszValue) + if (!psFilterNode || !psFilterNode->pOther || !psFilterNode->psLeftNode || !psFilterNode->psRightNode || !psFilterNode->psRightNode->pszValue) return NULL; propIsLike = (FEPropertyIsLike *)psFilterNode->pOther; @@ -62,12 +60,9 @@ char *FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode) pszEscape = propIsLike->pszEscapeChar; bCaseInsensitive = propIsLike->bCaseInsensitive; - if (!pszWild || strlen(pszWild) == 0 || - !pszSingle || strlen(pszSingle) == 0 || - !pszEscape || strlen(pszEscape) == 0) + if (!pszWild || strlen(pszWild) == 0 || !pszSingle || strlen(pszSingle) == 0 || !pszEscape || strlen(pszEscape) == 0) return NULL; - /* -------------------------------------------------------------------- */ /* Use operand with regular expressions. */ /* -------------------------------------------------------------------- */ @@ -81,8 +76,8 @@ char *FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode) strlcat(szBuffer, psFilterNode->psLeftNode->pszValue, bufferSize); szBuffer[strlen(szBuffer)] = '\0'; - /*#3521 */ - if(bCaseInsensitive == 1) + /* #3521 */ + if (bCaseInsensitive == 1) sprintf(szTmp, "%s", "]\" ~* \""); else sprintf(szTmp, "%s", "]\" ~ \""); @@ -90,35 +85,28 @@ char *FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode) strlcat(szBuffer, szTmp, bufferSize); szBuffer[strlen(szBuffer)] = '\0'; - pszValue = psFilterNode->psRightNode->pszValue; nLength = strlen(pszValue); iTmp =0; - if (nLength > 0 && pszValue[0] != pszWild[0] && - pszValue[0] != pszSingle[0] && - pszValue[0] != pszEscape[0]) { + if (nLength > 0 && pszValue[0] != pszWild[0] && pszValue[0] != pszSingle[0] && pszValue[0] != pszEscape[0]) { szTmp[iTmp]= '^'; iTmp++; } for (i=0; i<nLength; i++) { - if (pszValue[i] != pszWild[0] && - pszValue[i] != pszSingle[0] && - pszValue[i] != pszEscape[0]) { + if (pszValue[i] != pszWild[0] && pszValue[i] != pszSingle[0] && pszValue[i] != pszEscape[0]) { szTmp[iTmp] = pszValue[i]; iTmp++; szTmp[iTmp] = '\0'; - } else if (pszValue[i] == pszSingle[0]) { + } else if (pszValue[i] == pszSingle[0]) { szTmp[iTmp] = '.'; iTmp++; szTmp[iTmp] = '\0'; - } else if (pszValue[i] == pszEscape[0]) { + } else if (pszValue[i] == pszEscape[0]) { szTmp[iTmp] = '\\'; iTmp++; szTmp[iTmp] = '\0'; } else if (pszValue[i] == pszWild[0]) { - /* strcat(szBuffer, "[0-9,a-z,A-Z,\\s]*"); */ - /* iBuffer+=17; */ szTmp[iTmp++] = '.'; szTmp[iTmp++] = '*'; szTmp[iTmp] = '\0'; @@ -139,10 +127,10 @@ char *FLTGetIsBetweenComparisonCommonExpresssion(FilterEncodingNode *psFilterNod char **aszBounds = NULL; int nBounds = 0; int bString=0; + int bDateTime = 0; char *pszExpression=NULL, *pszTmpEscaped; - if (!psFilterNode || - !(strcasecmp(psFilterNode->pszValue, "PropertyIsBetween") == 0)) + if (!psFilterNode || !(strcasecmp(psFilterNode->pszValue, "PropertyIsBetween") == 0)) return NULL; if (psFilterNode->psLeftNode == NULL || psFilterNode->psRightNode == NULL ) @@ -156,27 +144,30 @@ char *FLTGetIsBetweenComparisonCommonExpresssion(FilterEncodingNode *psFilterNod msFreeCharArray(aszBounds, nBounds); return NULL; } + /* -------------------------------------------------------------------- */ /* check if the value is a numeric value or alphanumeric. If it */ /* is alphanumeric, add quotes around attribute and values. */ /* -------------------------------------------------------------------- */ bString = 0; if (aszBounds[0]) { + const char* pszType; snprintf(szBuffer, bufferSize, "%s_type", psFilterNode->psLeftNode->pszValue); - if (msOWSLookupMetadata(&(lp->metadata), "OFG", szBuffer) != NULL && - (strcasecmp(msOWSLookupMetadata(&(lp->metadata), "OFG", szBuffer), "Character") == 0)) + pszType = msOWSLookupMetadata(&(lp->metadata), "OFG", szBuffer); + if (pszType != NULL && (strcasecmp(pszType, "Character") == 0)) bString = 1; + else if (pszType != NULL && (strcasecmp(pszType, "Date") == 0)) + bDateTime = 1; else if (FLTIsNumeric(aszBounds[0]) == MS_FALSE) bString = 1; } - if (!bString) { + if (!bString && !bDateTime) { if (aszBounds[1]) { if (FLTIsNumeric(aszBounds[1]) == MS_FALSE) bString = 1; } } - /* -------------------------------------------------------------------- */ /* build expresssion. */ /* -------------------------------------------------------------------- */ @@ -199,8 +190,10 @@ char *FLTGetIsBetweenComparisonCommonExpresssion(FilterEncodingNode *psFilterNod pszExpression = msStringConcatenate(pszExpression, szBuffer); if (bString) { - sprintf(szBuffer,"%s", "\""); - pszExpression = msStringConcatenate(pszExpression, szBuffer); + pszExpression = msStringConcatenate(pszExpression, "\""); + } + else if (bDateTime) { + pszExpression = msStringConcatenate(pszExpression, "`"); } pszTmpEscaped = msStringEscape(aszBounds[0]); @@ -208,8 +201,10 @@ char *FLTGetIsBetweenComparisonCommonExpresssion(FilterEncodingNode *psFilterNod if(pszTmpEscaped != aszBounds[0] ) msFree(pszTmpEscaped); pszExpression = msStringConcatenate(pszExpression, szBuffer); if (bString) { - sprintf(szBuffer, "%s", "\""); - pszExpression = msStringConcatenate(pszExpression, szBuffer); + pszExpression = msStringConcatenate(pszExpression, "\""); + } + else if (bDateTime) { + pszExpression = msStringConcatenate(pszExpression, "`"); } sprintf(szBuffer, "%s", " AND "); @@ -233,17 +228,21 @@ char *FLTGetIsBetweenComparisonCommonExpresssion(FilterEncodingNode *psFilterNod sprintf(szBuffer, "%s", " <= "); pszExpression = msStringConcatenate(pszExpression, szBuffer); if (bString) { - sprintf(szBuffer,"%s", "\""); - pszExpression = msStringConcatenate(pszExpression, szBuffer); + pszExpression = msStringConcatenate(pszExpression, "\""); + } + else if (bDateTime) { + pszExpression = msStringConcatenate(pszExpression, "`"); } pszTmpEscaped = msStringEscape(aszBounds[1]); snprintf(szBuffer, bufferSize, "%s", pszTmpEscaped); - if(pszTmpEscaped != aszBounds[1] ) msFree(pszTmpEscaped); + if (pszTmpEscaped != aszBounds[1]) msFree(pszTmpEscaped); pszExpression = msStringConcatenate(pszExpression, szBuffer); if (bString) { - sprintf(szBuffer,"\""); - pszExpression = msStringConcatenate(pszExpression, szBuffer); + pszExpression = msStringConcatenate(pszExpression, "\""); + } + else if (bDateTime) { + pszExpression = msStringConcatenate(pszExpression, "`"); } sprintf(szBuffer, "%s", ")"); pszExpression = msStringConcatenate(pszExpression, szBuffer); @@ -258,6 +257,7 @@ char *FLTGetBinaryComparisonCommonExpression(FilterEncodingNode *psFilterNode, l char szTmp[1024]; char *pszExpression = NULL, *pszTmpEscaped; int bString; + int bDateTime; if (psFilterNode == NULL) return NULL; @@ -267,23 +267,24 @@ char *FLTGetBinaryComparisonCommonExpression(FilterEncodingNode *psFilterNode, l /* is alphanumeric, add quotes around attribute and values. */ /* -------------------------------------------------------------------- */ bString = 0; + bDateTime = 0; if (psFilterNode->psRightNode->pszValue) { + const char* pszType; snprintf(szTmp, sizeof(szTmp), "%s_type", psFilterNode->psLeftNode->pszValue); - if (msOWSLookupMetadata(&(lp->metadata), "OFG", szTmp) != NULL && - (strcasecmp(msOWSLookupMetadata(&(lp->metadata), "OFG", szTmp), "Character") == 0)) + pszType = msOWSLookupMetadata(&(lp->metadata), "OFG", szTmp); + if (pszType!= NULL && (strcasecmp(pszType, "Character") == 0)) bString = 1; + else if (pszType!= NULL && (strcasecmp(pszType, "Date") == 0)) + bDateTime = 1; else if (FLTIsNumeric(psFilterNode->psRightNode->pszValue) == MS_FALSE) bString = 1; } /* specical case to be able to have empty strings in the expression. */ - /*propertyislike is always treated as string*/ - if (psFilterNode->psRightNode->pszValue == NULL || - strcasecmp(psFilterNode->pszValue, "PropertyIsLike") == 0) + /* propertyislike is always treated as string */ + if (psFilterNode->psRightNode->pszValue == NULL || strcasecmp(psFilterNode->pszValue, "PropertyIsLike") == 0) bString = 1; - - /* attribute */ if (bString) sprintf(szTmp, "%s", " (\"["); @@ -298,32 +299,23 @@ char *FLTGetBinaryComparisonCommonExpression(FilterEncodingNode *psFilterNode, l sprintf(szTmp, "%s", "] "); pszExpression = msStringConcatenate(pszExpression, szTmp); - if (strcasecmp(psFilterNode->pszValue, - "PropertyIsEqualTo") == 0) { - /*case insensitive set ? */ - if (psFilterNode->psRightNode->pOther && - (*(int *)psFilterNode->psRightNode->pOther) == 1) { + if (strcasecmp(psFilterNode->pszValue, "PropertyIsEqualTo") == 0) { + /* case insensitive set ? */ + if (psFilterNode->psRightNode->pOther && (*(int *)psFilterNode->psRightNode->pOther) == 1) sprintf(szTmp, "%s", "=*"); - } else + else sprintf(szTmp, "%s", "="); - - } else if (strcasecmp(psFilterNode->pszValue, - "PropertyIsNotEqualTo") == 0) + } else if (strcasecmp(psFilterNode->pszValue, "PropertyIsNotEqualTo") == 0) sprintf(szTmp, "%s", " != "); - else if (strcasecmp(psFilterNode->pszValue, - "PropertyIsLessThan") == 0) + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLessThan") == 0) sprintf(szTmp, "%s", " < "); - else if (strcasecmp(psFilterNode->pszValue, - "PropertyIsGreaterThan") == 0) + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsGreaterThan") == 0) sprintf(szTmp, "%s", " > "); - else if (strcasecmp(psFilterNode->pszValue, - "PropertyIsLessThanOrEqualTo") == 0) + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLessThanOrEqualTo") == 0) sprintf(szTmp, "%s", " <= "); - else if (strcasecmp(psFilterNode->pszValue, - "PropertyIsGreaterThanOrEqualTo") == 0) + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsGreaterThanOrEqualTo") == 0) sprintf(szTmp, "%s", " >= "); - else if (strcasecmp(psFilterNode->pszValue, - "PropertyIsLike") == 0) + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLike") == 0) sprintf(szTmp, "%s", " ~ "); pszExpression = msStringConcatenate(pszExpression, szTmp); @@ -333,6 +325,10 @@ char *FLTGetBinaryComparisonCommonExpression(FilterEncodingNode *psFilterNode, l sprintf(szTmp, "%s", "\""); pszExpression = msStringConcatenate(pszExpression, szTmp); } + else if (bDateTime) { + sprintf(szTmp, "%s", "`"); + pszExpression = msStringConcatenate(pszExpression, szTmp); + } if (psFilterNode->psRightNode->pszValue) { pszTmpEscaped = msStringEscape(psFilterNode->psRightNode->pszValue); @@ -344,6 +340,10 @@ char *FLTGetBinaryComparisonCommonExpression(FilterEncodingNode *psFilterNode, l sprintf(szTmp, "%s", "\""); pszExpression = msStringConcatenate(pszExpression, szTmp); } + else if (bDateTime) { + sprintf(szTmp, "%s", "`"); + pszExpression = msStringConcatenate(pszExpression, szTmp); + } sprintf(szTmp, "%s", ")"); pszExpression = msStringConcatenate(pszExpression, szTmp); @@ -351,8 +351,6 @@ char *FLTGetBinaryComparisonCommonExpression(FilterEncodingNode *psFilterNode, l return pszExpression; } - - char *FLTGetLogicalComparisonCommonExpression(FilterEncodingNode *psFilterNode, layerObj *lp) { char *pszExpression = NULL; @@ -382,7 +380,6 @@ char *FLTGetLogicalComparisonCommonExpression(FilterEncodingNode *psFilterNode, pszExpression = msStringConcatenate(pszExpression, psFilterNode->pszValue); sprintf(szBuffer, "%s", " "); - pszTmp = FLTGetCommonExpression(psFilterNode->psRightNode, lp); if (!pszTmp) { msFree(pszExpression); @@ -398,8 +395,7 @@ char *FLTGetLogicalComparisonCommonExpression(FilterEncodingNode *psFilterNode, /* -------------------------------------------------------------------- */ /* NOT */ /* -------------------------------------------------------------------- */ - else if (psFilterNode->psLeftNode && - strcasecmp(psFilterNode->pszValue, "NOT") == 0) { + else if (psFilterNode->psLeftNode && strcasecmp(psFilterNode->pszValue, "NOT") == 0) { pszTmp = FLTGetCommonExpression(psFilterNode->psLeftNode, lp); if (!pszTmp) return NULL; @@ -412,14 +408,11 @@ char *FLTGetLogicalComparisonCommonExpression(FilterEncodingNode *psFilterNode, sprintf(szBuffer, "%s", ") "); pszExpression = msStringConcatenate(pszExpression, szBuffer); - } - return pszExpression; } - char *FLTGetSpatialComparisonCommonExpression(FilterEncodingNode *psNode, layerObj *lp) { char *pszExpression = NULL; @@ -442,7 +435,7 @@ char *FLTGetSpatialComparisonCommonExpression(FilterEncodingNode *psNode, layerO return NULL; /* get the shape */ - if(FLTIsBBoxFilter(psNode)) { + if (FLTIsBBoxFilter(psNode)) { char szPolygon[512]; FLTGetBBOX(psNode, &sQueryRect); @@ -456,38 +449,40 @@ char *FLTGetSpatialComparisonCommonExpression(FilterEncodingNode *psNode, layerO psTmpShape = msShapeFromWKT(szPolygon); - /* This is a horrible hack to deal with world-extent requests and */ - /* reprojection. msProjectRect() detects if reprojection from longlat to */ - /* projected SRS, and in that case it transforms the bbox to -1e-15,-1e-15,1e15,1e15 */ - /* to ensure that all features are returned */ - /* Make wfs_200_cite_filter_bbox_world.xml and wfs_200_cite_postgis_bbox_world.xml pass */ - if( fabs(sQueryRect.minx - -180.0) < 1e-5 && + /* + ** This is a horrible hack to deal with world-extent requests and + ** reprojection. msProjectRect() detects if reprojection from longlat to + ** projected SRS, and in that case it transforms the bbox to -1e-15,-1e-15,1e15,1e15 + ** to ensure that all features are returned. + ** + ** Make wfs_200_cite_filter_bbox_world.xml and wfs_200_cite_postgis_bbox_world.xml pass + */ + if (fabs(sQueryRect.minx - -180.0) < 1e-5 && fabs(sQueryRect.miny - -90.0) < 1e-5 && fabs(sQueryRect.maxx - 180.0) < 1e-5 && - fabs(sQueryRect.maxy - 90.0) < 1e-5 ) + fabs(sQueryRect.maxy - 90.0) < 1e-5) { - if(lp->projection.numargs > 0) { + if (lp->projection.numargs > 0) { if (psNode->pszSRS) - msInitProjection(&sProjTmp); + msInitProjection(&sProjTmp); if (psNode->pszSRS) { - /* Use the non EPSG variant since axis swapping is done in FLTDoAxisSwappingIfNecessary */ - if (msLoadProjectionString(&sProjTmp, psNode->pszSRS) == 0) { - msProjectRect(&sProjTmp, &lp->projection, &sQueryRect); - } + /* Use the non EPSG variant since axis swapping is done in FLTDoAxisSwappingIfNecessary */ + if (msLoadProjectionString(&sProjTmp, psNode->pszSRS) == 0) { + msProjectRect(&sProjTmp, &lp->projection, &sQueryRect); + } } else if (lp->map->projection.numargs > 0) - msProjectRect(&lp->map->projection, &lp->projection, &sQueryRect); - if (psNode->pszSRS) - msFreeProjection(&sProjTmp); - } - if( sQueryRect.minx <= -1e14 ) - { - msFreeShape(psTmpShape); - msFree(psTmpShape); - psTmpShape = (shapeObj*) msSmallMalloc(sizeof(shapeObj)); - msInitShape(psTmpShape); - msRectToPolygon(sQueryRect, psTmpShape); - bAlreadyReprojected = 1; - } + msProjectRect(&lp->map->projection, &lp->projection, &sQueryRect); + if (psNode->pszSRS) + msFreeProjection(&sProjTmp); + } + if (sQueryRect.minx <= -1e14) { + msFreeShape(psTmpShape); + msFree(psTmpShape); + psTmpShape = (shapeObj*) msSmallMalloc(sizeof(shapeObj)); + msInitShape(psTmpShape); + msRectToPolygon(sQueryRect, psTmpShape); + bAlreadyReprojected = 1; + } } bBBoxQuery = 1; @@ -517,7 +512,7 @@ char *FLTGetSpatialComparisonCommonExpression(FilterEncodingNode *psNode, layerO /* ** target is layer projection */ - if(!bAlreadyReprojected && lp->projection.numargs > 0) { + if (!bAlreadyReprojected && lp->projection.numargs > 0) { if (psNode->pszSRS) msInitProjection(&sProjTmp); if (psNode->pszSRS) { @@ -575,9 +570,9 @@ char *FLTGetSpatialComparisonCommonExpression(FilterEncodingNode *psNode, layerO /* ** Cleanup */ - if(bBBoxQuery) { - msFreeShape(psTmpShape); - msFree(psTmpShape); + if (bBBoxQuery) { + msFreeShape(psTmpShape); + msFree(psTmpShape); } return pszExpression; @@ -585,13 +580,12 @@ char *FLTGetSpatialComparisonCommonExpression(FilterEncodingNode *psNode, layerO char *FLTGetFeatureIdCommonExpression(FilterEncodingNode *psFilterNode, layerObj *lp) { - char *pszExpression = NULL; int nTokens = 0, i=0, bString=0; char **tokens = NULL; const char *pszAttribute=NULL; -#if defined(USE_WMS_SVR) || defined (USE_WFS_SVR) || defined (USE_WCS_SVR) || defined(USE_SOS_SVR) +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || defined(USE_SOS_SVR) if (psFilterNode->pszValue) { pszAttribute = msOWSLookupMetadata(&(lp->metadata), "OFG", "featureid"); if (pszAttribute) { @@ -610,7 +604,6 @@ char *FLTGetFeatureIdCommonExpression(FilterEncodingNode *psFilterNode, layerObj bString = 1; } - if (bString) { bufferSize = 11+strlen(pszId)+strlen(pszAttribute)+1; pszTmp = (char *)msSmallMalloc(bufferSize); @@ -632,7 +625,8 @@ char *FLTGetFeatureIdCommonExpression(FilterEncodingNode *psFilterNode, layerObj msFreeCharArray(tokens, nTokens); } } - /*opening and closing brackets are needed for mapserver expressions*/ + + /* opening and closing brackets are needed for mapserver expressions */ if (pszExpression) pszExpression = msStringConcatenate(pszExpression, ")"); } @@ -654,13 +648,12 @@ char* FLTGetTimeExpression(FilterEncodingNode *psFilterNode, layerObj *lp) return NULL; pszTimeValue = FLTGetDuring(psFilterNode, &pszTimeField); - if( pszTimeField && pszTimeValue ) - { + if (pszTimeField && pszTimeValue) { expressionObj old_filter; msInitExpression(&old_filter); msCopyExpression(&old_filter, &lp->filter); /* save existing filter */ msFreeExpression(&lp->filter); - if( msLayerSetTimeFilter(lp, pszTimeValue, pszTimeField) == MS_TRUE ) { + if (msLayerSetTimeFilter(lp, pszTimeValue, pszTimeField) == MS_TRUE) { pszExpression = msStrdup(lp->filter.string); } msCopyExpression(&lp->filter, &old_filter); /* restore old filter */ @@ -669,7 +662,6 @@ char* FLTGetTimeExpression(FilterEncodingNode *psFilterNode, layerObj *lp) return pszExpression; } - char *FLTGetCommonExpression(FilterEncodingNode *psFilterNode, layerObj *lp) { char *pszExpression = NULL; diff --git a/mapows.c b/mapows.c index f1ce641..617abc3 100644 --- a/mapows.c +++ b/mapows.c @@ -80,6 +80,17 @@ static void msOWSClearRequestObj(owsRequestObj *ows_request) } } +#if defined(USE_LIBXML2) && LIBXML_VERSION < 20900 +static int bExternalEntityAsked = FALSE; +static xmlParserInputPtr dummyEntityLoader(const char * URL, + const char * ID, + xmlParserCtxtPtr context ) +{ + bExternalEntityAsked = TRUE; + return NULL; +} +#endif + /* ** msOWSPreParseRequest() parses a cgiRequestObj either with GET/KVP ** or with POST/XML. Only SERVICE, VERSION (or WMTVER) and REQUEST are @@ -121,6 +132,9 @@ static int msOWSPreParseRequest(cgiRequestObj *request, } else if (request->type == MS_POST_REQUEST) { #if defined(USE_LIBXML2) xmlNodePtr root = NULL; +#if LIBXML_VERSION < 20900 + xmlExternalEntityLoader oldExternalEntityLoader; +#endif #elif defined(USE_GDAL) CPLXMLNode *temp; #endif @@ -130,9 +144,24 @@ static int msOWSPreParseRequest(cgiRequestObj *request, return MS_FAILURE; } #if defined(USE_LIBXML2) +#if LIBXML_VERSION < 20900 + oldExternalEntityLoader = xmlGetExternalEntityLoader(); + /* to avoid XML External Entity vulnerability with libxml2 < 2.9 */ + xmlSetExternalEntityLoader (dummyEntityLoader); + bExternalEntityAsked = FALSE; +#endif /* parse to DOM-Structure with libxml2 and get the root element */ ows_request->document = xmlParseMemory(request->postrequest, strlen(request->postrequest)); +#if LIBXML_VERSION < 20900 + xmlSetExternalEntityLoader (oldExternalEntityLoader); + if( bExternalEntityAsked ) + { + msSetError(MS_OWSERR, "XML parsing error: %s", + "msOWSPreParseRequest()", "External entity fetch"); + return MS_FAILURE; + } +#endif if (ows_request->document == NULL || (root = xmlDocGetRootElement(ows_request->document)) == NULL) { xmlErrorPtr error = xmlGetLastError(); diff --git a/mappluginlayer.c b/mappluginlayer.c index 8b01508..0099e9b 100644 --- a/mappluginlayer.c +++ b/mappluginlayer.c @@ -154,6 +154,8 @@ static void copyVirtualTable(layerVTableObj *dest, const layerVTableObj *src) { + dest->LayerTranslateFilter = src->LayerTranslateFilter ? src->LayerTranslateFilter : dest->LayerTranslateFilter; + dest->LayerSupportsCommonFilters = src->LayerSupportsCommonFilters ? src->LayerSupportsCommonFilters : dest->LayerSupportsCommonFilters; dest->LayerInitItemInfo = src->LayerInitItemInfo ? src->LayerInitItemInfo : dest->LayerInitItemInfo; dest->LayerFreeItemInfo = src->LayerFreeItemInfo ? src->LayerFreeItemInfo : dest->LayerFreeItemInfo; dest->LayerOpen = src->LayerOpen ? src->LayerOpen : dest->LayerOpen; @@ -172,6 +174,11 @@ copyVirtualTable(layerVTableObj *dest, dest->LayerCreateItems = src->LayerCreateItems ? src->LayerCreateItems : dest->LayerCreateItems; dest->LayerGetNumFeatures = src->LayerGetNumFeatures ? src->LayerGetNumFeatures : dest->LayerGetNumFeatures; dest->LayerGetAutoProjection = src->LayerGetAutoProjection ? src->LayerGetAutoProjection: dest->LayerGetAutoProjection; + dest->LayerEscapeSQLParam = src->LayerEscapeSQLParam ? src->LayerEscapeSQLParam: dest->LayerEscapeSQLParam; + dest->LayerEscapePropertyName = src->LayerEscapePropertyName ? src->LayerEscapePropertyName: dest->LayerEscapePropertyName; + dest->LayerEscapeSQLParam = src->LayerEscapeSQLParam ? src->LayerEscapeSQLParam: dest->LayerEscapeSQLParam; + dest->LayerEnablePaging = src->LayerEnablePaging ? src->LayerEnablePaging: dest->LayerEnablePaging; + dest->LayerGetPaging = src->LayerGetPaging ? src->LayerGetPaging: dest->LayerGetPaging; } int diff --git a/maprasterquery.c b/maprasterquery.c index a420e0b..80accfa 100644 --- a/maprasterquery.c +++ b/maprasterquery.c @@ -1286,12 +1286,14 @@ int msRASTERLayerGetItems(layerObj *layer) #ifndef USE_GDAL return MS_FAILURE; #else + int maxnumitems = 0; rasterLayerInfo *rlinfo = (rasterLayerInfo *) layer->layerinfo; if( rlinfo == NULL ) return MS_FAILURE; - layer->items = (char **) msSmallCalloc(sizeof(char *),10); + maxnumitems = 8 + (rlinfo->qc_values?rlinfo->band_count:0); + layer->items = (char **) msSmallCalloc(sizeof(char *),maxnumitems); layer->numitems = 0; if( rlinfo->qc_x_reproj ) @@ -1318,6 +1320,8 @@ int msRASTERLayerGetItems(layerObj *layer) if( rlinfo->qc_count ) layer->items[layer->numitems++] = msStrdup("count"); + assert(layer->numitems <= maxnumitems); + return msRASTERLayerInitItemInfo(layer); #endif /* def USE_GDAL */ } diff --git a/maprendering.c b/maprendering.c index aec7386..2a24985 100644 --- a/maprendering.c +++ b/maprendering.c @@ -247,8 +247,8 @@ imageObj *getTile(imageObj *img, symbolObj *symbol, symbolStyleObj *s, int widt if(UNLIKELY(!face)) { status = MS_FAILURE; break; } msUTF8ToUniChar(symbol->character, &unicode); unicode = msGetGlyphIndex(face,unicode); - glyphc = msGetGlyphByIndex(face, s->scale, unicode); - if(UNLIKELY(!face)) { status = MS_FAILURE; break; } + glyphc = msGetGlyphByIndex(face, MS_MAX(MS_NINT(s->scale),1), unicode); + if(UNLIKELY(!glyphc)) { status = MS_FAILURE; break; } status = drawGlyphMarker(tileimg, face, glyphc, p_x, p_y, s->scale, s->rotation, s->color, s->outlinecolor, s->outlinewidth); } @@ -311,7 +311,7 @@ imageObj *getTile(imageObj *img, symbolObj *symbol, symbolStyleObj *s, int widt if(UNLIKELY(!face)) { status = MS_FAILURE; break; } msUTF8ToUniChar(symbol->character, &unicode); unicode = msGetGlyphIndex(face,unicode); - glyphc = msGetGlyphByIndex(face, s->scale, unicode); + glyphc = msGetGlyphByIndex(face, MS_MAX(MS_NINT(s->scale),1), unicode); if(UNLIKELY(!glyphc)) { status = MS_FAILURE; break; } status = drawGlyphMarker(tileimg, face, glyphc, p_x, p_y, s->scale, s->rotation, s->color, s->outlinecolor, s->outlinewidth); @@ -384,7 +384,7 @@ int msImagePolylineMarkers(imageObj *image, shapeObj *p, symbolObj *symbol, face = msGetFontFace(symbol->font, &image->map->fontset); if(UNLIKELY(!face)) return MS_FAILURE; unicode = msGetGlyphIndex(face,unicode); - glyphc = msGetGlyphByIndex(face, style->scale, unicode); + glyphc = msGetGlyphByIndex(face, MS_MAX(MS_NINT(style->scale),1), unicode); if(UNLIKELY(!glyphc)) return MS_FAILURE; symbol_width = glyphc->metrics.maxx - glyphc->metrics.minx; symbol_height = glyphc->metrics.maxy - glyphc->metrics.miny; @@ -561,7 +561,7 @@ int msDrawLineSymbol(mapObj *map, imageObj *image, shapeObj *p, rendererVTableObj *renderer = image->format->vtable; symbolObj *symbol; shapeObj *offsetLine = p; - int i,ret=MS_SUCCESS; + int i; double width; double finalscalefactor; @@ -922,7 +922,7 @@ int msDrawMarkerSymbol(mapObj *map, imageObj *image, pointObj *p, styleObj *styl if(UNLIKELY(!face)) return MS_FAILURE; msUTF8ToUniChar(symbol->character,&unicode); unicode = msGetGlyphIndex(face,unicode); - glyphc = msGetGlyphByIndex(face,s.scale,unicode); + glyphc = msGetGlyphByIndex(face, MS_MAX(MS_NINT(s.scale),1), unicode); if(UNLIKELY(!glyphc)) return MS_FAILURE; ret = drawGlyphMarker(image, face, glyphc, p_x, p_y, s.scale, s.rotation, s.color, s.outlinecolor, s.outlinewidth); } @@ -1023,7 +1023,7 @@ int msDrawTextSymbol(mapObj *map, imageObj *image, pointObj labelPnt, textSymbol c = &ts->label->color; if(MS_VALID_COLOR(ts->label->outlinecolor)) oc = &ts->label->outlinecolor; - ow = ts->label->outlinewidth * ts->scalefactor; + ow = ts->label->outlinewidth * (ts->textpath->glyph_size / ts->label->size); if(!renderer->renderGlyphs) return MS_FAILURE; return renderer->renderGlyphs(image,ts->textpath,c,oc,ow); @@ -1077,3 +1077,54 @@ int msDrawPieSlice(mapObj *map, imageObj *image, pointObj *p, styleObj *style, d msFree(circle); return status; } + +/* + * RFC 49 implementation + * if an outlinewidth is used: + * - augment the style's width to account for the outline width + * - swap the style color and outlinecolor + * - draw the shape (the outline) in the first pass of the + * caching mechanism + */ + +void msOutlineRenderingPrepareStyle(styleObj *pStyle, mapObj *map, layerObj *layer, imageObj *image) +{ + colorObj tmp; + + if (pStyle->outlinewidth > 0) { + /* adapt width (must take scalefactor into account) */ + pStyle->width += (pStyle->outlinewidth / (layer->scalefactor/image->resolutionfactor)) * 2; + pStyle->minwidth += pStyle->outlinewidth * 2; + pStyle->maxwidth += pStyle->outlinewidth * 2; + pStyle->size += (pStyle->outlinewidth/layer->scalefactor*(map->resolution/map->defresolution)); + + /*swap color and outlinecolor*/ + tmp = pStyle->color; + pStyle->color = pStyle->outlinecolor; + pStyle->outlinecolor = tmp; + } +} + +/* + * RFC 49 implementation: switch back the styleobj to its + * original state, so the line fill will be drawn in the + * second pass of the caching mechanism + */ + +void msOutlineRenderingRestoreStyle(styleObj *pStyle, mapObj *map, layerObj *layer, imageObj *image) +{ + colorObj tmp; + + if (pStyle->outlinewidth > 0) { + /* reset widths to original state */ + pStyle->width -= (pStyle->outlinewidth / (layer->scalefactor/image->resolutionfactor)) * 2; + pStyle->minwidth -= pStyle->outlinewidth * 2; + pStyle->maxwidth -= pStyle->outlinewidth * 2; + pStyle->size -= (pStyle->outlinewidth/layer->scalefactor*(map->resolution/map->defresolution)); + + /*reswap colors to original state*/ + tmp = pStyle->color; + pStyle->color = pStyle->outlinecolor; + pStyle->outlinecolor = tmp; + } +} diff --git a/mapscript/php/map.c b/mapscript/php/map.c index 6943d8d..9ddb2eb 100644 --- a/mapscript/php/map.c +++ b/mapscript/php/map.c @@ -1951,7 +1951,7 @@ PHP_METHOD(mapObj, saveQuery) zval *zobj = getThis(); char *filename; long filename_len = 0; - int results = MS_FALSE; + long results = MS_FALSE; int status = MS_FAILURE; php_map_object *php_map; diff --git a/mapserver.h b/mapserver.h index e2d396d..ec91380 100644 --- a/mapserver.h +++ b/mapserver.h @@ -2535,7 +2535,8 @@ void msPopulateTextSymbolForLabelAndString(textSymbolObj *ts, labelObj *l, char MS_DLL_EXPORT int WARN_UNUSED msDrawPieSlice(mapObj *map, imageObj *image, pointObj *p, styleObj *style, double radius, double start, double end); MS_DLL_EXPORT int WARN_UNUSED msDrawLabelBounds(mapObj *map, imageObj *image, label_bounds *bnds, styleObj *style, double scalefactor); - + MS_DLL_EXPORT void msOutlineRenderingPrepareStyle(styleObj *pStyle, mapObj *map, layerObj *layer, imageObj *image); + MS_DLL_EXPORT void msOutlineRenderingRestoreStyle(styleObj *pStyle, mapObj *map, layerObj *layer, imageObj *image); MS_DLL_EXPORT int WARN_UNUSED msDrawLabel(mapObj *map, imageObj *image, pointObj labelPnt, char *string, labelObj *label, double scalefactor); MS_DLL_EXPORT int WARN_UNUSED msDrawTextSymbol(mapObj *map, imageObj *image, pointObj labelPnt, textSymbolObj *ts); diff --git a/mapshape.c b/mapshape.c index e139b5e..174407c 100644 --- a/mapshape.c +++ b/mapshape.c @@ -2688,7 +2688,7 @@ int msSHPLayerNextShape(layerObj *layer, shapeObj *shape) msSHPReadShape(shpfile->hSHP, i, shape); if(shape->type == MS_SHAPE_NULL) { msFreeShape(shape); - msSHPLayerNextShape(layer, shape); /* skip NULL shapes */ + return msSHPLayerNextShape(layer, shape); /* skip NULL shapes */ } shape->numvalues = layer->numitems; shape->values = msDBFGetValueList(shpfile->hDBF, i, layer->iteminfo, layer->numitems); diff --git a/mapsymbol.c b/mapsymbol.c index 69b4a9f..6258ab2 100644 --- a/mapsymbol.c +++ b/mapsymbol.c @@ -318,6 +318,9 @@ void writeSymbol(symbolObj *s, FILE *stream) if(s->filled == MS_TRUE) msIO_fprintf(stream, " FILLED TRUE\n"); if(s->imagepath != NULL) msIO_fprintf(stream, " IMAGE \"%s\"\n", s->imagepath); + if(s->anchorpoint_y!=0.5 || s->anchorpoint_x!=0.5) { + msIO_fprintf(stream, " ANCHORPOINT %g %g\n", s->anchorpoint_x, s->anchorpoint_y); + } /* POINTS */ if(s->numpoints != 0) { diff --git a/mapwcs20.c b/mapwcs20.c index 69997cf..95351b8 100644 --- a/mapwcs20.c +++ b/mapwcs20.c @@ -3707,8 +3707,8 @@ static int msWCSGetCoverage20_FinalizeParamsObj(wcs20ParamsObjPtr params, wcs20A params->subsetcrs = msStrdup(crs); } } else if (!params->subsetcrs) { - /* default to imageCRS */ - params->subsetcrs = msStrdup("imageCRS"); + /* default to CRS of image */ + /* leave params->subsetcrs to null */ } return MS_SUCCESS; @@ -4126,7 +4126,7 @@ this request. Check wcs/ows_enable_request settings.", "msWCSGetCoverage20()", p msWCSClearCoverageMetadata20(&cm); msSetError(MS_WCSERR, "Error loading CRS %s.", - "msWCSGetCoverage20()", params->subsetcrs); + "msWCSGetCoverage20()", cm.srs); return msWCSException(map, "InvalidParameterValue", "projection", params->version); } @@ -4165,6 +4165,12 @@ this request. Check wcs/ows_enable_request settings.", "msWCSGetCoverage20()", p subsets = params->bbox; + /* if no subsetCRS was specified use the coverages CRS + (Requirement 27 of the WCS 2.0 specification) */ + if (!params->subsetcrs) { + params->subsetcrs = msStrdup(cm.srs); + } + if(EQUAL(params->subsetcrs, "imageCRS")) { /* subsets are in imageCRS; reproject them to real coordinates */ rectObj orig_bbox = subsets; diff --git a/mapwfslayer.c b/mapwfslayer.c index 6eca05a..fe6560e 100644 --- a/mapwfslayer.c +++ b/mapwfslayer.c @@ -658,7 +658,6 @@ int msPrepareWFSLayerRequest(int nLayerId, mapObj *map, layerObj *lp, pasReqInfo, *numRequests, map, "FO") != MS_SUCCESS) { if (psParams) { msWFSFreeParamsObj(psParams); - free(psParams); } return MS_FAILURE; } @@ -690,7 +689,6 @@ int msPrepareWFSLayerRequest(int nLayerId, mapObj *map, layerObj *lp, if (psParams) { msWFSFreeParamsObj(psParams); - free(psParams); } return nStatus; diff --git a/mapwms.c b/mapwms.c index 7418bbf..17a3a09 100644 --- a/mapwms.c +++ b/mapwms.c @@ -326,9 +326,15 @@ int msWMSApplyTime(mapObj *map, int version, char *time, char *wms_exception_for */ void msWMSPrepareNestedGroups(mapObj* map, int nVersion, char*** nestedGroups, int* numNestedGroups, int* isUsedInNestedGroup) { - int i, j, k; + int i, k; const char* groups; char* errorMsg; + //Create array to hold unique groups + int maxgroups = 2000; + int maxgroupiter = 1; + char** uniqgroups = malloc(maxgroups * sizeof(char*)); + int uniqgroupcount = 0; + for (i = 0; i < map->numlayers; i++) { nestedGroups[i] = NULL; /* default */ @@ -351,24 +357,42 @@ void msWMSPrepareNestedGroups(mapObj* map, int nVersion, char*** nestedGroups, i } else { /* split into subgroups. Start at address + 1 because the first '/' would cause an extra empty group */ nestedGroups[i] = msStringSplit(groups + 1, '/', &numNestedGroups[i]); - /* */ - for (j = 0; j < map->numlayers; j++) { - if (isUsedInNestedGroup[j]) - continue; - - for (k=0; k<numNestedGroups[i]; k++) { - if ( GET_LAYER(map, j)->name && strcasecmp(GET_LAYER(map, j)->name, nestedGroups[i][k]) == 0 ) { - isUsedInNestedGroup[j] = 1; + /* Iterate through the groups and add them to the unique groups array */ + for (k=0; k<numNestedGroups[i]; k++) { + int found ,l = 0; + found = 0; + for (l=0; l<uniqgroupcount; l++) { + if ( strcasecmp(uniqgroups[l], nestedGroups[i][k]) == 0 ){ + found = 1; break; } } - } + if(found == 0){ + uniqgroups[uniqgroupcount] = nestedGroups[i][k]; + uniqgroupcount++; + // Does need only when maximum unique groups exceed 2000 + if ( uniqgroupcount == (maxgroups*maxgroupiter)){ + uniqgroups = realloc(uniqgroups, (uniqgroupcount + maxgroups) * sizeof(char*)); + maxgroupiter++; + } + } + } + } + } + } + } + /* Iterate through layers to find out whether they are in any of the nested groups */ + for (i = 0; i < map->numlayers; i++) { + for (k=0; k<uniqgroupcount; k++) { + if ( strcasecmp(GET_LAYER(map, i)->name ,uniqgroups[k]) == 0 ){ + isUsedInNestedGroup[i] = 1; + break; } - } - } + } } } + /* ** Validate that a given dimension is inside the extents defined */ diff --git a/scripts/vagrant/packages.sh b/scripts/vagrant/packages.sh index 74d41d0..228fcd5 100755 --- a/scripts/vagrant/packages.sh +++ b/scripts/vagrant/packages.sh @@ -14,6 +14,6 @@ apt-get -y upgrade apt-get install -q -y git build-essential pkg-config cmake libgeos-dev rake \ libpq-dev python-all-dev libproj-dev libxml2-dev postgis php5-dev \ postgresql-server-dev-9.1 postgresql-9.1-postgis-2.1 vim bison flex swig \ - librsvg2-dev libpng12-dev libjpeg-dev libgif-dev libgd2-xpm-dev \ + librsvg2-dev libpng12-dev libjpeg-dev libgif-dev \ libfreetype6-dev libfcgi-dev libcurl4-gnutls-dev libcairo2-dev \ libgdal1-dev libfribidi-dev libexempi-dev -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mapserver.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel