LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/shape - shpopen.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 838 1288 65.1 %
Date: 2024-05-04 12:52:34 Functions: 19 25 76.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Shapelib
       4             :  * Purpose:  Implementation of core Shapefile read/write functions.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, 2001, Frank Warmerdam
       9             :  * Copyright (c) 2011-2019, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
      12             :  ******************************************************************************/
      13             : 
      14             : #include "shapefil_private.h"
      15             : 
      16             : #include <assert.h>
      17             : #include <errno.h>
      18             : #include <limits.h>
      19             : #include <math.h>
      20             : #include <stdbool.h>
      21             : #include <stdint.h>
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <string.h>
      25             : 
      26             : #ifndef FALSE
      27             : #define FALSE 0
      28             : #define TRUE 1
      29             : #endif
      30             : 
      31             : #define ByteCopy(a, b, c) memcpy(b, a, c)
      32             : #ifndef MAX
      33             : #define MIN(a, b) ((a < b) ? a : b)
      34             : #define MAX(a, b) ((a > b) ? a : b)
      35             : #endif
      36             : 
      37             : #ifndef USE_CPL
      38             : #if defined(_MSC_VER)
      39             : #if _MSC_VER < 1900
      40             : #define snprintf _snprintf
      41             : #endif
      42             : #elif defined(_WIN32)
      43             : #ifndef snprintf
      44             : #define snprintf _snprintf
      45             : #endif
      46             : #endif
      47             : #endif
      48             : 
      49             : /************************************************************************/
      50             : /*                          SHPWriteHeader()                            */
      51             : /*                                                                      */
      52             : /*      Write out a header for the .shp and .shx files as well as the   */
      53             : /*      contents of the index (.shx) file.                              */
      54             : /************************************************************************/
      55             : 
      56        1693 : void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP)
      57             : {
      58        1693 :     if (psSHP->fpSHX == SHPLIB_NULLPTR)
      59             :     {
      60           0 :         psSHP->sHooks.Error("SHPWriteHeader failed : SHX file is closed");
      61           0 :         return;
      62             :     }
      63             : 
      64             :     /* -------------------------------------------------------------------- */
      65             :     /*      Prepare header block for .shp file.                             */
      66             :     /* -------------------------------------------------------------------- */
      67             : 
      68        1693 :     unsigned char abyHeader[100] = {0};
      69        1693 :     abyHeader[2] = 0x27; /* magic cookie */
      70        1693 :     abyHeader[3] = 0x0a;
      71             : 
      72        1693 :     uint32_t i32 = psSHP->nFileSize / 2; /* file size */
      73        1693 :     ByteCopy(&i32, abyHeader + 24, 4);
      74             : #if !defined(SHP_BIG_ENDIAN)
      75        1693 :     SHP_SWAP32(abyHeader + 24);
      76             : #endif
      77             : 
      78        1693 :     i32 = 1000; /* version */
      79        1693 :     ByteCopy(&i32, abyHeader + 28, 4);
      80             : #if defined(SHP_BIG_ENDIAN)
      81             :     SHP_SWAP32(abyHeader + 28);
      82             : #endif
      83             : 
      84        1693 :     i32 = psSHP->nShapeType; /* shape type */
      85        1693 :     ByteCopy(&i32, abyHeader + 32, 4);
      86             : #if defined(SHP_BIG_ENDIAN)
      87             :     SHP_SWAP32(abyHeader + 32);
      88             : #endif
      89             : 
      90        1693 :     double dValue = psSHP->adBoundsMin[0]; /* set bounds */
      91        1693 :     ByteCopy(&dValue, abyHeader + 36, 8);
      92             : #if defined(SHP_BIG_ENDIAN)
      93             :     SHP_SWAP64(abyHeader + 36);
      94             : #endif
      95        1693 :     dValue = psSHP->adBoundsMin[1];
      96        1693 :     ByteCopy(&dValue, abyHeader + 44, 8);
      97             : #if defined(SHP_BIG_ENDIAN)
      98             :     SHP_SWAP64(abyHeader + 44);
      99             : #endif
     100        1693 :     dValue = psSHP->adBoundsMax[0];
     101        1693 :     ByteCopy(&dValue, abyHeader + 52, 8);
     102             : #if defined(SHP_BIG_ENDIAN)
     103             :     SHP_SWAP64(abyHeader + 52);
     104             : #endif
     105             : 
     106        1693 :     dValue = psSHP->adBoundsMax[1];
     107        1693 :     ByteCopy(&dValue, abyHeader + 60, 8);
     108             : #if defined(SHP_BIG_ENDIAN)
     109             :     SHP_SWAP64(abyHeader + 60);
     110             : #endif
     111             : 
     112        1693 :     dValue = psSHP->adBoundsMin[2]; /* z */
     113        1693 :     ByteCopy(&dValue, abyHeader + 68, 8);
     114             : #if defined(SHP_BIG_ENDIAN)
     115             :     SHP_SWAP64(abyHeader + 68);
     116             : #endif
     117             : 
     118        1693 :     dValue = psSHP->adBoundsMax[2];
     119        1693 :     ByteCopy(&dValue, abyHeader + 76, 8);
     120             : #if defined(SHP_BIG_ENDIAN)
     121             :     SHP_SWAP64(abyHeader + 76);
     122             : #endif
     123             : 
     124        1693 :     dValue = psSHP->adBoundsMin[3]; /* m */
     125        1693 :     ByteCopy(&dValue, abyHeader + 84, 8);
     126             : #if defined(SHP_BIG_ENDIAN)
     127             :     SHP_SWAP64(abyHeader + 84);
     128             : #endif
     129             : 
     130        1693 :     dValue = psSHP->adBoundsMax[3];
     131        1693 :     ByteCopy(&dValue, abyHeader + 92, 8);
     132             : #if defined(SHP_BIG_ENDIAN)
     133             :     SHP_SWAP64(abyHeader + 92);
     134             : #endif
     135             : 
     136             :     /* -------------------------------------------------------------------- */
     137             :     /*      Write .shp file header.                                         */
     138             :     /* -------------------------------------------------------------------- */
     139        3386 :     if (psSHP->sHooks.FSeek(psSHP->fpSHP, 0, 0) != 0 ||
     140        1693 :         psSHP->sHooks.FWrite(abyHeader, 100, 1, psSHP->fpSHP) != 1)
     141             :     {
     142             :         char szErrorMsg[200];
     143             : 
     144           0 :         snprintf(szErrorMsg, sizeof(szErrorMsg),
     145           0 :                  "Failure writing .shp header: %s", strerror(errno));
     146           0 :         szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
     147           0 :         psSHP->sHooks.Error(szErrorMsg);
     148           0 :         return;
     149             :     }
     150             : 
     151             :     /* -------------------------------------------------------------------- */
     152             :     /*      Prepare, and write .shx file header.                            */
     153             :     /* -------------------------------------------------------------------- */
     154        1693 :     i32 = (psSHP->nRecords * 2 * sizeof(uint32_t) + 100) / 2; /* file size */
     155        1693 :     ByteCopy(&i32, abyHeader + 24, 4);
     156             : #if !defined(SHP_BIG_ENDIAN)
     157        1693 :     SHP_SWAP32(abyHeader + 24);
     158             : #endif
     159             : 
     160        3386 :     if (psSHP->sHooks.FSeek(psSHP->fpSHX, 0, 0) != 0 ||
     161        1693 :         psSHP->sHooks.FWrite(abyHeader, 100, 1, psSHP->fpSHX) != 1)
     162             :     {
     163             :         char szErrorMsg[200];
     164             : 
     165           0 :         snprintf(szErrorMsg, sizeof(szErrorMsg),
     166           0 :                  "Failure writing .shx header: %s", strerror(errno));
     167           0 :         szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
     168           0 :         psSHP->sHooks.Error(szErrorMsg);
     169             : 
     170           0 :         return;
     171             :     }
     172             : 
     173             :     /* -------------------------------------------------------------------- */
     174             :     /*      Write out the .shx contents.                                    */
     175             :     /* -------------------------------------------------------------------- */
     176             :     uint32_t *panSHX =
     177        1693 :         STATIC_CAST(uint32_t *, malloc(sizeof(uint32_t) * 2 * psSHP->nRecords));
     178        1693 :     if (panSHX == SHPLIB_NULLPTR)
     179             :     {
     180           0 :         psSHP->sHooks.Error("Failure allocatin panSHX");
     181           0 :         return;
     182             :     }
     183             : 
     184      136326 :     for (int i = 0; i < psSHP->nRecords; i++)
     185             :     {
     186      134633 :         panSHX[i * 2] = psSHP->panRecOffset[i] / 2;
     187      134633 :         panSHX[i * 2 + 1] = psSHP->panRecSize[i] / 2;
     188             : #if !defined(SHP_BIG_ENDIAN)
     189      134633 :         SHP_SWAP32(panSHX + i * 2);
     190      134633 :         SHP_SWAP32(panSHX + i * 2 + 1);
     191             : #endif
     192             :     }
     193             : 
     194        1693 :     if (STATIC_CAST(int, psSHP->sHooks.FWrite(panSHX, sizeof(uint32_t) * 2,
     195        1693 :                                               psSHP->nRecords, psSHP->fpSHX)) !=
     196        1693 :         psSHP->nRecords)
     197             :     {
     198             :         char szErrorMsg[200];
     199             : 
     200           0 :         snprintf(szErrorMsg, sizeof(szErrorMsg),
     201           0 :                  "Failure writing .shx contents: %s", strerror(errno));
     202           0 :         szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
     203           0 :         psSHP->sHooks.Error(szErrorMsg);
     204             :     }
     205             : 
     206        1693 :     free(panSHX);
     207             : 
     208             :     /* -------------------------------------------------------------------- */
     209             :     /*      Flush to disk.                                                  */
     210             :     /* -------------------------------------------------------------------- */
     211        1693 :     psSHP->sHooks.FFlush(psSHP->fpSHP);
     212        1693 :     psSHP->sHooks.FFlush(psSHP->fpSHX);
     213             : }
     214             : 
     215             : /************************************************************************/
     216             : /*                              SHPOpen()                               */
     217             : /************************************************************************/
     218             : 
     219           0 : SHPHandle SHPAPI_CALL SHPOpen(const char *pszLayer, const char *pszAccess)
     220             : {
     221             :     SAHooks sHooks;
     222             : 
     223           0 :     SASetupDefaultHooks(&sHooks);
     224             : 
     225           0 :     return SHPOpenLL(pszLayer, pszAccess, &sHooks);
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*                      SHPGetLenWithoutExtension()                     */
     230             : /************************************************************************/
     231             : 
     232        5047 : static int SHPGetLenWithoutExtension(const char *pszBasename)
     233             : {
     234        5047 :     const int nLen = STATIC_CAST(int, strlen(pszBasename));
     235       20188 :     for (int i = nLen - 1;
     236       20188 :          i > 0 && pszBasename[i] != '/' && pszBasename[i] != '\\'; i--)
     237             :     {
     238       20188 :         if (pszBasename[i] == '.')
     239             :         {
     240        5047 :             return i;
     241             :         }
     242             :     }
     243           0 :     return nLen;
     244             : }
     245             : 
     246             : /************************************************************************/
     247             : /*                              SHPOpen()                               */
     248             : /*                                                                      */
     249             : /*      Open the .shp and .shx files based on the basename of the       */
     250             : /*      files or either file name.                                      */
     251             : /************************************************************************/
     252             : 
     253        3487 : SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess,
     254             :                                 const SAHooks *psHooks)
     255             : {
     256             :     /* -------------------------------------------------------------------- */
     257             :     /*      Ensure the access string is one of the legal ones.  We          */
     258             :     /*      ensure the result string indicates binary to avoid common       */
     259             :     /*      problems on Windows.                                            */
     260             :     /* -------------------------------------------------------------------- */
     261        3487 :     bool bLazySHXLoading = false;
     262        3487 :     if (strcmp(pszAccess, "rb+") == 0 || strcmp(pszAccess, "r+b") == 0 ||
     263        3487 :         strcmp(pszAccess, "r+") == 0)
     264             :     {
     265        1660 :         pszAccess = "r+b";
     266             :     }
     267             :     else
     268             :     {
     269        1827 :         bLazySHXLoading = strchr(pszAccess, 'l') != SHPLIB_NULLPTR;
     270        1827 :         pszAccess = "rb";
     271             :     }
     272             : 
     273             :     /* -------------------------------------------------------------------- */
     274             :     /*  Initialize the info structure.                  */
     275             :     /* -------------------------------------------------------------------- */
     276        3487 :     SHPHandle psSHP = STATIC_CAST(SHPHandle, calloc(sizeof(SHPInfo), 1));
     277             : 
     278        3487 :     psSHP->bUpdated = FALSE;
     279        3487 :     memcpy(&(psSHP->sHooks), psHooks, sizeof(SAHooks));
     280             : 
     281             :     /* -------------------------------------------------------------------- */
     282             :     /*  Open the .shp and .shx files.  Note that files pulled from  */
     283             :     /*  a PC to Unix with upper case filenames won't work!      */
     284             :     /* -------------------------------------------------------------------- */
     285        3487 :     const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
     286        3487 :     char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
     287        3487 :     memcpy(pszFullname, pszLayer, nLenWithoutExtension);
     288        3487 :     memcpy(pszFullname + nLenWithoutExtension, ".shp", 5);
     289        3487 :     psSHP->fpSHP =
     290        3487 :         psSHP->sHooks.FOpen(pszFullname, pszAccess, psSHP->sHooks.pvUserData);
     291        3487 :     if (psSHP->fpSHP == SHPLIB_NULLPTR)
     292             :     {
     293         324 :         memcpy(pszFullname + nLenWithoutExtension, ".SHP", 5);
     294         324 :         psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess,
     295             :                                            psSHP->sHooks.pvUserData);
     296             :     }
     297             : 
     298        3487 :     if (psSHP->fpSHP == SHPLIB_NULLPTR)
     299             :     {
     300         322 :         const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
     301         322 :         char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen));
     302         322 :         pszFullname[nLenWithoutExtension] = 0;
     303         322 :         snprintf(pszMessage, nMessageLen,
     304             :                  "Unable to open %s.shp or %s.SHP in %s mode.", pszFullname,
     305             :                  pszFullname, pszAccess);
     306         322 :         psHooks->Error(pszMessage);
     307         322 :         free(pszMessage);
     308             : 
     309         322 :         free(psSHP);
     310         322 :         free(pszFullname);
     311             : 
     312         322 :         return SHPLIB_NULLPTR;
     313             :     }
     314             : 
     315        3165 :     memcpy(pszFullname + nLenWithoutExtension, ".shx", 5);
     316        3165 :     psSHP->fpSHX =
     317        3165 :         psSHP->sHooks.FOpen(pszFullname, pszAccess, psSHP->sHooks.pvUserData);
     318        3165 :     if (psSHP->fpSHX == SHPLIB_NULLPTR)
     319             :     {
     320           2 :         memcpy(pszFullname + nLenWithoutExtension, ".SHX", 5);
     321           2 :         psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess,
     322             :                                            psSHP->sHooks.pvUserData);
     323             :     }
     324             : 
     325        3165 :     if (psSHP->fpSHX == SHPLIB_NULLPTR)
     326             :     {
     327           0 :         const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
     328           0 :         char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen));
     329           0 :         pszFullname[nLenWithoutExtension] = 0;
     330           0 :         snprintf(pszMessage, nMessageLen,
     331             :                  "Unable to open %s.shx or %s.SHX. "
     332             :                  "Set SHAPE_RESTORE_SHX config option to YES to restore or "
     333             :                  "create it.",
     334             :                  pszFullname, pszFullname);
     335           0 :         psHooks->Error(pszMessage);
     336           0 :         free(pszMessage);
     337             : 
     338           0 :         psSHP->sHooks.FClose(psSHP->fpSHP);
     339           0 :         free(psSHP);
     340           0 :         free(pszFullname);
     341           0 :         return SHPLIB_NULLPTR;
     342             :     }
     343             : 
     344        3165 :     free(pszFullname);
     345             : 
     346             :     /* -------------------------------------------------------------------- */
     347             :     /*  Read the file size from the SHP file.               */
     348             :     /* -------------------------------------------------------------------- */
     349        3165 :     unsigned char *pabyBuf = STATIC_CAST(unsigned char *, malloc(100));
     350        3165 :     if (psSHP->sHooks.FRead(pabyBuf, 100, 1, psSHP->fpSHP) != 1)
     351             :     {
     352           0 :         psSHP->sHooks.Error(".shp file is unreadable, or corrupt.");
     353           0 :         psSHP->sHooks.FClose(psSHP->fpSHP);
     354           0 :         psSHP->sHooks.FClose(psSHP->fpSHX);
     355           0 :         free(pabyBuf);
     356           0 :         free(psSHP);
     357             : 
     358           0 :         return SHPLIB_NULLPTR;
     359             :     }
     360             : 
     361        3165 :     psSHP->nFileSize = (STATIC_CAST(unsigned int, pabyBuf[24]) << 24) |
     362        3165 :                        (pabyBuf[25] << 16) | (pabyBuf[26] << 8) | pabyBuf[27];
     363        3165 :     if (psSHP->nFileSize < UINT_MAX / 2)
     364        3165 :         psSHP->nFileSize *= 2;
     365             :     else
     366           0 :         psSHP->nFileSize = (UINT_MAX / 2) * 2;
     367             : 
     368             :     /* -------------------------------------------------------------------- */
     369             :     /*  Read SHX file Header info                                           */
     370             :     /* -------------------------------------------------------------------- */
     371        3165 :     if (psSHP->sHooks.FRead(pabyBuf, 100, 1, psSHP->fpSHX) != 1 ||
     372        6330 :         pabyBuf[0] != 0 || pabyBuf[1] != 0 || pabyBuf[2] != 0x27 ||
     373        3165 :         (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d))
     374             :     {
     375           0 :         psSHP->sHooks.Error(".shx file is unreadable, or corrupt.");
     376           0 :         psSHP->sHooks.FClose(psSHP->fpSHP);
     377           0 :         psSHP->sHooks.FClose(psSHP->fpSHX);
     378           0 :         free(pabyBuf);
     379           0 :         free(psSHP);
     380             : 
     381           0 :         return SHPLIB_NULLPTR;
     382             :     }
     383             : 
     384        3165 :     psSHP->nRecords = pabyBuf[27] | (pabyBuf[26] << 8) | (pabyBuf[25] << 16) |
     385        3165 :                       ((pabyBuf[24] & 0x7F) << 24);
     386        3165 :     psSHP->nRecords = (psSHP->nRecords - 50) / 4;
     387             : 
     388        3165 :     psSHP->nShapeType = pabyBuf[32];
     389             : 
     390        3165 :     if (psSHP->nRecords < 0 || psSHP->nRecords > 256000000)
     391             :     {
     392             :         char szErrorMsg[200];
     393             : 
     394           0 :         snprintf(szErrorMsg, sizeof(szErrorMsg),
     395             :                  "Record count in .shx header is %d, which seems\n"
     396             :                  "unreasonable.  Assuming header is corrupt.",
     397             :                  psSHP->nRecords);
     398           0 :         szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
     399           0 :         psSHP->sHooks.Error(szErrorMsg);
     400           0 :         psSHP->sHooks.FClose(psSHP->fpSHP);
     401           0 :         psSHP->sHooks.FClose(psSHP->fpSHX);
     402           0 :         free(psSHP);
     403           0 :         free(pabyBuf);
     404             : 
     405           0 :         return SHPLIB_NULLPTR;
     406             :     }
     407             : 
     408             :     /* If a lot of records are advertized, check that the file is big enough */
     409             :     /* to hold them */
     410        3165 :     if (psSHP->nRecords >= 1024 * 1024)
     411             :     {
     412           2 :         psSHP->sHooks.FSeek(psSHP->fpSHX, 0, 2);
     413           2 :         const SAOffset nFileSize = psSHP->sHooks.FTell(psSHP->fpSHX);
     414           2 :         if (nFileSize > 100 &&
     415           2 :             nFileSize / 2 < STATIC_CAST(SAOffset, psSHP->nRecords * 4 + 50))
     416             :         {
     417           1 :             psSHP->nRecords = STATIC_CAST(int, (nFileSize - 100) / 8);
     418             :         }
     419           2 :         psSHP->sHooks.FSeek(psSHP->fpSHX, 100, 0);
     420             :     }
     421             : 
     422             :     /* -------------------------------------------------------------------- */
     423             :     /*      Read the bounds.                                                */
     424             :     /* -------------------------------------------------------------------- */
     425             :     double dValue;
     426             : 
     427             : #if defined(SHP_BIG_ENDIAN)
     428             :     SHP_SWAP64(pabyBuf + 36);
     429             : #endif
     430        3165 :     memcpy(&dValue, pabyBuf + 36, 8);
     431        3165 :     psSHP->adBoundsMin[0] = dValue;
     432             : 
     433             : #if defined(SHP_BIG_ENDIAN)
     434             :     SHP_SWAP64(pabyBuf + 44);
     435             : #endif
     436        3165 :     memcpy(&dValue, pabyBuf + 44, 8);
     437        3165 :     psSHP->adBoundsMin[1] = dValue;
     438             : 
     439             : #if defined(SHP_BIG_ENDIAN)
     440             :     SHP_SWAP64(pabyBuf + 52);
     441             : #endif
     442        3165 :     memcpy(&dValue, pabyBuf + 52, 8);
     443        3165 :     psSHP->adBoundsMax[0] = dValue;
     444             : 
     445             : #if defined(SHP_BIG_ENDIAN)
     446             :     SHP_SWAP64(pabyBuf + 60);
     447             : #endif
     448        3165 :     memcpy(&dValue, pabyBuf + 60, 8);
     449        3165 :     psSHP->adBoundsMax[1] = dValue;
     450             : 
     451             : #if defined(SHP_BIG_ENDIAN)
     452             :     SHP_SWAP64(pabyBuf + 68); /* z */
     453             : #endif
     454        3165 :     memcpy(&dValue, pabyBuf + 68, 8);
     455        3165 :     psSHP->adBoundsMin[2] = dValue;
     456             : 
     457             : #if defined(SHP_BIG_ENDIAN)
     458             :     SHP_SWAP64(pabyBuf + 76);
     459             : #endif
     460        3165 :     memcpy(&dValue, pabyBuf + 76, 8);
     461        3165 :     psSHP->adBoundsMax[2] = dValue;
     462             : 
     463             : #if defined(SHP_BIG_ENDIAN)
     464             :     SHP_SWAP64(pabyBuf + 84); /* z */
     465             : #endif
     466        3165 :     memcpy(&dValue, pabyBuf + 84, 8);
     467        3165 :     psSHP->adBoundsMin[3] = dValue;
     468             : 
     469             : #if defined(SHP_BIG_ENDIAN)
     470             :     SHP_SWAP64(pabyBuf + 92);
     471             : #endif
     472        3165 :     memcpy(&dValue, pabyBuf + 92, 8);
     473        3165 :     psSHP->adBoundsMax[3] = dValue;
     474             : 
     475        3165 :     free(pabyBuf);
     476             : 
     477             :     /* -------------------------------------------------------------------- */
     478             :     /*  Read the .shx file to get the offsets to each record in     */
     479             :     /*  the .shp file.                          */
     480             :     /* -------------------------------------------------------------------- */
     481        3165 :     psSHP->nMaxRecords = psSHP->nRecords;
     482             : 
     483        3165 :     psSHP->panRecOffset =
     484        3165 :         STATIC_CAST(unsigned int *,
     485             :                     malloc(sizeof(unsigned int) * MAX(1, psSHP->nMaxRecords)));
     486        3165 :     psSHP->panRecSize =
     487        3165 :         STATIC_CAST(unsigned int *,
     488             :                     malloc(sizeof(unsigned int) * MAX(1, psSHP->nMaxRecords)));
     489        3165 :     if (bLazySHXLoading)
     490           0 :         pabyBuf = SHPLIB_NULLPTR;
     491             :     else
     492             :         pabyBuf =
     493        3165 :             STATIC_CAST(unsigned char *, malloc(8 * MAX(1, psSHP->nRecords)));
     494             : 
     495        3165 :     if (psSHP->panRecOffset == SHPLIB_NULLPTR ||
     496        3165 :         psSHP->panRecSize == SHPLIB_NULLPTR ||
     497        3165 :         (!bLazySHXLoading && pabyBuf == SHPLIB_NULLPTR))
     498             :     {
     499             :         char szErrorMsg[200];
     500             : 
     501           0 :         snprintf(
     502             :             szErrorMsg, sizeof(szErrorMsg),
     503             :             "Not enough memory to allocate requested memory (nRecords=%d).\n"
     504             :             "Probably broken SHP file",
     505             :             psSHP->nRecords);
     506           0 :         szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
     507           0 :         psSHP->sHooks.Error(szErrorMsg);
     508           0 :         psSHP->sHooks.FClose(psSHP->fpSHP);
     509           0 :         psSHP->sHooks.FClose(psSHP->fpSHX);
     510           0 :         if (psSHP->panRecOffset)
     511           0 :             free(psSHP->panRecOffset);
     512           0 :         if (psSHP->panRecSize)
     513           0 :             free(psSHP->panRecSize);
     514           0 :         if (pabyBuf)
     515           0 :             free(pabyBuf);
     516           0 :         free(psSHP);
     517           0 :         return SHPLIB_NULLPTR;
     518             :     }
     519             : 
     520        3165 :     if (bLazySHXLoading)
     521             :     {
     522           0 :         memset(psSHP->panRecOffset, 0,
     523           0 :                sizeof(unsigned int) * MAX(1, psSHP->nMaxRecords));
     524           0 :         memset(psSHP->panRecSize, 0,
     525           0 :                sizeof(unsigned int) * MAX(1, psSHP->nMaxRecords));
     526           0 :         free(pabyBuf);  // sometimes make cppcheck happy, but
     527           0 :         return (psSHP);
     528             :     }
     529             : 
     530        3165 :     if (STATIC_CAST(int, psSHP->sHooks.FRead(pabyBuf, 8, psSHP->nRecords,
     531        3165 :                                              psSHP->fpSHX)) != psSHP->nRecords)
     532             :     {
     533             :         char szErrorMsg[200];
     534             : 
     535           0 :         snprintf(szErrorMsg, sizeof(szErrorMsg),
     536             :                  "Failed to read all values for %d records in .shx file: %s.",
     537           0 :                  psSHP->nRecords, strerror(errno));
     538           0 :         szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
     539           0 :         psSHP->sHooks.Error(szErrorMsg);
     540             : 
     541             :         /* SHX is short or unreadable for some reason. */
     542           0 :         psSHP->sHooks.FClose(psSHP->fpSHP);
     543           0 :         psSHP->sHooks.FClose(psSHP->fpSHX);
     544           0 :         free(psSHP->panRecOffset);
     545           0 :         free(psSHP->panRecSize);
     546           0 :         free(pabyBuf);
     547           0 :         free(psSHP);
     548             : 
     549           0 :         return SHPLIB_NULLPTR;
     550             :     }
     551             : 
     552             :     /* In read-only mode, we can close the SHX now */
     553        3165 :     if (strcmp(pszAccess, "rb") == 0)
     554             :     {
     555        1596 :         psSHP->sHooks.FClose(psSHP->fpSHX);
     556        1596 :         psSHP->fpSHX = SHPLIB_NULLPTR;
     557             :     }
     558             : 
     559     1386320 :     for (int i = 0; i < psSHP->nRecords; i++)
     560             :     {
     561             :         unsigned int nOffset;
     562     1383160 :         memcpy(&nOffset, pabyBuf + i * 8, 4);
     563             : #if !defined(SHP_BIG_ENDIAN)
     564     1383160 :         SHP_SWAP32(&nOffset);
     565             : #endif
     566             : 
     567             :         unsigned int nLength;
     568     1383160 :         memcpy(&nLength, pabyBuf + i * 8 + 4, 4);
     569             : #if !defined(SHP_BIG_ENDIAN)
     570     1383160 :         SHP_SWAP32(&nLength);
     571             : #endif
     572             : 
     573     1383160 :         if (nOffset > STATIC_CAST(unsigned int, INT_MAX))
     574             :         {
     575             :             char str[128];
     576           0 :             snprintf(str, sizeof(str), "Invalid offset for entity %d", i);
     577           0 :             str[sizeof(str) - 1] = '\0';
     578             : 
     579           0 :             psSHP->sHooks.Error(str);
     580           0 :             SHPClose(psSHP);
     581           0 :             free(pabyBuf);
     582           0 :             return SHPLIB_NULLPTR;
     583             :         }
     584     1383160 :         if (nLength > STATIC_CAST(unsigned int, INT_MAX / 2 - 4))
     585             :         {
     586             :             char str[128];
     587           0 :             snprintf(str, sizeof(str), "Invalid length for entity %d", i);
     588           0 :             str[sizeof(str) - 1] = '\0';
     589             : 
     590           0 :             psSHP->sHooks.Error(str);
     591           0 :             SHPClose(psSHP);
     592           0 :             free(pabyBuf);
     593           0 :             return SHPLIB_NULLPTR;
     594             :         }
     595     1383160 :         psSHP->panRecOffset[i] = nOffset * 2;
     596     1383160 :         psSHP->panRecSize[i] = nLength * 2;
     597             :     }
     598        3165 :     free(pabyBuf);
     599             : 
     600        3165 :     return (psSHP);
     601             : }
     602             : 
     603             : /************************************************************************/
     604             : /*                              SHPOpenLLEx()                           */
     605             : /*                                                                      */
     606             : /*      Open the .shp and .shx files based on the basename of the       */
     607             : /*      files or either file name. It generally invokes SHPRestoreSHX() */
     608             : /*      in case when bRestoreSHX equals true.                           */
     609             : /************************************************************************/
     610             : 
     611        3488 : SHPHandle SHPAPI_CALL SHPOpenLLEx(const char *pszLayer, const char *pszAccess,
     612             :                                   const SAHooks *psHooks, int bRestoreSHX)
     613             : {
     614        3488 :     if (!bRestoreSHX)
     615        3467 :         return SHPOpenLL(pszLayer, pszAccess, psHooks);
     616             :     else
     617             :     {
     618          21 :         if (SHPRestoreSHX(pszLayer, pszAccess, psHooks))
     619             :         {
     620          20 :             return SHPOpenLL(pszLayer, pszAccess, psHooks);
     621             :         }
     622             :     }
     623             : 
     624           1 :     return SHPLIB_NULLPTR;
     625             : }
     626             : 
     627             : /************************************************************************/
     628             : /*                              SHPRestoreSHX()                         */
     629             : /*                                                                      */
     630             : /*      Restore .SHX file using associated .SHP file.                   */
     631             : /*                                                                      */
     632             : /************************************************************************/
     633             : 
     634          21 : int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess,
     635             :                               const SAHooks *psHooks)
     636             : {
     637             :     /* -------------------------------------------------------------------- */
     638             :     /*      Ensure the access string is one of the legal ones.  We          */
     639             :     /*      ensure the result string indicates binary to avoid common       */
     640             :     /*      problems on Windows.                                            */
     641             :     /* -------------------------------------------------------------------- */
     642          21 :     if (strcmp(pszAccess, "rb+") == 0 || strcmp(pszAccess, "r+b") == 0 ||
     643          21 :         strcmp(pszAccess, "r+") == 0)
     644             :     {
     645          20 :         pszAccess = "r+b";
     646             :     }
     647             :     else
     648             :     {
     649           1 :         pszAccess = "rb";
     650             :     }
     651             : 
     652             :     /* -------------------------------------------------------------------- */
     653             :     /*  Open the .shp file.  Note that files pulled from                    */
     654             :     /*  a PC to Unix with upper case filenames won't work!                  */
     655             :     /* -------------------------------------------------------------------- */
     656          21 :     const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
     657          21 :     char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
     658          21 :     memcpy(pszFullname, pszLayer, nLenWithoutExtension);
     659          21 :     memcpy(pszFullname + nLenWithoutExtension, ".shp", 5);
     660          21 :     SAFile fpSHP = psHooks->FOpen(pszFullname, pszAccess, psHooks->pvUserData);
     661          21 :     if (fpSHP == SHPLIB_NULLPTR)
     662             :     {
     663           0 :         memcpy(pszFullname + nLenWithoutExtension, ".SHP", 5);
     664           0 :         fpSHP = psHooks->FOpen(pszFullname, pszAccess, psHooks->pvUserData);
     665             :     }
     666             : 
     667          21 :     if (fpSHP == SHPLIB_NULLPTR)
     668             :     {
     669           0 :         const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
     670           0 :         char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen));
     671             : 
     672           0 :         pszFullname[nLenWithoutExtension] = 0;
     673           0 :         snprintf(pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
     674             :                  pszFullname, pszFullname);
     675           0 :         psHooks->Error(pszMessage);
     676           0 :         free(pszMessage);
     677             : 
     678           0 :         free(pszFullname);
     679             : 
     680           0 :         return (0);
     681             :     }
     682             : 
     683             :     /* -------------------------------------------------------------------- */
     684             :     /*  Read the file size from the SHP file.                               */
     685             :     /* -------------------------------------------------------------------- */
     686          21 :     unsigned char *pabyBuf = STATIC_CAST(unsigned char *, malloc(100));
     687          21 :     if (psHooks->FRead(pabyBuf, 100, 1, fpSHP) != 1)
     688             :     {
     689           1 :         psHooks->Error(".shp file is unreadable, or corrupt.");
     690           1 :         psHooks->FClose(fpSHP);
     691             : 
     692           1 :         free(pabyBuf);
     693           1 :         free(pszFullname);
     694             : 
     695           1 :         return (0);
     696             :     }
     697             : 
     698          20 :     unsigned int nSHPFilesize = (STATIC_CAST(unsigned int, pabyBuf[24]) << 24) |
     699          20 :                                 (pabyBuf[25] << 16) | (pabyBuf[26] << 8) |
     700          20 :                                 pabyBuf[27];
     701          20 :     if (nSHPFilesize < UINT_MAX / 2)
     702          20 :         nSHPFilesize *= 2;
     703             :     else
     704           0 :         nSHPFilesize = (UINT_MAX / 2) * 2;
     705             : 
     706          20 :     memcpy(pszFullname + nLenWithoutExtension, ".shx", 5);
     707          20 :     const char pszSHXAccess[] = "w+b";
     708             :     SAFile fpSHX =
     709          20 :         psHooks->FOpen(pszFullname, pszSHXAccess, psHooks->pvUserData);
     710          20 :     if (fpSHX == SHPLIB_NULLPTR)
     711             :     {
     712           0 :         size_t nMessageLen = strlen(pszFullname) * 2 + 256;
     713           0 :         char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen));
     714           0 :         pszFullname[nLenWithoutExtension] = 0;
     715           0 :         snprintf(pszMessage, nMessageLen,
     716             :                  "Error opening file %s.shx for writing", pszFullname);
     717           0 :         psHooks->Error(pszMessage);
     718           0 :         free(pszMessage);
     719             : 
     720           0 :         psHooks->FClose(fpSHP);
     721             : 
     722           0 :         free(pabyBuf);
     723           0 :         free(pszFullname);
     724             : 
     725           0 :         return (0);
     726             :     }
     727             : 
     728             :     /* -------------------------------------------------------------------- */
     729             :     /*  Open SHX and create it using SHP file content.                      */
     730             :     /* -------------------------------------------------------------------- */
     731          20 :     psHooks->FSeek(fpSHP, 100, 0);
     732          20 :     char *pabySHXHeader = STATIC_CAST(char *, malloc(100));
     733          20 :     memcpy(pabySHXHeader, pabyBuf, 100);
     734          20 :     psHooks->FWrite(pabySHXHeader, 100, 1, fpSHX);
     735          20 :     free(pabyBuf);
     736             : 
     737             :     // unsigned int nCurrentRecordOffset = 0;
     738          20 :     unsigned int nCurrentSHPOffset = 100;
     739          20 :     unsigned int nRealSHXContentSize = 100;
     740          20 :     int nRetCode = TRUE;
     741          20 :     unsigned int nRecordOffset = 50;
     742             : 
     743          52 :     while (nCurrentSHPOffset < nSHPFilesize)
     744             :     {
     745          32 :         unsigned int niRecord = 0;
     746          32 :         unsigned int nRecordLength = 0;
     747             :         int nSHPType;
     748             : 
     749          32 :         if (psHooks->FRead(&niRecord, 4, 1, fpSHP) == 1 &&
     750          64 :             psHooks->FRead(&nRecordLength, 4, 1, fpSHP) == 1 &&
     751          32 :             psHooks->FRead(&nSHPType, 4, 1, fpSHP) == 1)
     752             :         {
     753             :             char abyReadRecord[8];
     754          32 :             unsigned int nRecordOffsetBE = nRecordOffset;
     755             : 
     756             : #if !defined(SHP_BIG_ENDIAN)
     757          32 :             SHP_SWAP32(&nRecordOffsetBE);
     758             : #endif
     759          32 :             memcpy(abyReadRecord, &nRecordOffsetBE, 4);
     760          32 :             memcpy(abyReadRecord + 4, &nRecordLength, 4);
     761             : 
     762             : #if !defined(SHP_BIG_ENDIAN)
     763          32 :             SHP_SWAP32(&nRecordLength);
     764             : #endif
     765             : #if defined(SHP_BIG_ENDIAN)
     766             :             SHP_SWAP32(&nSHPType);
     767             : #endif
     768             : 
     769             :             // Sanity check on record length
     770          32 :             if (nRecordLength < 1 ||
     771          32 :                 nRecordLength > (nSHPFilesize - (nCurrentSHPOffset + 8)) / 2)
     772             :             {
     773             :                 char szErrorMsg[200];
     774           0 :                 snprintf(szErrorMsg, sizeof(szErrorMsg),
     775             :                          "Error parsing .shp to restore .shx. "
     776             :                          "Invalid record length = %u at record starting at "
     777             :                          "offset %u",
     778             :                          nRecordLength, nCurrentSHPOffset);
     779           0 :                 psHooks->Error(szErrorMsg);
     780             : 
     781           0 :                 nRetCode = FALSE;
     782           0 :                 break;
     783             :             }
     784             : 
     785             :             // Sanity check on record type
     786          32 :             if (nSHPType != SHPT_NULL && nSHPType != SHPT_POINT &&
     787          18 :                 nSHPType != SHPT_ARC && nSHPType != SHPT_POLYGON &&
     788          14 :                 nSHPType != SHPT_MULTIPOINT && nSHPType != SHPT_POINTZ &&
     789          11 :                 nSHPType != SHPT_ARCZ && nSHPType != SHPT_POLYGONZ &&
     790           7 :                 nSHPType != SHPT_MULTIPOINTZ && nSHPType != SHPT_POINTM &&
     791           4 :                 nSHPType != SHPT_ARCM && nSHPType != SHPT_POLYGONM &&
     792           2 :                 nSHPType != SHPT_MULTIPOINTM && nSHPType != SHPT_MULTIPATCH)
     793             :             {
     794             :                 char szErrorMsg[200];
     795           0 :                 snprintf(szErrorMsg, sizeof(szErrorMsg),
     796             :                          "Error parsing .shp to restore .shx. "
     797             :                          "Invalid shape type = %d at record starting at "
     798             :                          "offset %u",
     799             :                          nSHPType, nCurrentSHPOffset);
     800           0 :                 psHooks->Error(szErrorMsg);
     801             : 
     802           0 :                 nRetCode = FALSE;
     803           0 :                 break;
     804             :             }
     805             : 
     806          32 :             psHooks->FWrite(abyReadRecord, 8, 1, fpSHX);
     807             : 
     808          32 :             nRecordOffset += nRecordLength + 4;
     809             :             // nCurrentRecordOffset += 8;
     810          32 :             nCurrentSHPOffset += 8 + nRecordLength * 2;
     811             : 
     812          32 :             psHooks->FSeek(fpSHP, nCurrentSHPOffset, 0);
     813          32 :             nRealSHXContentSize += 8;
     814             :         }
     815             :         else
     816             :         {
     817             :             char szErrorMsg[200];
     818           0 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
     819             :                      "Error parsing .shp to restore .shx. "
     820             :                      "Cannot read first bytes of record starting at "
     821             :                      "offset %u",
     822             :                      nCurrentSHPOffset);
     823           0 :             psHooks->Error(szErrorMsg);
     824             : 
     825           0 :             nRetCode = FALSE;
     826           0 :             break;
     827             :         }
     828             :     }
     829          20 :     if (nRetCode && nCurrentSHPOffset != nSHPFilesize)
     830             :     {
     831           0 :         psHooks->Error("Error parsing .shp to restore .shx. "
     832             :                        "Not expected number of bytes");
     833             : 
     834           0 :         nRetCode = FALSE;
     835             :     }
     836             : 
     837          20 :     nRealSHXContentSize /= 2;  // Bytes counted -> WORDs
     838             : #if !defined(SHP_BIG_ENDIAN)
     839          20 :     SHP_SWAP32(&nRealSHXContentSize);
     840             : #endif
     841             : 
     842          20 :     psHooks->FSeek(fpSHX, 24, 0);
     843          20 :     psHooks->FWrite(&nRealSHXContentSize, 4, 1, fpSHX);
     844             : 
     845          20 :     psHooks->FClose(fpSHP);
     846          20 :     psHooks->FClose(fpSHX);
     847             : 
     848          20 :     free(pszFullname);
     849          20 :     free(pabySHXHeader);
     850             : 
     851          20 :     return nRetCode;
     852             : }
     853             : 
     854             : /************************************************************************/
     855             : /*                              SHPClose()                              */
     856             : /*                                                                      */
     857             : /*      Close the .shp and .shx files.                                  */
     858             : /************************************************************************/
     859             : 
     860        4696 : void SHPAPI_CALL SHPClose(SHPHandle psSHP)
     861             : {
     862        4696 :     if (psSHP == SHPLIB_NULLPTR)
     863           1 :         return;
     864             : 
     865             :     /* -------------------------------------------------------------------- */
     866             :     /*      Update the header if we have modified anything.                 */
     867             :     /* -------------------------------------------------------------------- */
     868        4695 :     if (psSHP->bUpdated)
     869        1533 :         SHPWriteHeader(psSHP);
     870             : 
     871             :     /* -------------------------------------------------------------------- */
     872             :     /*      Free all resources, and close files.                            */
     873             :     /* -------------------------------------------------------------------- */
     874        4695 :     free(psSHP->panRecOffset);
     875        4695 :     free(psSHP->panRecSize);
     876             : 
     877        4695 :     if (psSHP->fpSHX != SHPLIB_NULLPTR)
     878        3104 :         psSHP->sHooks.FClose(psSHP->fpSHX);
     879        4695 :     psSHP->sHooks.FClose(psSHP->fpSHP);
     880             : 
     881        4695 :     if (psSHP->pabyRec != SHPLIB_NULLPTR)
     882             :     {
     883        2062 :         free(psSHP->pabyRec);
     884             :     }
     885             : 
     886        4695 :     if (psSHP->pabyObjectBuf != SHPLIB_NULLPTR)
     887             :     {
     888         754 :         free(psSHP->pabyObjectBuf);
     889             :     }
     890        4695 :     if (psSHP->psCachedObject != SHPLIB_NULLPTR)
     891             :     {
     892        4672 :         free(psSHP->psCachedObject);
     893             :     }
     894             : 
     895        4695 :     free(psSHP);
     896             : }
     897             : 
     898             : /************************************************************************/
     899             : /*                    SHPSetFastModeReadObject()                        */
     900             : /************************************************************************/
     901             : 
     902             : /* If setting bFastMode = TRUE, the content of SHPReadObject() is owned by the SHPHandle. */
     903             : /* So you cannot have 2 valid instances of SHPReadObject() simultaneously. */
     904             : /* The SHPObject padfZ and padfM members may be NULL depending on the geometry */
     905             : /* type. It is illegal to free at hand any of the pointer members of the SHPObject structure */
     906        4679 : void SHPAPI_CALL SHPSetFastModeReadObject(SHPHandle hSHP, int bFastMode)
     907             : {
     908        4679 :     if (bFastMode)
     909             :     {
     910        4679 :         if (hSHP->psCachedObject == SHPLIB_NULLPTR)
     911             :         {
     912        4679 :             hSHP->psCachedObject =
     913        4679 :                 STATIC_CAST(SHPObject *, calloc(1, sizeof(SHPObject)));
     914        4679 :             assert(hSHP->psCachedObject != SHPLIB_NULLPTR);
     915             :         }
     916             :     }
     917             : 
     918        4679 :     hSHP->bFastModeReadObject = bFastMode;
     919        4679 : }
     920             : 
     921             : /************************************************************************/
     922             : /*                             SHPGetInfo()                             */
     923             : /*                                                                      */
     924             : /*      Fetch general information about the shape file.                 */
     925             : /************************************************************************/
     926             : 
     927       12854 : void SHPAPI_CALL SHPGetInfo(const SHPHandle psSHP, int *pnEntities,
     928             :                             int *pnShapeType, double *padfMinBound,
     929             :                             double *padfMaxBound)
     930             : {
     931       12854 :     if (psSHP == SHPLIB_NULLPTR)
     932           0 :         return;
     933             : 
     934       12854 :     if (pnEntities != SHPLIB_NULLPTR)
     935          34 :         *pnEntities = psSHP->nRecords;
     936             : 
     937       12854 :     if (pnShapeType != SHPLIB_NULLPTR)
     938           0 :         *pnShapeType = psSHP->nShapeType;
     939             : 
     940       64270 :     for (int i = 0; i < 4; i++)
     941             :     {
     942       51416 :         if (padfMinBound != SHPLIB_NULLPTR)
     943       51280 :             padfMinBound[i] = psSHP->adBoundsMin[i];
     944       51416 :         if (padfMaxBound != SHPLIB_NULLPTR)
     945       51280 :             padfMaxBound[i] = psSHP->adBoundsMax[i];
     946             :     }
     947             : }
     948             : 
     949             : /************************************************************************/
     950             : /*                             SHPCreate()                              */
     951             : /*                                                                      */
     952             : /*      Create a new shape file and return a handle to the open         */
     953             : /*      shape file with read/write access.                              */
     954             : /************************************************************************/
     955             : 
     956          23 : SHPHandle SHPAPI_CALL SHPCreate(const char *pszLayer, int nShapeType)
     957             : {
     958             :     SAHooks sHooks;
     959             : 
     960          23 :     SASetupDefaultHooks(&sHooks);
     961             : 
     962          46 :     return SHPCreateLL(pszLayer, nShapeType, &sHooks);
     963             : }
     964             : 
     965             : /************************************************************************/
     966             : /*                             SHPCreate()                              */
     967             : /*                                                                      */
     968             : /*      Create a new shape file and return a handle to the open         */
     969             : /*      shape file with read/write access.                              */
     970             : /************************************************************************/
     971             : 
     972        1539 : SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType,
     973             :                                   const SAHooks *psHooks)
     974             : {
     975             :     /* -------------------------------------------------------------------- */
     976             :     /*      Open the two files so we can write their headers.               */
     977             :     /* -------------------------------------------------------------------- */
     978        1539 :     const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
     979        1539 :     char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
     980        1539 :     memcpy(pszFullname, pszLayer, nLenWithoutExtension);
     981        1539 :     memcpy(pszFullname + nLenWithoutExtension, ".shp", 5);
     982        1539 :     SAFile fpSHP = psHooks->FOpen(pszFullname, "w+b", psHooks->pvUserData);
     983        1539 :     if (fpSHP == SHPLIB_NULLPTR)
     984             :     {
     985             :         char szErrorMsg[200];
     986           4 :         snprintf(szErrorMsg, sizeof(szErrorMsg), "Failed to create file %s: %s",
     987           2 :                  pszFullname, strerror(errno));
     988           2 :         psHooks->Error(szErrorMsg);
     989             : 
     990           2 :         free(pszFullname);
     991           2 :         return SHPLIB_NULLPTR;
     992             :     }
     993             : 
     994        1537 :     memcpy(pszFullname + nLenWithoutExtension, ".shx", 5);
     995        1537 :     SAFile fpSHX = psHooks->FOpen(pszFullname, "w+b", psHooks->pvUserData);
     996        1537 :     if (fpSHX == SHPLIB_NULLPTR)
     997             :     {
     998             :         char szErrorMsg[200];
     999           0 :         snprintf(szErrorMsg, sizeof(szErrorMsg), "Failed to create file %s: %s",
    1000           0 :                  pszFullname, strerror(errno));
    1001           0 :         psHooks->Error(szErrorMsg);
    1002             : 
    1003           0 :         free(pszFullname);
    1004           0 :         psHooks->FClose(fpSHP);
    1005           0 :         return SHPLIB_NULLPTR;
    1006             :     }
    1007             : 
    1008        1537 :     free(pszFullname);
    1009        1537 :     pszFullname = SHPLIB_NULLPTR;
    1010             : 
    1011             :     /* -------------------------------------------------------------------- */
    1012             :     /*      Prepare header block for .shp file.                             */
    1013             :     /* -------------------------------------------------------------------- */
    1014             :     unsigned char abyHeader[100];
    1015        1537 :     memset(abyHeader, 0, sizeof(abyHeader));
    1016             : 
    1017        1537 :     abyHeader[2] = 0x27; /* magic cookie */
    1018        1537 :     abyHeader[3] = 0x0a;
    1019             : 
    1020        1537 :     uint32_t i32 = 50; /* file size */
    1021        1537 :     ByteCopy(&i32, abyHeader + 24, 4);
    1022             : #if !defined(SHP_BIG_ENDIAN)
    1023        1537 :     SHP_SWAP32(abyHeader + 24);
    1024             : #endif
    1025             : 
    1026        1537 :     i32 = 1000; /* version */
    1027        1537 :     ByteCopy(&i32, abyHeader + 28, 4);
    1028             : #if defined(SHP_BIG_ENDIAN)
    1029             :     SHP_SWAP32(abyHeader + 28);
    1030             : #endif
    1031             : 
    1032        1537 :     i32 = nShapeType; /* shape type */
    1033        1537 :     ByteCopy(&i32, abyHeader + 32, 4);
    1034             : #if defined(SHP_BIG_ENDIAN)
    1035             :     SHP_SWAP32(abyHeader + 32);
    1036             : #endif
    1037             : 
    1038        1537 :     double dValue = 0.0; /* set bounds */
    1039        1537 :     ByteCopy(&dValue, abyHeader + 36, 8);
    1040        1537 :     ByteCopy(&dValue, abyHeader + 44, 8);
    1041        1537 :     ByteCopy(&dValue, abyHeader + 52, 8);
    1042        1537 :     ByteCopy(&dValue, abyHeader + 60, 8);
    1043             : 
    1044             :     /* -------------------------------------------------------------------- */
    1045             :     /*      Write .shp file header.                                         */
    1046             :     /* -------------------------------------------------------------------- */
    1047        1537 :     if (psHooks->FWrite(abyHeader, 100, 1, fpSHP) != 1)
    1048             :     {
    1049             :         char szErrorMsg[200];
    1050             : 
    1051           0 :         snprintf(szErrorMsg, sizeof(szErrorMsg),
    1052           0 :                  "Failed to write .shp header: %s", strerror(errno));
    1053           0 :         szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    1054           0 :         psHooks->Error(szErrorMsg);
    1055             : 
    1056           0 :         free(pszFullname);
    1057           0 :         psHooks->FClose(fpSHP);
    1058           0 :         psHooks->FClose(fpSHX);
    1059           0 :         return SHPLIB_NULLPTR;
    1060             :     }
    1061             : 
    1062             :     /* -------------------------------------------------------------------- */
    1063             :     /*      Prepare, and write .shx file header.                            */
    1064             :     /* -------------------------------------------------------------------- */
    1065        1537 :     i32 = 50; /* file size */
    1066        1537 :     ByteCopy(&i32, abyHeader + 24, 4);
    1067             : #if !defined(SHP_BIG_ENDIAN)
    1068        1537 :     SHP_SWAP32(abyHeader + 24);
    1069             : #endif
    1070             : 
    1071        1537 :     if (psHooks->FWrite(abyHeader, 100, 1, fpSHX) != 1)
    1072             :     {
    1073             :         char szErrorMsg[200];
    1074             : 
    1075           0 :         snprintf(szErrorMsg, sizeof(szErrorMsg),
    1076           0 :                  "Failure writing .shx header: %s", strerror(errno));
    1077           0 :         szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    1078           0 :         psHooks->Error(szErrorMsg);
    1079             : 
    1080           0 :         free(pszFullname);
    1081           0 :         psHooks->FClose(fpSHP);
    1082           0 :         psHooks->FClose(fpSHX);
    1083           0 :         return SHPLIB_NULLPTR;
    1084             :     }
    1085             : 
    1086        1537 :     SHPHandle psSHP = STATIC_CAST(SHPHandle, calloc(sizeof(SHPInfo), 1));
    1087             : 
    1088        1537 :     psSHP->bUpdated = FALSE;
    1089        1537 :     memcpy(&(psSHP->sHooks), psHooks, sizeof(SAHooks));
    1090             : 
    1091        1537 :     psSHP->fpSHP = fpSHP;
    1092        1537 :     psSHP->fpSHX = fpSHX;
    1093        1537 :     psSHP->nShapeType = nShapeType;
    1094        1537 :     psSHP->nFileSize = 100;
    1095        1537 :     psSHP->panRecOffset =
    1096        1537 :         STATIC_CAST(unsigned int *, malloc(sizeof(unsigned int)));
    1097        1537 :     psSHP->panRecSize =
    1098        1537 :         STATIC_CAST(unsigned int *, malloc(sizeof(unsigned int)));
    1099             : 
    1100        1537 :     if (psSHP->panRecOffset == SHPLIB_NULLPTR ||
    1101        1537 :         psSHP->panRecSize == SHPLIB_NULLPTR)
    1102             :     {
    1103           0 :         psSHP->sHooks.Error("Not enough memory to allocate requested memory");
    1104           0 :         psSHP->sHooks.FClose(psSHP->fpSHP);
    1105           0 :         psSHP->sHooks.FClose(psSHP->fpSHX);
    1106           0 :         if (psSHP->panRecOffset)
    1107           0 :             free(psSHP->panRecOffset);
    1108           0 :         if (psSHP->panRecSize)
    1109           0 :             free(psSHP->panRecSize);
    1110           0 :         free(psSHP);
    1111           0 :         return SHPLIB_NULLPTR;
    1112             :     }
    1113             : 
    1114        1537 :     return psSHP;
    1115             : }
    1116             : 
    1117             : /************************************************************************/
    1118             : /*                           _SHPSetBounds()                            */
    1119             : /*                                                                      */
    1120             : /*      Compute a bounds rectangle for a shape, and set it into the     */
    1121             : /*      indicated location in the record.                               */
    1122             : /************************************************************************/
    1123             : 
    1124       31561 : static void _SHPSetBounds(unsigned char *pabyRec, const SHPObject *psShape)
    1125             : {
    1126       31561 :     ByteCopy(&(psShape->dfXMin), pabyRec + 0, 8);
    1127       31561 :     ByteCopy(&(psShape->dfYMin), pabyRec + 8, 8);
    1128       31561 :     ByteCopy(&(psShape->dfXMax), pabyRec + 16, 8);
    1129       31561 :     ByteCopy(&(psShape->dfYMax), pabyRec + 24, 8);
    1130             : 
    1131             : #if defined(SHP_BIG_ENDIAN)
    1132             :     SHP_SWAP64(pabyRec + 0);
    1133             :     SHP_SWAP64(pabyRec + 8);
    1134             :     SHP_SWAP64(pabyRec + 16);
    1135             :     SHP_SWAP64(pabyRec + 24);
    1136             : #endif
    1137       31561 : }
    1138             : 
    1139             : /************************************************************************/
    1140             : /*                         SHPComputeExtents()                          */
    1141             : /*                                                                      */
    1142             : /*      Recompute the extents of a shape.  Automatically done by        */
    1143             : /*      SHPCreateObject().                                              */
    1144             : /************************************************************************/
    1145             : 
    1146       76783 : void SHPAPI_CALL SHPComputeExtents(SHPObject *psObject)
    1147             : {
    1148             :     /* -------------------------------------------------------------------- */
    1149             :     /*      Build extents for this object.                                  */
    1150             :     /* -------------------------------------------------------------------- */
    1151       76783 :     if (psObject->nVertices > 0)
    1152             :     {
    1153       76167 :         psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];
    1154       76167 :         psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];
    1155       76167 :         psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
    1156       76167 :         psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
    1157             :     }
    1158             : 
    1159      320743 :     for (int i = 0; i < psObject->nVertices; i++)
    1160             :     {
    1161      243960 :         psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
    1162      243960 :         psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);
    1163      243960 :         psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);
    1164      243960 :         psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);
    1165             : 
    1166      243960 :         psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);
    1167      243960 :         psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);
    1168      243960 :         psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);
    1169      243960 :         psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);
    1170             :     }
    1171       76783 : }
    1172             : 
    1173             : /************************************************************************/
    1174             : /*                          SHPCreateObject()                           */
    1175             : /*                                                                      */
    1176             : /*      Create a shape object.  It should be freed with                 */
    1177             : /*      SHPDestroyObject().                                             */
    1178             : /************************************************************************/
    1179             : 
    1180             : SHPObject SHPAPI_CALL1(*)
    1181       76783 :     SHPCreateObject(int nSHPType, int nShapeId, int nParts,
    1182             :                     const int *panPartStart, const int *panPartType,
    1183             :                     int nVertices, const double *padfX, const double *padfY,
    1184             :                     const double *padfZ, const double *padfM)
    1185             : {
    1186             :     SHPObject *psObject =
    1187       76783 :         STATIC_CAST(SHPObject *, calloc(1, sizeof(SHPObject)));
    1188       76783 :     psObject->nSHPType = nSHPType;
    1189       76783 :     psObject->nShapeId = nShapeId;
    1190       76783 :     psObject->bMeasureIsUsed = FALSE;
    1191             : 
    1192             :     /* -------------------------------------------------------------------- */
    1193             :     /*      Establish whether this shape type has M, and Z values.          */
    1194             :     /* -------------------------------------------------------------------- */
    1195             :     bool bHasM;
    1196             :     bool bHasZ;
    1197             : 
    1198       76783 :     if (nSHPType == SHPT_ARCM || nSHPType == SHPT_POINTM ||
    1199       76768 :         nSHPType == SHPT_POLYGONM || nSHPType == SHPT_MULTIPOINTM)
    1200             :     {
    1201          18 :         bHasM = true;
    1202          18 :         bHasZ = false;
    1203             :     }
    1204       76765 :     else if (nSHPType == SHPT_ARCZ || nSHPType == SHPT_POINTZ ||
    1205       30870 :              nSHPType == SHPT_POLYGONZ || nSHPType == SHPT_MULTIPOINTZ ||
    1206             :              nSHPType == SHPT_MULTIPATCH)
    1207             :     {
    1208       45918 :         bHasM = true;
    1209       45918 :         bHasZ = true;
    1210             :     }
    1211             :     else
    1212             :     {
    1213       30847 :         bHasM = false;
    1214       30847 :         bHasZ = false;
    1215             :     }
    1216             : 
    1217             :     /* -------------------------------------------------------------------- */
    1218             :     /*      Capture parts.  Note that part type is optional, and            */
    1219             :     /*      defaults to ring.                                               */
    1220             :     /* -------------------------------------------------------------------- */
    1221       76783 :     if (nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON ||
    1222       47311 :         nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM ||
    1223       45424 :         nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ ||
    1224             :         nSHPType == SHPT_MULTIPATCH)
    1225             :     {
    1226       31445 :         psObject->nParts = MAX(1, nParts);
    1227             : 
    1228       31445 :         psObject->panPartStart =
    1229       31445 :             STATIC_CAST(int *, calloc(sizeof(int), psObject->nParts));
    1230       31445 :         psObject->panPartType =
    1231       31445 :             STATIC_CAST(int *, malloc(sizeof(int) * psObject->nParts));
    1232             : 
    1233       31445 :         psObject->panPartStart[0] = 0;
    1234       31445 :         psObject->panPartType[0] = SHPP_RING;
    1235             : 
    1236       63008 :         for (int i = 0; i < nParts; i++)
    1237             :         {
    1238       31563 :             if (panPartStart != SHPLIB_NULLPTR)
    1239       31563 :                 psObject->panPartStart[i] = panPartStart[i];
    1240             : 
    1241       31563 :             if (panPartType != SHPLIB_NULLPTR)
    1242          15 :                 psObject->panPartType[i] = panPartType[i];
    1243             :             else
    1244       31548 :                 psObject->panPartType[i] = SHPP_RING;
    1245             :         }
    1246             : 
    1247       31445 :         psObject->panPartStart[0] = 0;
    1248             :     }
    1249             : 
    1250             :     /* -------------------------------------------------------------------- */
    1251             :     /*      Capture vertices.  Note that X, Y, Z and M are optional.        */
    1252             :     /* -------------------------------------------------------------------- */
    1253       76783 :     if (nVertices > 0)
    1254             :     {
    1255       76167 :         const size_t nSize = sizeof(double) * nVertices;
    1256       76167 :         psObject->padfX =
    1257       76167 :             STATIC_CAST(double *, padfX ? malloc(nSize)
    1258             :                                         : calloc(sizeof(double), nVertices));
    1259       76167 :         psObject->padfY =
    1260       76167 :             STATIC_CAST(double *, padfY ? malloc(nSize)
    1261             :                                         : calloc(sizeof(double), nVertices));
    1262       76167 :         psObject->padfZ = STATIC_CAST(
    1263             :             double *,
    1264             :             padfZ &&bHasZ ? malloc(nSize) : calloc(sizeof(double), nVertices));
    1265       76167 :         psObject->padfM = STATIC_CAST(
    1266             :             double *,
    1267             :             padfM &&bHasM ? malloc(nSize) : calloc(sizeof(double), nVertices));
    1268       76167 :         if (padfX != SHPLIB_NULLPTR)
    1269       76167 :             memcpy(psObject->padfX, padfX, nSize);
    1270       76167 :         if (padfY != SHPLIB_NULLPTR)
    1271       76167 :             memcpy(psObject->padfY, padfY, nSize);
    1272       76167 :         if (padfZ != SHPLIB_NULLPTR && bHasZ)
    1273       45918 :             memcpy(psObject->padfZ, padfZ, nSize);
    1274       76167 :         if (padfM != SHPLIB_NULLPTR && bHasM)
    1275             :         {
    1276          36 :             memcpy(psObject->padfM, padfM, nSize);
    1277          36 :             psObject->bMeasureIsUsed = TRUE;
    1278             :         }
    1279             :     }
    1280             : 
    1281             :     /* -------------------------------------------------------------------- */
    1282             :     /*      Compute the extents.                                            */
    1283             :     /* -------------------------------------------------------------------- */
    1284       76783 :     psObject->nVertices = nVertices;
    1285       76783 :     SHPComputeExtents(psObject);
    1286             : 
    1287       76783 :     return (psObject);
    1288             : }
    1289             : 
    1290             : /************************************************************************/
    1291             : /*                       SHPCreateSimpleObject()                        */
    1292             : /*                                                                      */
    1293             : /*      Create a simple (common) shape object.  Destroy with            */
    1294             : /*      SHPDestroyObject().                                             */
    1295             : /************************************************************************/
    1296             : 
    1297             : SHPObject SHPAPI_CALL1(*)
    1298           0 :     SHPCreateSimpleObject(int nSHPType, int nVertices, const double *padfX,
    1299             :                           const double *padfY, const double *padfZ)
    1300             : {
    1301           0 :     return (SHPCreateObject(nSHPType, -1, 0, SHPLIB_NULLPTR, SHPLIB_NULLPTR,
    1302           0 :                             nVertices, padfX, padfY, padfZ, SHPLIB_NULLPTR));
    1303             : }
    1304             : 
    1305             : /************************************************************************/
    1306             : /*                           SHPWriteObject()                           */
    1307             : /*                                                                      */
    1308             : /*      Write out the vertices of a new structure.  Note that it is     */
    1309             : /*      only possible to write vertices at the end of the file.         */
    1310             : /************************************************************************/
    1311             : 
    1312       76934 : int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId,
    1313             :                                const SHPObject *psObject)
    1314             : {
    1315       76934 :     psSHP->bUpdated = TRUE;
    1316             : 
    1317             :     /* -------------------------------------------------------------------- */
    1318             :     /*      Ensure that shape object matches the type of the file it is     */
    1319             :     /*      being written to.                                               */
    1320             :     /* -------------------------------------------------------------------- */
    1321       76934 :     assert(psObject->nSHPType == psSHP->nShapeType ||
    1322             :            psObject->nSHPType == SHPT_NULL);
    1323             : 
    1324             :     /* -------------------------------------------------------------------- */
    1325             :     /*      Ensure that -1 is used for appends.  Either blow an             */
    1326             :     /*      assertion, or if they are disabled, set the shapeid to -1       */
    1327             :     /*      for appends.                                                    */
    1328             :     /* -------------------------------------------------------------------- */
    1329       76934 :     assert(nShapeId == -1 || (nShapeId >= 0 && nShapeId < psSHP->nRecords));
    1330             : 
    1331       76934 :     if (nShapeId != -1 && nShapeId >= psSHP->nRecords)
    1332           0 :         nShapeId = -1;
    1333             : 
    1334             :     /* -------------------------------------------------------------------- */
    1335             :     /*      Add the new entity to the in memory index.                      */
    1336             :     /* -------------------------------------------------------------------- */
    1337       76934 :     if (nShapeId == -1 && psSHP->nRecords + 1 > psSHP->nMaxRecords)
    1338             :     {
    1339             :         /* This cannot overflow given that we check that the file size does
    1340             :          * not grow over 4 GB, and the minimum size of a record is 12 bytes,
    1341             :          * hence the maximm value for nMaxRecords is 357,913,941
    1342             :          */
    1343        1608 :         int nNewMaxRecords = psSHP->nMaxRecords + psSHP->nMaxRecords / 3 + 100;
    1344             :         unsigned int *panRecOffsetNew;
    1345             :         unsigned int *panRecSizeNew;
    1346             : 
    1347        1608 :         panRecOffsetNew = STATIC_CAST(
    1348             :             unsigned int *, realloc(psSHP->panRecOffset,
    1349             :                                     sizeof(unsigned int) * nNewMaxRecords));
    1350        1608 :         if (panRecOffsetNew == SHPLIB_NULLPTR)
    1351             :         {
    1352           0 :             psSHP->sHooks.Error("Failed to write shape object. "
    1353             :                                 "Memory allocation error.");
    1354           0 :             return -1;
    1355             :         }
    1356        1608 :         psSHP->panRecOffset = panRecOffsetNew;
    1357             : 
    1358        1608 :         panRecSizeNew = STATIC_CAST(
    1359             :             unsigned int *,
    1360             :             realloc(psSHP->panRecSize, sizeof(unsigned int) * nNewMaxRecords));
    1361        1608 :         if (panRecSizeNew == SHPLIB_NULLPTR)
    1362             :         {
    1363           0 :             psSHP->sHooks.Error("Failed to write shape object. "
    1364             :                                 "Memory allocation error.");
    1365           0 :             return -1;
    1366             :         }
    1367        1608 :         psSHP->panRecSize = panRecSizeNew;
    1368             : 
    1369        1608 :         psSHP->nMaxRecords = nNewMaxRecords;
    1370             :     }
    1371             : 
    1372             :     /* -------------------------------------------------------------------- */
    1373             :     /*      Initialize record.                                              */
    1374             :     /* -------------------------------------------------------------------- */
    1375             : 
    1376             :     /* The following computation cannot overflow on 32-bit platforms given that
    1377             :      * the user had to allocate arrays of at least that size. */
    1378       76934 :     size_t nRecMaxSize =
    1379       76934 :         psObject->nVertices * 4 * sizeof(double) + psObject->nParts * 8;
    1380             :     /* But the following test could trigger on 64-bit platforms on huge
    1381             :      * geometries. */
    1382       76934 :     const unsigned nExtraSpaceForGeomHeader = 128;
    1383       76934 :     if (nRecMaxSize > UINT_MAX - nExtraSpaceForGeomHeader)
    1384             :     {
    1385           0 :         psSHP->sHooks.Error("Failed to write shape object. Too big geometry.");
    1386           0 :         return -1;
    1387             :     }
    1388       76934 :     nRecMaxSize += nExtraSpaceForGeomHeader;
    1389       76934 :     unsigned char *pabyRec = STATIC_CAST(unsigned char *, malloc(nRecMaxSize));
    1390       76934 :     if (pabyRec == SHPLIB_NULLPTR)
    1391             :     {
    1392           0 :         psSHP->sHooks.Error("Failed to write shape object. "
    1393             :                             "Memory allocation error.");
    1394           0 :         return -1;
    1395             :     }
    1396             : 
    1397             :     /* -------------------------------------------------------------------- */
    1398             :     /*      Extract vertices for a Polygon or Arc.                          */
    1399             :     /* -------------------------------------------------------------------- */
    1400       76934 :     unsigned int nRecordSize = 0;
    1401       76934 :     const bool bFirstFeature = psSHP->nRecords == 0;
    1402             : 
    1403       76934 :     if (psObject->nSHPType == SHPT_POLYGON ||
    1404       63641 :         psObject->nSHPType == SHPT_POLYGONZ ||
    1405       63567 :         psObject->nSHPType == SHPT_POLYGONM || psObject->nSHPType == SHPT_ARC ||
    1406       47295 :         psObject->nSHPType == SHPT_ARCZ || psObject->nSHPType == SHPT_ARCM ||
    1407       45408 :         psObject->nSHPType == SHPT_MULTIPATCH)
    1408             :     {
    1409       31538 :         uint32_t nPoints = psObject->nVertices;
    1410       31538 :         uint32_t nParts = psObject->nParts;
    1411             : 
    1412       31538 :         _SHPSetBounds(pabyRec + 12, psObject);
    1413             : 
    1414             : #if defined(SHP_BIG_ENDIAN)
    1415             :         SHP_SWAP32(&nPoints);
    1416             :         SHP_SWAP32(&nParts);
    1417             : #endif
    1418             : 
    1419       31538 :         ByteCopy(&nPoints, pabyRec + 40 + 8, 4);
    1420       31538 :         ByteCopy(&nParts, pabyRec + 36 + 8, 4);
    1421             : 
    1422       31538 :         nRecordSize = 52;
    1423             : 
    1424             :         /*
    1425             :          * Write part start positions.
    1426             :          */
    1427       31538 :         ByteCopy(psObject->panPartStart, pabyRec + 44 + 8,
    1428             :                  4 * psObject->nParts);
    1429       63194 :         for (int i = 0; i < psObject->nParts; i++)
    1430             :         {
    1431             : #if defined(SHP_BIG_ENDIAN)
    1432             :             SHP_SWAP32(pabyRec + 44 + 8 + 4 * i);
    1433             : #endif
    1434       31656 :             nRecordSize += 4;
    1435             :         }
    1436             : 
    1437             :         /*
    1438             :          * Write multipatch part types if needed.
    1439             :          */
    1440       31538 :         if (psObject->nSHPType == SHPT_MULTIPATCH)
    1441             :         {
    1442          12 :             memcpy(pabyRec + nRecordSize, psObject->panPartType,
    1443          12 :                    4 * psObject->nParts);
    1444          27 :             for (int i = 0; i < psObject->nParts; i++)
    1445             :             {
    1446             : #if defined(SHP_BIG_ENDIAN)
    1447             :                 SHP_SWAP32(pabyRec + nRecordSize);
    1448             : #endif
    1449          15 :                 nRecordSize += 4;
    1450             :             }
    1451             :         }
    1452             : 
    1453             :         /*
    1454             :          * Write the (x,y) vertex values.
    1455             :          */
    1456      232870 :         for (int i = 0; i < psObject->nVertices; i++)
    1457             :         {
    1458      201332 :             ByteCopy(psObject->padfX + i, pabyRec + nRecordSize, 8);
    1459      201332 :             ByteCopy(psObject->padfY + i, pabyRec + nRecordSize + 8, 8);
    1460             : 
    1461             : #if defined(SHP_BIG_ENDIAN)
    1462             :             SHP_SWAP64(pabyRec + nRecordSize);
    1463             :             SHP_SWAP64(pabyRec + nRecordSize + 8);
    1464             : #endif
    1465             : 
    1466      201332 :             nRecordSize += 2 * 8;
    1467             :         }
    1468             : 
    1469             :         /*
    1470             :          * Write the Z coordinates (if any).
    1471             :          */
    1472       31538 :         if (psObject->nSHPType == SHPT_POLYGONZ ||
    1473       31464 :             psObject->nSHPType == SHPT_ARCZ ||
    1474       29582 :             psObject->nSHPType == SHPT_MULTIPATCH)
    1475             :         {
    1476        1968 :             ByteCopy(&(psObject->dfZMin), pabyRec + nRecordSize, 8);
    1477             : #if defined(SHP_BIG_ENDIAN)
    1478             :             SHP_SWAP64(pabyRec + nRecordSize);
    1479             : #endif
    1480        1968 :             nRecordSize += 8;
    1481             : 
    1482        1968 :             ByteCopy(&(psObject->dfZMax), pabyRec + nRecordSize, 8);
    1483             : #if defined(SHP_BIG_ENDIAN)
    1484             :             SHP_SWAP64(pabyRec + nRecordSize);
    1485             : #endif
    1486        1968 :             nRecordSize += 8;
    1487             : 
    1488       53256 :             for (int i = 0; i < psObject->nVertices; i++)
    1489             :             {
    1490       51288 :                 ByteCopy(psObject->padfZ + i, pabyRec + nRecordSize, 8);
    1491             : #if defined(SHP_BIG_ENDIAN)
    1492             :                 SHP_SWAP64(pabyRec + nRecordSize);
    1493             : #endif
    1494       51288 :                 nRecordSize += 8;
    1495             :             }
    1496             :         }
    1497             : 
    1498             :         /*
    1499             :          * Write the M values, if any.
    1500             :          */
    1501       31538 :         if (psObject->bMeasureIsUsed &&
    1502          20 :             (psObject->nSHPType == SHPT_POLYGONM ||
    1503          15 :              psObject->nSHPType == SHPT_ARCM
    1504             : #ifndef DISABLE_MULTIPATCH_MEASURE
    1505             :              || psObject->nSHPType == SHPT_MULTIPATCH
    1506             : #endif
    1507          10 :              || psObject->nSHPType == SHPT_POLYGONZ ||
    1508           5 :              psObject->nSHPType == SHPT_ARCZ))
    1509             :         {
    1510          20 :             ByteCopy(&(psObject->dfMMin), pabyRec + nRecordSize, 8);
    1511             : #if defined(SHP_BIG_ENDIAN)
    1512             :             SHP_SWAP64(pabyRec + nRecordSize);
    1513             : #endif
    1514          20 :             nRecordSize += 8;
    1515             : 
    1516          20 :             ByteCopy(&(psObject->dfMMax), pabyRec + nRecordSize, 8);
    1517             : #if defined(SHP_BIG_ENDIAN)
    1518             :             SHP_SWAP64(pabyRec + nRecordSize);
    1519             : #endif
    1520          20 :             nRecordSize += 8;
    1521             : 
    1522         104 :             for (int i = 0; i < psObject->nVertices; i++)
    1523             :             {
    1524          84 :                 ByteCopy(psObject->padfM + i, pabyRec + nRecordSize, 8);
    1525             : #if defined(SHP_BIG_ENDIAN)
    1526             :                 SHP_SWAP64(pabyRec + nRecordSize);
    1527             : #endif
    1528          84 :                 nRecordSize += 8;
    1529             :             }
    1530       31538 :         }
    1531             :     }
    1532             : 
    1533             :     /* -------------------------------------------------------------------- */
    1534             :     /*      Extract vertices for a MultiPoint.                              */
    1535             :     /* -------------------------------------------------------------------- */
    1536       45396 :     else if (psObject->nSHPType == SHPT_MULTIPOINT ||
    1537       45387 :              psObject->nSHPType == SHPT_MULTIPOINTZ ||
    1538       45376 :              psObject->nSHPType == SHPT_MULTIPOINTM)
    1539             :     {
    1540          23 :         uint32_t nPoints = psObject->nVertices;
    1541             : 
    1542          23 :         _SHPSetBounds(pabyRec + 12, psObject);
    1543             : 
    1544             : #if defined(SHP_BIG_ENDIAN)
    1545             :         SHP_SWAP32(&nPoints);
    1546             : #endif
    1547          23 :         ByteCopy(&nPoints, pabyRec + 44, 4);
    1548             : 
    1549          56 :         for (int i = 0; i < psObject->nVertices; i++)
    1550             :         {
    1551          33 :             ByteCopy(psObject->padfX + i, pabyRec + 48 + i * 16, 8);
    1552          33 :             ByteCopy(psObject->padfY + i, pabyRec + 48 + i * 16 + 8, 8);
    1553             : 
    1554             : #if defined(SHP_BIG_ENDIAN)
    1555             :             SHP_SWAP64(pabyRec + 48 + i * 16);
    1556             :             SHP_SWAP64(pabyRec + 48 + i * 16 + 8);
    1557             : #endif
    1558             :         }
    1559             : 
    1560          23 :         nRecordSize = 48 + 16 * psObject->nVertices;
    1561             : 
    1562          23 :         if (psObject->nSHPType == SHPT_MULTIPOINTZ)
    1563             :         {
    1564          11 :             ByteCopy(&(psObject->dfZMin), pabyRec + nRecordSize, 8);
    1565             : #if defined(SHP_BIG_ENDIAN)
    1566             :             SHP_SWAP64(pabyRec + nRecordSize);
    1567             : #endif
    1568          11 :             nRecordSize += 8;
    1569             : 
    1570          11 :             ByteCopy(&(psObject->dfZMax), pabyRec + nRecordSize, 8);
    1571             : #if defined(SHP_BIG_ENDIAN)
    1572             :             SHP_SWAP64(pabyRec + nRecordSize);
    1573             : #endif
    1574          11 :             nRecordSize += 8;
    1575             : 
    1576          27 :             for (int i = 0; i < psObject->nVertices; i++)
    1577             :             {
    1578          16 :                 ByteCopy(psObject->padfZ + i, pabyRec + nRecordSize, 8);
    1579             : #if defined(SHP_BIG_ENDIAN)
    1580             :                 SHP_SWAP64(pabyRec + nRecordSize);
    1581             : #endif
    1582          16 :                 nRecordSize += 8;
    1583             :             }
    1584             :         }
    1585             : 
    1586          23 :         if (psObject->bMeasureIsUsed &&
    1587           6 :             (psObject->nSHPType == SHPT_MULTIPOINTZ ||
    1588           3 :              psObject->nSHPType == SHPT_MULTIPOINTM))
    1589             :         {
    1590           6 :             ByteCopy(&(psObject->dfMMin), pabyRec + nRecordSize, 8);
    1591             : #if defined(SHP_BIG_ENDIAN)
    1592             :             SHP_SWAP64(pabyRec + nRecordSize);
    1593             : #endif
    1594           6 :             nRecordSize += 8;
    1595             : 
    1596           6 :             ByteCopy(&(psObject->dfMMax), pabyRec + nRecordSize, 8);
    1597             : #if defined(SHP_BIG_ENDIAN)
    1598             :             SHP_SWAP64(pabyRec + nRecordSize);
    1599             : #endif
    1600           6 :             nRecordSize += 8;
    1601             : 
    1602          14 :             for (int i = 0; i < psObject->nVertices; i++)
    1603             :             {
    1604           8 :                 ByteCopy(psObject->padfM + i, pabyRec + nRecordSize, 8);
    1605             : #if defined(SHP_BIG_ENDIAN)
    1606             :                 SHP_SWAP64(pabyRec + nRecordSize);
    1607             : #endif
    1608           8 :                 nRecordSize += 8;
    1609             :             }
    1610          23 :         }
    1611             :     }
    1612             : 
    1613             :     /* -------------------------------------------------------------------- */
    1614             :     /*      Write point.                                                    */
    1615             :     /* -------------------------------------------------------------------- */
    1616       45373 :     else if (psObject->nSHPType == SHPT_POINT ||
    1617       44567 :              psObject->nSHPType == SHPT_POINTZ ||
    1618         628 :              psObject->nSHPType == SHPT_POINTM)
    1619             :     {
    1620       44750 :         ByteCopy(psObject->padfX, pabyRec + 12, 8);
    1621       44750 :         ByteCopy(psObject->padfY, pabyRec + 20, 8);
    1622             : 
    1623             : #if defined(SHP_BIG_ENDIAN)
    1624             :         SHP_SWAP64(pabyRec + 12);
    1625             :         SHP_SWAP64(pabyRec + 20);
    1626             : #endif
    1627             : 
    1628       44750 :         nRecordSize = 28;
    1629             : 
    1630       44750 :         if (psObject->nSHPType == SHPT_POINTZ)
    1631             :         {
    1632       43939 :             ByteCopy(psObject->padfZ, pabyRec + nRecordSize, 8);
    1633             : #if defined(SHP_BIG_ENDIAN)
    1634             :             SHP_SWAP64(pabyRec + nRecordSize);
    1635             : #endif
    1636       43939 :             nRecordSize += 8;
    1637             :         }
    1638             : 
    1639       44750 :         if (psObject->bMeasureIsUsed && (psObject->nSHPType == SHPT_POINTZ ||
    1640           5 :                                          psObject->nSHPType == SHPT_POINTM))
    1641             :         {
    1642          10 :             ByteCopy(psObject->padfM, pabyRec + nRecordSize, 8);
    1643             : #if defined(SHP_BIG_ENDIAN)
    1644             :             SHP_SWAP64(pabyRec + nRecordSize);
    1645             : #endif
    1646          10 :             nRecordSize += 8;
    1647             :         }
    1648             :     }
    1649             : 
    1650             :     /* -------------------------------------------------------------------- */
    1651             :     /*      Not much to do for null geometries.                             */
    1652             :     /* -------------------------------------------------------------------- */
    1653         623 :     else if (psObject->nSHPType == SHPT_NULL)
    1654             :     {
    1655         623 :         nRecordSize = 12;
    1656             :     }
    1657             :     else
    1658             :     {
    1659             :         /* unknown type */
    1660           0 :         assert(false);
    1661             :     }
    1662             : 
    1663             :     /* -------------------------------------------------------------------- */
    1664             :     /*      Establish where we are going to put this record. If we are      */
    1665             :     /*      rewriting the last record of the file, then we can update it in */
    1666             :     /*      place. Otherwise if rewriting an existing record, and it will   */
    1667             :     /*      fit, then put it  back where the original came from.  Otherwise */
    1668             :     /*      write at the end.                                               */
    1669             :     /* -------------------------------------------------------------------- */
    1670             :     SAOffset nRecordOffset;
    1671       76934 :     bool bAppendToLastRecord = false;
    1672       76934 :     bool bAppendToFile = false;
    1673       76934 :     if (nShapeId != -1 &&
    1674          47 :         psSHP->panRecOffset[nShapeId] + psSHP->panRecSize[nShapeId] + 8 ==
    1675          47 :             psSHP->nFileSize)
    1676             :     {
    1677          19 :         nRecordOffset = psSHP->panRecOffset[nShapeId];
    1678          19 :         bAppendToLastRecord = true;
    1679             :     }
    1680       76915 :     else if (nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize - 8)
    1681             :     {
    1682       76893 :         if (psSHP->nFileSize > UINT_MAX - nRecordSize)
    1683             :         {
    1684             :             char str[255];
    1685           0 :             snprintf(str, sizeof(str),
    1686             :                      "Failed to write shape object. "
    1687             :                      "The maximum file size of %u has been reached. "
    1688             :                      "The current record of size %u cannot be added.",
    1689             :                      psSHP->nFileSize, nRecordSize);
    1690           0 :             str[sizeof(str) - 1] = '\0';
    1691           0 :             psSHP->sHooks.Error(str);
    1692           0 :             free(pabyRec);
    1693           0 :             return -1;
    1694             :         }
    1695             : 
    1696       76893 :         bAppendToFile = true;
    1697       76893 :         nRecordOffset = psSHP->nFileSize;
    1698             :     }
    1699             :     else
    1700             :     {
    1701          22 :         nRecordOffset = psSHP->panRecOffset[nShapeId];
    1702             :     }
    1703             : 
    1704             :     /* -------------------------------------------------------------------- */
    1705             :     /*      Set the shape type, record number, and record size.             */
    1706             :     /* -------------------------------------------------------------------- */
    1707       76934 :     uint32_t i32 =
    1708       76934 :         (nShapeId < 0) ? psSHP->nRecords + 1 : nShapeId + 1; /* record # */
    1709             : #if !defined(SHP_BIG_ENDIAN)
    1710       76934 :     SHP_SWAP32(&i32);
    1711             : #endif
    1712       76934 :     ByteCopy(&i32, pabyRec, 4);
    1713             : 
    1714       76934 :     i32 = (nRecordSize - 8) / 2; /* record size */
    1715             : #if !defined(SHP_BIG_ENDIAN)
    1716       76934 :     SHP_SWAP32(&i32);
    1717             : #endif
    1718       76934 :     ByteCopy(&i32, pabyRec + 4, 4);
    1719             : 
    1720       76934 :     i32 = psObject->nSHPType; /* shape type */
    1721             : #if defined(SHP_BIG_ENDIAN)
    1722             :     SHP_SWAP32(&i32);
    1723             : #endif
    1724       76934 :     ByteCopy(&i32, pabyRec + 8, 4);
    1725             : 
    1726             :     /* -------------------------------------------------------------------- */
    1727             :     /*      Write out record.                                               */
    1728             :     /* -------------------------------------------------------------------- */
    1729             : 
    1730             :     /* -------------------------------------------------------------------- */
    1731             :     /*      Guard FSeek with check for whether we're already at position;   */
    1732             :     /*      no-op FSeeks defeat network filesystems' write buffering.       */
    1733             :     /* -------------------------------------------------------------------- */
    1734       76934 :     if (psSHP->sHooks.FTell(psSHP->fpSHP) != nRecordOffset)
    1735             :     {
    1736          64 :         if (psSHP->sHooks.FSeek(psSHP->fpSHP, nRecordOffset, 0) != 0)
    1737             :         {
    1738             :             char szErrorMsg[200];
    1739             : 
    1740           0 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    1741             :                      "Error in psSHP->sHooks.FSeek() while writing object to "
    1742             :                      ".shp file: %s",
    1743           0 :                      strerror(errno));
    1744           0 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    1745           0 :             psSHP->sHooks.Error(szErrorMsg);
    1746             : 
    1747           0 :             free(pabyRec);
    1748           0 :             return -1;
    1749             :         }
    1750             :     }
    1751       76934 :     if (psSHP->sHooks.FWrite(pabyRec, nRecordSize, 1, psSHP->fpSHP) < 1)
    1752             :     {
    1753             :         char szErrorMsg[200];
    1754             : 
    1755           0 :         snprintf(szErrorMsg, sizeof(szErrorMsg),
    1756             :                  "Error in psSHP->sHooks.FWrite() while writing object of %u "
    1757             :                  "bytes to .shp file: %s",
    1758           0 :                  nRecordSize, strerror(errno));
    1759           0 :         szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    1760           0 :         psSHP->sHooks.Error(szErrorMsg);
    1761             : 
    1762           0 :         free(pabyRec);
    1763           0 :         return -1;
    1764             :     }
    1765             : 
    1766       76934 :     free(pabyRec);
    1767             : 
    1768       76934 :     if (bAppendToLastRecord)
    1769             :     {
    1770          19 :         psSHP->nFileSize = psSHP->panRecOffset[nShapeId] + nRecordSize;
    1771             :     }
    1772       76915 :     else if (bAppendToFile)
    1773             :     {
    1774       76893 :         if (nShapeId == -1)
    1775       76887 :             nShapeId = psSHP->nRecords++;
    1776             : 
    1777       76893 :         psSHP->panRecOffset[nShapeId] = psSHP->nFileSize;
    1778       76893 :         psSHP->nFileSize += nRecordSize;
    1779             :     }
    1780       76934 :     psSHP->panRecSize[nShapeId] = nRecordSize - 8;
    1781             : 
    1782             :     /* -------------------------------------------------------------------- */
    1783             :     /*      Expand file wide bounds based on this shape.                    */
    1784             :     /* -------------------------------------------------------------------- */
    1785       76934 :     if (bFirstFeature)
    1786             :     {
    1787        1490 :         if (psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0)
    1788             :         {
    1789         563 :             psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;
    1790         563 :             psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;
    1791         563 :             psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;
    1792         563 :             psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;
    1793             :         }
    1794             :         else
    1795             :         {
    1796         927 :             psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
    1797         927 :             psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
    1798         927 :             psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] =
    1799         927 :                 psObject->padfZ ? psObject->padfZ[0] : 0.0;
    1800         927 :             psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] =
    1801         927 :                 psObject->padfM ? psObject->padfM[0] : 0.0;
    1802             :         }
    1803             :     }
    1804             : 
    1805      323049 :     for (int i = 0; i < psObject->nVertices; i++)
    1806             :     {
    1807      246115 :         psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0], psObject->padfX[i]);
    1808      246115 :         psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1], psObject->padfY[i]);
    1809      246115 :         psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0], psObject->padfX[i]);
    1810      246115 :         psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1], psObject->padfY[i]);
    1811      246115 :         if (psObject->padfZ)
    1812             :         {
    1813      244011 :             psSHP->adBoundsMin[2] =
    1814      244011 :                 MIN(psSHP->adBoundsMin[2], psObject->padfZ[i]);
    1815      244011 :             psSHP->adBoundsMax[2] =
    1816      244011 :                 MAX(psSHP->adBoundsMax[2], psObject->padfZ[i]);
    1817             :         }
    1818      246115 :         if (psObject->padfM)
    1819             :         {
    1820      244011 :             psSHP->adBoundsMin[3] =
    1821      244011 :                 MIN(psSHP->adBoundsMin[3], psObject->padfM[i]);
    1822      244011 :             psSHP->adBoundsMax[3] =
    1823      244011 :                 MAX(psSHP->adBoundsMax[3], psObject->padfM[i]);
    1824             :         }
    1825             :     }
    1826             : 
    1827       76934 :     return (nShapeId);
    1828             : }
    1829             : 
    1830             : /************************************************************************/
    1831             : /*                         SHPAllocBuffer()                             */
    1832             : /************************************************************************/
    1833             : 
    1834      845592 : static void *SHPAllocBuffer(unsigned char **pBuffer, int nSize)
    1835             : {
    1836      845592 :     if (pBuffer == SHPLIB_NULLPTR)
    1837           0 :         return calloc(1, nSize);
    1838             : 
    1839      845592 :     unsigned char *pRet = *pBuffer;
    1840      845592 :     if (pRet == SHPLIB_NULLPTR)
    1841           0 :         return SHPLIB_NULLPTR;
    1842             : 
    1843      845592 :     (*pBuffer) += nSize;
    1844      845592 :     return pRet;
    1845             : }
    1846             : 
    1847             : /************************************************************************/
    1848             : /*                    SHPReallocObjectBufIfNecessary()                  */
    1849             : /************************************************************************/
    1850             : 
    1851      140953 : static unsigned char *SHPReallocObjectBufIfNecessary(SHPHandle psSHP,
    1852             :                                                      int nObjectBufSize)
    1853             : {
    1854      140953 :     if (nObjectBufSize == 0)
    1855             :     {
    1856           1 :         nObjectBufSize = 4 * sizeof(double);
    1857             :     }
    1858             : 
    1859             :     unsigned char *pBuffer;
    1860      140953 :     if (nObjectBufSize > psSHP->nObjectBufSize)
    1861             :     {
    1862        1739 :         pBuffer = STATIC_CAST(unsigned char *,
    1863             :                               realloc(psSHP->pabyObjectBuf, nObjectBufSize));
    1864        1739 :         if (pBuffer != SHPLIB_NULLPTR)
    1865             :         {
    1866        1739 :             psSHP->pabyObjectBuf = pBuffer;
    1867        1739 :             psSHP->nObjectBufSize = nObjectBufSize;
    1868             :         }
    1869             :     }
    1870             :     else
    1871             :     {
    1872      139214 :         pBuffer = psSHP->pabyObjectBuf;
    1873             :     }
    1874             : 
    1875      140953 :     return pBuffer;
    1876             : }
    1877             : 
    1878             : /************************************************************************/
    1879             : /*                          SHPReadObject()                             */
    1880             : /*                                                                      */
    1881             : /*      Read the vertices, parts, and other non-attribute information   */
    1882             : /*      for one shape.                                                  */
    1883             : /************************************************************************/
    1884             : 
    1885      238345 : SHPObject SHPAPI_CALL1(*) SHPReadObject(const SHPHandle psSHP, int hEntity)
    1886             : {
    1887             :     /* -------------------------------------------------------------------- */
    1888             :     /*      Validate the record/entity number.                              */
    1889             :     /* -------------------------------------------------------------------- */
    1890      238345 :     if (hEntity < 0 || hEntity >= psSHP->nRecords)
    1891           0 :         return SHPLIB_NULLPTR;
    1892             : 
    1893             :     /* -------------------------------------------------------------------- */
    1894             :     /*      Read offset/length from SHX loading if necessary.               */
    1895             :     /* -------------------------------------------------------------------- */
    1896      238345 :     if (psSHP->panRecOffset[hEntity] == 0 && psSHP->fpSHX != SHPLIB_NULLPTR)
    1897             :     {
    1898             :         unsigned int nOffset;
    1899             :         unsigned int nLength;
    1900             : 
    1901           0 :         if (psSHP->sHooks.FSeek(psSHP->fpSHX, 100 + 8 * hEntity, 0) != 0 ||
    1902           0 :             psSHP->sHooks.FRead(&nOffset, 1, 4, psSHP->fpSHX) != 4 ||
    1903           0 :             psSHP->sHooks.FRead(&nLength, 1, 4, psSHP->fpSHX) != 4)
    1904             :         {
    1905             :             char str[128];
    1906           0 :             snprintf(str, sizeof(str),
    1907             :                      "Error in fseek()/fread() reading object from .shx file "
    1908             :                      "at offset %d",
    1909           0 :                      100 + 8 * hEntity);
    1910           0 :             str[sizeof(str) - 1] = '\0';
    1911             : 
    1912           0 :             psSHP->sHooks.Error(str);
    1913           0 :             return SHPLIB_NULLPTR;
    1914             :         }
    1915             : #if !defined(SHP_BIG_ENDIAN)
    1916           0 :         SHP_SWAP32(&nOffset);
    1917           0 :         SHP_SWAP32(&nLength);
    1918             : #endif
    1919             : 
    1920           0 :         if (nOffset > STATIC_CAST(unsigned int, INT_MAX))
    1921             :         {
    1922             :             char str[128];
    1923           0 :             snprintf(str, sizeof(str), "Invalid offset for entity %d", hEntity);
    1924           0 :             str[sizeof(str) - 1] = '\0';
    1925             : 
    1926           0 :             psSHP->sHooks.Error(str);
    1927           0 :             return SHPLIB_NULLPTR;
    1928             :         }
    1929           0 :         if (nLength > STATIC_CAST(unsigned int, INT_MAX / 2 - 4))
    1930             :         {
    1931             :             char str[128];
    1932           0 :             snprintf(str, sizeof(str), "Invalid length for entity %d", hEntity);
    1933           0 :             str[sizeof(str) - 1] = '\0';
    1934             : 
    1935           0 :             psSHP->sHooks.Error(str);
    1936           0 :             return SHPLIB_NULLPTR;
    1937             :         }
    1938             : 
    1939           0 :         psSHP->panRecOffset[hEntity] = nOffset * 2;
    1940           0 :         psSHP->panRecSize[hEntity] = nLength * 2;
    1941             :     }
    1942             : 
    1943             :     /* -------------------------------------------------------------------- */
    1944             :     /*      Ensure our record buffer is large enough.                       */
    1945             :     /* -------------------------------------------------------------------- */
    1946      238345 :     const int nEntitySize = psSHP->panRecSize[hEntity] + 8;
    1947      238345 :     if (nEntitySize > psSHP->nBufSize)
    1948             :     {
    1949        2708 :         int nNewBufSize = nEntitySize;
    1950        2708 :         if (nNewBufSize < INT_MAX - nNewBufSize / 3)
    1951        2708 :             nNewBufSize += nNewBufSize / 3;
    1952             :         else
    1953           0 :             nNewBufSize = INT_MAX;
    1954             : 
    1955             :         /* Before allocating too much memory, check that the file is big enough */
    1956             :         /* and do not trust the file size in the header the first time we */
    1957             :         /* need to allocate more than 10 MB */
    1958        2708 :         if (nNewBufSize >= 10 * 1024 * 1024)
    1959             :         {
    1960           2 :             if (psSHP->nBufSize < 10 * 1024 * 1024)
    1961             :             {
    1962             :                 SAOffset nFileSize;
    1963           2 :                 psSHP->sHooks.FSeek(psSHP->fpSHP, 0, 2);
    1964           2 :                 nFileSize = psSHP->sHooks.FTell(psSHP->fpSHP);
    1965           2 :                 if (nFileSize >= UINT_MAX)
    1966           0 :                     psSHP->nFileSize = UINT_MAX;
    1967             :                 else
    1968           2 :                     psSHP->nFileSize = STATIC_CAST(unsigned int, nFileSize);
    1969             :             }
    1970             : 
    1971           2 :             if (psSHP->panRecOffset[hEntity] >= psSHP->nFileSize ||
    1972             :                 /* We should normally use nEntitySize instead of*/
    1973             :                 /* psSHP->panRecSize[hEntity] in the below test, but because of */
    1974             :                 /* the case of non conformant .shx files detailed a bit below, */
    1975             :                 /* let be more tolerant */
    1976           2 :                 psSHP->panRecSize[hEntity] >
    1977           2 :                     psSHP->nFileSize - psSHP->panRecOffset[hEntity])
    1978             :             {
    1979             :                 char str[128];
    1980           1 :                 snprintf(str, sizeof(str),
    1981             :                          "Error in fread() reading object of size %d at offset "
    1982             :                          "%u from .shp file",
    1983           1 :                          nEntitySize, psSHP->panRecOffset[hEntity]);
    1984           1 :                 str[sizeof(str) - 1] = '\0';
    1985             : 
    1986           1 :                 psSHP->sHooks.Error(str);
    1987           1 :                 return SHPLIB_NULLPTR;
    1988             :             }
    1989             :         }
    1990             : 
    1991             :         unsigned char *pabyRecNew =
    1992        2707 :             STATIC_CAST(unsigned char *, realloc(psSHP->pabyRec, nNewBufSize));
    1993        2707 :         if (pabyRecNew == SHPLIB_NULLPTR)
    1994             :         {
    1995             :             char szErrorMsg[160];
    1996           0 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    1997             :                      "Not enough memory to allocate requested memory "
    1998             :                      "(nNewBufSize=%d). "
    1999             :                      "Probably broken SHP file",
    2000             :                      nNewBufSize);
    2001           0 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2002           0 :             psSHP->sHooks.Error(szErrorMsg);
    2003           0 :             return SHPLIB_NULLPTR;
    2004             :         }
    2005             : 
    2006             :         /* Only set new buffer size after successful alloc */
    2007        2707 :         psSHP->pabyRec = pabyRecNew;
    2008        2707 :         psSHP->nBufSize = nNewBufSize;
    2009             :     }
    2010             : 
    2011             :     /* In case we were not able to reallocate the buffer on a previous step */
    2012      238344 :     if (psSHP->pabyRec == SHPLIB_NULLPTR)
    2013             :     {
    2014           0 :         return SHPLIB_NULLPTR;
    2015             :     }
    2016             : 
    2017             :     /* -------------------------------------------------------------------- */
    2018             :     /*      Read the record.                                                */
    2019             :     /* -------------------------------------------------------------------- */
    2020      238344 :     if (psSHP->sHooks.FSeek(psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0) != 0)
    2021             :     {
    2022             :         /*
    2023             :          * TODO - mloskot: Consider detailed diagnostics of shape file,
    2024             :          * for example to detect if file is truncated.
    2025             :          */
    2026             :         char str[128];
    2027           0 :         snprintf(str, sizeof(str),
    2028             :                  "Error in fseek() reading object from .shp file at offset %u",
    2029           0 :                  psSHP->panRecOffset[hEntity]);
    2030           0 :         str[sizeof(str) - 1] = '\0';
    2031             : 
    2032           0 :         psSHP->sHooks.Error(str);
    2033           0 :         return SHPLIB_NULLPTR;
    2034             :     }
    2035             : 
    2036      238344 :     const int nBytesRead = STATIC_CAST(
    2037             :         int, psSHP->sHooks.FRead(psSHP->pabyRec, 1, nEntitySize, psSHP->fpSHP));
    2038             : 
    2039             :     /* Special case for a shapefile whose .shx content length field is not equal */
    2040             :     /* to the content length field of the .shp, which is a violation of "The */
    2041             :     /* content length stored in the index record is the same as the value stored in the main */
    2042             :     /* file record header." (http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf, page 24) */
    2043             :     /* Actually in that case the .shx content length is equal to the .shp content length + */
    2044             :     /* 4 (16 bit words), representing the 8 bytes of the record header... */
    2045      238344 :     if (nBytesRead >= 8 && nBytesRead == nEntitySize - 8)
    2046             :     {
    2047             :         /* Do a sanity check */
    2048             :         int nSHPContentLength;
    2049           1 :         memcpy(&nSHPContentLength, psSHP->pabyRec + 4, 4);
    2050             : #if !defined(SHP_BIG_ENDIAN)
    2051           1 :         SHP_SWAP32(&(nSHPContentLength));
    2052             : #endif
    2053           1 :         if (nSHPContentLength < 0 || nSHPContentLength > INT_MAX / 2 - 4 ||
    2054           1 :             2 * nSHPContentLength + 8 != nBytesRead)
    2055             :         {
    2056             :             char str[128];
    2057           0 :             snprintf(str, sizeof(str),
    2058             :                      "Sanity check failed when trying to recover from "
    2059             :                      "inconsistent .shx/.shp with shape %d",
    2060             :                      hEntity);
    2061           0 :             str[sizeof(str) - 1] = '\0';
    2062             : 
    2063           0 :             psSHP->sHooks.Error(str);
    2064           0 :             return SHPLIB_NULLPTR;
    2065           1 :         }
    2066             :     }
    2067      238343 :     else if (nBytesRead != nEntitySize)
    2068             :     {
    2069             :         /*
    2070             :          * TODO - mloskot: Consider detailed diagnostics of shape file,
    2071             :          * for example to detect if file is truncated.
    2072             :          */
    2073             :         char str[128];
    2074           0 :         snprintf(str, sizeof(str),
    2075             :                  "Error in fread() reading object of size %d at offset %u from "
    2076             :                  ".shp file",
    2077           0 :                  nEntitySize, psSHP->panRecOffset[hEntity]);
    2078           0 :         str[sizeof(str) - 1] = '\0';
    2079             : 
    2080           0 :         psSHP->sHooks.Error(str);
    2081           0 :         return SHPLIB_NULLPTR;
    2082             :     }
    2083             : 
    2084      238344 :     if (8 + 4 > nEntitySize)
    2085             :     {
    2086             :         char szErrorMsg[160];
    2087           0 :         snprintf(szErrorMsg, sizeof(szErrorMsg),
    2088             :                  "Corrupted .shp file : shape %d : nEntitySize = %d", hEntity,
    2089             :                  nEntitySize);
    2090           0 :         szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2091           0 :         psSHP->sHooks.Error(szErrorMsg);
    2092           0 :         return SHPLIB_NULLPTR;
    2093             :     }
    2094             :     int nSHPType;
    2095      238344 :     memcpy(&nSHPType, psSHP->pabyRec + 8, 4);
    2096             : 
    2097             : #if defined(SHP_BIG_ENDIAN)
    2098             :     SHP_SWAP32(&(nSHPType));
    2099             : #endif
    2100             : 
    2101             :     /* -------------------------------------------------------------------- */
    2102             :     /*      Allocate and minimally initialize the object.                   */
    2103             :     /* -------------------------------------------------------------------- */
    2104             :     SHPObject *psShape;
    2105      238344 :     if (psSHP->bFastModeReadObject)
    2106             :     {
    2107      238344 :         if (psSHP->psCachedObject->bFastModeReadObject)
    2108             :         {
    2109           0 :             psSHP->sHooks.Error("Invalid read pattern in fast read mode. "
    2110             :                                 "SHPDestroyObject() should be called.");
    2111           0 :             return SHPLIB_NULLPTR;
    2112             :         }
    2113             : 
    2114      238344 :         psShape = psSHP->psCachedObject;
    2115      238344 :         memset(psShape, 0, sizeof(SHPObject));
    2116             :     }
    2117             :     else
    2118             :     {
    2119           0 :         psShape = STATIC_CAST(SHPObject *, calloc(1, sizeof(SHPObject)));
    2120             :     }
    2121      238344 :     psShape->nShapeId = hEntity;
    2122      238344 :     psShape->nSHPType = nSHPType;
    2123      238344 :     psShape->bMeasureIsUsed = FALSE;
    2124      238344 :     psShape->bFastModeReadObject = psSHP->bFastModeReadObject;
    2125             : 
    2126             :     /* ==================================================================== */
    2127             :     /*  Extract vertices for a Polygon or Arc.                              */
    2128             :     /* ==================================================================== */
    2129      238344 :     if (psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC ||
    2130       99505 :         psShape->nSHPType == SHPT_POLYGONZ ||
    2131       99435 :         psShape->nSHPType == SHPT_POLYGONM || psShape->nSHPType == SHPT_ARCZ ||
    2132       97475 :         psShape->nSHPType == SHPT_ARCM || psShape->nSHPType == SHPT_MULTIPATCH)
    2133             :     {
    2134      140896 :         if (40 + 8 + 4 > nEntitySize)
    2135             :         {
    2136             :             char szErrorMsg[160];
    2137           0 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    2138             :                      "Corrupted .shp file : shape %d : nEntitySize = %d",
    2139             :                      hEntity, nEntitySize);
    2140           0 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2141           0 :             psSHP->sHooks.Error(szErrorMsg);
    2142           0 :             SHPDestroyObject(psShape);
    2143           0 :             return SHPLIB_NULLPTR;
    2144             :         }
    2145             :         /* -------------------------------------------------------------------- */
    2146             :         /*      Get the X/Y bounds.                                             */
    2147             :         /* -------------------------------------------------------------------- */
    2148             : #if defined(SHP_BIG_ENDIAN)
    2149             :         SHP_SWAPDOUBLE_CPY(&psShape->dfXMin, psSHP->pabyRec + 8 + 4);
    2150             :         SHP_SWAPDOUBLE_CPY(&psShape->dfYMin, psSHP->pabyRec + 8 + 12);
    2151             :         SHP_SWAPDOUBLE_CPY(&psShape->dfXMax, psSHP->pabyRec + 8 + 20);
    2152             :         SHP_SWAPDOUBLE_CPY(&psShape->dfYMax, psSHP->pabyRec + 8 + 28);
    2153             : #else
    2154      140896 :         memcpy(&psShape->dfXMin, psSHP->pabyRec + 8 + 4, 8);
    2155      140896 :         memcpy(&psShape->dfYMin, psSHP->pabyRec + 8 + 12, 8);
    2156      140896 :         memcpy(&psShape->dfXMax, psSHP->pabyRec + 8 + 20, 8);
    2157      140896 :         memcpy(&psShape->dfYMax, psSHP->pabyRec + 8 + 28, 8);
    2158             : #endif
    2159             : 
    2160             :         /* -------------------------------------------------------------------- */
    2161             :         /*      Extract part/point count, and build vertex and part arrays      */
    2162             :         /*      to proper size.                                                 */
    2163             :         /* -------------------------------------------------------------------- */
    2164             :         uint32_t nPoints;
    2165      140896 :         memcpy(&nPoints, psSHP->pabyRec + 40 + 8, 4);
    2166             :         uint32_t nParts;
    2167      140896 :         memcpy(&nParts, psSHP->pabyRec + 36 + 8, 4);
    2168             : 
    2169             : #if defined(SHP_BIG_ENDIAN)
    2170             :         SHP_SWAP32(&nPoints);
    2171             :         SHP_SWAP32(&nParts);
    2172             : #endif
    2173             : 
    2174             :         /* nPoints and nParts are unsigned */
    2175      140896 :         if (/* nPoints < 0 || nParts < 0 || */
    2176      140896 :             nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
    2177             :         {
    2178             :             char szErrorMsg[160];
    2179           0 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    2180             :                      "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u.",
    2181             :                      hEntity, nPoints, nParts);
    2182           0 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2183           0 :             psSHP->sHooks.Error(szErrorMsg);
    2184           0 :             SHPDestroyObject(psShape);
    2185           0 :             return SHPLIB_NULLPTR;
    2186             :         }
    2187             : 
    2188             :         /* With the previous checks on nPoints and nParts, */
    2189             :         /* we should not overflow here and after */
    2190             :         /* since 50 M * (16 + 8 + 8) = 1 600 MB */
    2191      140896 :         int nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
    2192      140896 :         if (psShape->nSHPType == SHPT_POLYGONZ ||
    2193      140826 :             psShape->nSHPType == SHPT_ARCZ ||
    2194      138881 :             psShape->nSHPType == SHPT_MULTIPATCH)
    2195             :         {
    2196        2027 :             nRequiredSize += 16 + 8 * nPoints;
    2197             :         }
    2198      140896 :         if (psShape->nSHPType == SHPT_MULTIPATCH)
    2199             :         {
    2200          12 :             nRequiredSize += 4 * nParts;
    2201             :         }
    2202      140896 :         if (nRequiredSize > nEntitySize)
    2203             :         {
    2204             :             char szErrorMsg[160];
    2205           6 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    2206             :                      "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u, "
    2207             :                      "nEntitySize=%d.",
    2208             :                      hEntity, nPoints, nParts, nEntitySize);
    2209           6 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2210           6 :             psSHP->sHooks.Error(szErrorMsg);
    2211           6 :             SHPDestroyObject(psShape);
    2212           6 :             return SHPLIB_NULLPTR;
    2213             :         }
    2214             : 
    2215      140890 :         unsigned char *pBuffer = SHPLIB_NULLPTR;
    2216      140890 :         unsigned char **ppBuffer = SHPLIB_NULLPTR;
    2217             : 
    2218      140890 :         if (psShape->bFastModeReadObject)
    2219             :         {
    2220      140890 :             const int nObjectBufSize =
    2221      140890 :                 4 * sizeof(double) * nPoints + 2 * sizeof(int) * nParts;
    2222      140890 :             pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
    2223      140890 :             ppBuffer = &pBuffer;
    2224             :         }
    2225             : 
    2226      140890 :         psShape->nVertices = nPoints;
    2227      140890 :         psShape->padfX = STATIC_CAST(
    2228             :             double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
    2229      140890 :         psShape->padfY = STATIC_CAST(
    2230             :             double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
    2231      140890 :         psShape->padfZ = STATIC_CAST(
    2232             :             double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
    2233      140890 :         psShape->padfM = STATIC_CAST(
    2234             :             double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
    2235             : 
    2236      140890 :         psShape->nParts = nParts;
    2237      140890 :         psShape->panPartStart =
    2238      140890 :             STATIC_CAST(int *, SHPAllocBuffer(ppBuffer, nParts * sizeof(int)));
    2239      140890 :         psShape->panPartType =
    2240      140890 :             STATIC_CAST(int *, SHPAllocBuffer(ppBuffer, nParts * sizeof(int)));
    2241             : 
    2242      140890 :         if (psShape->padfX == SHPLIB_NULLPTR ||
    2243      140890 :             psShape->padfY == SHPLIB_NULLPTR ||
    2244      140890 :             psShape->padfZ == SHPLIB_NULLPTR ||
    2245      140890 :             psShape->padfM == SHPLIB_NULLPTR ||
    2246      140890 :             psShape->panPartStart == SHPLIB_NULLPTR ||
    2247      140890 :             psShape->panPartType == SHPLIB_NULLPTR)
    2248             :         {
    2249             :             char szErrorMsg[160];
    2250           0 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    2251             :                      "Not enough memory to allocate requested memory "
    2252             :                      "(nPoints=%u, nParts=%u) for shape %d. "
    2253             :                      "Probably broken SHP file",
    2254             :                      nPoints, nParts, hEntity);
    2255           0 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2256           0 :             psSHP->sHooks.Error(szErrorMsg);
    2257           0 :             SHPDestroyObject(psShape);
    2258           0 :             return SHPLIB_NULLPTR;
    2259             :         }
    2260             : 
    2261      282119 :         for (int i = 0; STATIC_CAST(uint32_t, i) < nParts; i++)
    2262      141229 :             psShape->panPartType[i] = SHPP_RING;
    2263             : 
    2264             :         /* -------------------------------------------------------------------- */
    2265             :         /*      Copy out the part array from the record.                        */
    2266             :         /* -------------------------------------------------------------------- */
    2267      140890 :         memcpy(psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts);
    2268      282113 :         for (int i = 0; STATIC_CAST(uint32_t, i) < nParts; i++)
    2269             :         {
    2270             : #if defined(SHP_BIG_ENDIAN)
    2271             :             SHP_SWAP32(psShape->panPartStart + i);
    2272             : #endif
    2273             : 
    2274             :             /* We check that the offset is inside the vertex array */
    2275      141226 :             if (psShape->panPartStart[i] < 0 ||
    2276      141226 :                 (psShape->panPartStart[i] >= psShape->nVertices &&
    2277           0 :                  psShape->nVertices > 0) ||
    2278      141226 :                 (psShape->panPartStart[i] > 0 && psShape->nVertices == 0))
    2279             :             {
    2280             :                 char szErrorMsg[160];
    2281           0 :                 snprintf(szErrorMsg, sizeof(szErrorMsg),
    2282             :                          "Corrupted .shp file : shape %d : panPartStart[%d] = "
    2283             :                          "%d, nVertices = %d",
    2284           0 :                          hEntity, i, psShape->panPartStart[i],
    2285             :                          psShape->nVertices);
    2286           0 :                 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2287           0 :                 psSHP->sHooks.Error(szErrorMsg);
    2288           0 :                 SHPDestroyObject(psShape);
    2289           0 :                 return SHPLIB_NULLPTR;
    2290             :             }
    2291      141226 :             if (i > 0 &&
    2292         338 :                 psShape->panPartStart[i] <= psShape->panPartStart[i - 1])
    2293             :             {
    2294             :                 char szErrorMsg[160];
    2295           3 :                 snprintf(szErrorMsg, sizeof(szErrorMsg),
    2296             :                          "Corrupted .shp file : shape %d : panPartStart[%d] = "
    2297             :                          "%d, panPartStart[%d] = %d",
    2298           3 :                          hEntity, i, psShape->panPartStart[i], i - 1,
    2299           3 :                          psShape->panPartStart[i - 1]);
    2300           3 :                 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2301           3 :                 psSHP->sHooks.Error(szErrorMsg);
    2302           3 :                 SHPDestroyObject(psShape);
    2303           3 :                 return SHPLIB_NULLPTR;
    2304             :             }
    2305             :         }
    2306             : 
    2307      140887 :         int nOffset = 44 + 8 + 4 * nParts;
    2308             : 
    2309             :         /* -------------------------------------------------------------------- */
    2310             :         /*      If this is a multipatch, we will also have parts types.         */
    2311             :         /* -------------------------------------------------------------------- */
    2312      140887 :         if (psShape->nSHPType == SHPT_MULTIPATCH)
    2313             :         {
    2314          12 :             memcpy(psShape->panPartType, psSHP->pabyRec + nOffset, 4 * nParts);
    2315          31 :             for (int i = 0; STATIC_CAST(uint32_t, i) < nParts; i++)
    2316             :             {
    2317             : #if defined(SHP_BIG_ENDIAN)
    2318             :                 SHP_SWAP32(psShape->panPartType + i);
    2319             : #endif
    2320             :             }
    2321             : 
    2322          12 :             nOffset += 4 * nParts;
    2323             :         }
    2324             : 
    2325             :         /* -------------------------------------------------------------------- */
    2326             :         /*      Copy out the vertices from the record.                          */
    2327             :         /* -------------------------------------------------------------------- */
    2328     1020930 :         for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++)
    2329             :         {
    2330             : #if defined(SHP_BIG_ENDIAN)
    2331             :             SHP_SWAPDOUBLE_CPY(psShape->padfX + i,
    2332             :                                psSHP->pabyRec + nOffset + i * 16);
    2333             :             SHP_SWAPDOUBLE_CPY(psShape->padfY + i,
    2334             :                                psSHP->pabyRec + nOffset + i * 16 + 8);
    2335             : #else
    2336      880046 :             memcpy(psShape->padfX + i, psSHP->pabyRec + nOffset + i * 16, 8);
    2337      880046 :             memcpy(psShape->padfY + i, psSHP->pabyRec + nOffset + i * 16 + 8,
    2338             :                    8);
    2339             : #endif
    2340             :         }
    2341             : 
    2342      140887 :         nOffset += 16 * nPoints;
    2343             : 
    2344             :         /* -------------------------------------------------------------------- */
    2345             :         /*      If we have a Z coordinate, collect that now.                    */
    2346             :         /* -------------------------------------------------------------------- */
    2347      140887 :         if (psShape->nSHPType == SHPT_POLYGONZ ||
    2348      140817 :             psShape->nSHPType == SHPT_ARCZ ||
    2349      138872 :             psShape->nSHPType == SHPT_MULTIPATCH)
    2350             :         {
    2351             : #if defined(SHP_BIG_ENDIAN)
    2352             :             SHP_SWAPDOUBLE_CPY(&psShape->dfZMin, psSHP->pabyRec + nOffset);
    2353             :             SHP_SWAPDOUBLE_CPY(&psShape->dfZMax, psSHP->pabyRec + nOffset + 8);
    2354             : #else
    2355        2027 :             memcpy(&psShape->dfZMin, psSHP->pabyRec + nOffset, 8);
    2356        2027 :             memcpy(&psShape->dfZMax, psSHP->pabyRec + nOffset + 8, 8);
    2357             : 
    2358             : #endif
    2359             : 
    2360       54234 :             for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++)
    2361             :             {
    2362             : #if defined(SHP_BIG_ENDIAN)
    2363             :                 SHP_SWAPDOUBLE_CPY(psShape->padfZ + i,
    2364             :                                    psSHP->pabyRec + nOffset + 16 + i * 8);
    2365             : #else
    2366       52207 :                 memcpy(psShape->padfZ + i,
    2367       52207 :                        psSHP->pabyRec + nOffset + 16 + i * 8, 8);
    2368             : #endif
    2369             :             }
    2370             : 
    2371        2027 :             nOffset += 16 + 8 * nPoints;
    2372             :         }
    2373      138860 :         else if (psShape->bFastModeReadObject)
    2374             :         {
    2375      138860 :             psShape->padfZ = SHPLIB_NULLPTR;
    2376             :         }
    2377             : 
    2378             :         /* -------------------------------------------------------------------- */
    2379             :         /*      If we have a M measure value, then read it now.  We assume      */
    2380             :         /*      that the measure can be present for any shape if the size is    */
    2381             :         /*      big enough, but really it will only occur for the Z shapes      */
    2382             :         /*      (options), and the M shapes.                                    */
    2383             :         /* -------------------------------------------------------------------- */
    2384      140887 :         if (nEntitySize >= STATIC_CAST(int, nOffset + 16 + 8 * nPoints))
    2385             :         {
    2386             : #if defined(SHP_BIG_ENDIAN)
    2387             :             SHP_SWAPDOUBLE_CPY(&psShape->dfMMin, psSHP->pabyRec + nOffset);
    2388             :             SHP_SWAPDOUBLE_CPY(&psShape->dfMMax, psSHP->pabyRec + nOffset + 8);
    2389             : #else
    2390          43 :             memcpy(&psShape->dfMMin, psSHP->pabyRec + nOffset, 8);
    2391          43 :             memcpy(&psShape->dfMMax, psSHP->pabyRec + nOffset + 8, 8);
    2392             : #endif
    2393             : 
    2394         225 :             for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++)
    2395             :             {
    2396             : #if defined(SHP_BIG_ENDIAN)
    2397             :                 SHP_SWAPDOUBLE_CPY(psShape->padfM + i,
    2398             :                                    psSHP->pabyRec + nOffset + 16 + i * 8);
    2399             : #else
    2400         182 :                 memcpy(psShape->padfM + i,
    2401         182 :                        psSHP->pabyRec + nOffset + 16 + i * 8, 8);
    2402             : #endif
    2403             :             }
    2404          43 :             psShape->bMeasureIsUsed = TRUE;
    2405             :         }
    2406      140844 :         else if (psShape->bFastModeReadObject)
    2407             :         {
    2408      140844 :             psShape->padfM = SHPLIB_NULLPTR;
    2409      140887 :         }
    2410             :     }
    2411             : 
    2412             :     /* ==================================================================== */
    2413             :     /*  Extract vertices for a MultiPoint.                                  */
    2414             :     /* ==================================================================== */
    2415       97448 :     else if (psShape->nSHPType == SHPT_MULTIPOINT ||
    2416       97433 :              psShape->nSHPType == SHPT_MULTIPOINTM ||
    2417       97428 :              psShape->nSHPType == SHPT_MULTIPOINTZ)
    2418             :     {
    2419          66 :         if (44 + 4 > nEntitySize)
    2420             :         {
    2421             :             char szErrorMsg[160];
    2422           0 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    2423             :                      "Corrupted .shp file : shape %d : nEntitySize = %d",
    2424             :                      hEntity, nEntitySize);
    2425           0 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2426           0 :             psSHP->sHooks.Error(szErrorMsg);
    2427           0 :             SHPDestroyObject(psShape);
    2428           0 :             return SHPLIB_NULLPTR;
    2429             :         }
    2430             :         uint32_t nPoints;
    2431          66 :         memcpy(&nPoints, psSHP->pabyRec + 44, 4);
    2432             : 
    2433             : #if defined(SHP_BIG_ENDIAN)
    2434             :         SHP_SWAP32(&nPoints);
    2435             : #endif
    2436             : 
    2437             :         /* nPoints is unsigned */
    2438          66 :         if (/* nPoints < 0 || */ nPoints > 50 * 1000 * 1000)
    2439             :         {
    2440             :             char szErrorMsg[160];
    2441           0 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    2442             :                      "Corrupted .shp file : shape %d : nPoints = %u", hEntity,
    2443             :                      nPoints);
    2444           0 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2445           0 :             psSHP->sHooks.Error(szErrorMsg);
    2446           0 :             SHPDestroyObject(psShape);
    2447           0 :             return SHPLIB_NULLPTR;
    2448             :         }
    2449             : 
    2450          66 :         int nRequiredSize = 48 + nPoints * 16;
    2451          66 :         if (psShape->nSHPType == SHPT_MULTIPOINTZ)
    2452             :         {
    2453          46 :             nRequiredSize += 16 + nPoints * 8;
    2454             :         }
    2455          66 :         if (nRequiredSize > nEntitySize)
    2456             :         {
    2457             :             char szErrorMsg[160];
    2458           3 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    2459             :                      "Corrupted .shp file : shape %d : nPoints = %u, "
    2460             :                      "nEntitySize = %d",
    2461             :                      hEntity, nPoints, nEntitySize);
    2462           3 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2463           3 :             psSHP->sHooks.Error(szErrorMsg);
    2464           3 :             SHPDestroyObject(psShape);
    2465           3 :             return SHPLIB_NULLPTR;
    2466             :         }
    2467             : 
    2468          63 :         unsigned char *pBuffer = SHPLIB_NULLPTR;
    2469          63 :         unsigned char **ppBuffer = SHPLIB_NULLPTR;
    2470             : 
    2471          63 :         if (psShape->bFastModeReadObject)
    2472             :         {
    2473          63 :             const int nObjectBufSize = 4 * sizeof(double) * nPoints;
    2474          63 :             pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
    2475          63 :             ppBuffer = &pBuffer;
    2476             :         }
    2477             : 
    2478          63 :         psShape->nVertices = nPoints;
    2479             : 
    2480          63 :         psShape->padfX = STATIC_CAST(
    2481             :             double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
    2482          63 :         psShape->padfY = STATIC_CAST(
    2483             :             double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
    2484          63 :         psShape->padfZ = STATIC_CAST(
    2485             :             double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
    2486          63 :         psShape->padfM = STATIC_CAST(
    2487             :             double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
    2488             : 
    2489          63 :         if (psShape->padfX == SHPLIB_NULLPTR ||
    2490          63 :             psShape->padfY == SHPLIB_NULLPTR ||
    2491          63 :             psShape->padfZ == SHPLIB_NULLPTR ||
    2492          63 :             psShape->padfM == SHPLIB_NULLPTR)
    2493             :         {
    2494             :             char szErrorMsg[160];
    2495           0 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    2496             :                      "Not enough memory to allocate requested memory "
    2497             :                      "(nPoints=%u) for shape %d. "
    2498             :                      "Probably broken SHP file",
    2499             :                      nPoints, hEntity);
    2500           0 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2501           0 :             psSHP->sHooks.Error(szErrorMsg);
    2502           0 :             SHPDestroyObject(psShape);
    2503           0 :             return SHPLIB_NULLPTR;
    2504             :         }
    2505             : 
    2506         172 :         for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++)
    2507             :         {
    2508             : #if defined(SHP_BIG_ENDIAN)
    2509             :             SHP_SWAPDOUBLE_CPY(psShape->padfX + i,
    2510             :                                psSHP->pabyRec + 48 + 16 * i);
    2511             :             SHP_SWAPDOUBLE_CPY(psShape->padfY + i,
    2512             :                                psSHP->pabyRec + 48 + 16 * i + 8);
    2513             : #else
    2514         109 :             memcpy(psShape->padfX + i, psSHP->pabyRec + 48 + 16 * i, 8);
    2515         109 :             memcpy(psShape->padfY + i, psSHP->pabyRec + 48 + 16 * i + 8, 8);
    2516             : #endif
    2517             :         }
    2518             : 
    2519          63 :         int nOffset = 48 + 16 * nPoints;
    2520             : 
    2521             :         /* -------------------------------------------------------------------- */
    2522             :         /*      Get the X/Y bounds.                                             */
    2523             :         /* -------------------------------------------------------------------- */
    2524             : #if defined(SHP_BIG_ENDIAN)
    2525             :         SHP_SWAPDOUBLE_CPY(&psShape->dfXMin, psSHP->pabyRec + 8 + 4);
    2526             :         SHP_SWAPDOUBLE_CPY(&psShape->dfYMin, psSHP->pabyRec + 8 + 12);
    2527             :         SHP_SWAPDOUBLE_CPY(&psShape->dfXMax, psSHP->pabyRec + 8 + 20);
    2528             :         SHP_SWAPDOUBLE_CPY(&psShape->dfYMax, psSHP->pabyRec + 8 + 28);
    2529             : #else
    2530          63 :         memcpy(&psShape->dfXMin, psSHP->pabyRec + 8 + 4, 8);
    2531          63 :         memcpy(&psShape->dfYMin, psSHP->pabyRec + 8 + 12, 8);
    2532          63 :         memcpy(&psShape->dfXMax, psSHP->pabyRec + 8 + 20, 8);
    2533          63 :         memcpy(&psShape->dfYMax, psSHP->pabyRec + 8 + 28, 8);
    2534             : #endif
    2535             : 
    2536             :         /* -------------------------------------------------------------------- */
    2537             :         /*      If we have a Z coordinate, collect that now.                    */
    2538             :         /* -------------------------------------------------------------------- */
    2539          63 :         if (psShape->nSHPType == SHPT_MULTIPOINTZ)
    2540             :         {
    2541             : #if defined(SHP_BIG_ENDIAN)
    2542             :             SHP_SWAPDOUBLE_CPY(&psShape->dfZMin, psSHP->pabyRec + nOffset);
    2543             :             SHP_SWAPDOUBLE_CPY(&psShape->dfZMax, psSHP->pabyRec + nOffset + 8);
    2544             : #else
    2545          46 :             memcpy(&psShape->dfZMin, psSHP->pabyRec + nOffset, 8);
    2546          46 :             memcpy(&psShape->dfZMax, psSHP->pabyRec + nOffset + 8, 8);
    2547             : #endif
    2548             : 
    2549         130 :             for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++)
    2550             :             {
    2551             : #if defined(SHP_BIG_ENDIAN)
    2552             :                 SHP_SWAPDOUBLE_CPY(psShape->padfZ + i,
    2553             :                                    psSHP->pabyRec + nOffset + 16 + i * 8);
    2554             : #else
    2555          84 :                 memcpy(psShape->padfZ + i,
    2556          84 :                        psSHP->pabyRec + nOffset + 16 + i * 8, 8);
    2557             : #endif
    2558             :             }
    2559             : 
    2560          46 :             nOffset += 16 + 8 * nPoints;
    2561             :         }
    2562          17 :         else if (psShape->bFastModeReadObject)
    2563          17 :             psShape->padfZ = SHPLIB_NULLPTR;
    2564             : 
    2565             :         /* -------------------------------------------------------------------- */
    2566             :         /*      If we have a M measure value, then read it now.  We assume      */
    2567             :         /*      that the measure can be present for any shape if the size is    */
    2568             :         /*      big enough, but really it will only occur for the Z shapes      */
    2569             :         /*      (options), and the M shapes.                                    */
    2570             :         /* -------------------------------------------------------------------- */
    2571          63 :         if (nEntitySize >= STATIC_CAST(int, nOffset + 16 + 8 * nPoints))
    2572             :         {
    2573             : #if defined(SHP_BIG_ENDIAN)
    2574             :             SHP_SWAPDOUBLE_CPY(&psShape->dfMMin, psSHP->pabyRec + nOffset);
    2575             :             SHP_SWAPDOUBLE_CPY(&psShape->dfMMax, psSHP->pabyRec + nOffset + 8);
    2576             : #else
    2577          11 :             memcpy(&psShape->dfMMin, psSHP->pabyRec + nOffset, 8);
    2578          11 :             memcpy(&psShape->dfMMax, psSHP->pabyRec + nOffset + 8, 8);
    2579             : #endif
    2580             : 
    2581          23 :             for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++)
    2582             :             {
    2583             : #if defined(SHP_BIG_ENDIAN)
    2584             :                 SHP_SWAPDOUBLE_CPY(psShape->padfM + i,
    2585             :                                    psSHP->pabyRec + nOffset + 16 + i * 8);
    2586             : #else
    2587          12 :                 memcpy(psShape->padfM + i,
    2588          12 :                        psSHP->pabyRec + nOffset + 16 + i * 8, 8);
    2589             : #endif
    2590             :             }
    2591          11 :             psShape->bMeasureIsUsed = TRUE;
    2592             :         }
    2593          52 :         else if (psShape->bFastModeReadObject)
    2594          63 :             psShape->padfM = SHPLIB_NULLPTR;
    2595             :     }
    2596             : 
    2597             :     /* ==================================================================== */
    2598             :     /*      Extract vertices for a point.                                   */
    2599             :     /* ==================================================================== */
    2600       97382 :     else if (psShape->nSHPType == SHPT_POINT ||
    2601       88644 :              psShape->nSHPType == SHPT_POINTM ||
    2602       88633 :              psShape->nSHPType == SHPT_POINTZ)
    2603             :     {
    2604       96674 :         psShape->nVertices = 1;
    2605       96674 :         if (psShape->bFastModeReadObject)
    2606             :         {
    2607       96674 :             psShape->padfX = &(psShape->dfXMin);
    2608       96674 :             psShape->padfY = &(psShape->dfYMin);
    2609       96674 :             psShape->padfZ = &(psShape->dfZMin);
    2610       96674 :             psShape->padfM = &(psShape->dfMMin);
    2611       96674 :             psShape->padfZ[0] = 0.0;
    2612       96674 :             psShape->padfM[0] = 0.0;
    2613             :         }
    2614             :         else
    2615             :         {
    2616           0 :             psShape->padfX = STATIC_CAST(double *, calloc(1, sizeof(double)));
    2617           0 :             psShape->padfY = STATIC_CAST(double *, calloc(1, sizeof(double)));
    2618           0 :             psShape->padfZ = STATIC_CAST(double *, calloc(1, sizeof(double)));
    2619           0 :             psShape->padfM = STATIC_CAST(double *, calloc(1, sizeof(double)));
    2620             :         }
    2621             : 
    2622       96674 :         if (20 + 8 + ((psShape->nSHPType == SHPT_POINTZ) ? 8 : 0) > nEntitySize)
    2623             :         {
    2624             :             char szErrorMsg[160];
    2625           3 :             snprintf(szErrorMsg, sizeof(szErrorMsg),
    2626             :                      "Corrupted .shp file : shape %d : nEntitySize = %d",
    2627             :                      hEntity, nEntitySize);
    2628           3 :             szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
    2629           3 :             psSHP->sHooks.Error(szErrorMsg);
    2630           3 :             SHPDestroyObject(psShape);
    2631           3 :             return SHPLIB_NULLPTR;
    2632             :         }
    2633             : #if defined(SHP_BIG_ENDIAN)
    2634             :         SHP_SWAPDOUBLE_CPY(psShape->padfX, psSHP->pabyRec + 12);
    2635             :         SHP_SWAPDOUBLE_CPY(psShape->padfY, psSHP->pabyRec + 20);
    2636             : #else
    2637       96671 :         memcpy(psShape->padfX, psSHP->pabyRec + 12, 8);
    2638       96671 :         memcpy(psShape->padfY, psSHP->pabyRec + 20, 8);
    2639             : #endif
    2640             : 
    2641       96671 :         int nOffset = 20 + 8;
    2642             : 
    2643             :         /* -------------------------------------------------------------------- */
    2644             :         /*      If we have a Z coordinate, collect that now.                    */
    2645             :         /* -------------------------------------------------------------------- */
    2646       96671 :         if (psShape->nSHPType == SHPT_POINTZ)
    2647             :         {
    2648             : #if defined(SHP_BIG_ENDIAN)
    2649             :             SHP_SWAPDOUBLE_CPY(psShape->padfZ, psSHP->pabyRec + nOffset);
    2650             : #else
    2651       87925 :             memcpy(psShape->padfZ, psSHP->pabyRec + nOffset, 8);
    2652             : #endif
    2653             : 
    2654       87925 :             nOffset += 8;
    2655             :         }
    2656             : 
    2657             :         /* -------------------------------------------------------------------- */
    2658             :         /*      If we have a M measure value, then read it now.  We assume      */
    2659             :         /*      that the measure can be present for any shape if the size is    */
    2660             :         /*      big enough, but really it will only occur for the Z shapes      */
    2661             :         /*      (options), and the M shapes.                                    */
    2662             :         /* -------------------------------------------------------------------- */
    2663       96671 :         if (nEntitySize >= nOffset + 8)
    2664             :         {
    2665             : #if defined(SHP_BIG_ENDIAN)
    2666             :             SHP_SWAPDOUBLE_CPY(psShape->padfM, psSHP->pabyRec + nOffset);
    2667             : #else
    2668          29 :             memcpy(psShape->padfM, psSHP->pabyRec + nOffset, 8);
    2669             : #endif
    2670          29 :             psShape->bMeasureIsUsed = TRUE;
    2671             :         }
    2672             : 
    2673             :         /* -------------------------------------------------------------------- */
    2674             :         /*      Since no extents are supplied in the record, we will apply      */
    2675             :         /*      them from the single vertex.                                    */
    2676             :         /* -------------------------------------------------------------------- */
    2677       96671 :         psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];
    2678       96671 :         psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];
    2679       96671 :         psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];
    2680       96671 :         psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];
    2681             :     }
    2682             : 
    2683      238329 :     return (psShape);
    2684             : }
    2685             : 
    2686             : /************************************************************************/
    2687             : /*                            SHPTypeName()                             */
    2688             : /************************************************************************/
    2689             : 
    2690           0 : const char SHPAPI_CALL1(*) SHPTypeName(int nSHPType)
    2691             : {
    2692           0 :     switch (nSHPType)
    2693             :     {
    2694           0 :         case SHPT_NULL:
    2695           0 :             return "NullShape";
    2696             : 
    2697           0 :         case SHPT_POINT:
    2698           0 :             return "Point";
    2699             : 
    2700           0 :         case SHPT_ARC:
    2701           0 :             return "Arc";
    2702             : 
    2703           0 :         case SHPT_POLYGON:
    2704           0 :             return "Polygon";
    2705             : 
    2706           0 :         case SHPT_MULTIPOINT:
    2707           0 :             return "MultiPoint";
    2708             : 
    2709           0 :         case SHPT_POINTZ:
    2710           0 :             return "PointZ";
    2711             : 
    2712           0 :         case SHPT_ARCZ:
    2713           0 :             return "ArcZ";
    2714             : 
    2715           0 :         case SHPT_POLYGONZ:
    2716           0 :             return "PolygonZ";
    2717             : 
    2718           0 :         case SHPT_MULTIPOINTZ:
    2719           0 :             return "MultiPointZ";
    2720             : 
    2721           0 :         case SHPT_POINTM:
    2722           0 :             return "PointM";
    2723             : 
    2724           0 :         case SHPT_ARCM:
    2725           0 :             return "ArcM";
    2726             : 
    2727           0 :         case SHPT_POLYGONM:
    2728           0 :             return "PolygonM";
    2729             : 
    2730           0 :         case SHPT_MULTIPOINTM:
    2731           0 :             return "MultiPointM";
    2732             : 
    2733           0 :         case SHPT_MULTIPATCH:
    2734           0 :             return "MultiPatch";
    2735             : 
    2736           0 :         default:
    2737           0 :             return "UnknownShapeType";
    2738             :     }
    2739             : }
    2740             : 
    2741             : /************************************************************************/
    2742             : /*                          SHPPartTypeName()                           */
    2743             : /************************************************************************/
    2744             : 
    2745           0 : const char SHPAPI_CALL1(*) SHPPartTypeName(int nPartType)
    2746             : {
    2747           0 :     switch (nPartType)
    2748             :     {
    2749           0 :         case SHPP_TRISTRIP:
    2750           0 :             return "TriangleStrip";
    2751             : 
    2752           0 :         case SHPP_TRIFAN:
    2753           0 :             return "TriangleFan";
    2754             : 
    2755           0 :         case SHPP_OUTERRING:
    2756           0 :             return "OuterRing";
    2757             : 
    2758           0 :         case SHPP_INNERRING:
    2759           0 :             return "InnerRing";
    2760             : 
    2761           0 :         case SHPP_FIRSTRING:
    2762           0 :             return "FirstRing";
    2763             : 
    2764           0 :         case SHPP_RING:
    2765           0 :             return "Ring";
    2766             : 
    2767           0 :         default:
    2768           0 :             return "UnknownPartType";
    2769             :     }
    2770             : }
    2771             : 
    2772             : /************************************************************************/
    2773             : /*                          SHPDestroyObject()                          */
    2774             : /************************************************************************/
    2775             : 
    2776      315127 : void SHPAPI_CALL SHPDestroyObject(SHPObject *psShape)
    2777             : {
    2778      315127 :     if (psShape == SHPLIB_NULLPTR)
    2779           0 :         return;
    2780             : 
    2781      315127 :     if (psShape->bFastModeReadObject)
    2782             :     {
    2783      238344 :         psShape->bFastModeReadObject = FALSE;
    2784      238344 :         return;
    2785             :     }
    2786             : 
    2787       76783 :     if (psShape->padfX != SHPLIB_NULLPTR)
    2788       76167 :         free(psShape->padfX);
    2789       76783 :     if (psShape->padfY != SHPLIB_NULLPTR)
    2790       76167 :         free(psShape->padfY);
    2791       76783 :     if (psShape->padfZ != SHPLIB_NULLPTR)
    2792       76167 :         free(psShape->padfZ);
    2793       76783 :     if (psShape->padfM != SHPLIB_NULLPTR)
    2794       76167 :         free(psShape->padfM);
    2795             : 
    2796       76783 :     if (psShape->panPartStart != SHPLIB_NULLPTR)
    2797       31445 :         free(psShape->panPartStart);
    2798       76783 :     if (psShape->panPartType != SHPLIB_NULLPTR)
    2799       31445 :         free(psShape->panPartType);
    2800             : 
    2801       76783 :     free(psShape);
    2802             : }
    2803             : 
    2804             : /************************************************************************/
    2805             : /*                       SHPGetPartVertexCount()                        */
    2806             : /************************************************************************/
    2807             : 
    2808           0 : static int SHPGetPartVertexCount(const SHPObject *psObject, int iPart)
    2809             : {
    2810           0 :     if (iPart == psObject->nParts - 1)
    2811           0 :         return psObject->nVertices - psObject->panPartStart[iPart];
    2812             :     else
    2813           0 :         return psObject->panPartStart[iPart + 1] -
    2814           0 :                psObject->panPartStart[iPart];
    2815             : }
    2816             : 
    2817             : /************************************************************************/
    2818             : /*                      SHPRewindIsInnerRing()                          */
    2819             : /************************************************************************/
    2820             : 
    2821             : /* Return -1 in case of ambiguity */
    2822           0 : static int SHPRewindIsInnerRing(const SHPObject *psObject, int iOpRing,
    2823             :                                 double dfTestX, double dfTestY,
    2824             :                                 double dfRelativeTolerance, int bSameZ,
    2825             :                                 double dfTestZ)
    2826             : {
    2827             :     /* -------------------------------------------------------------------- */
    2828             :     /*      Determine if this ring is an inner ring or an outer ring        */
    2829             :     /*      relative to all the other rings.  For now we assume the         */
    2830             :     /*      first ring is outer and all others are inner, but eventually    */
    2831             :     /*      we need to fix this to handle multiple island polygons and      */
    2832             :     /*      unordered sets of rings.                                        */
    2833             :     /*                                                                      */
    2834             :     /* -------------------------------------------------------------------- */
    2835             : 
    2836           0 :     bool bInner = false;
    2837           0 :     for (int iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++)
    2838             :     {
    2839           0 :         if (iCheckRing == iOpRing)
    2840           0 :             continue;
    2841             : 
    2842           0 :         const int nVertStartCheck = psObject->panPartStart[iCheckRing];
    2843           0 :         const int nVertCountCheck = SHPGetPartVertexCount(psObject, iCheckRing);
    2844             : 
    2845             :         /* Ignore rings that don't have the same (constant) Z value as the
    2846             :          * point. */
    2847             :         /* As noted in SHPRewindObject(), this is a simplification */
    2848             :         /* of what we should ideally do. */
    2849           0 :         if (!bSameZ)
    2850             :         {
    2851           0 :             int bZTestOK = TRUE;
    2852           0 :             for (int iVert = nVertStartCheck + 1;
    2853           0 :                  iVert < nVertStartCheck + nVertCountCheck; ++iVert)
    2854             :             {
    2855           0 :                 if (psObject->padfZ[iVert] != dfTestZ)
    2856             :                 {
    2857           0 :                     bZTestOK = FALSE;
    2858           0 :                     break;
    2859             :                 }
    2860             :             }
    2861           0 :             if (!bZTestOK)
    2862           0 :                 continue;
    2863             :         }
    2864             : 
    2865           0 :         for (int iEdge = 0; iEdge < nVertCountCheck; iEdge++)
    2866             :         {
    2867             :             int iNext;
    2868           0 :             if (iEdge < nVertCountCheck - 1)
    2869           0 :                 iNext = iEdge + 1;
    2870             :             else
    2871           0 :                 iNext = 0;
    2872             : 
    2873           0 :             const double y0 = psObject->padfY[iEdge + nVertStartCheck];
    2874           0 :             const double y1 = psObject->padfY[iNext + nVertStartCheck];
    2875             :             /* Rule #1:
    2876             :              * Test whether the edge 'straddles' the horizontal ray from
    2877             :              * the test point (dfTestY,dfTestY)
    2878             :              * The rule #1 also excludes edges colinear with the ray.
    2879             :              */
    2880           0 :             if ((y0 < dfTestY && dfTestY <= y1) ||
    2881           0 :                 (y1 < dfTestY && dfTestY <= y0))
    2882             :             {
    2883             :                 /* Rule #2:
    2884             :                  * Test if edge-ray intersection is on the right from the
    2885             :                  * test point (dfTestY,dfTestY)
    2886             :                  */
    2887           0 :                 const double x0 = psObject->padfX[iEdge + nVertStartCheck];
    2888           0 :                 const double x1 = psObject->padfX[iNext + nVertStartCheck];
    2889           0 :                 const double intersect_minus_testX =
    2890           0 :                     (x0 - dfTestX) + (dfTestY - y0) / (y1 - y0) * (x1 - x0);
    2891             : 
    2892           0 :                 if (fabs(intersect_minus_testX) <=
    2893           0 :                     dfRelativeTolerance * fabs(dfTestX))
    2894             :                 {
    2895             :                     /* Potential shared edge, or slightly overlapping polygons
    2896             :                      */
    2897           0 :                     return -1;
    2898             :                 }
    2899           0 :                 else if (intersect_minus_testX < 0)
    2900             :                 {
    2901           0 :                     bInner = !bInner;
    2902             :                 }
    2903             :             }
    2904             :         }
    2905             :     } /* for iCheckRing */
    2906           0 :     return bInner;
    2907             : }
    2908             : 
    2909             : /************************************************************************/
    2910             : /*                          SHPRewindObject()                           */
    2911             : /*                                                                      */
    2912             : /*      Reset the winding of polygon objects to adhere to the           */
    2913             : /*      specification.                                                  */
    2914             : /************************************************************************/
    2915             : 
    2916           5 : int SHPAPI_CALL SHPRewindObject(const SHPHandle hSHP, SHPObject *psObject)
    2917             : {
    2918             :     (void)hSHP;
    2919             :     /* -------------------------------------------------------------------- */
    2920             :     /*      Do nothing if this is not a polygon object.                     */
    2921             :     /* -------------------------------------------------------------------- */
    2922           5 :     if (psObject->nSHPType != SHPT_POLYGON &&
    2923           5 :         psObject->nSHPType != SHPT_POLYGONZ &&
    2924           5 :         psObject->nSHPType != SHPT_POLYGONM)
    2925           5 :         return 0;
    2926             : 
    2927           0 :     if (psObject->nVertices == 0 || psObject->nParts == 0)
    2928           0 :         return 0;
    2929             : 
    2930             :     /* -------------------------------------------------------------------- */
    2931             :     /*      Test if all points have the same Z value.                       */
    2932             :     /* -------------------------------------------------------------------- */
    2933           0 :     int bSameZ = TRUE;
    2934           0 :     if (psObject->nSHPType == SHPT_POLYGONZ ||
    2935           0 :         psObject->nSHPType == SHPT_POLYGONM)
    2936             :     {
    2937           0 :         for (int iVert = 1; iVert < psObject->nVertices; ++iVert)
    2938             :         {
    2939           0 :             if (psObject->padfZ[iVert] != psObject->padfZ[0])
    2940             :             {
    2941           0 :                 bSameZ = FALSE;
    2942           0 :                 break;
    2943             :             }
    2944             :         }
    2945             :     }
    2946             : 
    2947             :     /* -------------------------------------------------------------------- */
    2948             :     /*      Process each of the rings.                                      */
    2949             :     /* -------------------------------------------------------------------- */
    2950           0 :     int bAltered = 0;
    2951           0 :     for (int iOpRing = 0; iOpRing < psObject->nParts; iOpRing++)
    2952             :     {
    2953           0 :         const int nVertStart = psObject->panPartStart[iOpRing];
    2954           0 :         const int nVertCount = SHPGetPartVertexCount(psObject, iOpRing);
    2955             : 
    2956           0 :         if (nVertCount < 2)
    2957           0 :             continue;
    2958             : 
    2959             :         /* If a ring has a non-constant Z value, then consider it as an outer */
    2960             :         /* ring. */
    2961             :         /* NOTE: this is a rough approximation. If we were smarter, */
    2962             :         /* we would check that all points of the ring are coplanar, and compare
    2963             :          */
    2964             :         /* that to other rings in the same (oblique) plane. */
    2965           0 :         int bDoIsInnerRingTest = TRUE;
    2966           0 :         if (!bSameZ)
    2967             :         {
    2968           0 :             int bPartSameZ = TRUE;
    2969           0 :             for (int iVert = nVertStart + 1; iVert < nVertStart + nVertCount;
    2970             :                  ++iVert)
    2971             :             {
    2972           0 :                 if (psObject->padfZ[iVert] != psObject->padfZ[nVertStart])
    2973             :                 {
    2974           0 :                     bPartSameZ = FALSE;
    2975           0 :                     break;
    2976             :                 }
    2977             :             }
    2978           0 :             if (!bPartSameZ)
    2979           0 :                 bDoIsInnerRingTest = FALSE;
    2980             :         }
    2981             : 
    2982           0 :         int bInner = FALSE;
    2983           0 :         if (bDoIsInnerRingTest)
    2984             :         {
    2985           0 :             for (int iTolerance = 0; iTolerance < 2; iTolerance++)
    2986             :             {
    2987             :                 /* In a first attempt, use a relaxed criterion to decide if a
    2988             :                  * point */
    2989             :                 /* is inside another ring. If all points of the current ring are
    2990             :                  * in the */
    2991             :                 /* "grey" zone w.r.t that criterion, which seems really
    2992             :                  * unlikely, */
    2993             :                 /* then use the strict criterion for another pass. */
    2994           0 :                 const double dfRelativeTolerance = (iTolerance == 0) ? 1e-9 : 0;
    2995           0 :                 for (int iVert = nVertStart;
    2996           0 :                      iVert + 1 < nVertStart + nVertCount; ++iVert)
    2997             :                 {
    2998             :                     /* Use point in the middle of segment to avoid testing
    2999             :                      * common points of rings.
    3000             :                      */
    3001           0 :                     const double dfTestX =
    3002           0 :                         (psObject->padfX[iVert] + psObject->padfX[iVert + 1]) /
    3003             :                         2;
    3004           0 :                     const double dfTestY =
    3005           0 :                         (psObject->padfY[iVert] + psObject->padfY[iVert + 1]) /
    3006             :                         2;
    3007           0 :                     const double dfTestZ =
    3008           0 :                         !bSameZ ? psObject->padfZ[nVertStart] : 0;
    3009             : 
    3010           0 :                     bInner = SHPRewindIsInnerRing(psObject, iOpRing, dfTestX,
    3011             :                                                   dfTestY, dfRelativeTolerance,
    3012             :                                                   bSameZ, dfTestZ);
    3013           0 :                     if (bInner >= 0)
    3014           0 :                         break;
    3015             :                 }
    3016           0 :                 if (bInner >= 0)
    3017           0 :                     break;
    3018             :             }
    3019           0 :             if (bInner < 0)
    3020             :             {
    3021             :                 /* Completely degenerate case. Do not bother touching order. */
    3022           0 :                 continue;
    3023             :             }
    3024             :         }
    3025             : 
    3026             :         /* -------------------------------------------------------------------- */
    3027             :         /*      Determine the current order of this ring so we will know if     */
    3028             :         /*      it has to be reversed.                                          */
    3029             :         /* -------------------------------------------------------------------- */
    3030             : 
    3031           0 :         double dfSum = psObject->padfX[nVertStart] *
    3032           0 :                        (psObject->padfY[nVertStart + 1] -
    3033           0 :                         psObject->padfY[nVertStart + nVertCount - 1]);
    3034           0 :         int iVert = nVertStart + 1;
    3035           0 :         for (; iVert < nVertStart + nVertCount - 1; iVert++)
    3036             :         {
    3037           0 :             dfSum += psObject->padfX[iVert] *
    3038           0 :                      (psObject->padfY[iVert + 1] - psObject->padfY[iVert - 1]);
    3039             :         }
    3040             : 
    3041           0 :         dfSum += psObject->padfX[iVert] *
    3042           0 :                  (psObject->padfY[nVertStart] - psObject->padfY[iVert - 1]);
    3043             : 
    3044             :         /* -------------------------------------------------------------------- */
    3045             :         /*      Reverse if necessary.                                           */
    3046             :         /* -------------------------------------------------------------------- */
    3047           0 :         if ((dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner))
    3048             :         {
    3049           0 :             bAltered++;
    3050           0 :             for (int i = 0; i < nVertCount / 2; i++)
    3051             :             {
    3052             :                 /* Swap X */
    3053           0 :                 double dfSaved = psObject->padfX[nVertStart + i];
    3054           0 :                 psObject->padfX[nVertStart + i] =
    3055           0 :                     psObject->padfX[nVertStart + nVertCount - i - 1];
    3056           0 :                 psObject->padfX[nVertStart + nVertCount - i - 1] = dfSaved;
    3057             : 
    3058             :                 /* Swap Y */
    3059           0 :                 dfSaved = psObject->padfY[nVertStart + i];
    3060           0 :                 psObject->padfY[nVertStart + i] =
    3061           0 :                     psObject->padfY[nVertStart + nVertCount - i - 1];
    3062           0 :                 psObject->padfY[nVertStart + nVertCount - i - 1] = dfSaved;
    3063             : 
    3064             :                 /* Swap Z */
    3065           0 :                 if (psObject->padfZ)
    3066             :                 {
    3067           0 :                     dfSaved = psObject->padfZ[nVertStart + i];
    3068           0 :                     psObject->padfZ[nVertStart + i] =
    3069           0 :                         psObject->padfZ[nVertStart + nVertCount - i - 1];
    3070           0 :                     psObject->padfZ[nVertStart + nVertCount - i - 1] = dfSaved;
    3071             :                 }
    3072             : 
    3073             :                 /* Swap M */
    3074           0 :                 if (psObject->padfM)
    3075             :                 {
    3076           0 :                     dfSaved = psObject->padfM[nVertStart + i];
    3077           0 :                     psObject->padfM[nVertStart + i] =
    3078           0 :                         psObject->padfM[nVertStart + nVertCount - i - 1];
    3079           0 :                     psObject->padfM[nVertStart + nVertCount - i - 1] = dfSaved;
    3080             :                 }
    3081             :             }
    3082             :         }
    3083             :     }
    3084             : 
    3085           0 :     return bAltered;
    3086             : }

Generated by: LCOV version 1.14