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

Generated by: LCOV version 1.14