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

Generated by: LCOV version 1.14