LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/shape - shape2ogr.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 769 829 92.8 %
Date: 2024-05-04 12:52:34 Functions: 10 10 100.0 %

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

Generated by: LCOV version 1.14