LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/shape - shape2ogr.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 826 895 92.3 %
Date: 2026-02-12 23:49:34 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements translation of Shapefile shapes into OGR
       5             :  *           representation.
       6             :  * Author:   Frank Warmerdam, warmerda@home.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 1999,  Les Technologies SoftMap Inc.
      10             :  * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "ogrshape.h"
      17             : 
      18             : #include <cmath>
      19             : #include <cstdio>
      20             : #include <cstdlib>
      21             : #include <cstring>
      22             : #include <algorithm>
      23             : #include <limits>
      24             : #include <memory>
      25             : #include <utility>
      26             : 
      27             : #include "cpl_conv.h"
      28             : #include "cpl_error.h"
      29             : #include "cpl_string.h"
      30             : #include "cpl_minixml.h"
      31             : #include "cpl_vsi_virtual.h"
      32             : #include "ogr_core.h"
      33             : #include "ogr_feature.h"
      34             : #include "ogr_geometry.h"
      35             : #include "ogrpgeogeometry.h"
      36             : #include "ogrshape.h"
      37             : #include "shapefil.h"
      38             : 
      39             : /************************************************************************/
      40             : /*                        RingStartEnd                                  */
      41             : /*        Set first and last vertex for given ring.                     */
      42             : /************************************************************************/
      43       37180 : static void RingStartEnd(SHPObject *psShape, int ring, int *start, int *end)
      44             : {
      45       37180 :     if (psShape->panPartStart == nullptr)
      46             :     {
      47           0 :         *start = 0;
      48           0 :         *end = psShape->nVertices - 1;
      49             :     }
      50             :     else
      51             :     {
      52       37180 :         *start = psShape->panPartStart[ring];
      53             : 
      54       37180 :         if (ring == psShape->nParts - 1)
      55       36688 :             *end = psShape->nVertices - 1;
      56             :         else
      57         492 :             *end = psShape->panPartStart[ring + 1] - 1;
      58             :     }
      59       37180 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                           CreateLinearRing                           */
      63             : /************************************************************************/
      64             : static std::unique_ptr<OGRLinearRing>
      65       37180 : CreateLinearRing(SHPObject *psShape, int ring, bool bHasZ, bool bHasM)
      66             : {
      67       37180 :     int nRingStart = 0;
      68       37180 :     int nRingEnd = 0;
      69       37180 :     RingStartEnd(psShape, ring, &nRingStart, &nRingEnd);
      70             : 
      71       37180 :     auto poRing = std::make_unique<OGRLinearRing>();
      72       37180 :     if (!(nRingEnd >= nRingStart))
      73           0 :         return poRing;
      74             : 
      75       37180 :     const int nRingPoints = nRingEnd - nRingStart + 1;
      76             : 
      77       37180 :     if (bHasZ && bHasM)
      78          78 :         poRing->setPoints(
      79          42 :             nRingPoints, psShape->padfX + nRingStart,
      80          42 :             psShape->padfY + nRingStart, psShape->padfZ + nRingStart,
      81          42 :             psShape->padfM ? psShape->padfM + nRingStart : nullptr);
      82       37138 :     else if (bHasM)
      83          15 :         poRing->setPointsM(nRingPoints, psShape->padfX + nRingStart,
      84          12 :                            psShape->padfY + nRingStart,
      85          12 :                            psShape->padfM ? psShape->padfM + nRingStart
      86             :                                           : nullptr);
      87             :     else
      88       37126 :         poRing->setPoints(nRingPoints, psShape->padfX + nRingStart,
      89       37126 :                           psShape->padfY + nRingStart);
      90             : 
      91       37180 :     return poRing;
      92             : }
      93             : 
      94             : /************************************************************************/
      95             : /*                          SHPReadOGRObject()                          */
      96             : /*                                                                      */
      97             : /*      Read an item in a shapefile, and translate to OGR geometry      */
      98             : /*      representation.                                                 */
      99             : /************************************************************************/
     100             : 
     101       92611 : OGRGeometry *SHPReadOGRObject(SHPHandle hSHP, int iShape, SHPObject *psShape,
     102             :                               bool &bHasWarnedWrongWindingOrder)
     103             : {
     104             : #if DEBUG_VERBOSE
     105             :     CPLDebug("Shape", "SHPReadOGRObject( iShape=%d )", iShape);
     106             : #endif
     107             : 
     108       92611 :     if (psShape == nullptr)
     109       60610 :         psShape = SHPReadObject(hSHP, iShape);
     110             : 
     111       92611 :     if (psShape == nullptr)
     112             :     {
     113          11 :         return nullptr;
     114             :     }
     115             : 
     116       92600 :     OGRGeometry *poOGR = nullptr;
     117             : 
     118             :     /* -------------------------------------------------------------------- */
     119             :     /*      Point.                                                          */
     120             :     /* -------------------------------------------------------------------- */
     121       92600 :     if (psShape->nSHPType == SHPT_POINT)
     122             :     {
     123        6464 :         poOGR = new OGRPoint(psShape->padfX[0], psShape->padfY[0]);
     124             :     }
     125       86136 :     else if (psShape->nSHPType == SHPT_POINTZ)
     126             :     {
     127       43947 :         if (psShape->bMeasureIsUsed)
     128             :         {
     129           7 :             poOGR = new OGRPoint(psShape->padfX[0], psShape->padfY[0],
     130           7 :                                  psShape->padfZ[0], psShape->padfM[0]);
     131             :         }
     132             :         else
     133             :         {
     134       43940 :             poOGR = new OGRPoint(psShape->padfX[0], psShape->padfY[0],
     135       43940 :                                  psShape->padfZ[0]);
     136             :         }
     137             :     }
     138       42189 :     else if (psShape->nSHPType == SHPT_POINTM)
     139             :     {
     140          10 :         poOGR = new OGRPoint(psShape->padfX[0], psShape->padfY[0], 0.0,
     141           5 :                              psShape->padfM[0]);
     142           5 :         poOGR->set3D(FALSE);
     143             :     }
     144             :     /* -------------------------------------------------------------------- */
     145             :     /*      Multipoint.                                                     */
     146             :     /* -------------------------------------------------------------------- */
     147       42184 :     else if (psShape->nSHPType == SHPT_MULTIPOINT ||
     148       42172 :              psShape->nSHPType == SHPT_MULTIPOINTM ||
     149       42170 :              psShape->nSHPType == SHPT_MULTIPOINTZ)
     150             :     {
     151          22 :         if (psShape->nVertices == 0)
     152             :         {
     153           1 :             poOGR = nullptr;
     154             :         }
     155             :         else
     156             :         {
     157          21 :             OGRMultiPoint *poOGRMPoint = new OGRMultiPoint();
     158             : 
     159          54 :             for (int i = 0; i < psShape->nVertices; i++)
     160             :             {
     161          33 :                 OGRPoint *poPoint = nullptr;
     162             : 
     163          33 :                 if (psShape->nSHPType == SHPT_MULTIPOINTZ)
     164             :                 {
     165          12 :                     if (psShape->padfM)
     166             :                     {
     167           2 :                         poPoint =
     168           2 :                             new OGRPoint(psShape->padfX[i], psShape->padfY[i],
     169           2 :                                          psShape->padfZ[i], psShape->padfM[i]);
     170             :                     }
     171             :                     else
     172             :                     {
     173          10 :                         poPoint =
     174          10 :                             new OGRPoint(psShape->padfX[i], psShape->padfY[i],
     175          10 :                                          psShape->padfZ[i]);
     176             :                     }
     177             :                 }
     178          21 :                 else if (psShape->nSHPType == SHPT_MULTIPOINTM &&
     179           2 :                          psShape->padfM)
     180             :                 {
     181           4 :                     poPoint = new OGRPoint(psShape->padfX[i], psShape->padfY[i],
     182           2 :                                            0.0, psShape->padfM[i]);
     183           2 :                     poPoint->set3D(FALSE);
     184             :                 }
     185             :                 else
     186             :                 {
     187          19 :                     poPoint =
     188          19 :                         new OGRPoint(psShape->padfX[i], psShape->padfY[i]);
     189             :                 }
     190             : 
     191          33 :                 poOGRMPoint->addGeometry(poPoint);
     192             : 
     193          33 :                 delete poPoint;
     194             :             }
     195             : 
     196          21 :             poOGR = poOGRMPoint;
     197          22 :         }
     198             :     }
     199             : 
     200             :     /* -------------------------------------------------------------------- */
     201             :     /*      Arc (LineString)                                                */
     202             :     /*                                                                      */
     203             :     /*      Ignoring parts though they can apply to arcs as well.           */
     204             :     /* -------------------------------------------------------------------- */
     205       42162 :     else if (psShape->nSHPType == SHPT_ARC || psShape->nSHPType == SHPT_ARCM ||
     206       39288 :              psShape->nSHPType == SHPT_ARCZ)
     207             :     {
     208        4757 :         if (psShape->nParts == 0)
     209             :         {
     210           1 :             poOGR = nullptr;
     211             :         }
     212        4756 :         else if (psShape->nParts == 1)
     213             :         {
     214        4732 :             OGRLineString *poOGRLine = new OGRLineString();
     215        4732 :             poOGR = poOGRLine;
     216             : 
     217        4732 :             if (psShape->nSHPType == SHPT_ARCZ)
     218        1876 :                 poOGRLine->setPoints(psShape->nVertices, psShape->padfX,
     219        1876 :                                      psShape->padfY, psShape->padfZ,
     220        1876 :                                      psShape->padfM);
     221        2856 :             else if (psShape->nSHPType == SHPT_ARCM)
     222           4 :                 poOGRLine->setPointsM(psShape->nVertices, psShape->padfX,
     223           4 :                                       psShape->padfY, psShape->padfM);
     224             :             else
     225        2852 :                 poOGRLine->setPoints(psShape->nVertices, psShape->padfX,
     226        2852 :                                      psShape->padfY);
     227             :         }
     228             :         else
     229             :         {
     230          24 :             OGRMultiLineString *poOGRMulti = new OGRMultiLineString();
     231          24 :             poOGR = poOGRMulti;
     232             : 
     233          73 :             for (int iRing = 0; iRing < psShape->nParts; iRing++)
     234             :             {
     235          49 :                 int nRingPoints = 0;
     236          49 :                 int nRingStart = 0;
     237             : 
     238          49 :                 OGRLineString *poLine = new OGRLineString();
     239             : 
     240          49 :                 if (psShape->panPartStart == nullptr)
     241             :                 {
     242           0 :                     nRingPoints = psShape->nVertices;
     243           0 :                     nRingStart = 0;
     244             :                 }
     245             :                 else
     246             :                 {
     247          49 :                     if (iRing == psShape->nParts - 1)
     248          24 :                         nRingPoints =
     249          24 :                             psShape->nVertices - psShape->panPartStart[iRing];
     250             :                     else
     251          25 :                         nRingPoints = psShape->panPartStart[iRing + 1] -
     252          25 :                                       psShape->panPartStart[iRing];
     253          49 :                     nRingStart = psShape->panPartStart[iRing];
     254             :                 }
     255             : 
     256          49 :                 if (psShape->nSHPType == SHPT_ARCZ)
     257          10 :                     poLine->setPoints(
     258          14 :                         nRingPoints, psShape->padfX + nRingStart,
     259          14 :                         psShape->padfY + nRingStart,
     260          14 :                         psShape->padfZ + nRingStart,
     261          14 :                         psShape->padfM ? psShape->padfM + nRingStart : nullptr);
     262          35 :                 else if (psShape->nSHPType == SHPT_ARCM &&
     263           8 :                          psShape->padfM != nullptr)
     264           6 :                     poLine->setPointsM(nRingPoints, psShape->padfX + nRingStart,
     265           6 :                                        psShape->padfY + nRingStart,
     266           6 :                                        psShape->padfM + nRingStart);
     267             :                 else
     268          29 :                     poLine->setPoints(nRingPoints, psShape->padfX + nRingStart,
     269          29 :                                       psShape->padfY + nRingStart);
     270             : 
     271          49 :                 poOGRMulti->addGeometryDirectly(poLine);
     272             :             }
     273        4757 :         }
     274             :     }
     275             : 
     276             :     /* -------------------------------------------------------------------- */
     277             :     /*      Polygon                                                         */
     278             :     /*                                                                      */
     279             :     /* As for now Z coordinate is not handled correctly                     */
     280             :     /* -------------------------------------------------------------------- */
     281       37405 :     else if (psShape->nSHPType == SHPT_POLYGON ||
     282         742 :              psShape->nSHPType == SHPT_POLYGONM ||
     283         734 :              psShape->nSHPType == SHPT_POLYGONZ)
     284             :     {
     285       36689 :         const bool bHasZ = psShape->nSHPType == SHPT_POLYGONZ;
     286       36689 :         const bool bHasM = bHasZ || psShape->nSHPType == SHPT_POLYGONM;
     287             : 
     288             : #if DEBUG_VERBOSE
     289             :         CPLDebug("Shape", "Shape type: polygon with nParts=%d",
     290             :                  psShape->nParts);
     291             : #endif
     292             : 
     293       36689 :         if (psShape->nParts == 0)
     294             :         {
     295           1 :             poOGR = nullptr;
     296             :         }
     297       36688 :         else if (psShape->nParts == 1)
     298             :         {
     299             :             // Surely outer ring.
     300       36519 :             OGRPolygon *poOGRPoly = new OGRPolygon();
     301       36519 :             poOGR = poOGRPoly;
     302             : 
     303       36519 :             poOGRPoly->addRing(CreateLinearRing(psShape, 0, bHasZ, bHasM));
     304             :         }
     305             :         else
     306             :         {
     307         338 :             std::vector<std::unique_ptr<OGRGeometry>> apoPolygons;
     308         169 :             apoPolygons.reserve(psShape->nParts);
     309         830 :             for (int iRing = 0; iRing < psShape->nParts; iRing++)
     310             :             {
     311         661 :                 auto poPoly = std::make_unique<OGRPolygon>();
     312         661 :                 poPoly->addRing(CreateLinearRing(psShape, iRing, bHasZ, bHasM));
     313         661 :                 apoPolygons.push_back(std::move(poPoly));
     314             :             }
     315             : 
     316             :             // Tries to detect bad geometries where a multi-part multipolygon is
     317             :             // written as a single-part multipolygon with its parts as inner
     318             :             // rings, like done by QGIS <= 3.28.11 with GDAL >= 3.7
     319             :             // Cf https://github.com/qgis/QGIS/issues/54537
     320         169 :             bool bUseSlowMethod = false;
     321         169 :             if (!bHasZ && !bHasM)
     322             :             {
     323         155 :                 bool bFoundCW = false;
     324         311 :                 for (int iRing = 1; iRing < psShape->nParts; iRing++)
     325             :                 {
     326         209 :                     if (apoPolygons[iRing]
     327             :                             ->toPolygon()
     328         209 :                             ->getExteriorRing()
     329         209 :                             ->isClockwise())
     330             :                     {
     331          53 :                         bFoundCW = true;
     332          53 :                         break;
     333             :                     }
     334             :                 }
     335         155 :                 if (!bFoundCW)
     336             :                 {
     337             :                     // Only inner rings
     338         102 :                     OGREnvelope sFirstEnvelope;
     339         102 :                     OGREnvelope sCurEnvelope;
     340             :                     const OGRLinearRing *poExteriorRing =
     341         102 :                         apoPolygons[0]->toPolygon()->getExteriorRing();
     342         102 :                     poExteriorRing->getEnvelope(&sFirstEnvelope);
     343         203 :                     for (int iRing = 1; iRing < psShape->nParts; iRing++)
     344             :                     {
     345         103 :                         apoPolygons[iRing]->getEnvelope(&sCurEnvelope);
     346         103 :                         if (!sFirstEnvelope.Intersects(sCurEnvelope))
     347             :                         {
     348             :                             // If the envelopes of the rings don't intersect,
     349             :                             // then it is clearly a multi-part polygon
     350           1 :                             bUseSlowMethod = true;
     351           1 :                             break;
     352             :                         }
     353             :                         else
     354             :                         {
     355             :                             // Otherwise take 4 points at each extremity of
     356             :                             // the inner rings and check if there are in the
     357             :                             // outer ring. If none are within it, then it is
     358             :                             // very likely a outer ring (or an invalid ring
     359             :                             // which is neither a outer nor a inner ring)
     360         102 :                             const auto poRing = apoPolygons[iRing]
     361             :                                                     ->toPolygon()
     362         102 :                                                     ->getExteriorRing();
     363         102 :                             const auto nNumPoints = poRing->getNumPoints();
     364         102 :                             OGRPoint p;
     365             :                             OGRPoint leftPoint(
     366         102 :                                 std::numeric_limits<double>::infinity(), 0);
     367             :                             OGRPoint rightPoint(
     368         102 :                                 -std::numeric_limits<double>::infinity(), 0);
     369             :                             OGRPoint bottomPoint(
     370         102 :                                 0, std::numeric_limits<double>::infinity());
     371             :                             OGRPoint topPoint(
     372         102 :                                 0, -std::numeric_limits<double>::infinity());
     373       15694 :                             for (int iPoint = 0; iPoint < nNumPoints - 1;
     374             :                                  ++iPoint)
     375             :                             {
     376       15592 :                                 poRing->getPoint(iPoint, &p);
     377       34724 :                                 if (p.getX() < leftPoint.getX() ||
     378       19132 :                                     (p.getX() == leftPoint.getX() &&
     379        7607 :                                      p.getY() < leftPoint.getY()))
     380             :                                 {
     381        7866 :                                     leftPoint = p;
     382             :                                 }
     383       34876 :                                 if (p.getX() > rightPoint.getX() ||
     384       19284 :                                     (p.getX() == rightPoint.getX() &&
     385        3813 :                                      p.getY() > rightPoint.getY()))
     386             :                                 {
     387        3931 :                                     rightPoint = p;
     388             :                                 }
     389       34890 :                                 if (p.getY() < bottomPoint.getY() ||
     390       19298 :                                     (p.getY() == bottomPoint.getY() &&
     391        3894 :                                      p.getX() > bottomPoint.getX()))
     392             :                                 {
     393        3997 :                                     bottomPoint = p;
     394             :                                 }
     395       31007 :                                 if (p.getY() > topPoint.getY() ||
     396       15415 :                                     (p.getY() == topPoint.getY() &&
     397        3824 :                                      p.getX() < topPoint.getX()))
     398             :                                 {
     399        7811 :                                     topPoint = p;
     400             :                                 }
     401             :                             }
     402         102 :                             if (!poExteriorRing->isPointInRing(&leftPoint) &&
     403           1 :                                 !poExteriorRing->isPointInRing(&rightPoint) &&
     404         104 :                                 !poExteriorRing->isPointInRing(&bottomPoint) &&
     405           1 :                                 !poExteriorRing->isPointInRing(&topPoint))
     406             :                             {
     407           1 :                                 bUseSlowMethod = true;
     408           1 :                                 break;
     409             :                             }
     410             :                         }
     411             :                     }
     412         102 :                     if (bUseSlowMethod && !bHasWarnedWrongWindingOrder)
     413             :                     {
     414           1 :                         bHasWarnedWrongWindingOrder = true;
     415           1 :                         CPLError(CE_Warning, CPLE_AppDefined,
     416             :                                  "%s contains polygon(s) with rings with "
     417             :                                  "invalid winding order. Autocorrecting them, "
     418             :                                  "but that shapefile should be corrected using "
     419             :                                  "ogr2ogr for example.",
     420             :                                  VSI_SHP_GetFilename(hSHP->fpSHP));
     421             :                     }
     422             :                 }
     423             :             }
     424             : 
     425         169 :             bool isValidGeometry = false;
     426         169 :             const char *const apszOptions[] = {
     427         169 :                 bUseSlowMethod ? "METHOD=DEFAULT" : "METHOD=ONLY_CCW", nullptr};
     428         338 :             poOGR = OGRGeometryFactory::organizePolygons(
     429             :                         apoPolygons, &isValidGeometry, apszOptions)
     430         169 :                         .release();
     431             : 
     432         169 :             if (!isValidGeometry)
     433             :             {
     434           0 :                 CPLError(
     435             :                     CE_Warning, CPLE_AppDefined,
     436             :                     "Geometry of polygon of fid %d cannot be translated to "
     437             :                     "Simple Geometry. "
     438             :                     "All polygons will be contained in a multipolygon.",
     439             :                     iShape);
     440             :             }
     441       36689 :         }
     442             :     }
     443             : 
     444             :     /* -------------------------------------------------------------------- */
     445             :     /*      MultiPatch                                                      */
     446             :     /* -------------------------------------------------------------------- */
     447         716 :     else if (psShape->nSHPType == SHPT_MULTIPATCH)
     448             :     {
     449          12 :         poOGR = OGRCreateFromMultiPatch(
     450          12 :             psShape->nParts, psShape->panPartStart, psShape->panPartType,
     451          12 :             psShape->nVertices, psShape->padfX, psShape->padfY, psShape->padfZ);
     452             :     }
     453             : 
     454             :     /* -------------------------------------------------------------------- */
     455             :     /*      Otherwise for now we just ignore the object.                    */
     456             :     /* -------------------------------------------------------------------- */
     457             :     else
     458             :     {
     459         704 :         if (psShape->nSHPType != SHPT_NULL)
     460             :         {
     461           0 :             CPLDebug("OGR", "Unsupported shape type in SHPReadOGRObject()");
     462             :         }
     463             : 
     464             :         // Nothing returned.
     465             :     }
     466             : 
     467             :     /* -------------------------------------------------------------------- */
     468             :     /*      Cleanup shape, and set feature id.                              */
     469             :     /* -------------------------------------------------------------------- */
     470       92600 :     SHPDestroyObject(psShape);
     471             : 
     472       92600 :     return poOGR;
     473             : }
     474             : 
     475             : /************************************************************************/
     476             : /*                     CheckNonFiniteCoordinates()                      */
     477             : /************************************************************************/
     478             : 
     479       77152 : static bool CheckNonFiniteCoordinates(const double *v, size_t vsize)
     480             : {
     481         114 :     static bool bAllowNonFiniteCoordinates = CPLTestBool(
     482       77266 :         CPLGetConfigOption("OGR_SHAPE_ALLOW_NON_FINITE_COORDINATES", "NO"));
     483             :     // Do not document this. Only for edge case testing
     484       77152 :     if (bAllowNonFiniteCoordinates)
     485             :     {
     486           0 :         return true;
     487             :     }
     488      550342 :     for (size_t i = 0; i < vsize; ++i)
     489             :     {
     490      473194 :         if (!std::isfinite(v[i]))
     491             :         {
     492           4 :             CPLError(CE_Failure, CPLE_NotSupported,
     493             :                      "Coordinates with non-finite values are not allowed");
     494           4 :             return false;
     495             :         }
     496             :     }
     497       77148 :     return true;
     498             : }
     499             : 
     500       77116 : static bool CheckNonFiniteCoordinates(const std::vector<double> &v)
     501             : {
     502       77116 :     return CheckNonFiniteCoordinates(v.data(), v.size());
     503             : }
     504             : 
     505             : /************************************************************************/
     506             : /*                         SHPWriteOGRObject()                          */
     507             : /************************************************************************/
     508       64673 : static OGRErr SHPWriteOGRObject(SHPHandle hSHP, int iShape,
     509             :                                 const OGRGeometry *poGeom, bool bRewind,
     510             :                                 OGRwkbGeometryType eLayerGeomType)
     511             : 
     512             : {
     513             :     /* ==================================================================== */
     514             :     /*      Write "shape" with no geometry or with empty geometry           */
     515             :     /* ==================================================================== */
     516       64673 :     if (poGeom == nullptr || poGeom->IsEmpty())
     517             :     {
     518             :         SHPObject *psShape =
     519         617 :             SHPCreateObject(SHPT_NULL, -1, 0, nullptr, nullptr, 0, nullptr,
     520             :                             nullptr, nullptr, nullptr);
     521         617 :         const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
     522         617 :         SHPDestroyObject(psShape);
     523         617 :         if (nReturnedShapeID == -1)
     524             :         {
     525             :             // Assuming error is reported by SHPWriteObject().
     526           0 :             return OGRERR_FAILURE;
     527             :         }
     528             :     }
     529             : 
     530             :     /* ==================================================================== */
     531             :     /*      Write point geometry.                                           */
     532             :     /* ==================================================================== */
     533       64056 :     else if (hSHP->nShapeType == SHPT_POINT ||
     534       63284 :              hSHP->nShapeType == SHPT_POINTM || hSHP->nShapeType == SHPT_POINTZ)
     535             :     {
     536       44724 :         if (wkbFlatten(poGeom->getGeometryType()) != wkbPoint)
     537             :         {
     538          12 :             CPLError(CE_Failure, CPLE_AppDefined,
     539             :                      "Attempt to write non-point (%s) geometry to"
     540             :                      " point shapefile.",
     541          12 :                      poGeom->getGeometryName());
     542             : 
     543          13 :             return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     544             :         }
     545             : 
     546       44712 :         const OGRPoint *poPoint = poGeom->toPoint();
     547       44712 :         const double dfX = poPoint->getX();
     548       44712 :         const double dfY = poPoint->getY();
     549       44712 :         const double dfZ = poPoint->getZ();
     550       44712 :         double dfM = -std::numeric_limits<double>::max();
     551       44712 :         double *pdfM = nullptr;
     552       44717 :         if (wkbHasM(eLayerGeomType) && (hSHP->nShapeType == SHPT_POINTM ||
     553           5 :                                         hSHP->nShapeType == SHPT_POINTZ))
     554             :         {
     555          10 :             if (poGeom->IsMeasured())
     556          10 :                 dfM = poPoint->getM();
     557          10 :             pdfM = &dfM;
     558             :         }
     559       89424 :         if ((!std::isfinite(dfX) || !std::isfinite(dfY) ||
     560       89425 :              !std::isfinite(dfZ) || (pdfM && !std::isfinite(*pdfM))) &&
     561           1 :             !CPLTestBool(CPLGetConfigOption(
     562             :                 "OGR_SHAPE_ALLOW_NON_FINITE_COORDINATES", "NO")))
     563             :         {
     564           1 :             CPLError(CE_Failure, CPLE_NotSupported,
     565             :                      "Coordinates with non-finite values are not allowed");
     566           1 :             return OGRERR_FAILURE;
     567             :         }
     568             :         SHPObject *psShape =
     569       44711 :             SHPCreateObject(hSHP->nShapeType, -1, 0, nullptr, nullptr, 1, &dfX,
     570             :                             &dfY, &dfZ, pdfM);
     571       44711 :         const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
     572       44711 :         SHPDestroyObject(psShape);
     573       44711 :         if (nReturnedShapeID == -1)
     574       44711 :             return OGRERR_FAILURE;
     575             :     }
     576             :     /* ==================================================================== */
     577             :     /*      MultiPoint.                                                     */
     578             :     /* ==================================================================== */
     579       19332 :     else if (hSHP->nShapeType == SHPT_MULTIPOINT ||
     580       19318 :              hSHP->nShapeType == SHPT_MULTIPOINTM ||
     581       19315 :              hSHP->nShapeType == SHPT_MULTIPOINTZ)
     582             :     {
     583          31 :         if (wkbFlatten(poGeom->getGeometryType()) != wkbMultiPoint)
     584             :         {
     585           8 :             CPLError(CE_Failure, CPLE_AppDefined,
     586             :                      "Attempt to write non-multipoint (%s) geometry to "
     587             :                      "multipoint shapefile.",
     588           8 :                      poGeom->getGeometryName());
     589             : 
     590           8 :             return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     591             :         }
     592             : 
     593          23 :         const OGRMultiPoint *poMP = poGeom->toMultiPoint();
     594          23 :         const int nNumGeometries = poMP->getNumGeometries();
     595          43 :         const bool bHasZ = (hSHP->nShapeType == SHPT_MULTIPOINTM ||
     596          20 :                             hSHP->nShapeType == SHPT_MULTIPOINTZ);
     597          23 :         const bool bHasM = wkbHasM(eLayerGeomType) && bHasZ;
     598          23 :         const bool bIsGeomMeasured = CPL_TO_BOOL(poGeom->IsMeasured());
     599             : 
     600          23 :         std::vector<double> adfX;
     601          23 :         std::vector<double> adfY;
     602          23 :         std::vector<double> adfZ;
     603          23 :         std::vector<double> adfM;
     604             :         try
     605             :         {
     606          23 :             adfX.reserve(nNumGeometries);
     607          23 :             adfY.reserve(nNumGeometries);
     608          23 :             if (bHasZ)
     609          14 :                 adfZ.reserve(nNumGeometries);
     610          23 :             if (bHasM)
     611           6 :                 adfM.reserve(nNumGeometries);
     612             :         }
     613           0 :         catch (const std::exception &e)
     614             :         {
     615           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
     616           0 :             return OGRERR_FAILURE;
     617             :         }
     618             : 
     619          57 :         for (const OGRPoint *poPoint : *poMP)
     620             :         {
     621             :             // Ignore POINT EMPTY.
     622          34 :             if (!poPoint->IsEmpty())
     623             :             {
     624          33 :                 adfX.push_back(poPoint->getX());
     625          33 :                 adfY.push_back(poPoint->getY());
     626          33 :                 if (bHasZ)
     627          20 :                     adfZ.push_back(poPoint->getZ());
     628          33 :                 if (bHasM)
     629             :                 {
     630           8 :                     if (bIsGeomMeasured)
     631           8 :                         adfM.push_back(poPoint->getM());
     632             :                     else
     633           0 :                         adfM.push_back(-std::numeric_limits<double>::max());
     634             :                 }
     635             :             }
     636             :             else
     637             :             {
     638           1 :                 CPLDebug("OGR",
     639             :                          "Ignored POINT EMPTY inside MULTIPOINT in shapefile "
     640             :                          "writer.");
     641             :             }
     642             :         }
     643          23 :         if (!CheckNonFiniteCoordinates(adfX) ||
     644          23 :             !CheckNonFiniteCoordinates(adfY) ||
     645          69 :             !CheckNonFiniteCoordinates(adfZ) ||
     646          23 :             !CheckNonFiniteCoordinates(adfM))
     647             :         {
     648           0 :             return OGRERR_FAILURE;
     649             :         }
     650             : 
     651          52 :         SHPObject *psShape = SHPCreateObject(
     652             :             hSHP->nShapeType, -1, 0, nullptr, nullptr,
     653          23 :             static_cast<int>(adfX.size()), adfX.data(), adfY.data(),
     654          20 :             bHasZ ? adfZ.data() : nullptr, bHasM ? adfM.data() : nullptr);
     655          23 :         const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
     656          23 :         SHPDestroyObject(psShape);
     657             : 
     658          23 :         if (nReturnedShapeID == -1)
     659          23 :             return OGRERR_FAILURE;
     660             :     }
     661             : 
     662             :     /* ==================================================================== */
     663             :     /*      Arcs                                                            */
     664             :     /* ==================================================================== */
     665       19301 :     else if (hSHP->nShapeType == SHPT_ARC || hSHP->nShapeType == SHPT_ARCM ||
     666       16774 :              hSHP->nShapeType == SHPT_ARCZ)
     667             :     {
     668           0 :         std::unique_ptr<OGRGeometry> poGeomToDelete;  // keep in that scope
     669        4418 :         const OGRMultiLineString *poML = nullptr;
     670        4418 :         OGRMultiLineString oMLFromLineString;
     671        4418 :         const auto eFlatGeomType = wkbFlatten(poGeom->getGeometryType());
     672        4418 :         if (eFlatGeomType == wkbMultiLineString)
     673             :         {
     674          27 :             poML = poGeom->toMultiLineString();
     675             :         }
     676        4391 :         else if (eFlatGeomType == wkbLineString)
     677             :         {
     678             :             // Borrow the geometry
     679        4371 :             oMLFromLineString.addGeometryDirectly(
     680        4371 :                 const_cast<OGRLineString *>(poGeom->toLineString()));
     681        4371 :             poML = &oMLFromLineString;
     682             :         }
     683             :         else
     684             :         {
     685          40 :             poGeomToDelete = std::unique_ptr<OGRGeometry>(
     686          40 :                 OGRGeometryFactory::forceToMultiLineString(poGeom->clone()));
     687          20 :             if (wkbFlatten(poGeomToDelete->getGeometryType()) !=
     688             :                 wkbMultiLineString)
     689             :             {
     690          13 :                 CPLError(CE_Failure, CPLE_AppDefined,
     691             :                          "Attempt to write non-linestring (%s) geometry to "
     692             :                          "ARC type shapefile.",
     693          13 :                          poGeom->getGeometryName());
     694             : 
     695          13 :                 return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     696             :             }
     697           7 :             poML = poGeomToDelete->toMultiLineString();
     698             :         }
     699             : 
     700        4405 :         const int nNumGeometries = poML->getNumGeometries();
     701             : 
     702        4405 :         int nTotalPoints = 0;
     703        8829 :         for (const auto poArc : poML)
     704             :         {
     705        4424 :             const int nNumPoints = poArc->getNumPoints();
     706        4424 :             if (nTotalPoints > std::numeric_limits<int>::max() - nNumPoints)
     707             :             {
     708           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Too big geometry");
     709           0 :                 return OGRERR_FAILURE;
     710             :             }
     711        4424 :             nTotalPoints += nNumPoints;
     712             :         }
     713             : 
     714        4405 :         std::vector<int> anRingStart;
     715        4405 :         std::vector<double> adfX;
     716        4405 :         std::vector<double> adfY;
     717        4405 :         std::vector<double> adfZ;
     718        4405 :         std::vector<double> adfM;
     719        4405 :         const bool bHasZ =
     720        4405 :             (hSHP->nShapeType == SHPT_ARCM || hSHP->nShapeType == SHPT_ARCZ);
     721        4405 :         const bool bHasM = wkbHasM(eLayerGeomType) && bHasZ;
     722        4405 :         const bool bIsGeomMeasured = CPL_TO_BOOL(poGeom->IsMeasured());
     723             : 
     724             :         try
     725             :         {
     726        4405 :             anRingStart.reserve(nNumGeometries);
     727             : 
     728        4405 :             adfX.reserve(nTotalPoints);
     729        4405 :             adfY.reserve(nTotalPoints);
     730        4405 :             if (bHasZ)
     731             :             {
     732        1892 :                 adfZ.reserve(nTotalPoints);
     733             :             }
     734        4405 :             if (bHasM)
     735             :             {
     736          10 :                 adfM.reserve(nTotalPoints);
     737             :             }
     738             :         }
     739           0 :         catch (const std::exception &e)
     740             :         {
     741           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
     742             :             // Give back the borrowed line string
     743           0 :             if (eFlatGeomType == wkbLineString)
     744           0 :                 oMLFromLineString.removeGeometry(0, /* bDelete=*/false);
     745           0 :             return OGRERR_FAILURE;
     746             :         }
     747             : 
     748        8829 :         for (const auto poArc : poML)
     749             :         {
     750        4424 :             const int nNumPoints = poArc->getNumPoints();
     751             : 
     752             :             // Ignore LINESTRING EMPTY.
     753        4424 :             if (nNumPoints == 0)
     754             :             {
     755           1 :                 CPLDebug("OGR",
     756             :                          "Ignore LINESTRING EMPTY inside MULTILINESTRING in "
     757             :                          "shapefile writer.");
     758           1 :                 continue;
     759             :             }
     760             : 
     761        4423 :             anRingStart.push_back(static_cast<int>(adfX.size()));
     762             : 
     763       81565 :             for (int iPoint = 0; iPoint < nNumPoints; iPoint++)
     764             :             {
     765       77142 :                 adfX.push_back(poArc->getX(iPoint));
     766       77142 :                 adfY.push_back(poArc->getY(iPoint));
     767       77142 :                 if (bHasZ)
     768             :                 {
     769       49841 :                     adfZ.push_back(poArc->getZ(iPoint));
     770             :                 }
     771       77142 :                 if (bHasM)
     772             :                 {
     773          28 :                     if (bIsGeomMeasured)
     774          28 :                         adfM.push_back(poArc->getM(iPoint));
     775             :                     else
     776           0 :                         adfM.push_back(-std::numeric_limits<double>::max());
     777             :                 }
     778             :             }
     779             :         }
     780             : 
     781             :         // Give back the borrowed line string
     782        4405 :         if (eFlatGeomType == wkbLineString)
     783        4371 :             oMLFromLineString.removeGeometry(0, /* bDelete=*/false);
     784             : 
     785        4405 :         if (!CheckNonFiniteCoordinates(adfX) ||
     786        4405 :             !CheckNonFiniteCoordinates(adfY) ||
     787       13213 :             !CheckNonFiniteCoordinates(adfZ) ||
     788        4403 :             !CheckNonFiniteCoordinates(adfM))
     789             :         {
     790           2 :             return OGRERR_FAILURE;
     791             :         }
     792             : 
     793        8816 :         SHPObject *psShape = SHPCreateObject(
     794        4403 :             hSHP->nShapeType, iShape, static_cast<int>(anRingStart.size()),
     795        4403 :             anRingStart.data(), nullptr, static_cast<int>(adfX.size()),
     796        4403 :             adfX.data(), adfY.data(), bHasZ ? adfZ.data() : nullptr,
     797          10 :             bHasM ? adfM.data() : nullptr);
     798        4403 :         const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
     799        4403 :         SHPDestroyObject(psShape);
     800             : 
     801        4403 :         if (nReturnedShapeID == -1)
     802        4403 :             return OGRERR_FAILURE;
     803             :     }
     804             : 
     805             :     /* ==================================================================== */
     806             :     /*      Polygons/MultiPolygons                                          */
     807             :     /* ==================================================================== */
     808       14883 :     else if (hSHP->nShapeType == SHPT_POLYGON ||
     809         100 :              hSHP->nShapeType == SHPT_POLYGONM ||
     810          95 :              hSHP->nShapeType == SHPT_POLYGONZ)
     811             :     {
     812             :         // bool = true means outer ring
     813       14870 :         std::vector<std::pair<const OGRLinearRing *, bool>> apoRings;
     814       14870 :         const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
     815           0 :         std::unique_ptr<OGRGeometry> poGeomToDelete;
     816             : 
     817       14870 :         if (eType == wkbPolygon || eType == wkbTriangle)
     818             :         {
     819       14724 :             const OGRPolygon *poPoly = poGeom->toPolygon();
     820             : 
     821       29448 :             if (poPoly->getExteriorRing() == nullptr ||
     822       14724 :                 poPoly->getExteriorRing()->IsEmpty())
     823             :             {
     824           1 :                 CPLDebug("OGR", "Ignore POLYGON EMPTY in shapefile writer.");
     825             :             }
     826             :             else
     827             :             {
     828       14723 :                 const int nSrcRings = poPoly->getNumInteriorRings() + 1;
     829       14723 :                 apoRings.reserve(nSrcRings);
     830       14723 :                 bool bFirstRing = true;
     831       29457 :                 for (const auto poRing : poPoly)
     832             :                 {
     833       14734 :                     const int nNumPoints = poRing->getNumPoints();
     834             : 
     835             :                     // Ignore LINEARRING EMPTY.
     836       14734 :                     if (nNumPoints != 0)
     837             :                     {
     838       14733 :                         apoRings.push_back(std::make_pair(poRing, bFirstRing));
     839             :                     }
     840             :                     else
     841             :                     {
     842           1 :                         CPLDebug("OGR",
     843             :                                  "Ignore LINEARRING EMPTY inside POLYGON in "
     844             :                                  "shapefile writer.");
     845             :                     }
     846       14734 :                     bFirstRing = false;
     847             :                 }
     848       14724 :             }
     849             :         }
     850         146 :         else if (eType == wkbMultiPolygon || eType == wkbGeometryCollection ||
     851          14 :                  eType == wkbPolyhedralSurface || eType == wkbTIN)
     852             :         {
     853             :             const OGRGeometryCollection *poGC;
     854             :             // for PolyhedralSurface and TIN
     855         132 :             if (eType == wkbPolyhedralSurface || eType == wkbTIN)
     856             :             {
     857           0 :                 poGeomToDelete = OGRGeometryFactory::forceTo(
     858           0 :                     std::unique_ptr<OGRGeometry>(poGeom->clone()),
     859           0 :                     wkbMultiPolygon, nullptr);
     860           0 :                 poGC = poGeomToDelete->toGeometryCollection();
     861             :             }
     862             : 
     863             :             else
     864         132 :                 poGC = poGeom->toGeometryCollection();
     865             : 
     866             :             // Shouldn't happen really, but to please x86_64-w64-mingw32-g++ -O2
     867             :             // -Wnull-dereference
     868         132 :             if (poGC == nullptr)
     869           3 :                 return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     870             : 
     871         365 :             for (const auto poSubGeom : poGC)
     872             :             {
     873         236 :                 if (wkbFlatten(poSubGeom->getGeometryType()) != wkbPolygon)
     874             :                 {
     875           3 :                     CPLError(CE_Failure, CPLE_AppDefined,
     876             :                              "Attempt to write non-polygon (%s) geometry to "
     877             :                              "POLYGON type shapefile.",
     878           3 :                              poSubGeom->getGeometryName());
     879             : 
     880           3 :                     return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     881             :                 }
     882         233 :                 const OGRPolygon *poPoly = poSubGeom->toPolygon();
     883             : 
     884             :                 // Ignore POLYGON EMPTY.
     885         465 :                 if (poPoly->getExteriorRing() == nullptr ||
     886         232 :                     poPoly->getExteriorRing()->IsEmpty())
     887             :                 {
     888           1 :                     CPLDebug("OGR",
     889             :                              "Ignore POLYGON EMPTY inside MULTIPOLYGON in "
     890             :                              "shapefile writer.");
     891           1 :                     continue;
     892             :                 }
     893             : 
     894         232 :                 const int nNumInteriorRings = poPoly->getNumInteriorRings();
     895             :                 // to avoid coverity scan warning: "To avoid a quadratic time
     896             :                 // penalty when using reserve(), always increase the capacity
     897             :                 /// by a multiple of its current value"
     898         232 :                 if (apoRings.size() + nNumInteriorRings + 1 >
     899         413 :                         apoRings.capacity() &&
     900         181 :                     apoRings.size() < std::numeric_limits<size_t>::max() / 2)
     901             :                 {
     902         181 :                     apoRings.reserve(std::max(
     903         181 :                         2 * apoRings.size(), apoRings.size() + apoRings.size() +
     904         362 :                                                  nNumInteriorRings + 1));
     905             :                 }
     906         232 :                 bool bFirstRing = true;
     907         589 :                 for (const auto poRing : poPoly)
     908             :                 {
     909         357 :                     const int nNumPoints = poRing->getNumPoints();
     910             : 
     911             :                     // Ignore LINEARRING EMPTY.
     912         357 :                     if (nNumPoints != 0)
     913             :                     {
     914         356 :                         apoRings.push_back(std::make_pair(poRing, bFirstRing));
     915             :                     }
     916             :                     else
     917             :                     {
     918           1 :                         CPLDebug("OGR",
     919             :                                  "Ignore LINEARRING EMPTY inside POLYGON in "
     920             :                                  "shapefile writer.");
     921             :                     }
     922         357 :                     bFirstRing = false;
     923             :                 }
     924         129 :             }
     925             :         }
     926             :         else
     927             :         {
     928          14 :             CPLError(CE_Failure, CPLE_AppDefined,
     929             :                      "Attempt to write non-polygon (%s) geometry to "
     930             :                      "POLYGON type shapefile.",
     931          14 :                      poGeom->getGeometryName());
     932             : 
     933          14 :             return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     934             :         }
     935             : 
     936             :         /* --------------------------------------------------------------------
     937             :          */
     938             :         /*      If we only had emptypolygons or unacceptable geometries */
     939             :         /*      write NULL geometry object. */
     940             :         /* --------------------------------------------------------------------
     941             :          */
     942       14853 :         if (apoRings.empty())
     943             :         {
     944             :             SHPObject *psShape =
     945           1 :                 SHPCreateObject(SHPT_NULL, -1, 0, nullptr, nullptr, 0, nullptr,
     946             :                                 nullptr, nullptr, nullptr);
     947           1 :             const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
     948           1 :             SHPDestroyObject(psShape);
     949             : 
     950           1 :             if (nReturnedShapeID == -1)
     951           0 :                 return OGRERR_FAILURE;
     952             : 
     953           1 :             return OGRERR_NONE;
     954             :         }
     955             : 
     956             :         // Count vertices.
     957       14852 :         int nVertex = 0;
     958       29941 :         for (const auto &ring : apoRings)
     959       15089 :             nVertex += ring.first->getNumPoints();
     960             : 
     961       29699 :         const bool bHasZ = (hSHP->nShapeType == SHPT_POLYGONM ||
     962       14847 :                             hSHP->nShapeType == SHPT_POLYGONZ);
     963       14852 :         const bool bHasM = wkbHasM(eLayerGeomType) && bHasZ;
     964       14852 :         const bool bIsGeomMeasured = CPL_TO_BOOL(poGeom->IsMeasured());
     965             : 
     966       14852 :         std::vector<int> anRingStart;
     967       14852 :         std::vector<double> adfX;
     968       14852 :         std::vector<double> adfY;
     969       14852 :         std::vector<double> adfZ;
     970       14852 :         std::vector<double> adfM;
     971             :         try
     972             :         {
     973       14852 :             anRingStart.reserve(apoRings.size());
     974       14852 :             adfX.reserve(nVertex);
     975       14852 :             adfY.reserve(nVertex);
     976       14852 :             if (bHasZ)
     977          81 :                 adfZ.reserve(nVertex);
     978       14852 :             if (bHasM)
     979          10 :                 adfM.reserve(nVertex);
     980             :         }
     981           0 :         catch (const std::exception &e)
     982             :         {
     983           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
     984           0 :             return OGRERR_FAILURE;
     985             :         }
     986             : 
     987             :         // Collect vertices.
     988       29941 :         for (const auto &ring : apoRings)
     989             :         {
     990       15089 :             const auto poRing = ring.first;
     991       15089 :             const bool bIsOuterRing = ring.second;
     992       15089 :             anRingStart.push_back(static_cast<int>(adfX.size()));
     993             : 
     994       15089 :             const int nNumPoints = poRing->getNumPoints();
     995             :             // Exterior ring must be clockwise oriented in shapefiles
     996             :             const bool bInvertOrder =
     997       15223 :                 !bRewind && CPL_TO_BOOL(bIsOuterRing ? !poRing->isClockwise()
     998         134 :                                                      : poRing->isClockwise());
     999      148728 :             for (int i = 0; i < nNumPoints; i++)
    1000             :             {
    1001      133639 :                 const int iPoint = bInvertOrder ? nNumPoints - 1 - i : i;
    1002      133639 :                 adfX.push_back(poRing->getX(iPoint));
    1003      133639 :                 adfY.push_back(poRing->getY(iPoint));
    1004      133639 :                 if (bHasZ)
    1005        1461 :                     adfZ.push_back(poRing->getZ(iPoint));
    1006      133639 :                 if (bHasM)
    1007             :                 {
    1008          56 :                     adfM.push_back(bIsGeomMeasured
    1009          56 :                                        ? poRing->getM(iPoint)
    1010           0 :                                        : -std::numeric_limits<double>::max());
    1011             :                 }
    1012             :             }
    1013             :         }
    1014       14852 :         if (!CheckNonFiniteCoordinates(adfX) ||
    1015       14852 :             !CheckNonFiniteCoordinates(adfY) ||
    1016       44554 :             !CheckNonFiniteCoordinates(adfZ) ||
    1017       14850 :             !CheckNonFiniteCoordinates(adfM))
    1018             :         {
    1019           2 :             return OGRERR_FAILURE;
    1020             :         }
    1021             : 
    1022       29710 :         SHPObject *psShape = SHPCreateObject(
    1023       14850 :             hSHP->nShapeType, iShape, static_cast<int>(anRingStart.size()),
    1024       14850 :             anRingStart.data(), nullptr, static_cast<int>(adfX.size()),
    1025       14850 :             adfX.data(), adfY.data(), bHasZ ? adfZ.data() : nullptr,
    1026          10 :             bHasM ? adfM.data() : nullptr);
    1027       14850 :         if (bRewind)
    1028           0 :             SHPRewindObject(hSHP, psShape);
    1029       14850 :         const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
    1030       14850 :         SHPDestroyObject(psShape);
    1031             : 
    1032       14850 :         if (nReturnedShapeID == -1)
    1033       14850 :             return OGRERR_FAILURE;
    1034             :     }
    1035             : 
    1036             :     /* ==================================================================== */
    1037             :     /*      Multipatch                                                      */
    1038             :     /* ==================================================================== */
    1039          13 :     else if (hSHP->nShapeType == SHPT_MULTIPATCH)
    1040             :     {
    1041          13 :         int nParts = 0;
    1042          13 :         std::vector<int> anPartStart;
    1043          13 :         std::vector<int> anPartType;
    1044          13 :         int nPoints = 0;
    1045          13 :         std::vector<OGRRawPoint> aoPoints;
    1046          13 :         std::vector<double> adfZ;
    1047          13 :         OGRErr eErr = OGRCreateMultiPatch(poGeom,
    1048             :                                           FALSE,  // no SHPP_TRIANGLES
    1049             :                                           nParts, anPartStart, anPartType,
    1050             :                                           nPoints, aoPoints, adfZ);
    1051          13 :         if (eErr != OGRERR_NONE)
    1052           1 :             return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1053             : 
    1054          12 :         std::vector<double> adfX(nPoints);
    1055          12 :         std::vector<double> adfY(nPoints);
    1056          64 :         for (int i = 0; i < nPoints; ++i)
    1057             :         {
    1058          52 :             adfX[i] = aoPoints[i].x;
    1059          52 :             adfY[i] = aoPoints[i].y;
    1060             :         }
    1061             : 
    1062          12 :         if (!CheckNonFiniteCoordinates(adfX.data(), nPoints) ||
    1063          24 :             !CheckNonFiniteCoordinates(adfY.data(), nPoints) ||
    1064          12 :             !CheckNonFiniteCoordinates(adfZ.data(), nPoints))
    1065             :         {
    1066           0 :             return OGRERR_FAILURE;
    1067             :         }
    1068             : 
    1069             :         SHPObject *psShape =
    1070          12 :             SHPCreateObject(hSHP->nShapeType, iShape, nParts,
    1071          12 :                             anPartStart.data(), anPartType.data(), nPoints,
    1072          12 :                             adfX.data(), adfY.data(), adfZ.data(), nullptr);
    1073          12 :         if (bRewind)
    1074           5 :             SHPRewindObject(hSHP, psShape);
    1075          12 :         const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
    1076          12 :         SHPDestroyObject(psShape);
    1077             : 
    1078          12 :         if (nReturnedShapeID == -1)
    1079           0 :             return OGRERR_FAILURE;
    1080             :     }
    1081             : 
    1082             :     else
    1083             :     {
    1084           0 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1085             :     }
    1086             : 
    1087       64616 :     return OGRERR_NONE;
    1088             : }
    1089             : 
    1090             : /************************************************************************/
    1091             : /*                       SHPReadOGRFeatureDefn()                        */
    1092             : /************************************************************************/
    1093             : 
    1094        7782 : OGRFeatureDefn *SHPReadOGRFeatureDefn(const char *pszName, SHPHandle hSHP,
    1095             :                                       DBFHandle hDBF, VSILFILE *fpSHPXML,
    1096             :                                       const char *pszSHPEncoding,
    1097             :                                       int bAdjustType)
    1098             : 
    1099             : {
    1100        7782 :     int nAdjustableFields = 0;
    1101        7782 :     const int nFieldCount = hDBF ? DBFGetFieldCount(hDBF) : 0;
    1102             : 
    1103        7782 :     OGRFeatureDefn *const poDefn = new OGRFeatureDefn(pszName);
    1104        7782 :     poDefn->Reference();
    1105             : 
    1106             :     // Parse .shp.xml side car if available, to get long field names and aliases
    1107             :     // but only if they are consistent with the number of DBF fields and their
    1108             :     // content.
    1109        7782 :     std::vector<OGRFieldDefn> aFieldsFromSHPXML;
    1110        7782 :     if (fpSHPXML)
    1111             :     {
    1112           2 :         fpSHPXML->Seek(0, SEEK_END);
    1113           2 :         const auto nSize = fpSHPXML->Tell();
    1114           2 :         if (nSize < 10 * 1024 * 1024)
    1115             :         {
    1116           2 :             fpSHPXML->Seek(0, SEEK_SET);
    1117           2 :             GByte *pabyOut = nullptr;
    1118           2 :             if (VSIIngestFile(fpSHPXML, nullptr, &pabyOut, nullptr, -1))
    1119             :             {
    1120           2 :                 const char *pszXML = reinterpret_cast<char *>(pabyOut);
    1121           4 :                 CPLXMLTreeCloser oTree(CPLParseXMLString(pszXML));
    1122           2 :                 if (oTree)
    1123             :                 {
    1124             :                     const CPLXMLNode *psFields =
    1125           2 :                         CPLGetXMLNode(oTree.get(), "=metadata.eainfo.detailed");
    1126           2 :                     int iField = 0;
    1127           2 :                     for (const CPLXMLNode *psIter = psFields ? psFields->psChild
    1128             :                                                              : nullptr;
    1129          19 :                          psIter; psIter = psIter->psNext)
    1130             :                     {
    1131          17 :                         if (psIter->eType != CXT_Element ||
    1132          15 :                             strcmp(psIter->pszValue, "attr") != 0)
    1133           8 :                             continue;
    1134             :                         const char *pszType =
    1135          13 :                             CPLGetXMLValue(psIter, "attrtype", "");
    1136          13 :                         if (strcmp(pszType, "OID") == 0 ||
    1137          11 :                             strcmp(pszType, "Geometry") == 0)
    1138           4 :                             continue;
    1139             :                         const char *pszLabel =
    1140           9 :                             CPLGetXMLValue(psIter, "attrlabl", "");
    1141           9 :                         if (iField == nFieldCount)
    1142             :                         {
    1143           0 :                             CPLDebug("Shape",
    1144             :                                      "More fields in .shp.xml than in .dbf");
    1145           0 :                             aFieldsFromSHPXML.clear();
    1146           0 :                             break;
    1147             :                         }
    1148             : 
    1149           9 :                         char szFieldNameFromDBF[XBASE_FLDNAME_LEN_READ + 1] =
    1150             :                             {};
    1151           9 :                         int nWidth = 0;
    1152           9 :                         int nPrecision = 0;
    1153           9 :                         CPL_IGNORE_RET_VAL(
    1154           9 :                             DBFGetFieldInfo(hDBF, iField, szFieldNameFromDBF,
    1155             :                                             &nWidth, &nPrecision));
    1156           9 :                         std::string osFieldNameFromDBF(szFieldNameFromDBF);
    1157           9 :                         if (strlen(pszSHPEncoding) > 0)
    1158             :                         {
    1159             :                             char *pszUTF8Field =
    1160           9 :                                 CPLRecode(szFieldNameFromDBF, pszSHPEncoding,
    1161             :                                           CPL_ENC_UTF8);
    1162           9 :                             osFieldNameFromDBF = pszUTF8Field;
    1163           9 :                             CPLFree(pszUTF8Field);
    1164             :                         }
    1165             :                         // Check that field names are consistent
    1166          26 :                         if ((strlen(pszLabel) < 10 &&
    1167          18 :                              pszLabel != osFieldNameFromDBF) ||
    1168          10 :                             (strlen(pszLabel) >= 10 &&
    1169           1 :                              osFieldNameFromDBF.size() >= 10 &&
    1170           1 :                              strncmp(pszLabel, osFieldNameFromDBF.c_str(), 5) !=
    1171             :                                  0))
    1172             :                         {
    1173           0 :                             CPLDebug("Shape",
    1174             :                                      "For field at index %d, mismatch between "
    1175             :                                      ".shp.xml name (%s) vs .dbf name (%s)",
    1176             :                                      iField, pszLabel, szFieldNameFromDBF);
    1177           0 :                             aFieldsFromSHPXML.clear();
    1178           0 :                             break;
    1179             :                         }
    1180             : 
    1181           9 :                         OGRFieldDefn oField(pszLabel, OFTMaxType);
    1182             :                         const char *pszAlias =
    1183           9 :                             CPLGetXMLValue(psIter, "attalias", "");
    1184           9 :                         if (pszAlias[0] && strcmp(pszLabel, pszAlias) != 0)
    1185           1 :                             oField.SetAlternativeName(pszAlias);
    1186             :                         const char *pszWidth =
    1187           9 :                             CPLGetXMLValue(psIter, "attwidth", "");
    1188           9 :                         if (strcmp(pszType, "Integer") == 0 &&
    1189           1 :                             strcmp(pszWidth, "4") == 0)
    1190           1 :                             oField.SetType(OFTInteger);
    1191           9 :                         aFieldsFromSHPXML.push_back(std::move(oField));
    1192           9 :                         ++iField;
    1193             :                     }
    1194           2 :                     if (iField != nFieldCount)
    1195           0 :                         aFieldsFromSHPXML.clear();
    1196             :                 }
    1197             :             }
    1198           2 :             CPLFree(pabyOut);
    1199             :         }
    1200             :     }
    1201             : 
    1202       19393 :     for (int iField = 0; iField < nFieldCount; iField++)
    1203             :     {
    1204             :         // On reading we support up to 11 characters
    1205       11611 :         char szFieldName[XBASE_FLDNAME_LEN_READ + 1] = {};
    1206       11611 :         int nWidth = 0;
    1207       11611 :         int nPrecision = 0;
    1208             :         DBFFieldType eDBFType =
    1209       11611 :             DBFGetFieldInfo(hDBF, iField, szFieldName, &nWidth, &nPrecision);
    1210             : 
    1211       23222 :         OGRFieldDefn oField("", OFTInteger);
    1212       11611 :         if (!aFieldsFromSHPXML.empty())
    1213             :         {
    1214           9 :             oField = aFieldsFromSHPXML[iField];
    1215             :         }
    1216       11602 :         else if (strlen(pszSHPEncoding) > 0)
    1217             :         {
    1218             :             char *const pszUTF8Field =
    1219        7237 :                 CPLRecode(szFieldName, pszSHPEncoding, CPL_ENC_UTF8);
    1220        7237 :             oField.SetName(pszUTF8Field);
    1221        7237 :             CPLFree(pszUTF8Field);
    1222             :         }
    1223             :         else
    1224             :         {
    1225        4365 :             oField.SetName(szFieldName);
    1226             :         }
    1227             : 
    1228       11611 :         oField.SetWidth(nWidth);
    1229       11611 :         oField.SetPrecision(nPrecision);
    1230             : 
    1231       11611 :         if (eDBFType == FTDate)
    1232             :         {
    1233             :             // Shapefile date has following 8-chars long format:
    1234             :             //
    1235             :             //     20060101.
    1236             :             //
    1237             :             // Split as YYYY/MM/DD, so 2 additional characters are required.
    1238          63 :             oField.SetWidth(nWidth + 2);
    1239          63 :             oField.SetType(OFTDate);
    1240             :         }
    1241       11548 :         else if (eDBFType == FTDouble)
    1242             :         {
    1243        4384 :             nAdjustableFields += (nPrecision == 0);
    1244        4384 :             if (nPrecision == 0 && nWidth < 19)
    1245             :             {
    1246        2532 :                 if (!aFieldsFromSHPXML.empty() &&
    1247           1 :                     aFieldsFromSHPXML[iField].GetType() == OFTInteger)
    1248           0 :                     oField.SetType(OFTInteger);
    1249             :                 else
    1250        2531 :                     oField.SetType(OFTInteger64);
    1251             :             }
    1252             :             else
    1253        1853 :                 oField.SetType(OFTReal);
    1254             :         }
    1255        7164 :         else if (eDBFType == FTInteger)
    1256        1153 :             oField.SetType(OFTInteger);
    1257        6011 :         else if (eDBFType == FTLogical)
    1258             :         {
    1259           2 :             oField.SetType(OFTInteger);
    1260           2 :             oField.SetSubType(OFSTBoolean);
    1261             :         }
    1262             :         else
    1263        6009 :             oField.SetType(OFTString);
    1264             : 
    1265       11611 :         poDefn->AddFieldDefn(&oField);
    1266             :     }
    1267             : 
    1268             :     // Do an optional past if requested and needed to demote Integer64->Integer
    1269             :     // or Real->Integer64/Integer.
    1270        7782 :     if (nAdjustableFields && bAdjustType)
    1271             :     {
    1272             :         int *panAdjustableField =
    1273           1 :             static_cast<int *>(CPLCalloc(sizeof(int), nFieldCount));
    1274           3 :         for (int iField = 0; iField < nFieldCount; iField++)
    1275             :         {
    1276           2 :             OGRFieldType eType = poDefn->GetFieldDefn(iField)->GetType();
    1277           3 :             if (poDefn->GetFieldDefn(iField)->GetPrecision() == 0 &&
    1278           1 :                 (eType == OFTInteger64 || eType == OFTReal))
    1279             :             {
    1280           2 :                 panAdjustableField[iField] = TRUE;
    1281           2 :                 poDefn->GetFieldDefn(iField)->SetType(OFTInteger);
    1282             :             }
    1283             :         }
    1284             : 
    1285           1 :         const int nRowCount = DBFGetRecordCount(hDBF);
    1286           2 :         for (int iRow = 0; iRow < nRowCount && nAdjustableFields; iRow++)
    1287             :         {
    1288           3 :             for (int iField = 0; iField < nFieldCount; iField++)
    1289             :             {
    1290           2 :                 if (panAdjustableField[iField])
    1291             :                 {
    1292             :                     const char *pszValue =
    1293           2 :                         DBFReadStringAttribute(hDBF, iRow, iField);
    1294           2 :                     const int nValueLength = static_cast<int>(strlen(pszValue));
    1295           2 :                     if (nValueLength >= 10)
    1296             :                     {
    1297           2 :                         int bOverflow = FALSE;
    1298             :                         const GIntBig nVal =
    1299           2 :                             CPLAtoGIntBigEx(pszValue, FALSE, &bOverflow);
    1300           2 :                         if (bOverflow)
    1301             :                         {
    1302           0 :                             poDefn->GetFieldDefn(iField)->SetType(OFTReal);
    1303           0 :                             panAdjustableField[iField] = FALSE;
    1304           0 :                             nAdjustableFields--;
    1305             :                         }
    1306           2 :                         else if (!CPL_INT64_FITS_ON_INT32(nVal))
    1307             :                         {
    1308           1 :                             poDefn->GetFieldDefn(iField)->SetType(OFTInteger64);
    1309           1 :                             if (poDefn->GetFieldDefn(iField)->GetWidth() <= 18)
    1310             :                             {
    1311           0 :                                 panAdjustableField[iField] = FALSE;
    1312           0 :                                 nAdjustableFields--;
    1313             :                             }
    1314             :                         }
    1315             :                     }
    1316             :                 }
    1317             :             }
    1318             :         }
    1319             : 
    1320           1 :         CPLFree(panAdjustableField);
    1321             :     }
    1322             : 
    1323        7782 :     if (hSHP == nullptr)
    1324             :     {
    1325         788 :         poDefn->SetGeomType(wkbNone);
    1326             :     }
    1327             :     else
    1328             :     {
    1329        6994 :         switch (hSHP->nShapeType)
    1330             :         {
    1331        1732 :             case SHPT_POINT:
    1332        1732 :                 poDefn->SetGeomType(wkbPoint);
    1333        1732 :                 break;
    1334             : 
    1335         142 :             case SHPT_POINTZ:
    1336         142 :                 poDefn->SetGeomType(wkbPointZM);
    1337         142 :                 break;
    1338             : 
    1339          10 :             case SHPT_POINTM:
    1340          10 :                 poDefn->SetGeomType(wkbPointM);
    1341          10 :                 break;
    1342             : 
    1343        2922 :             case SHPT_ARC:
    1344        2922 :                 poDefn->SetGeomType(wkbLineString);
    1345        2922 :                 break;
    1346             : 
    1347         177 :             case SHPT_ARCZ:
    1348         177 :                 poDefn->SetGeomType(wkbLineStringZM);
    1349         177 :                 break;
    1350             : 
    1351          14 :             case SHPT_ARCM:
    1352          14 :                 poDefn->SetGeomType(wkbLineStringM);
    1353          14 :                 break;
    1354             : 
    1355         140 :             case SHPT_MULTIPOINT:
    1356         140 :                 poDefn->SetGeomType(wkbMultiPoint);
    1357         140 :                 break;
    1358             : 
    1359         105 :             case SHPT_MULTIPOINTZ:
    1360         105 :                 poDefn->SetGeomType(wkbMultiPointZM);
    1361         105 :                 break;
    1362             : 
    1363           6 :             case SHPT_MULTIPOINTM:
    1364           6 :                 poDefn->SetGeomType(wkbMultiPointM);
    1365           6 :                 break;
    1366             : 
    1367        1577 :             case SHPT_POLYGON:
    1368        1577 :                 poDefn->SetGeomType(wkbPolygon);
    1369        1577 :                 break;
    1370             : 
    1371         135 :             case SHPT_POLYGONZ:
    1372         135 :                 poDefn->SetGeomType(wkbPolygonZM);
    1373         135 :                 break;
    1374             : 
    1375          14 :             case SHPT_POLYGONM:
    1376          14 :                 poDefn->SetGeomType(wkbPolygonM);
    1377          14 :                 break;
    1378             : 
    1379          20 :             case SHPT_MULTIPATCH:
    1380          20 :                 poDefn->SetGeomType(wkbUnknown);  // not ideal
    1381          20 :                 break;
    1382             :         }
    1383             :     }
    1384             : 
    1385       15564 :     return poDefn;
    1386             : }
    1387             : 
    1388             : /************************************************************************/
    1389             : /*                         SHPReadOGRFeature()                          */
    1390             : /************************************************************************/
    1391             : 
    1392       96759 : OGRFeature *SHPReadOGRFeature(SHPHandle hSHP, DBFHandle hDBF,
    1393             :                               OGRFeatureDefn *poDefn, int iShape,
    1394             :                               SHPObject *psShape, const char *pszSHPEncoding,
    1395             :                               bool &bHasWarnedWrongWindingOrder)
    1396             : 
    1397             : {
    1398       96759 :     if (iShape < 0 || (hSHP != nullptr && iShape >= hSHP->nRecords) ||
    1399       96696 :         (hDBF != nullptr && iShape >= hDBF->nRecords))
    1400             :     {
    1401          21 :         CPLError(CE_Failure, CPLE_AppDefined,
    1402             :                  "Attempt to read shape with feature id (%d) out of available"
    1403             :                  " range.",
    1404             :                  iShape);
    1405          21 :         return nullptr;
    1406             :     }
    1407             : 
    1408       96738 :     if (hDBF && DBFIsRecordDeleted(hDBF, iShape))
    1409             :     {
    1410           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    1411             :                  "Attempt to read shape with feature id (%d), "
    1412             :                  "but it is marked deleted.",
    1413             :                  iShape);
    1414           2 :         if (psShape != nullptr)
    1415           0 :             SHPDestroyObject(psShape);
    1416           2 :         return nullptr;
    1417             :     }
    1418             : 
    1419       96736 :     OGRFeature *poFeature = new OGRFeature(poDefn);
    1420             : 
    1421             :     /* -------------------------------------------------------------------- */
    1422             :     /*      Fetch geometry from Shapefile to OGRFeature.                    */
    1423             :     /* -------------------------------------------------------------------- */
    1424       96736 :     if (hSHP != nullptr)
    1425             :     {
    1426       92932 :         if (!poDefn->IsGeometryIgnored())
    1427             :         {
    1428       92055 :             OGRGeometry *poGeometry = SHPReadOGRObject(
    1429             :                 hSHP, iShape, psShape, bHasWarnedWrongWindingOrder);
    1430             : 
    1431             :             // Two possibilities are expected here (both are tested by
    1432             :             // GDAL Autotests):
    1433             :             //   1. Read valid geometry and assign it directly.
    1434             :             //   2. Read and assign null geometry if it can not be read
    1435             :             //      correctly from a shapefile.
    1436             :             //
    1437             :             // It is NOT required here to test poGeometry == NULL.
    1438             : 
    1439       92055 :             if (poGeometry)
    1440             :             {
    1441             :                 // Set/unset flags.
    1442             :                 const OGRwkbGeometryType eMyGeomType =
    1443       91337 :                     poFeature->GetDefnRef()->GetGeomFieldDefn(0)->GetType();
    1444             : 
    1445       91337 :                 if (eMyGeomType != wkbUnknown)
    1446             :                 {
    1447             :                     OGRwkbGeometryType eGeomInType =
    1448       91325 :                         poGeometry->getGeometryType();
    1449       91325 :                     if (wkbHasZ(eMyGeomType) && !wkbHasZ(eGeomInType))
    1450             :                     {
    1451           0 :                         poGeometry->set3D(TRUE);
    1452             :                     }
    1453       91325 :                     else if (!wkbHasZ(eMyGeomType) && wkbHasZ(eGeomInType))
    1454             :                     {
    1455           0 :                         poGeometry->set3D(FALSE);
    1456             :                     }
    1457       91325 :                     if (wkbHasM(eMyGeomType) && !wkbHasM(eGeomInType))
    1458             :                     {
    1459           0 :                         poGeometry->setMeasured(TRUE);
    1460             :                     }
    1461       91325 :                     else if (!wkbHasM(eMyGeomType) && wkbHasM(eGeomInType))
    1462             :                     {
    1463           1 :                         poGeometry->setMeasured(FALSE);
    1464             :                     }
    1465             :                 }
    1466             :             }
    1467             : 
    1468       92055 :             poFeature->SetGeometryDirectly(poGeometry);
    1469             :         }
    1470         877 :         else if (psShape != nullptr)
    1471             :         {
    1472          10 :             SHPDestroyObject(psShape);
    1473             :         }
    1474             :     }
    1475             : 
    1476             :     /* -------------------------------------------------------------------- */
    1477             :     /*      Fetch feature attributes to OGRFeature fields.                  */
    1478             :     /* -------------------------------------------------------------------- */
    1479             : 
    1480      239796 :     for (int iField = 0; hDBF != nullptr && iField < poDefn->GetFieldCount();
    1481             :          iField++)
    1482             :     {
    1483      143060 :         const OGRFieldDefn *const poFieldDefn = poDefn->GetFieldDefn(iField);
    1484      143060 :         if (poFieldDefn->IsIgnored())
    1485        1926 :             continue;
    1486             : 
    1487      141134 :         switch (poFieldDefn->GetType())
    1488             :         {
    1489       15915 :             case OFTString:
    1490             :             {
    1491             :                 const char *const pszFieldVal =
    1492       15915 :                     DBFReadStringAttribute(hDBF, iShape, iField);
    1493       15915 :                 if (pszFieldVal != nullptr && pszFieldVal[0] != '\0')
    1494             :                 {
    1495       14367 :                     if (pszSHPEncoding[0] != '\0')
    1496             :                     {
    1497        4636 :                         char *const pszUTF8Field = CPLRecode(
    1498             :                             pszFieldVal, pszSHPEncoding, CPL_ENC_UTF8);
    1499        4636 :                         poFeature->SetField(iField, pszUTF8Field);
    1500        4636 :                         CPLFree(pszUTF8Field);
    1501             :                     }
    1502             :                     else
    1503       14367 :                         poFeature->SetField(iField, pszFieldVal);
    1504             :                 }
    1505             :                 else
    1506             :                 {
    1507        1548 :                     poFeature->SetFieldNull(iField);
    1508             :                 }
    1509       15915 :                 break;
    1510             :             }
    1511      125194 :             case OFTInteger:
    1512             :             case OFTInteger64:
    1513             :             case OFTReal:
    1514             :             {
    1515      125194 :                 if (DBFIsAttributeNULL(hDBF, iShape, iField))
    1516             :                 {
    1517          82 :                     poFeature->SetFieldNull(iField);
    1518             :                 }
    1519             :                 else
    1520             :                 {
    1521      125112 :                     if (poFieldDefn->GetSubType() == OFSTBoolean)
    1522             :                     {
    1523             :                         const char *pszVal =
    1524           2 :                             DBFReadLogicalAttribute(hDBF, iShape, iField);
    1525           2 :                         poFeature->SetField(
    1526           2 :                             iField, pszVal[0] == 'T' || pszVal[0] == 't' ||
    1527           1 :                                             pszVal[0] == 'Y' || pszVal[0] == 'y'
    1528             :                                         ? 1
    1529             :                                         : 0);
    1530             :                     }
    1531             :                     else
    1532             :                     {
    1533             :                         const char *pszVal =
    1534      125110 :                             DBFReadStringAttribute(hDBF, iShape, iField);
    1535      125110 :                         poFeature->SetField(iField, pszVal);
    1536             :                     }
    1537             :                 }
    1538      125194 :                 break;
    1539             :             }
    1540          25 :             case OFTDate:
    1541             :             {
    1542          25 :                 if (DBFIsAttributeNULL(hDBF, iShape, iField))
    1543             :                 {
    1544          16 :                     poFeature->SetFieldNull(iField);
    1545          16 :                     continue;
    1546             :                 }
    1547             : 
    1548             :                 const char *const pszDateValue =
    1549           9 :                     DBFReadStringAttribute(hDBF, iShape, iField);
    1550             : 
    1551             :                 OGRField sFld;
    1552           9 :                 memset(&sFld, 0, sizeof(sFld));
    1553             : 
    1554           9 :                 if (strlen(pszDateValue) >= 10 && pszDateValue[2] == '/' &&
    1555           1 :                     pszDateValue[5] == '/')
    1556             :                 {
    1557           1 :                     sFld.Date.Month =
    1558           1 :                         static_cast<GByte>(atoi(pszDateValue + 0));
    1559           1 :                     sFld.Date.Day = static_cast<GByte>(atoi(pszDateValue + 3));
    1560           1 :                     sFld.Date.Year =
    1561           1 :                         static_cast<GInt16>(atoi(pszDateValue + 6));
    1562             :                 }
    1563             :                 else
    1564             :                 {
    1565           8 :                     const int nFullDate = atoi(pszDateValue);
    1566           8 :                     sFld.Date.Year = static_cast<GInt16>(nFullDate / 10000);
    1567           8 :                     sFld.Date.Month =
    1568           8 :                         static_cast<GByte>((nFullDate / 100) % 100);
    1569           8 :                     sFld.Date.Day = static_cast<GByte>(nFullDate % 100);
    1570             :                 }
    1571             : 
    1572           9 :                 poFeature->SetField(iField, &sFld);
    1573             :             }
    1574           9 :             break;
    1575             : 
    1576           0 :             default:
    1577           0 :                 CPLAssert(false);
    1578             :         }
    1579             :     }
    1580             : 
    1581       96736 :     if (poFeature != nullptr)
    1582       96736 :         poFeature->SetFID(iShape);
    1583             : 
    1584       96736 :     return poFeature;
    1585             : }
    1586             : 
    1587             : /************************************************************************/
    1588             : /*                             GrowField()                              */
    1589             : /************************************************************************/
    1590             : 
    1591           6 : static OGRErr GrowField(DBFHandle hDBF, int iField, OGRFieldDefn *poFieldDefn,
    1592             :                         int nNewSize)
    1593             : {
    1594           6 :     char szFieldName[20] = {};
    1595           6 :     int nOriWidth = 0;
    1596           6 :     int nPrecision = 0;
    1597           6 :     DBFGetFieldInfo(hDBF, iField, szFieldName, &nOriWidth, &nPrecision);
    1598             : 
    1599           6 :     CPLDebug("SHAPE", "Extending field %d (%s) from %d to %d characters",
    1600             :              iField, poFieldDefn->GetNameRef(), nOriWidth, nNewSize);
    1601             : 
    1602           6 :     const char chNativeType = DBFGetNativeFieldType(hDBF, iField);
    1603           6 :     if (!DBFAlterFieldDefn(hDBF, iField, szFieldName, chNativeType, nNewSize,
    1604             :                            nPrecision))
    1605             :     {
    1606           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1607             :                  "Extending field %d (%s) from %d to %d characters failed",
    1608             :                  iField, poFieldDefn->GetNameRef(), nOriWidth, nNewSize);
    1609           0 :         return OGRERR_FAILURE;
    1610             :     }
    1611             : 
    1612           6 :     auto oTemporaryUnsealer(poFieldDefn->GetTemporaryUnsealer());
    1613           6 :     poFieldDefn->SetWidth(nNewSize);
    1614           6 :     return OGRERR_NONE;
    1615             : }
    1616             : 
    1617             : /************************************************************************/
    1618             : /*                         SHPWriteOGRFeature()                         */
    1619             : /*                                                                      */
    1620             : /*      Write to an existing feature in a shapefile, or create a new    */
    1621             : /*      feature.                                                        */
    1622             : /************************************************************************/
    1623             : 
    1624       66808 : OGRErr SHPWriteOGRFeature(SHPHandle hSHP, DBFHandle hDBF,
    1625             :                           OGRFeatureDefn *poDefn, OGRFeature *poFeature,
    1626             :                           const char *pszSHPEncoding,
    1627             :                           bool *pbTruncationWarningEmitted, bool bRewind)
    1628             : 
    1629             : {
    1630             :     /* -------------------------------------------------------------------- */
    1631             :     /*      Write the geometry.                                             */
    1632             :     /* -------------------------------------------------------------------- */
    1633       66808 :     if (hSHP != nullptr)
    1634             :     {
    1635       64673 :         const OGRErr eErr = SHPWriteOGRObject(
    1636       64673 :             hSHP, static_cast<int>(poFeature->GetFID()),
    1637       64673 :             poFeature->GetGeometryRef(), bRewind, poDefn->GetGeomType());
    1638       64673 :         if (eErr != OGRERR_NONE)
    1639          56 :             return eErr;
    1640             :     }
    1641             : 
    1642             :     /* -------------------------------------------------------------------- */
    1643             :     /*      If there is no DBF, the job is done now.                        */
    1644             :     /* -------------------------------------------------------------------- */
    1645       66752 :     if (hDBF == nullptr)
    1646             :     {
    1647             :         /* --------------------------------------------------------------------
    1648             :          */
    1649             :         /*      If this is a new feature, establish its feature id. */
    1650             :         /* --------------------------------------------------------------------
    1651             :          */
    1652          15 :         if (hSHP != nullptr && poFeature->GetFID() == OGRNullFID)
    1653           1 :             poFeature->SetFID(hSHP->nRecords - 1);
    1654             : 
    1655          15 :         return OGRERR_NONE;
    1656             :     }
    1657             : 
    1658             :     /* -------------------------------------------------------------------- */
    1659             :     /*      If this is a new feature, establish its feature id.             */
    1660             :     /* -------------------------------------------------------------------- */
    1661       66737 :     if (poFeature->GetFID() == OGRNullFID)
    1662       66691 :         poFeature->SetFID(DBFGetRecordCount(hDBF));
    1663             : 
    1664             :     /* -------------------------------------------------------------------- */
    1665             :     /*      If this is the first feature to be written, verify that we      */
    1666             :     /*      have at least one attribute in the DBF file.  If not, create    */
    1667             :     /*      a dummy FID attribute to satisfy the requirement that there     */
    1668             :     /*      be at least one attribute.                                      */
    1669             :     /* -------------------------------------------------------------------- */
    1670       66737 :     if (DBFGetRecordCount(hDBF) == 0 && DBFGetFieldCount(hDBF) == 0)
    1671             :     {
    1672         241 :         CPLDebug(
    1673             :             "OGR",
    1674             :             "Created dummy FID field for shapefile since schema is empty.");
    1675         241 :         DBFAddField(hDBF, "FID", FTInteger, 11, 0);
    1676             :     }
    1677             : 
    1678             :     /* -------------------------------------------------------------------- */
    1679             :     /*      Write out dummy field value if it exists.                       */
    1680             :     /* -------------------------------------------------------------------- */
    1681       66737 :     if (poDefn->GetFieldCount() == 0)
    1682             :     {
    1683       56527 :         if (DBFGetFieldCount(hDBF) == 1)
    1684             :         {
    1685       56526 :             DBFWriteIntegerAttribute(hDBF,
    1686       56526 :                                      static_cast<int>(poFeature->GetFID()), 0,
    1687       56526 :                                      static_cast<int>(poFeature->GetFID()));
    1688             :         }
    1689           1 :         else if (DBFGetFieldCount(hDBF) == 0)
    1690             :         {
    1691             :             // Far from being nominal... Could happen if deleting all fields
    1692             :             // of a DBF with rows
    1693           1 :             DBFWriteAttributeDirectly(
    1694           1 :                 hDBF, static_cast<int>(poFeature->GetFID()), -1, nullptr);
    1695             :         }
    1696             :     }
    1697             : 
    1698             :     /* -------------------------------------------------------------------- */
    1699             :     /*      Write all the fields.                                           */
    1700             :     /* -------------------------------------------------------------------- */
    1701       88849 :     for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
    1702             :     {
    1703       22112 :         if (!poFeature->IsFieldSetAndNotNull(iField))
    1704             :         {
    1705         617 :             DBFWriteNULLAttribute(hDBF, static_cast<int>(poFeature->GetFID()),
    1706             :                                   iField);
    1707         617 :             continue;
    1708             :         }
    1709             : 
    1710       21495 :         OGRFieldDefn *const poFieldDefn = poDefn->GetFieldDefn(iField);
    1711             : 
    1712       21495 :         switch (poFieldDefn->GetType())
    1713             :         {
    1714        4511 :             case OFTString:
    1715             :             {
    1716        4511 :                 const char *pszStr = poFeature->GetFieldAsString(iField);
    1717        4511 :                 char *pszEncoded = nullptr;
    1718        4511 :                 if (pszSHPEncoding[0] != '\0')
    1719             :                 {
    1720             :                     pszEncoded =
    1721        4501 :                         CPLRecode(pszStr, CPL_ENC_UTF8, pszSHPEncoding);
    1722        4501 :                     pszStr = pszEncoded;
    1723             :                 }
    1724             : 
    1725        4511 :                 int nStrLen = static_cast<int>(strlen(pszStr));
    1726        4511 :                 if (nStrLen > OGR_DBF_MAX_FIELD_WIDTH)
    1727             :                 {
    1728           3 :                     if (!(*pbTruncationWarningEmitted))
    1729             :                     {
    1730           2 :                         *pbTruncationWarningEmitted = true;
    1731           2 :                         CPLError(
    1732             :                             CE_Warning, CPLE_AppDefined,
    1733             :                             "Value '%s' of field %s has been truncated to %d "
    1734             :                             "characters.  This warning will not be emitted any "
    1735             :                             "more for that layer.",
    1736             :                             poFeature->GetFieldAsString(iField),
    1737             :                             poFieldDefn->GetNameRef(), OGR_DBF_MAX_FIELD_WIDTH);
    1738             :                     }
    1739             : 
    1740           3 :                     nStrLen = OGR_DBF_MAX_FIELD_WIDTH;
    1741             : 
    1742           3 :                     if (pszEncoded != nullptr &&  // For Coverity.
    1743           3 :                         EQUAL(pszSHPEncoding, CPL_ENC_UTF8))
    1744             :                     {
    1745             :                         // Truncate string by making sure we don't cut in the
    1746             :                         // middle of a UTF-8 multibyte character
    1747             :                         // Continuation bytes of such characters are of the form
    1748             :                         // 10xxxxxx (0x80), whereas single-byte are 0xxxxxxx
    1749             :                         // and the start of a multi-byte is 11xxxxxx
    1750           2 :                         const char *p = pszStr + nStrLen;
    1751           2 :                         while (nStrLen > 0)
    1752             :                         {
    1753           2 :                             if ((*p & 0xc0) != 0x80)
    1754             :                             {
    1755           2 :                                 break;
    1756             :                             }
    1757             : 
    1758           0 :                             nStrLen--;
    1759           0 :                             p--;
    1760             :                         }
    1761             : 
    1762           2 :                         pszEncoded[nStrLen] = 0;
    1763             :                     }
    1764             :                 }
    1765             : 
    1766        4511 :                 if (nStrLen > poFieldDefn->GetWidth())
    1767             :                 {
    1768           2 :                     if (GrowField(hDBF, iField, poFieldDefn, nStrLen) !=
    1769             :                         OGRERR_NONE)
    1770             :                     {
    1771           0 :                         CPLFree(pszEncoded);
    1772           0 :                         return OGRERR_FAILURE;
    1773             :                     }
    1774             :                 }
    1775             : 
    1776        4511 :                 DBFWriteStringAttribute(hDBF,
    1777        4511 :                                         static_cast<int>(poFeature->GetFID()),
    1778             :                                         iField, pszStr);
    1779             : 
    1780        4511 :                 CPLFree(pszEncoded);
    1781        4511 :                 break;
    1782             :             }
    1783       12895 :             case OFTInteger:
    1784             :             case OFTInteger64:
    1785             :             {
    1786       12895 :                 if (poFieldDefn->GetSubType() == OFSTBoolean)
    1787             :                 {
    1788           4 :                     DBFWriteAttributeDirectly(
    1789           2 :                         hDBF, static_cast<int>(poFeature->GetFID()), iField,
    1790           2 :                         poFeature->GetFieldAsInteger(iField) ? "T" : "F");
    1791             :                 }
    1792             :                 else
    1793             :                 {
    1794       12893 :                     char szValue[32] = {};
    1795       12893 :                     const int nFieldWidth = poFieldDefn->GetWidth();
    1796       12893 :                     snprintf(szValue, sizeof(szValue),
    1797             :                              "%*" CPL_FRMT_GB_WITHOUT_PREFIX "d",
    1798             :                              std::min(nFieldWidth,
    1799       12893 :                                       static_cast<int>(sizeof(szValue)) - 1),
    1800             :                              poFeature->GetFieldAsInteger64(iField));
    1801             : 
    1802       12893 :                     const int nStrLen = static_cast<int>(strlen(szValue));
    1803       12893 :                     if (nStrLen > nFieldWidth)
    1804             :                     {
    1805           4 :                         if (GrowField(hDBF, iField, poFieldDefn, nStrLen) !=
    1806             :                             OGRERR_NONE)
    1807             :                         {
    1808           0 :                             return OGRERR_FAILURE;
    1809             :                         }
    1810             :                     }
    1811             : 
    1812       12893 :                     DBFWriteAttributeDirectly(
    1813       12893 :                         hDBF, static_cast<int>(poFeature->GetFID()), iField,
    1814             :                         szValue);
    1815             :                 }
    1816             : 
    1817       12895 :                 break;
    1818             :             }
    1819             : 
    1820        4051 :             case OFTReal:
    1821             :             {
    1822        4051 :                 const double dfVal = poFeature->GetFieldAsDouble(iField);
    1823             :                 // IEEE754 doubles can store exact values of all integers
    1824             :                 // below 2^53.
    1825        4053 :                 if (poFieldDefn->GetPrecision() == 0 &&
    1826           2 :                     fabs(dfVal) > (static_cast<GIntBig>(1) << 53))
    1827             :                 {
    1828             :                     static int nCounter = 0;
    1829           1 :                     if (nCounter <= 10)
    1830             :                     {
    1831           1 :                         CPLError(CE_Warning, CPLE_AppDefined,
    1832             :                                  "Value %.17g of field %s with 0 decimal of "
    1833             :                                  "feature " CPL_FRMT_GIB
    1834             :                                  " is bigger than 2^53. "
    1835             :                                  "Precision loss likely occurred or going to "
    1836             :                                  "happen.%s",
    1837             :                                  dfVal, poFieldDefn->GetNameRef(),
    1838             :                                  poFeature->GetFID(),
    1839           1 :                                  (nCounter == 10) ? " This warning will not be "
    1840             :                                                     "emitted anymore."
    1841             :                                                   : "");
    1842           1 :                         nCounter++;
    1843             :                     }
    1844             :                 }
    1845        4051 :                 int ret = DBFWriteDoubleAttribute(
    1846        4051 :                     hDBF, static_cast<int>(poFeature->GetFID()), iField, dfVal);
    1847        4051 :                 if (!ret)
    1848             :                 {
    1849           6 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1850             :                              "Value %.17g of field %s of feature " CPL_FRMT_GIB
    1851             :                              " not "
    1852             :                              "successfully written. Possibly due to too larger "
    1853             :                              "number "
    1854             :                              "with respect to field width",
    1855             :                              dfVal, poFieldDefn->GetNameRef(),
    1856             :                              poFeature->GetFID());
    1857             :                 }
    1858        4051 :                 break;
    1859             :             }
    1860          38 :             case OFTDate:
    1861             :             {
    1862             :                 const OGRField *const psField =
    1863          38 :                     poFeature->GetRawFieldRef(iField);
    1864             : 
    1865          38 :                 if (psField->Date.Year < 0 || psField->Date.Year > 9999)
    1866             :                 {
    1867           0 :                     CPLError(
    1868             :                         CE_Warning, CPLE_NotSupported,
    1869             :                         "Year < 0 or > 9999 is not a valid date for shapefile");
    1870             :                 }
    1871          38 :                 else if (psField->Date.Year == 0 && psField->Date.Month == 0 &&
    1872           0 :                          psField->Date.Day == 0)
    1873             :                 {
    1874           0 :                     DBFWriteNULLAttribute(
    1875           0 :                         hDBF, static_cast<int>(poFeature->GetFID()), iField);
    1876             :                 }
    1877             :                 else
    1878             :                 {
    1879          38 :                     DBFWriteIntegerAttribute(
    1880          38 :                         hDBF, static_cast<int>(poFeature->GetFID()), iField,
    1881          38 :                         psField->Date.Year * 10000 + psField->Date.Month * 100 +
    1882          38 :                             psField->Date.Day);
    1883             :                 }
    1884             :             }
    1885          38 :             break;
    1886             : 
    1887           0 :             default:
    1888             :             {
    1889             :                 // Ignore fields of other types.
    1890           0 :                 break;
    1891             :             }
    1892             :         }
    1893             :     }
    1894             : 
    1895       66737 :     return OGRERR_NONE;
    1896             : }

Generated by: LCOV version 1.14