Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package mapserver for openSUSE:Factory checked in at 2026-03-28 20:14:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/mapserver (Old) and /work/SRC/openSUSE:Factory/.mapserver.new.8177 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mapserver" Sat Mar 28 20:14:02 2026 rev:11 rq:1343220 version:8.6.1 Changes: -------- --- /work/SRC/openSUSE:Factory/mapserver/mapserver.changes 2026-03-03 15:31:39.450841657 +0100 +++ /work/SRC/openSUSE:Factory/.mapserver.new.8177/mapserver.changes 2026-03-28 20:15:45.131368804 +0100 @@ -1,0 +2,15 @@ +Fri Mar 27 11:52:01 UTC 2026 - Jan Engelhardt <[email protected]> + +- Update to release 8.6.1 + * msSLDParseRasterSymbolizer: fix potential heap buffer overflow + [boo#1260869] [CVE-2026-33721] + * GetFeatureInfo with IDENTIFY CLASSAUTO: take into account + SYMBOL.ANCHORPOINT + * WCS 2.0: fix issue when input raster in a rotated pole lon/lat + CRS with lon_0 > 180 + * UVRaster: fix WMS-Time support on layers with TILEINDEX + pointing to a shapefile + * WMS GetCapabilities response: use group title and abstract when + using wms_layer_group instead of GROUP + +------------------------------------------------------------------- Old: ---- mapserver-8.6.0.tar.gz New: ---- mapserver-8.6.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mapserver.spec ++++++ --- /var/tmp/diff_new_pack.OYgnzZ/_old 2026-03-28 20:15:45.615388780 +0100 +++ /var/tmp/diff_new_pack.OYgnzZ/_new 2026-03-28 20:15:45.619388945 +0100 @@ -33,7 +33,7 @@ %{?sle15_python_module_pythons} Name: mapserver -Version: 8.6.0 +Version: 8.6.1 Release: 0 Summary: Environment for building spatially-enabled internet applications License: MIT @@ -50,8 +50,13 @@ BuildRequires: cmake >= 2.4 BuildRequires: freetype2-devel BuildRequires: fribidi-devel +%if 0%{?suse_version} < 1590 +BuildRequires: gcc13 +BuildRequires: gcc13-c++ +%else BuildRequires: gcc BuildRequires: gcc-c++ +%endif BuildRequires: gd-devel >= 2.0.16 BuildRequires: giflib-devel BuildRequires: harfbuzz-devel @@ -205,14 +210,18 @@ #Pre export the PREFIX ( having it on the command line doesn't expand correctly for #dynamic postgresql location export CMAKE_PREFIX_PATH="%{_includedir}:%{_includedir}/fastcgi:%%(pg_config --includedir):%%(pg_config --includedir-server):%%(pg_config --libdir)" +%if 0%{?suse_version} < 1590 +export CC=gcc-13 CXX=g++-13 +%endif export CFLAGS="%{optflags} -fno-strict-aliasing" export CXXFLAGS="%{optflags} -fno-strict-aliasing" #specify all options and play with true/false #so we always know which option are included in our build. %{python_expand # +origpwd="$PWD" mkdir b$python -pushd b$python +cd b$python cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \ -DCMAKE_SKIP_RPATH=ON \ -DCMAKE_INSTALL_LIBDIR=%{_libdir} \ @@ -276,7 +285,7 @@ .. %make_build -popd +cd "$origpwd" } %check @@ -286,9 +295,9 @@ mkdir -p %{buildroot}/%{_cgibindir} %{python_expand # -pushd b$python +cd b$python %make_install -popd +cd - } %if 0%{with php} ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.OYgnzZ/_old 2026-03-28 20:15:45.647390101 +0100 +++ /var/tmp/diff_new_pack.OYgnzZ/_new 2026-03-28 20:15:45.651390266 +0100 @@ -1,5 +1,5 @@ -mtime: 1772469939 -commit: 38fd2136019976e263221ce355a9c8470af35e741a692dc777b9949702b66ca6 +mtime: 1774624531 +commit: 529d913ae5b120e667a50862589bb50bf593708fa299424c777fac7e7b090b9e url: https://src.opensuse.org/jengelh/mapserver revision: master ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-03-27 16:15:44.000000000 +0100 @@ -0,0 +1 @@ +.osc ++++++ mapserver-8.6.0.tar.gz -> mapserver-8.6.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/CITATION.cff new/mapserver-8.6.1/CITATION.cff --- old/mapserver-8.6.0/CITATION.cff 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/CITATION.cff 2026-03-23 16:36:42.000000000 +0100 @@ -1,8 +1,8 @@ cff-version: 1.2.0 title: MapServer message: If you use this software, please cite it using the metadata from this file. -version: 8.6.0 -date-released: 2025-12-03 +version: 8.6.1 +date-released: 2026-03-23 abstract: MapServer is an Open Source platform for publishing spatial data and interactive mapping applications to the web. type: software authors: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/CMakeLists.txt new/mapserver-8.6.1/CMakeLists.txt --- old/mapserver-8.6.0/CMakeLists.txt 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/CMakeLists.txt 2026-03-23 16:36:42.000000000 +0100 @@ -17,7 +17,7 @@ set (MapServer_VERSION_MAJOR 8) set (MapServer_VERSION_MINOR 6) -set (MapServer_VERSION_REVISION 0) +set (MapServer_VERSION_REVISION 1) set (MapServer_VERSION_SUFFIX "") # Set C++ version @@ -1049,6 +1049,9 @@ add_definitions(-D_XKEYCHECK_H=1) endif(WIN32) +# Defines M_PI in particular +add_definitions(-D_USE_MATH_DEFINES) + #INSTALL(FILES mapserver-api.h ${PROJECT_BINARY_DIR}/mapserver-version.h DESTINATION include) if(USE_ORACLE_PLUGIN) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/HISTORY.md new/mapserver-8.6.1/HISTORY.md --- old/mapserver-8.6.0/HISTORY.md 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/HISTORY.md 2026-03-23 16:36:42.000000000 +0100 @@ -13,6 +13,15 @@ The online Migration Guide can be found at https://mapserver.org/MIGRATION_GUIDE.html +8.6.1 release (2026-03-23) +-------------------------- + +- security: fix potential heap buffer overflow (#7461) + +- No longer depend on GDAL's cpl_port.h MIN/MAX/ABS macros (#7438) + +see detailed changelog for other fixes + 8.6.0 release (2025-12-03) -------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/LICENSE.md new/mapserver-8.6.1/LICENSE.md --- old/mapserver-8.6.0/LICENSE.md 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/LICENSE.md 2026-03-23 16:36:42.000000000 +0100 @@ -4,7 +4,7 @@ MapServer General ----------------- -Copyright (c) 2008-2025 Open Source Geospatial Foundation. +Copyright (c) 2008-2026 Open Source Geospatial Foundation. Copyright (c) 1996-2008 Regents of the University of Minnesota. Permission is hereby granted, free of charge, to any person obtaining a copy diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/ci/ubuntu/build.sh new/mapserver-8.6.1/ci/ubuntu/build.sh --- old/mapserver-8.6.0/ci/ubuntu/build.sh 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/ci/ubuntu/build.sh 2026-03-23 16:36:42.000000000 +0100 @@ -47,10 +47,10 @@ echo "PHP version" php -v PHPVersionMinor=$(php --version | head -n 1 | cut -d " " -f 2 | cut -c 1,3) -if [ ${PHPVersionMinor} -gt 82 ]; then - cd php && curl -LO https://phar.phpunit.de/phpunit-12.phar +if [ ${PHPVersionMinor} -gt 83 ]; then + cd php && curl -LO https://phar.phpunit.de/phpunit-13.phar echo "PHPUnit version" - php phpunit-12.phar --version + php phpunit-13.phar --version else cd php && curl -LO https://phar.phpunit.de/phpunit-10.phar echo "PHPUnit version" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/idw.c new/mapserver-8.6.1/src/idw.c --- old/mapserver-8.6.0/src/idw.c 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/idw.c 2026-03-23 16:36:42.000000000 +0100 @@ -69,7 +69,7 @@ if (interpParamsProcessing) { interpParams->radius = atof(interpParamsProcessing); } else { - interpParams->radius = MAX(layer->map->width, layer->map->height); + interpParams->radius = MS_MAX(layer->map->width, layer->map->height); } interpParamsProcessing = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapcontour.c new/mapserver-8.6.1/src/mapcontour.c --- old/mapserver-8.6.0/src/mapcontour.c 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapcontour.c 2026-03-23 16:36:42.000000000 +0100 @@ -59,6 +59,10 @@ OGRDataSourceH hOGRDS; double cellsize; + /* set if the map->extent and map->projection are + valid in msContourLayerWhichShapes() */ + mapObj *mapToUseForWhichShapes; + } contourLayerInfo; static int msContourLayerInitItemInfo(layerObj *layer) { @@ -226,12 +230,7 @@ src_xsize = GDALGetRasterXSize(clinfo->hOrigDS); src_ysize = GDALGetRasterYSize(clinfo->hOrigDS); - /* set the Dataset extent */ msGetGDALGeoTransform(clinfo->hOrigDS, map, layer, adfGeoTransform); - clinfo->extent.minx = adfGeoTransform[0]; - clinfo->extent.maxy = adfGeoTransform[3]; - clinfo->extent.maxx = adfGeoTransform[0] + src_xsize * adfGeoTransform[1]; - clinfo->extent.miny = adfGeoTransform[3] + src_ysize * adfGeoTransform[5]; if (layer->transform) { if (layer->debug) @@ -240,12 +239,41 @@ InvGeoTransform(adfGeoTransform, adfInvGeoTransform); mapRect = rect; - if (map->cellsize == 0) { - map->cellsize = msAdjustExtent(&mapRect, map->width, map->height); - } - map_cellsize_x = map_cellsize_y = map->cellsize; + /* if necessary, project the searchrect to source coords */ if (msProjectionsDiffer(&(map->projection), &(layer->projection))) { + + /* Deal with request in WebMercator, overlapping the anti-meridian, + * and raster in geographic coordinates within (approximatively) + * [-180,180] longitude range. + */ + double map_cellsize_x_override = 0; + if (clinfo->mapToUseForWhichShapes) { + mapRect = clinfo->mapToUseForWhichShapes->extent; + const double WEB_MERCATOR_MAX_X = 20037508.34; + if (clinfo->mapToUseForWhichShapes->projection.numargs == 1 && + strcmp(clinfo->mapToUseForWhichShapes->projection.args[0], + "init=epsg:3857") == 0 && + (clinfo->mapToUseForWhichShapes->extent.minx < + -WEB_MERCATOR_MAX_X || + clinfo->mapToUseForWhichShapes->extent.maxx > + WEB_MERCATOR_MAX_X) && + msProjIsGeographicCRS(&layer->projection) && + clinfo->extent.minx > -180 - 2 * adfGeoTransform[1] && + clinfo->extent.maxx < 180 + 2 * adfGeoTransform[1]) { + + // First do a reprojection with +over to compute cellsize_x + msProjectRect(&map->projection, &layer->projection, &mapRect); + map_cellsize_x_override = + MS_CELLSIZE(mapRect.minx, mapRect.maxx, map->width); + + // Then clamp to +/- 180 deg + mapRect = clinfo->mapToUseForWhichShapes->extent; + mapRect.minx = MS_MAX(mapRect.minx, -WEB_MERCATOR_MAX_X); + mapRect.maxx = MS_MIN(mapRect.maxx, WEB_MERCATOR_MAX_X); + } + } + if (msProjectRect(&map->projection, &layer->projection, &mapRect) != MS_SUCCESS) { msDebug("msContourLayerReadRaster(%s): unable to reproject map request " @@ -254,7 +282,10 @@ return MS_FAILURE; } - map_cellsize_x = MS_CELLSIZE(mapRect.minx, mapRect.maxx, map->width); + map_cellsize_x = + map_cellsize_x_override != 0 + ? map_cellsize_x_override + : MS_CELLSIZE(mapRect.minx, mapRect.maxx, map->width); map_cellsize_y = MS_CELLSIZE(mapRect.miny, mapRect.maxy, map->height); /* if the projection failed to project the extent requested, we need to @@ -279,6 +310,11 @@ map_cellsize_y = MS_CONVERT_UNIT( src_unit, dst_unit, MS_CELLSIZE(rect.miny, rect.maxy, map->height)); } + } else { + if (map->cellsize == 0) { + map->cellsize = msAdjustExtent(&mapRect, map->width, map->height); + } + map_cellsize_x = map_cellsize_y = map->cellsize; } if (map_cellsize_x == 0 || map_cellsize_y == 0) { @@ -309,19 +345,21 @@ * there is no point in interpolating the data for contours in this case. */ - virtual_grid_step_x = (int)floor(map_cellsize_x / ABS(adfGeoTransform[1])); + virtual_grid_step_x = + (int)floor(map_cellsize_x / MS_ABS(adfGeoTransform[1])); if (virtual_grid_step_x < 1) virtual_grid_step_x = 1; /* Do not interpolate data if grid sampling step < 1 */ - virtual_grid_step_y = (int)floor(map_cellsize_y / ABS(adfGeoTransform[5])); + virtual_grid_step_y = + (int)floor(map_cellsize_y / MS_ABS(adfGeoTransform[5])); if (virtual_grid_step_y < 1) virtual_grid_step_y = 1; /* Do not interpolate data if grid sampling step < 1 */ /* target cellsize is a multiple of raw data cellsize based on grid step*/ - dst_cellsize_x = ABS(adfGeoTransform[1]) * virtual_grid_step_x; - dst_cellsize_y = ABS(adfGeoTransform[5]) * virtual_grid_step_y; + dst_cellsize_x = MS_ABS(adfGeoTransform[1]) * virtual_grid_step_x; + dst_cellsize_y = MS_ABS(adfGeoTransform[5]) * virtual_grid_step_y; /* Compute overlap between source and target views */ @@ -750,6 +788,19 @@ } else clinfo->hOrigDS = NULL; + if (clinfo->hOrigDS) { + const int src_xsize = GDALGetRasterXSize(clinfo->hOrigDS); + const int src_ysize = GDALGetRasterYSize(clinfo->hOrigDS); + + /* set the Dataset extent */ + double adfGeoTransform[6]; + msGetGDALGeoTransform(clinfo->hOrigDS, layer->map, layer, adfGeoTransform); + clinfo->extent.minx = adfGeoTransform[0]; + clinfo->extent.maxy = adfGeoTransform[3]; + clinfo->extent.maxx = adfGeoTransform[0] + src_xsize * adfGeoTransform[1]; + clinfo->extent.miny = adfGeoTransform[3] + src_ysize * adfGeoTransform[5]; + } + msReleaseLock(TLOCK_GDAL); if (clinfo->hOrigDS == NULL) { @@ -758,24 +809,6 @@ return MS_FAILURE; } - /* Open the raster source */ - if (msContourLayerReadRaster(layer, layer->map->extent) != MS_SUCCESS) - return MS_FAILURE; - - /* Generate Contour Dataset */ - if (msContourLayerGenerateContour(layer) != MS_SUCCESS) - return MS_FAILURE; - - if (clinfo->hDS) { - GDALClose(clinfo->hDS); - clinfo->hDS = NULL; - free(clinfo->buffer); - } - - /* Open our virtual ogr layer */ - if (clinfo->hOGRDS && (msLayerOpen(&clinfo->ogrLayer) != MS_SUCCESS)) - return MS_FAILURE; - return MS_SUCCESS; } @@ -833,7 +866,13 @@ layer->items[layer->numitems++] = msStrdup(elevItem); } - return msLayerGetItems(&clinfo->ogrLayer); + return MS_SUCCESS; +} + +void msContourLayerUseMapExtentAndProjectionForNextWhichShapes(layerObj *layer, + mapObj *map) { + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + clinfo->mapToUseForWhichShapes = map; } int msContourLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { @@ -900,7 +939,8 @@ clinfo->ogrLayer.items[i] = msStrdup(layer->items[i]); } - return msLayerWhichShapes(&clinfo->ogrLayer, rect, isQuery); + const rectObj invalid_rect = MS_INIT_INVALID_RECT; + return msLayerWhichShapes(&clinfo->ogrLayer, invalid_rect, isQuery); } int msContourLayerGetShape(layerObj *layer, shapeObj *shape, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapcopy.c new/mapserver-8.6.1/src/mapcopy.c --- old/mapserver-8.6.0/src/mapcopy.c 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapcopy.c 2026-03-23 16:36:42.000000000 +0100 @@ -56,7 +56,7 @@ **********************************************************************/ int msCopyProjectionExtended(projectionObj *dst, const projectionObj *src, - char **args, int num_args) { + const char *const *args, int num_args) { MS_COPYSTELEM(numargs); MS_COPYSTELEM(gt); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapdraw.c new/mapserver-8.6.1/src/mapdraw.c --- old/mapserver-8.6.0/src/mapdraw.c 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapdraw.c 2026-03-23 16:36:42.000000000 +0100 @@ -1163,6 +1163,8 @@ searchrect = msUVRASTERGetSearchRect(layer, map); bDone = MS_TRUE; + } else if (layer->connectiontype == MS_CONTOUR) { + msContourLayerUseMapExtentAndProjectionForNextWhichShapes(layer, map); } if (!bDone) @@ -1183,6 +1185,8 @@ msUVRASTERLayerUseMapExtentAndProjectionForNextWhichShapes(layer, NULL); } else if (layer->connectiontype == MS_RASTER_LABEL) { msRasterLabelLayerUseMapExtentAndProjectionForNextWhichShapes(layer, NULL); + } else if (layer->connectiontype == MS_CONTOUR) { + msContourLayerUseMapExtentAndProjectionForNextWhichShapes(layer, NULL); } if (status == MS_DONE) { /* no overlap */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapdrawgdal.c new/mapserver-8.6.1/src/mapdrawgdal.c --- old/mapserver-8.6.0/src/mapdrawgdal.c 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapdrawgdal.c 2026-03-23 16:36:42.000000000 +0100 @@ -601,7 +601,7 @@ const int j = bScaleColors - ? MAX(0, MIN(255, (int)((i - dfScaleMin) * dfScaleRatio))) + ? MS_MAX(0, MS_MIN(255, (int)((i - dfScaleMin) * dfScaleRatio))) : i; pixel.red = sEntry.c1; @@ -685,7 +685,7 @@ GDALGetColorEntryAsRGB(hColorMap, i, &sEntry); const int j = bScaleColors - ? MAX(0, MIN(255, (int)((i - dfScaleMin) * dfScaleRatio))) + ? MS_MAX(0, MS_MIN(255, (int)((i - dfScaleMin) * dfScaleRatio))) : i; if (sEntry.c4 != 0 && @@ -1497,7 +1497,7 @@ pabyBuffer = pabyWholeBuffer + iColorIndex * nPixelCount; if (iColorIndex == 0 && bGotNoData) - *ppbIsNoDataBuffer = (bool *)calloc(nPixelCount, 1); + *ppbIsNoDataBuffer = (bool *)calloc(nPixelCount, sizeof(bool)); for (i = 0; i < nPixelCount; i++) { float fScaledValue; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapogcsld.cpp new/mapserver-8.6.1/src/mapogcsld.cpp --- old/mapserver-8.6.0/src/mapogcsld.cpp 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapogcsld.cpp 2026-03-23 16:36:42.000000000 +0100 @@ -2894,7 +2894,7 @@ } else if (strcasecmp(psNode->pszValue, "Threshold") == 0) { papszThresholds[nThresholds] = psNode->psChild->pszValue; nThresholds++; - if (nValues == nMaxThreshold) { + if (nThresholds == nMaxThreshold) { nMaxThreshold += 100; papszThresholds = (char **)msSmallRealloc( papszThresholds, sizeof(char *) * nMaxThreshold); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapogr.cpp new/mapserver-8.6.1/src/mapogr.cpp --- old/mapserver-8.6.0/src/mapogr.cpp 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapogr.cpp 2026-03-23 16:36:42.000000000 +0100 @@ -33,6 +33,8 @@ #include "mapproject.h" #include "mapthread.h" #include "mapows.h" + +#include <algorithm> #include <string> #include <vector> @@ -2223,10 +2225,10 @@ * no _efficient_ way to do that with OGR. * ------------------------------------------------------------------ */ if (psInfo->rect_is_defined) { - rect.minx = MAX(psInfo->rect.minx, rect.minx); - rect.miny = MAX(psInfo->rect.miny, rect.miny); - rect.maxx = MIN(psInfo->rect.maxx, rect.maxx); - rect.maxy = MIN(psInfo->rect.maxy, rect.maxy); + rect.minx = std::max(psInfo->rect.minx, rect.minx); + rect.miny = std::max(psInfo->rect.miny, rect.miny); + rect.maxx = std::min(psInfo->rect.maxx, rect.maxx); + rect.maxy = std::min(psInfo->rect.maxy, rect.maxy); bIsValidRect = true; } psInfo->rect = rect; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mappostgis.cpp new/mapserver-8.6.1/src/mappostgis.cpp --- old/mapserver-8.6.0/src/mappostgis.cpp 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mappostgis.cpp 2026-03-23 16:36:42.000000000 +0100 @@ -54,9 +54,6 @@ ** */ -/* required for MSVC */ -#define _USE_MATH_DEFINES - #include <assert.h> #include <string.h> #include <math.h> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapproject.c new/mapserver-8.6.1/src/mapproject.c --- old/mapserver-8.6.0/src/mapproject.c 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapproject.c 2026-03-23 16:36:42.000000000 +0100 @@ -1056,7 +1056,11 @@ } } - if (!(!in->gt.need_geotransform && !msProjIsGeographicCRS(in) && + const bool isRotatedPole = + msProjIsGeographicCRS(in) && in->proj && + proj_crs_is_derived(in->proj_ctx->proj_ctx, in->proj); + if (!(!in->gt.need_geotransform && + (!msProjIsGeographicCRS(in) || isRotatedPole) && (msProjIsGeographicCRS(out) || (out->numargs == 1 && strcmp(out->args[0], "init=epsg:3857") == 0)))) { reprojector->lineCuttingCase = LINE_CUTTING_NONE; @@ -1065,6 +1069,7 @@ int srcIsPolar; double extremeLongEasting; + double extremeLatNorthing; if (msProjIsGeographicCRS(out)) { pointObj p; double gt3 = out->gt.need_geotransform ? out->gt.geotransform[3] : 0.0; @@ -1075,6 +1080,7 @@ srcIsPolar = msProjectPointEx(reprojector, &p) == MS_SUCCESS && fabs(gt3 + p.x * gt4 + p.y * gt5 - 90) < 1e-8; extremeLongEasting = 180; + extremeLatNorthing = 90; } else { pointObj p1; pointObj p2; @@ -1087,44 +1093,143 @@ msProjectPointEx(reprojector, &p2) == MS_SUCCESS && fabs((p1.x - p2.x) * gt1) > 20e6; extremeLongEasting = 20037508.3427892; + extremeLatNorthing = extremeLongEasting; } - if (!srcIsPolar) { + if (!srcIsPolar && !isRotatedPole) { reprojector->lineCuttingCase = LINE_CUTTING_NONE; return reprojector->lineCuttingCase; } pointObj p = {0}; // initialize - double invgt0 = out->gt.need_geotransform ? out->gt.invgeotransform[0] : 0.0; - double invgt1 = out->gt.need_geotransform ? out->gt.invgeotransform[1] : 1.0; - double invgt3 = out->gt.need_geotransform ? out->gt.invgeotransform[3] : 0.0; - double invgt4 = out->gt.need_geotransform ? out->gt.invgeotransform[4] : 0.0; + const double invgt0 = + out->gt.need_geotransform ? out->gt.invgeotransform[0] : 0.0; + const double invgt1 = + out->gt.need_geotransform ? out->gt.invgeotransform[1] : 1.0; + const double invgt3 = + out->gt.need_geotransform ? out->gt.invgeotransform[3] : 0.0; + const double invgt4 = + out->gt.need_geotransform ? out->gt.invgeotransform[4] : 0.0; + const double invgt5 = + out->gt.need_geotransform ? out->gt.invgeotransform[5] : 1.0; lineObj newLine = {0, NULL}; - p.x = invgt0 + -extremeLongEasting * (1 - EPS) * invgt1; - p.y = invgt3 + -extremeLongEasting * (1 - EPS) * invgt4; - /* coverity[swapped_arguments] */ - msProjectPoint(out, in, &p); - pointObj first = p; - msAddPointToLine(&newLine, &p); - - p.x = invgt0 + extremeLongEasting * (1 - EPS) * invgt1; - p.y = invgt3 + extremeLongEasting * (1 - EPS) * invgt4; - /* coverity[swapped_arguments] */ - msProjectPoint(out, in, &p); - msAddPointToLine(&newLine, &p); - - p.x = 0; - p.y = 0; - msAddPointToLine(&newLine, &p); + if (isRotatedPole) { + // Thresholds determined experimentally... + const double EPSILON = 1e-5; + if (msProjIsGeographicCRS(out)) { + const int stepCountMiddleLat = 400; + const int stepCountHighLat = 100; + const double middleLat = 80; + const double poleLat = 90; + + for (int j = 0; j <= stepCountHighLat; j++) { + p.x = invgt0 + extremeLongEasting * (1 - EPSILON) * invgt1; + p.y = + invgt3 + + (-poleLat + (poleLat - middleLat) * j / stepCountHighLat) * invgt5; + /* coverity[swapped_arguments] */ + msProjectPoint(out, in, &p); + msAddPointToLine(&newLine, &p); + } + + for (int j = 0; j <= stepCountMiddleLat; j++) { + p.x = invgt0 + extremeLongEasting * (1 - EPSILON) * invgt1; + p.y = invgt3 + + (-middleLat + (2 * middleLat) * j / stepCountMiddleLat) * invgt5; + /* coverity[swapped_arguments] */ + msProjectPoint(out, in, &p); + msAddPointToLine(&newLine, &p); + } + + for (int j = 0; j <= stepCountHighLat; ++j) { + p.x = invgt0 + extremeLongEasting * (1 - EPSILON) * invgt1; + p.y = + invgt3 + + (middleLat + (poleLat - middleLat) * j / stepCountHighLat) * invgt5; + /* coverity[swapped_arguments] */ + msProjectPoint(out, in, &p); + msAddPointToLine(&newLine, &p); + } + + for (int j = stepCountHighLat; j >= 0; --j) { + p.x = invgt0 - extremeLongEasting * (1 - EPSILON) * invgt1; + p.y = + invgt3 + + (middleLat + (poleLat - middleLat) * j / stepCountHighLat) * invgt5; + /* coverity[swapped_arguments] */ + msProjectPoint(out, in, &p); + msAddPointToLine(&newLine, &p); + } + + for (int j = stepCountMiddleLat; j >= 0; --j) { + p.x = invgt0 - extremeLongEasting * (1 - EPSILON) * invgt1; + p.y = invgt3 + + (-middleLat + (2 * middleLat) * j / stepCountMiddleLat) * invgt5; + /* coverity[swapped_arguments] */ + msProjectPoint(out, in, &p); + msAddPointToLine(&newLine, &p); + } + + for (int j = stepCountHighLat; j >= 0; --j) { + p.x = invgt0 - extremeLongEasting * (1 - EPSILON) * invgt1; + p.y = + invgt3 + + (-poleLat + (poleLat - middleLat) * j / stepCountHighLat) * invgt5; + /* coverity[swapped_arguments] */ + msProjectPoint(out, in, &p); + msAddPointToLine(&newLine, &p); + } + } else { + const int stepCountHalf = 200; + for (int j = 0; j <= 2 * stepCountHalf; j++) { + p.x = invgt0 + extremeLongEasting * (1 - EPSILON) * invgt1; + p.y = invgt3 + + (-extremeLatNorthing + extremeLatNorthing * j / stepCountHalf) * + invgt5; + /* coverity[swapped_arguments] */ + msProjectPoint(out, in, &p); + msAddPointToLine(&newLine, &p); + } + + for (int j = 2 * stepCountHalf; j >= 0; j--) { + p.x = invgt0 - extremeLongEasting * (1 - EPSILON) * invgt1; + p.y = invgt3 + + (-extremeLatNorthing + extremeLatNorthing * j / stepCountHalf) * + invgt5; + /* coverity[swapped_arguments] */ + msProjectPoint(out, in, &p); + msAddPointToLine(&newLine, &p); + } + } - msAddPointToLine(&newLine, &first); + pointObj firstPoint = newLine.point[0]; + msAddPointToLine(&newLine, &firstPoint); + } else { + p.x = invgt0 + -extremeLongEasting * (1 - EPS) * invgt1; + p.y = invgt3 + -extremeLongEasting * (1 - EPS) * invgt4; + /* coverity[swapped_arguments] */ + msProjectPoint(out, in, &p); + pointObj first = p; + msAddPointToLine(&newLine, &p); + + p.x = invgt0 + extremeLongEasting * (1 - EPS) * invgt1; + p.y = invgt3 + extremeLongEasting * (1 - EPS) * invgt4; + msProjectPoint(out, in, &p); + msAddPointToLine(&newLine, &p); + + p.x = 0; + p.y = 0; + msAddPointToLine(&newLine, &p); + + msAddPointToLine(&newLine, &first); + } msInitShape(&(reprojector->splitShape)); reprojector->splitShape.type = MS_SHAPE_POLYGON; msAddLineDirectly(&(reprojector->splitShape), &newLine); - reprojector->lineCuttingCase = LINE_CUTTING_FROM_POLAR; + reprojector->lineCuttingCase = LINE_CUTTING_WITH_SHAPE; return reprojector->lineCuttingCase; } #endif @@ -1219,7 +1324,7 @@ int use_splitShape = MS_FALSE; int use_splitShape_check_intersects = MS_FALSE; if (shape->type == MS_SHAPE_LINE && - msProjectGetLineCuttingCase(reprojector) == LINE_CUTTING_FROM_POLAR) { + msProjectGetLineCuttingCase(reprojector) == LINE_CUTTING_WITH_SHAPE) { use_splitShape = MS_TRUE; use_splitShape_check_intersects = MS_TRUE; } else if (shape->type == MS_SHAPE_LINE && @@ -1864,7 +1969,7 @@ /************************************************************************/ int msProjectRect(projectionObj *in, projectionObj *out, rectObj *rect) { - char *over = "+over"; + const char *over = "+over"; int ret; int bFreeInOver = MS_FALSE; int bFreeOutOver = MS_FALSE; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapproject.h new/mapserver-8.6.1/src/mapproject.h --- old/mapserver-8.6.0/src/mapproject.h 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapproject.h 2026-03-23 16:36:42.000000000 +0100 @@ -49,7 +49,7 @@ typedef enum { LINE_CUTTING_UNKNOWN = -1, LINE_CUTTING_NONE = 0, - LINE_CUTTING_FROM_POLAR = 1, + LINE_CUTTING_WITH_SHAPE = 1, LINE_CUTTING_FROM_LONGLAT_WRAP0 = 2 } msLineCuttingCase; #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapquery.cpp new/mapserver-8.6.1/src/mapquery.cpp --- old/mapserver-8.6.0/src/mapquery.cpp 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapquery.cpp 2026-03-23 16:36:42.000000000 +0100 @@ -1981,6 +1981,8 @@ int classindex = -1; styleObj *style = nullptr; imageObj *cachedImage = nullptr; + double center_x_in_map = 0; + double center_y_in_map = 0; SearchSymbol(mapObj *map) : m_map(map) {} ~SearchSymbol() { @@ -2014,6 +2016,8 @@ classindex = other.classindex; std::swap(style, other.style); std::swap(cachedImage, other.cachedImage); + center_x_in_map = other.center_x_in_map; + center_y_in_map = other.center_y_in_map; } SearchSymbol &operator=(SearchSymbol &&other) { m_map = other.m_map; @@ -2021,6 +2025,8 @@ classindex = other.classindex; std::swap(style, other.style); std::swap(cachedImage, other.cachedImage); + center_x_in_map = other.center_x_in_map; + center_y_in_map = other.center_y_in_map; return *this; } }; @@ -2066,16 +2072,21 @@ computeSymbolStyle(&s, style, symbol, style->scalefactor, resolutionfactor); + double pos_offset_x = 0; + double pos_offset_y = 0; + if (msAdjustMarkerPos(map, style, symbol, &pos_offset_x, + &pos_offset_y, style->scalefactor, + s.rotation) != MS_SUCCESS) { + continue; + } + double center_x = MS_MAP2IMAGE_X(map->query.point.x, map->extent.minx, cellx); double center_y = MS_MAP2IMAGE_Y(map->query.point.y, map->extent.maxy, celly); - if (msAdjustMarkerPos(map, style, symbol, ¢er_x, ¢er_y, - style->scalefactor, - s.rotation) != MS_SUCCESS) { - continue; - } + center_x -= pos_offset_x; + center_y -= pos_offset_y; center_x = MS_IMAGE2MAP_X(center_x, map->extent.minx, cellx); center_y = MS_IMAGE2MAP_Y(center_y, map->extent.maxy, celly); @@ -2116,6 +2127,8 @@ SearchSymbol searchSymbol(map); searchSymbol.style = style; searchSymbol.classindex = classindex; + searchSymbol.center_x_in_map = center_x; + searchSymbol.center_y_in_map = center_y; lineObj line = {0, NULL}; line.numpoints = 5; @@ -2135,14 +2148,18 @@ searchSymbols.push_back(std::move(searchSymbol)); - rect.minx = MIN(rect.minx, - center_x + MIN(MIN(P1_X, P2_X), MIN(P3_X, P4_X))); - rect.miny = MIN(rect.miny, - center_y + MIN(MIN(P1_Y, P2_Y), MIN(P3_Y, P4_Y))); - rect.maxx = MAX(rect.maxx, - center_x + MAX(MAX(P1_X, P2_X), MAX(P3_X, P4_X))); - rect.maxy = MAX(rect.maxy, - center_y + MAX(MAX(P1_Y, P2_Y), MAX(P3_Y, P4_Y))); + rect.minx = + std::min(rect.minx, center_x + std::min(std::min(P1_X, P2_X), + std::min(P3_X, P4_X))); + rect.miny = + std::min(rect.miny, center_y + std::min(std::min(P1_Y, P2_Y), + std::min(P3_Y, P4_Y))); + rect.maxx = + std::max(rect.maxx, center_x + std::max(std::max(P1_X, P2_X), + std::max(P3_X, P4_X))); + rect.maxy = + std::max(rect.maxy, center_y + std::max(std::max(P1_Y, P2_Y), + std::max(P3_Y, P4_Y))); } } }; @@ -2327,10 +2344,10 @@ pointObj imCenter; imCenter.x = searchSymbol.cachedImage->width / 2; imCenter.y = searchSymbol.cachedImage->height / 2; - if (msDrawMarkerSymbol(map, searchSymbol.cachedImage, &imCenter, - searchSymbol.style, - searchSymbol.style->scalefactor) != - MS_SUCCESS) { + if (msDrawMarkerSymbolInternal( + map, searchSymbol.cachedImage, &imCenter, + searchSymbol.style, searchSymbol.style->scalefactor, + /* adjustMarkerPos = */ false) != MS_SUCCESS) { msSetError(MS_MISCERR, "Unable to draw symbol image.", "msQueryByPoint()"); return (MS_FAILURE); @@ -2347,10 +2364,12 @@ const int test_x = static_cast<int>(std::round( searchSymbol.cachedImage->width / 2 + - (map->query.point.x - shape.line[0].point[0].x) / cellx)); + (searchSymbol.center_x_in_map - shape.line[0].point[0].x) / + cellx)); const int test_y = static_cast<int>(std::round( searchSymbol.cachedImage->height / 2 - - (map->query.point.y - shape.line[0].point[0].y) / celly)); + (searchSymbol.center_y_in_map - shape.line[0].point[0].y) / + celly)); // Check that the queried pixel hits a non-transparent pixel of // the symbol diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/maprendering.c new/mapserver-8.6.1/src/maprendering.c --- old/mapserver-8.6.0/src/maprendering.c 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/maprendering.c 2026-03-23 16:36:42.000000000 +0100 @@ -899,6 +899,13 @@ int msDrawMarkerSymbol(mapObj *map, imageObj *image, pointObj *p, styleObj *style, double scalefactor) { + return msDrawMarkerSymbolInternal(map, image, p, style, scalefactor, + /* adjustMarkerPos =*/true); +} + +int msDrawMarkerSymbolInternal(mapObj *map, imageObj *image, pointObj *p, + styleObj *style, double scalefactor, + bool adjustMarkerPos) { int ret = MS_SUCCESS; if (!p) return MS_SUCCESS; @@ -937,7 +944,8 @@ p_x = p->x; p_y = p->y; - if (MS_UNLIKELY(MS_FAILURE == msAdjustMarkerPos(map, style, symbol, &p_x, + if (adjustMarkerPos && + MS_UNLIKELY(MS_FAILURE == msAdjustMarkerPos(map, style, symbol, &p_x, &p_y, scalefactor, s.rotation))) { return MS_FAILURE; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapserver.h new/mapserver-8.6.1/src/mapserver.h --- old/mapserver-8.6.0/src/mapserver.h 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapserver.h 2026-03-23 16:36:42.000000000 +0100 @@ -73,6 +73,12 @@ #define MS_UNLIKELY(x) (x) #endif +/** Macro to compute the minimum of 2 values */ +#define MS_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/** Macro to compute the maximum of 2 values */ +#define MS_MAX(a, b) (((a) > (b)) ? (a) : (b)) + /* definition of ms_int32/ms_uint32 */ #include <limits.h> #ifndef _WIN32 @@ -3303,6 +3309,9 @@ layerObj *layer, mapObj *map); rectObj msRasterLabelGetSearchRect(layerObj *layer, mapObj *map); +void msContourLayerUseMapExtentAndProjectionForNextWhichShapes(layerObj *layer, + mapObj *map); + /* ==================================================================== */ /* Prototypes for functions in mapdraw.c */ /* ==================================================================== */ @@ -3351,6 +3360,12 @@ MS_DLL_EXPORT int WARN_UNUSED msDrawMarkerSymbol(mapObj *map, imageObj *image, pointObj *p, styleObj *style, double scalefactor); + +int WARN_UNUSED msDrawMarkerSymbolInternal(mapObj *map, imageObj *image, + pointObj *p, styleObj *style, + double scalefactor, + bool adjustMarkerPos); + MS_DLL_EXPORT int WARN_UNUSED msDrawLineSymbol(mapObj *map, imageObj *image, shapeObj *p, styleObj *style, double scalefactor); @@ -3718,7 +3733,8 @@ const projectionObj *src); MS_DLL_EXPORT int msCopyProjectionExtended(projectionObj *dst, const projectionObj *src, - char **args, int num_args); + const char *const *args, + int num_args); int msCopyExpression(expressionObj *dst, const expressionObj *src); int msCopyProjection(projectionObj *dst, const projectionObj *src); MS_DLL_EXPORT int msCopyRasterBuffer(rasterBufferObj *dst, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapstring.cpp new/mapserver-8.6.1/src/mapstring.cpp --- old/mapserver-8.6.0/src/mapstring.cpp 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapstring.cpp 2026-03-23 16:36:42.000000000 +0100 @@ -2515,7 +2515,7 @@ if (sb->length + nAppendLen >= sb->alloc_size) { size_t newAllocSize1 = sb->alloc_size + sb->alloc_size / 3; size_t newAllocSize2 = sb->length + nAppendLen + 1; - size_t newAllocSize = MAX(newAllocSize1, newAllocSize2); + size_t newAllocSize = std::max(newAllocSize1, newAllocSize2); void *newStr = realloc(sb->str, newAllocSize); if (newStr == NULL) { msSetError(MS_MEMERR, "Not enough memory", "msStringBufferAppend()"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapuvraster.cpp new/mapserver-8.6.1/src/mapuvraster.cpp --- old/mapserver-8.6.0/src/mapuvraster.cpp 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapuvraster.cpp 2026-03-23 16:36:42.000000000 +0100 @@ -57,42 +57,48 @@ #define MSUVRASTER_LAT "lat" #define MSUVRASTER_LATINDEX -107 -typedef struct { +struct uvRasterLayerInfo { /* query cache results */ - int query_results; + int query_results = 0; - int refcount; + int refcount = 0; - float *u; /* u values */ - float *v; /* v values */ - int width; - int height; - rectObj extent; - int next_shape; + float *u = nullptr; /* u values */ + float *v = nullptr; /* v values */ + int width = 0; + int height = 0; + rectObj extent{}; + int next_shape = 0; /* To improve performance of GetShape() when queried on increasing shapeindex */ - long last_queried_shapeindex; // value in [0, query_results[ range - size_t last_raster_off; // value in [0, width*height[ range + long last_queried_shapeindex = 0; // value in [0, query_results[ range + size_t last_raster_off = 0; // value in [0, width*height[ range - bool needsLonLat; - reprojectionObj *reprojectorToLonLat; + bool needsLonLat = false; + reprojectionObj *reprojectorToLonLat = nullptr; - mapObj - *mapToUseForWhichShapes; /* set if the map->extent and map->projection are - valid in msUVRASTERLayerWhichShapes() */ + /* set if the map->extent and map->projection are + valid in msUVRASTERLayerWhichShapes() */ + mapObj *mapToUseForWhichShapes = nullptr; + + std::string timestring{}; + std::string timefield{}; +}; -} uvRasterLayerInfo; +static uvRasterLayerInfo *getLayerInfo(layerObj *layer) { + return static_cast<uvRasterLayerInfo *>(layer->layerinfo); +} void msUVRASTERLayerUseMapExtentAndProjectionForNextWhichShapes(layerObj *layer, mapObj *map) { - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); uvlinfo->mapToUseForWhichShapes = map; } static int msUVRASTERLayerInitItemInfo(layerObj *layer) { - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); int i; int *itemindexes; int failed = 0; @@ -154,19 +160,14 @@ } static void msUVRasterLayerInfoInitialize(layerObj *layer) { - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); if (uvlinfo != NULL) return; - uvlinfo = (uvRasterLayerInfo *)msSmallCalloc(1, sizeof(uvRasterLayerInfo)); + uvlinfo = new uvRasterLayerInfo; layer->layerinfo = uvlinfo; - uvlinfo->u = NULL; - uvlinfo->v = NULL; - uvlinfo->width = 0; - uvlinfo->height = 0; - /* Set attribute type to Real, unless the user has explicitly set */ /* something else. */ { @@ -189,7 +190,7 @@ static void msUVRasterLayerInfoFree(layerObj *layer) { - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); if (uvlinfo == NULL) return; @@ -201,7 +202,7 @@ msProjectDestroyReprojector(uvlinfo->reprojectorToLonLat); } - free(uvlinfo); + delete uvlinfo; layer->layerinfo = NULL; } @@ -213,7 +214,7 @@ if (layer->layerinfo == NULL) return MS_FAILURE; - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); uvlinfo->refcount = uvlinfo->refcount + 1; @@ -227,7 +228,7 @@ } int msUVRASTERLayerClose(layerObj *layer) { - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); if (uvlinfo != NULL) { uvlinfo->refcount--; @@ -239,7 +240,7 @@ } int msUVRASTERLayerGetItems(layerObj *layer) { - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); if (uvlinfo == NULL) return MS_FAILURE; @@ -273,7 +274,7 @@ char tmp[100]; float size_scale; int *itemindexes = (int *)layer->iteminfo; - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); double lon = HUGE_VAL; double lat = HUGE_VAL; @@ -452,7 +453,7 @@ } int msUVRASTERLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); imageObj *image_tmp; outputFormatObj *outputformat = NULL; mapObj *map_tmp; @@ -753,7 +754,26 @@ */ saved_layer_mask = layer->mask; layer->mask = NULL; - ret = msDrawRasterLayerLow(map_tmp, layer, image_tmp, NULL); + + if (layer->tileindex) { + expressionObj old_filter; + if (!uvlinfo->timestring.empty()) { + msInitExpression(&old_filter); + msCopyExpression(&old_filter, &layer->filter); /* save existing filter */ + msFreeExpression(&layer->filter); + msLayerMakeBackticsTimeFilter(layer, uvlinfo->timestring.c_str(), + uvlinfo->timefield.c_str()); + } + + ret = msDrawRasterLayerLow(map_tmp, layer, image_tmp, NULL); + + if (!uvlinfo->timestring.empty()) { + msCopyExpression(&layer->filter, &old_filter); /* restore old filter */ + msFreeExpression(&old_filter); + } + } else { + ret = msDrawRasterLayerLow(map_tmp, layer, image_tmp, NULL); + } /* restore layer attributes if we went through the above on-the-fly VRT */ if (oldLayerData) { @@ -825,7 +845,7 @@ int msUVRASTERLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) { - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); lineObj line; pointObj point; const long shapeindex = record->shapeindex; @@ -889,7 +909,7 @@ } int msUVRASTERLayerNextShape(layerObj *layer, shapeObj *shape) { - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); if (uvlinfo->next_shape < 0 || uvlinfo->next_shape >= uvlinfo->query_results) { @@ -1029,12 +1049,20 @@ /* -------------------------------------------------------------------- */ /* If we are using a local shapefile as our tileindex (that is */ /* to say, the tileindex name is not of another layer), then we */ - /* just install a backtics style filter on the raster layer. */ - /* This is propagated to the "working layer" created for the */ - /* tileindex by code in mapraster.c. */ + /* will install a backtics style filter later. */ /* -------------------------------------------------------------------- */ - if (tilelayerindex == -1) - return msLayerMakeBackticsTimeFilter(layer, timestring, timefield); + if (tilelayerindex == -1) { + if (layer->layerinfo == NULL) + msUVRasterLayerInfoInitialize(layer); + if (layer->layerinfo == NULL) + return MS_FAILURE; + uvRasterLayerInfo *uvlinfo = getLayerInfo(layer); + if (timestring) + uvlinfo->timestring = timestring; + if (timefield) + uvlinfo->timefield = timefield; + return MS_SUCCESS; + } /* -------------------------------------------------------------------- */ /* Otherwise we invoke the tileindex layers SetTimeFilter */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapwcs.cpp new/mapserver-8.6.1/src/mapwcs.cpp --- old/mapserver-8.6.0/src/mapwcs.cpp 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapwcs.cpp 2026-03-23 16:36:42.000000000 +0100 @@ -1970,7 +1970,7 @@ int nDstBand = i + 1; GDALRasterBandH hBand = GDALGetRasterBand(hDS, nSrcBand); if (hBand) { - char **papszMD = GDALGetMetadata(hBand, NULL); + CSLConstList papszMD = GDALGetMetadata(hBand, NULL); const char *pszMDI = CSLFetchNameValue(papszMD, "GRIB_IDS"); // Make sure it is a GRIB2 band if (pszMDI) { @@ -2307,9 +2307,9 @@ } { - char **papszMD = GDALGetMetadata(hDS, NULL); + CSLConstList papszMD = GDALGetMetadata(hDS, NULL); if (papszMD) { - for (char **papszIter = papszMD; *papszIter; ++papszIter) { + for (CSLConstList papszIter = papszMD; *papszIter; ++papszIter) { // Copy netCDF global attributes, as well as the ones // of the extra dimension for 3D netCDF files if (STARTS_WITH(*papszIter, "NC_GLOBAL#") || @@ -2334,9 +2334,9 @@ int nDstBand = i + 1; GDALRasterBandH hBand = GDALGetRasterBand(hDS, nSrcBand); if (hBand) { - char **papszMD = GDALGetMetadata(hBand, NULL); + CSLConstList papszMD = GDALGetMetadata(hBand, NULL); if (papszMD) { - for (char **papszIter = papszMD; *papszIter; ++papszIter) { + for (CSLConstList papszIter = papszMD; *papszIter; ++papszIter) { char *pszKey = nullptr; const char *pszValue = CPLParseNameValue(*papszIter, &pszKey); if (pszKey && pszValue && !EQUAL(pszKey, "grid_name") && diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapwcs20.cpp new/mapserver-8.6.1/src/mapwcs20.cpp --- old/mapserver-8.6.0/src/mapwcs20.cpp 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapwcs20.cpp 2026-03-23 16:36:42.000000000 +0100 @@ -39,6 +39,7 @@ #include "mapows.h" #include "mapwcs.h" #include "mapgdal.h" +#include <cmath> #include <float.h> #include "gdal.h" #include "cpl_port.h" @@ -4641,14 +4642,16 @@ subsetInImageProj.maxy = MS_MIN(subsetInImageProj.maxy, layer->extent.maxy); { - double total = ABS(layer->extent.maxx - layer->extent.minx); - double part = ABS(subsetInImageProj.maxx - subsetInImageProj.minx); + double total = std::abs(layer->extent.maxx - layer->extent.minx); + double part = + std::abs(subsetInImageProj.maxx - subsetInImageProj.minx); widthFromComputationInImageCRS = MS_NINT((part * map->width) / total); } { - double total = ABS(layer->extent.maxy - layer->extent.miny); - double part = ABS(subsetInImageProj.maxy - subsetInImageProj.miny); + double total = std::abs(layer->extent.maxy - layer->extent.miny); + double part = + std::abs(subsetInImageProj.maxy - subsetInImageProj.miny); heightFromComputationInImageCRS = MS_NINT((part * map->height) / total); } @@ -4656,6 +4659,15 @@ } msProjectRect(&imageProj, &subsetProj, &(layer->extent)); + if (msProjIsGeographicCRS(&subsetProj)) { + if (layer->extent.minx > 180 && subsets.maxx <= 180) { + layer->extent.minx -= 360; + layer->extent.maxx -= 360; + } else if (layer->extent.maxx < -180 && subsets.minx >= -180) { + layer->extent.minx += 360; + layer->extent.maxx += 360; + } + } map->extent = layer->extent; msFreeProjection(&(map->projection)); map->projection = subsetProj; @@ -4710,10 +4722,10 @@ } else { if (widthFromComputationInImageCRS != 0) { params->width = widthFromComputationInImageCRS; - } else if (ABS(bbox.maxx - bbox.minx) != - ABS(map->extent.maxx - map->extent.minx)) { - double total = ABS(map->extent.maxx - map->extent.minx), - part = ABS(bbox.maxx - bbox.minx); + } else if (std::abs(bbox.maxx - bbox.minx) != + std::abs(map->extent.maxx - map->extent.minx)) { + double total = std::abs(map->extent.maxx - map->extent.minx), + part = std::abs(bbox.maxx - bbox.minx); params->width = MS_NINT((part * map->width) / total); } else { params->width = map->width; @@ -4735,10 +4747,10 @@ } else { if (heightFromComputationInImageCRS != 0) { params->height = heightFromComputationInImageCRS; - } else if (ABS(bbox.maxy - bbox.miny) != - ABS(map->extent.maxy - map->extent.miny)) { - double total = ABS(map->extent.maxy - map->extent.miny), - part = ABS(bbox.maxy - bbox.miny); + } else if (std::abs(bbox.maxy - bbox.miny) != + std::abs(map->extent.maxy - map->extent.miny)) { + double total = std::abs(map->extent.maxy - map->extent.miny), + part = std::abs(bbox.maxy - bbox.miny); params->height = MS_NINT((part * map->height) / total); } else { params->height = map->height; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mapserver-8.6.0/src/mapwms.cpp new/mapserver-8.6.1/src/mapwms.cpp --- old/mapserver-8.6.0/src/mapwms.cpp 2025-12-03 16:04:40.000000000 +0100 +++ new/mapserver-8.6.1/src/mapwms.cpp 2026-03-23 16:36:42.000000000 +0100 @@ -3028,8 +3028,32 @@ : ""); msIO_printf("%s <Name>%s</Name>\n", indent.c_str(), nestedGroups[index][level]); - msIO_printf("%s <Title>%s</Title>\n", indent.c_str(), - nestedGroups[index][level]); + + { + const char *value; + if ((value = msOWSLookupMetadataWithLanguage( + &(GET_LAYER(map, index)->metadata), "MO", "GROUP_TITLE", + validated_language))) { + char *encoded = msEncodeHTMLEntities(value); + msIO_printf("%s <Title>%s</Title>\n", indent.c_str(), encoded); + msFree(encoded); + } else { + msIO_printf("%s <Title>%s</Title>\n", indent.c_str(), + nestedGroups[index][level]); + } + } + { + const char *value; + if ((value = msOWSLookupMetadataWithLanguage( + &(GET_LAYER(map, index)->metadata), "MO", "GROUP_ABSTRACT", + validated_language))) { + char *encoded = msEncodeHTMLEntities(value); + msIO_printf("%s <Abstract>%s</Abstract>\n", indent.c_str(), + encoded); + msFree(encoded); + } + } + groupAdded = true; }
