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

Generated by: LCOV version 1.14