LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/shape - shape2ogr.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 826 894 92.4 %
Date: 2025-12-10 05:42:13 Functions: 10 10 100.0 %

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

Generated by: LCOV version 1.14