[Git][debian-gis-team/mapserver][master] 6 commits: New upstream version 8.6.1

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Mon Mar 23 17:33:42 GMT 2026



Bas Couwenberg pushed to branch master at Debian GIS Project / mapserver


Commits:
209dc6af by Bas Couwenberg at 2026-03-23T18:14:09+01:00
New upstream version 8.6.1
- - - - -
93ee233c by Bas Couwenberg at 2026-03-23T18:14:24+01:00
Update upstream source from tag 'upstream/8.6.1'

Update to upstream version '8.6.1'
with Debian dir 64ae47e6a34b18319198a30f19190321210a46d0
- - - - -
c8e2aa3c by Bas Couwenberg at 2026-03-23T18:16:14+01:00
New upstream release.

- - - - -
0889c96e by Bas Couwenberg at 2026-03-23T18:18:06+01:00
Update copyright file.

- - - - -
a6675c68 by Bas Couwenberg at 2026-03-23T18:29:19+01:00
Update symbols for 8.6.1.

- - - - -
335f7224 by Bas Couwenberg at 2026-03-23T18:29:19+01:00
Set distribution to unstable.

- - - - -


26 changed files:

- CITATION.cff
- CMakeLists.txt
- HISTORY.md
- LICENSE.md
- ci/ubuntu/build.sh
- debian/changelog
- debian/copyright
- debian/libmapserver2t64.symbols
- src/idw.c
- src/mapcontour.c
- src/mapcopy.c
- src/mapdraw.c
- src/mapdrawgdal.c
- src/mapogcsld.cpp
- src/mapogr.cpp
- src/mappostgis.cpp
- src/mapproject.c
- src/mapproject.h
- src/mapquery.cpp
- src/maprendering.c
- src/mapserver.h
- src/mapstring.cpp
- src/mapuvraster.cpp
- src/mapwcs.cpp
- src/mapwcs20.cpp
- src/mapwms.cpp


Changes:

=====================================
CITATION.cff
=====================================
@@ -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:


=====================================
CMakeLists.txt
=====================================
@@ -17,7 +17,7 @@ include(CheckCSourceCompiles)
 
 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 @@ set(USE_GENERIC_MS_NINT 1)
 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)


=====================================
HISTORY.md
=====================================
@@ -13,6 +13,15 @@ https://mapserver.org/development/changelog/
 
 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)
 --------------------------
 


=====================================
LICENSE.md
=====================================
@@ -4,7 +4,7 @@ MapServer Licensing
 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 


=====================================
ci/ubuntu/build.sh
=====================================
@@ -47,10 +47,10 @@ python -m http.server &> /dev/null &
 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"


=====================================
debian/changelog
=====================================
@@ -1,10 +1,13 @@
-mapserver (8.6.0-2) UNRELEASED; urgency=medium
+mapserver (8.6.1-1) unstable; urgency=high
 
+  * New upstream release.
   * Drop Priority: optional, default since dpkg 1.22.13.
   * Bump Standards-Version to 4.7.3, changes: priority.
   * Drop obsolete Breaks/Replaces.
+  * Update copyright file.
+  * Update symbols for 8.6.1.
 
- -- Bas Couwenberg <sebastic at debian.org>  Sat, 03 Jan 2026 14:01:55 +0100
+ -- Bas Couwenberg <sebastic at debian.org>  Mon, 23 Mar 2026 18:19:03 +0100
 
 mapserver (8.6.0-1) unstable; urgency=medium
 


=====================================
debian/copyright
=====================================
@@ -24,8 +24,8 @@ Copyright:                    Joyent, Inc. and other Node contributors
                         2021, MapServer team
             2008, 2010, 2021, Paul Ramsey
                    1996-2025, Regents of the University of Minnesota.
-                   2008-2025, Open Source Geospatial Foundation.
        2013, 2016, 2019-2025, Even Rouault
+                   2008-2026, Open Source Geospatial Foundation.
 License: MIT
 
 Files: fuzzers/build.sh


=====================================
debian/libmapserver2t64.symbols
=====================================
@@ -2058,6 +2058,7 @@ libmapserver.so.2 #PACKAGE# #MINVER#
  msContourLayerNextShape at Base 6.4.0
  msContourLayerOpen at Base 6.4.0
  msContourLayerSetTimeFilter at Base 6.4.0
+ msContourLayerUseMapExtentAndProjectionForNextWhichShapes at Base 8.6.1
  msContourLayerWhichShapes at Base 6.4.0
  msConvertWideStringFromUTF8 at Base 8.0.0
  msConvertWideStringToUTF8 at Base 6.2.1
@@ -2157,6 +2158,7 @@ libmapserver.so.2 #PACKAGE# #MINVER#
  msDrawMap at Base 6.2.1
  msDrawMarkerSymbol at Base 6.2.1
  msDrawMarkerSymbolIM at Base 6.2.1
+ msDrawMarkerSymbolInternal at Base 8.6.1
  msDrawOffsettedLabels at Base 6.2.1
  msDrawPieChart at Base 6.2.1
  msDrawPieChartLayer at Base 6.2.1


=====================================
src/idw.c
=====================================
@@ -69,7 +69,7 @@ void msIdwProcessing(layerObj *layer,
   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 =


=====================================
src/mapcontour.c
=====================================
@@ -59,6 +59,10 @@ typedef struct {
   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 @@ static int msContourLayerReadRaster(layerObj *layer, rectObj rect) {
   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 @@ static int msContourLayerReadRaster(layerObj *layer, rectObj rect) {
     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 @@ static int msContourLayerReadRaster(layerObj *layer, rectObj rect) {
         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 @@ static int msContourLayerReadRaster(layerObj *layer, rectObj rect) {
         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 @@ static int msContourLayerReadRaster(layerObj *layer, rectObj rect) {
      * 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 @@ int msContourLayerOpen(layerObj *layer) {
   } 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 @@ int msContourLayerOpen(layerObj *layer) {
     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 @@ int msContourLayerGetItems(layerObj *layer) {
     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 @@ int msContourLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) {
     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,


=====================================
src/mapcopy.c
=====================================
@@ -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);
 


=====================================
src/mapdraw.c
=====================================
@@ -1163,6 +1163,8 @@ int msDrawVectorLayer(mapObj *map, layerObj *layer, imageObj *image) {
 
         searchrect = msUVRASTERGetSearchRect(layer, map);
         bDone = MS_TRUE;
+      } else if (layer->connectiontype == MS_CONTOUR) {
+        msContourLayerUseMapExtentAndProjectionForNextWhichShapes(layer, map);
       }
 
       if (!bDone)
@@ -1183,6 +1185,8 @@ int msDrawVectorLayer(mapObj *map, layerObj *layer, imageObj *image) {
     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 */


=====================================
src/mapdrawgdal.c
=====================================
@@ -601,7 +601,7 @@ int msDrawRasterLayerGDAL(mapObj *map, layerObj *layer, imageObj *image,
 
       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 @@ int msDrawRasterLayerGDAL(mapObj *map, layerObj *layer, imageObj *image,
       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 @@ static int LoadGDALImages(GDALDatasetH hDS, int band_numbers[4], int band_count,
     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;


=====================================
src/mapogcsld.cpp
=====================================
@@ -2894,7 +2894,7 @@ int msSLDParseRasterSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer,
         } 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);


=====================================
src/mapogr.cpp
=====================================
@@ -33,6 +33,8 @@
 #include "mapproject.h"
 #include "mapthread.h"
 #include "mapows.h"
+
+#include <algorithm>
 #include <string>
 #include <vector>
 
@@ -2223,10 +2225,10 @@ static int msOGRFileWhichShapes(layerObj *layer, rectObj rect,
      * 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;


=====================================
src/mappostgis.cpp
=====================================
@@ -54,9 +54,6 @@
 **
 */
 
-/* required for MSVC */
-#define _USE_MATH_DEFINES
-
 #include <assert.h>
 #include <string.h>
 #include <math.h>


=====================================
src/mapproject.c
=====================================
@@ -1056,7 +1056,11 @@ msProjectGetLineCuttingCase(reprojectionObj *reprojector) {
     }
   }
 
-  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 @@ msProjectGetLineCuttingCase(reprojectionObj *reprojector) {
 
   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 @@ msProjectGetLineCuttingCase(reprojectionObj *reprojector) {
     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 @@ msProjectGetLineCuttingCase(reprojectionObj *reprojector) {
                  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);
+  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);
+      }
 
-  p.x = invgt0 + extremeLongEasting * (1 - EPS) * invgt1;
-  p.y = invgt3 + extremeLongEasting * (1 - EPS) * invgt4;
-  /* 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);
+      }
+    }
+
+    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 = 0;
-  p.y = 0;
-  msAddPointToLine(&newLine, &p);
+    p.x = invgt0 + extremeLongEasting * (1 - EPS) * invgt1;
+    p.y = invgt3 + extremeLongEasting * (1 - EPS) * invgt4;
+    msProjectPoint(out, in, &p);
+    msAddPointToLine(&newLine, &p);
 
-  msAddPointToLine(&newLine, &first);
+    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 @@ static int msProjectShapeLine(reprojectionObj *reprojector, shapeObj *shape,
   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 msProjectHasLonWrap(projectionObj *in, double *pdfLonWrap) {
 /************************************************************************/
 
 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;


=====================================
src/mapproject.h
=====================================
@@ -49,7 +49,7 @@ typedef struct projectionContext projectionContext;
 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


=====================================
src/mapquery.cpp
=====================================
@@ -1981,6 +1981,8 @@ int msQueryByPoint(mapObj *map) {
       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 @@ int msQueryByPoint(mapObj *map) {
         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 @@ int msQueryByPoint(mapObj *map) {
         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 @@ int msQueryByPoint(mapObj *map) {
             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, &center_x, &center_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 @@ int msQueryByPoint(mapObj *map) {
             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 @@ int msQueryByPoint(mapObj *map) {
 
             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 @@ int msQueryByPoint(mapObj *map) {
                 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 @@ int msQueryByPoint(mapObj *map) {
 
                 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


=====================================
src/maprendering.c
=====================================
@@ -899,6 +899,13 @@ int msDrawShadeSymbol(mapObj *map, imageObj *image, shapeObj *p,
 
 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 @@ int msDrawMarkerSymbol(mapObj *map, imageObj *image, pointObj *p,
       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;


=====================================
src/mapserver.h
=====================================
@@ -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 @@ void msRasterLabelLayerUseMapExtentAndProjectionForNextWhichShapes(
     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 msValueToRange(styleObj *style, double fieldVal,
 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 @@ MS_DLL_EXPORT int msCopyProjection(projectionObj *dst,
                                    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,


=====================================
src/mapstring.cpp
=====================================
@@ -2515,7 +2515,7 @@ int msStringBufferAppend(msStringBuffer *sb, const char *pszAppendedString) {
   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()");


=====================================
src/mapuvraster.cpp
=====================================
@@ -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;
 
-} uvRasterLayerInfo;
+  std::string timestring{};
+  std::string timefield{};
+};
+
+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 @@ void msUVRASTERLayerFreeItemInfo(layerObj *layer) {
 }
 
 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 msUVRasterLayerInfoInitialize(layerObj *layer) {
 static void msUVRasterLayerInfoFree(layerObj *layer)
 
 {
-  uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo;
+  uvRasterLayerInfo *uvlinfo = getLayerInfo(layer);
 
   if (uvlinfo == NULL)
     return;
@@ -201,7 +202,7 @@ static void msUVRasterLayerInfoFree(layerObj *layer)
     msProjectDestroyReprojector(uvlinfo->reprojectorToLonLat);
   }
 
-  free(uvlinfo);
+  delete uvlinfo;
 
   layer->layerinfo = NULL;
 }
@@ -213,7 +214,7 @@ int msUVRASTERLayerOpen(layerObj *layer) {
   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 msUVRASTERLayerIsOpen(layerObj *layer) {
 }
 
 int msUVRASTERLayerClose(layerObj *layer) {
-  uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo;
+  uvRasterLayerInfo *uvlinfo = getLayerInfo(layer);
 
   if (uvlinfo != NULL) {
     uvlinfo->refcount--;
@@ -239,7 +240,7 @@ int msUVRASTERLayerClose(layerObj *layer) {
 }
 
 int msUVRASTERLayerGetItems(layerObj *layer) {
-  uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo;
+  uvRasterLayerInfo *uvlinfo = getLayerInfo(layer);
 
   if (uvlinfo == NULL)
     return MS_FAILURE;
@@ -273,7 +274,7 @@ static char **msUVRASTERGetValues(layerObj *layer, float u, float v,
   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 @@ rectObj msUVRASTERGetSearchRect(layerObj *layer, mapObj *map) {
 }
 
 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 @@ int msUVRASTERLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) {
    */
   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 msUVRASTERLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) {
 
 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 msUVRASTERLayerGetShape(layerObj *layer, shapeObj *shape,
 }
 
 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 @@ int msUVRASTERLayerSetTimeFilter(layerObj *layer, const char *timestring,
   /* -------------------------------------------------------------------- */
   /*      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          */


=====================================
src/mapwcs.cpp
=====================================
@@ -1970,7 +1970,7 @@ void msWCSApplyDatasetMetadataAsCreationOptions(layerObj *lp,
         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 @@ void msWCSApplySourceDatasetMetadata(layerObj *lp, outputFormatObj *format,
       }
 
       {
-        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 @@ void msWCSApplySourceDatasetMetadata(layerObj *lp, outputFormatObj *format,
         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") &&


=====================================
src/mapwcs20.cpp
=====================================
@@ -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 @@ this request. Check wcs/ows_enable_request settings.",
           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 @@ this request. Check wcs/ows_enable_request settings.",
       }
 
       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 @@ this request. Check wcs/ows_enable_request settings.",
   } 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 @@ this request. Check wcs/ows_enable_request settings.",
   } 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;


=====================================
src/mapwms.cpp
=====================================
@@ -3028,8 +3028,32 @@ void msWMSPrintNestedGroups(mapObj *map, int nVersion, char *pabLayerProcessed,
                       : "");
       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;
     }
 



View it on GitLab: https://salsa.debian.org/debian-gis-team/mapserver/-/compare/1e462be1d549804d04db44cb0c1954c3a8579717...335f7224151db8b915d366d4275e0ee4b80c4d3f

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/mapserver/-/compare/1e462be1d549804d04db44cb0c1954c3a8579717...335f7224151db8b915d366d4275e0ee4b80c4d3f
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20260323/a6cf980f/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list