[GRASS-SVN] r69890 - grass/trunk/lib/external/shapelib

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Nov 24 01:57:15 PST 2016


Author: mmetz
Date: 2016-11-24 01:57:15 -0800 (Thu, 24 Nov 2016)
New Revision: 69890

Modified:
   grass/trunk/lib/external/shapelib/README
   grass/trunk/lib/external/shapelib/dbfopen.c
   grass/trunk/lib/external/shapelib/safileio.c
   grass/trunk/lib/external/shapelib/shapefil.h
   grass/trunk/lib/external/shapelib/shpopen.c
Log:
shapelib/DBF driver: re-sync to GDAL/OGR (#3079)

Modified: grass/trunk/lib/external/shapelib/README
===================================================================
--- grass/trunk/lib/external/shapelib/README	2016-11-24 06:37:41 UTC (rev 69889)
+++ grass/trunk/lib/external/shapelib/README	2016-11-24 09:57:15 UTC (rev 69890)
@@ -3,17 +3,131 @@
 * files shpopen.c,shapefil.h,dbfopen.c:
    from ogr/ogrsf_frmts/shape/
 * file safileio.c
-   from SHAPELIB itself (http://shapelib.maptools.org/)
+   from SHAPELIB itself (http://download.osgeo.org/shapelib/)
 
 Last update
+* taken from GDAL 2.1.2 and SHAPELIB 1.3.0 (Thu Nov 24 10:45:41 CET 2016)
 * taken from GDAL 1.5.1-SVN (Sun Mar 30 11:20:43 CEST 2008)
 * taken from GDAL 1.5.0-CVS (Wed Sep  5 13:48:48 CEST 2007)
 * taken from GDAL 1.3.2-CVS (Sat Jun 17 22:08:04 CEST 2006)
 
 Additional fixes:
-* dbfopen.c (around line 1013)
-   GDAL bug #809 (http://trac.osgeo.org/gdal/ticket/809)
+* dbfopen.c
+   around line 1270: GDAL bug #809 (http://trac.osgeo.org/gdal/ticket/809)
+   define CPLsnprintf
+   define CPL_IGNORE_RET_VAL_INT
 
+* shpopen.c
+  define CPL_UNUSED
+
+* safileio.c
+  SHP_CVSID: ISO C does not allow extra ‘;’ outside of a function
+
 * Use <grass/shapefil.h> etc rather than "shapefil.h"
-   in both shpopen.c and dbfopen.c
+   in shpopen.c, dbfopen.c, and safileio.c
 
+
+full fix for dbf_open.c
+-->
+diff -up shapelib_gdal/dbfopen.c shapelib/dbfopen.c 
+--- shapelib_gdal/dbfopen.c	2016-10-24 13:00:32.000000000 +0200
++++ shapelib/dbfopen.c	2016-11-24 10:25:24.423021915 +0100
+@@ -157,7 +157,7 @@
+  * Treat all blank numeric fields as null too.
+  */
+ 
+-#include "shapefil.h"
++#include <grass/shapefil.h>
+ 
+ #include <math.h>
+ #include <stdlib.h>
+@@ -168,6 +168,12 @@
+ #include "cpl_string.h"
+ #else
+ #define CPLsprintf sprintf
++#if defined(WIN32) || defined(_WIN32)
++#  ifndef snprintf
++#     define snprintf _snprintf
++#  endif
++#endif
++#define CPLsnprintf snprintf
+ #endif
+ 
+ SHP_CVSID("$Id$")
+@@ -177,7 +183,11 @@ SHP_CVSID("$Id: dbfopen.c,v 1.89 2011-07
+ #  define TRUE		1
+ #endif
+ 
++#ifdef USE_CPL
+ CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused) {}
++#else
++#define CPL_IGNORE_RET_VAL_INT(ret_val_int)	return
++#endif
+ 
+ /************************************************************************/
+ /*                             SfRealloc()                              */
+@@ -1273,8 +1283,8 @@ DBFGetFieldInfo( DBFHandle psDBF, int iF
+     else if( psDBF->pachFieldType[iField] == 'N'
+              || psDBF->pachFieldType[iField] == 'F' )
+     {
+-	if( psDBF->panFieldDecimals[iField] > 0
+-            || psDBF->panFieldSize[iField] >= 10 )
++	if( psDBF->panFieldDecimals[iField] > 0 )
++/*            || psDBF->panFieldSize[iField] >= 10 ) */ /* GDAL bug #809 */
+ 	    return( FTDouble );
+ 	else
+ 	    return( FTInteger );
+<--
+
+full fix for shpopen.c
+-->
+diff -up shapelib_gdal/shpopen.c shapelib/shpopen.c 
+--- shapelib_gdal/shpopen.c	2016-10-24 13:00:32.000000000 +0200
++++ shapelib/shpopen.c	2016-11-24 10:25:58.460964573 +0100
+@@ -265,7 +265,7 @@
+  *
+  */
+ 
+-#include "shapefil.h"
++#include <grass/shapefil.h>
+ 
+ #include <math.h>
+ #include <limits.h>
+@@ -276,6 +276,10 @@
+ 
+ SHP_CVSID("$Id$")
+ 
++#ifndef CPL_UNUSED
++#define CPL_UNUSED
++#endif
++
+ typedef unsigned char uchar;
+ 
+ #if UINT_MAX == 65535
+<--
+
+full fix for safileio.c
+-->
+diff -up shapelib_gdal/safileio.c shapelib/safileio.c 
+--- shapelib_gdal/safileio.c	2008-01-16 21:05:14.000000000 +0100
++++ shapelib/safileio.c	2016-11-24 10:25:42.734991066 +0100
+@@ -56,7 +56,7 @@
+  *
+  */
+ 
+-#include "shapefil.h"
++#include <grass/shapefil.h>
+ 
+ #include <math.h>
+ #include <limits.h>
+@@ -65,7 +65,7 @@
+ #include <string.h>
+ #include <stdio.h>
+ 
+-SHP_CVSID("$Id$");
++SHP_CVSID("$Id$")
+ 
+ #ifdef SHPAPI_UTF8_HOOKS
+ #   ifdef SHPAPI_WINDOWS
+<--
+

Modified: grass/trunk/lib/external/shapelib/dbfopen.c
===================================================================
--- grass/trunk/lib/external/shapelib/dbfopen.c	2016-11-24 06:37:41 UTC (rev 69889)
+++ grass/trunk/lib/external/shapelib/dbfopen.c	2016-11-24 09:57:15 UTC (rev 69890)
@@ -7,13 +7,14 @@
  *
  ******************************************************************************
  * Copyright (c) 1999, Frank Warmerdam
+ * Copyright (c) 2012-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * This software is available under the following "MIT Style" license,
  * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
  * option is discussed in more detail in shapelib.html.
  *
  * --
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
@@ -34,6 +35,58 @@
  ******************************************************************************
  *
  * $Log: dbfopen.c,v $
+ * Revision 1.89  2011-07-24 05:59:25  fwarmerdam
+ * minimize use of CPLError in favor of SAHooks.Error()
+ *
+ * Revision 1.88  2011-05-13 17:35:17  fwarmerdam
+ * added DBFReorderFields() and DBFAlterFields() functions (from Even)
+ *
+ * Revision 1.87  2011-05-07 22:41:02  fwarmerdam
+ * ensure pending record is flushed when adding a native field (GDAL #4073)
+ *
+ * Revision 1.86  2011-04-17 15:15:29  fwarmerdam
+ * Removed unused variable.
+ *
+ * Revision 1.85  2010-12-06 16:09:34  fwarmerdam
+ * fix buffer read overrun fetching code page (bug 2276)
+ *
+ * Revision 1.84  2009-10-29 19:59:48  fwarmerdam
+ * avoid crash on truncated header (gdal #3093)
+ *
+ * Revision 1.83  2008/11/12 14:28:15  fwarmerdam
+ * DBFCreateField() now works on files with records
+ *
+ * Revision 1.82  2008/11/11 17:47:09  fwarmerdam
+ * added DBFDeleteField() function
+ *
+ * Revision 1.81  2008/01/03 17:48:13  bram
+ * in DBFCreate, use default code page LDID/87 (= 0x57, ANSI)
+ * instead of LDID/3.  This seems to be the same as what ESRI
+ * would be doing by default.
+ *
+ * Revision 1.80  2007/12/30 14:36:39  fwarmerdam
+ * avoid syntax issue with last comment.
+ *
+ * Revision 1.79  2007/12/30 14:35:48  fwarmerdam
+ * Avoid char* / unsigned char* warnings.
+ *
+ * Revision 1.78  2007/12/18 18:28:07  bram
+ * - create hook for client specific atof (bugzilla ticket 1615)
+ * - check for NULL handle before closing cpCPG file, and close after reading.
+ *
+ * Revision 1.77  2007/12/15 20:25:21  bram
+ * dbfopen.c now reads the Code Page information from the DBF file, and exports
+ * this information as a string through the DBFGetCodePage function.  This is
+ * either the number from the LDID header field ("LDID/<number>") or as the
+ * content of an accompanying .CPG file.  When creating a DBF file, the code can
+ * be set using DBFCreateEx.
+ *
+ * Revision 1.76  2007/12/12 22:21:32  bram
+ * DBFClose: check for NULL psDBF handle before trying to close it.
+ *
+ * Revision 1.75  2007/12/06 13:58:19  fwarmerdam
+ * make sure file offset calculations are done in as SAOffset
+ *
  * Revision 1.74  2007/12/06 07:00:25  fwarmerdam
  * dbfopen now using SAHooks for fileio
  *
@@ -111,6 +164,18 @@
 #include <ctype.h>
 #include <string.h>
 
+#ifdef USE_CPL
+#include "cpl_string.h"
+#else
+#define CPLsprintf sprintf
+#if defined(WIN32) || defined(_WIN32)
+#  ifndef snprintf
+#     define snprintf _snprintf
+#  endif
+#endif
+#define CPLsnprintf snprintf
+#endif
+
 SHP_CVSID("$Id$")
 
 #ifndef FALSE
@@ -118,6 +183,12 @@
 #  define TRUE		1
 #endif
 
+#ifdef USE_CPL
+CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused) {}
+#else
+#define CPL_IGNORE_RET_VAL_INT(ret_val_int)	return
+#endif
+
 /************************************************************************/
 /*                             SfRealloc()                              */
 /*                                                                      */
@@ -162,26 +233,28 @@
 
     abyHeader[0] = 0x03;		/* memo field? - just copying 	*/
 
-    /* write out a dummy date */
-    abyHeader[1] = 95;			/* YY */
-    abyHeader[2] = 7;			/* MM */
-    abyHeader[3] = 26;			/* DD */
+    /* write out update date */
+    abyHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
+    abyHeader[2] = (unsigned char) psDBF->nUpdateMonth;
+    abyHeader[3] = (unsigned char) psDBF->nUpdateDay;
 
     /* record count preset at zero */
 
     abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
     abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
-    
+
     abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
     abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
 
+    abyHeader[29] = (unsigned char) (psDBF->iLanguageDriver);
+
 /* -------------------------------------------------------------------- */
 /*      Write the initial 32 byte file header, and all the field        */
 /*      descriptions.                                     		*/
 /* -------------------------------------------------------------------- */
     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
-    psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, 
+    psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
                           psDBF->fp );
 
 /* -------------------------------------------------------------------- */
@@ -211,23 +284,19 @@
     {
 	psDBF->bCurrentRecordModified = FALSE;
 
-	nRecordOffset = 
-            psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord 
+	nRecordOffset =
+            psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord
             + psDBF->nHeaderLength;
 
-	if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0 
-            || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord, 
-                                     psDBF->nRecordLength, 
+	if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0
+            || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord,
+                                     psDBF->nRecordLength,
                                      1, psDBF->fp ) != 1 )
         {
-#ifdef USE_CPL
-            CPLError( CE_Failure, CPLE_FileIO, 
-                      "Failure writing DBF record %d.", 
-                      psDBF->nCurrentRecord );
-#else           
-            fprintf( stderr, "Failure writing DBF record %d.", 
+            char szMessage[128];
+            snprintf( szMessage, sizeof(szMessage), "Failure writing DBF record %d.",
                      psDBF->nCurrentRecord );
-#endif
+            psDBF->sHooks.Error( szMessage );
             return FALSE;
         }
     }
@@ -249,33 +318,25 @@
 	if( !DBFFlushRecord( psDBF ) )
             return FALSE;
 
-	nRecordOffset = 
+	nRecordOffset =
             psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
 
 	if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
         {
-#ifdef USE_CPL
-            CPLError( CE_Failure, CPLE_FileIO,
-                      "fseek(%ld) failed on DBF file.\n",
-                      (long) nRecordOffset );
-#else
-            fprintf( stderr, "fseek(%ld) failed on DBF file.\n",
+            char szMessage[128];
+            snprintf( szMessage, sizeof(szMessage), "fseek(%ld) failed on DBF file.\n",
                      (long) nRecordOffset );
-#endif
+            psDBF->sHooks.Error( szMessage );
             return FALSE;
         }
 
-	if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord, 
+	if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
                                  psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
         {
-#ifdef USE_CPL
-            CPLError( CE_Failure, CPLE_FileIO, 
-                      "fread(%d) failed on DBF file.\n",
-                      psDBF->nRecordLength );
-#else
-            fprintf( stderr, "fread(%d) failed on DBF file.\n",
+            char szMessage[128];
+            snprintf( szMessage, sizeof(szMessage), "fread(%d) failed on DBF file.\n",
                      psDBF->nRecordLength );
-#endif
+            psDBF->sHooks.Error( szMessage );
             return FALSE;
         }
 
@@ -298,16 +359,20 @@
     if( psDBF->bNoHeader )
         DBFWriteHeader( psDBF );
 
-    DBFFlushRecord( psDBF );
+    if( !DBFFlushRecord( psDBF ) )
+        return;
 
     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
-    
+
+    abyFileHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
+    abyFileHeader[2] = (unsigned char) psDBF->nUpdateMonth;
+    abyFileHeader[3] = (unsigned char) psDBF->nUpdateDay;
     abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
     abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
     abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
     abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
-    
+
     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
 
@@ -315,11 +380,23 @@
 }
 
 /************************************************************************/
+/*                       DBFSetLastModifiedDate()                       */
+/************************************************************************/
+
+void SHPAPI_CALL
+DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD )
+{
+    psDBF->nUpdateYearSince1900 = nYYSince1900;
+    psDBF->nUpdateMonth = nMM;
+    psDBF->nUpdateDay = nDD;
+}
+
+/************************************************************************/
 /*                              DBFOpen()                               */
 /*                                                                      */
 /*      Open a .dbf file.                                               */
 /************************************************************************/
-   
+
 DBFHandle SHPAPI_CALL
 DBFOpen( const char * pszFilename, const char * pszAccess )
 
@@ -336,27 +413,30 @@
 /*                                                                      */
 /*      Open a .dbf file.                                               */
 /************************************************************************/
-   
+
 DBFHandle SHPAPI_CALL
 DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
 
 {
     DBFHandle		psDBF;
+    SAFile		pfCPG;
     unsigned char	*pabyBuf;
     int			nFields, nHeadLen, iField, i;
     char		*pszBasename, *pszFullname;
+    int                 nBufSize = 500;
+    size_t              nFullnameLen;
 
 /* -------------------------------------------------------------------- */
 /*      We only allow the access strings "rb" and "r+".                  */
 /* -------------------------------------------------------------------- */
-    if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 
+    if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
         && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
         && strcmp(pszAccess,"r+b") != 0 )
         return( NULL );
 
     if( strcmp(pszAccess,"r") == 0 )
         pszAccess = "rb";
- 
+
     if( strcmp(pszAccess,"r+") == 0 )
         pszAccess = "rb+";
 
@@ -366,7 +446,7 @@
 /* -------------------------------------------------------------------- */
     pszBasename = (char *) malloc(strlen(pszFilename)+5);
     strcpy( pszBasename, pszFilename );
-    for( i = strlen(pszBasename)-1; 
+    for( i = (int)strlen(pszBasename)-1;
 	 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
 	       && pszBasename[i] != '\\';
 	 i-- ) {}
@@ -374,25 +454,35 @@
     if( pszBasename[i] == '.' )
         pszBasename[i] = '\0';
 
-    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
-    sprintf( pszFullname, "%s.dbf", pszBasename );
-        
+    nFullnameLen = strlen(pszBasename) + 5;
+    pszFullname = (char *) malloc(nFullnameLen);
+    snprintf( pszFullname, nFullnameLen, "%s.dbf", pszBasename );
+
     psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
     psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
     memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
 
     if( psDBF->fp == NULL )
     {
-        sprintf( pszFullname, "%s.DBF", pszBasename );
+        snprintf( pszFullname, nFullnameLen, "%s.DBF", pszBasename );
         psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
     }
-    
+
+    snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
+    pfCPG = psHooks->FOpen( pszFullname, "r" );
+    if( pfCPG == NULL )
+    {
+        snprintf( pszFullname, nFullnameLen, "%s.CPG", pszBasename );
+        pfCPG = psHooks->FOpen( pszFullname, "r" );
+    }
+
     free( pszBasename );
     free( pszFullname );
-    
+
     if( psDBF->fp == NULL )
     {
         free( psDBF );
+        if( pfCPG ) psHooks->FClose( pfCPG );
         return( NULL );
     }
 
@@ -403,29 +493,68 @@
 /* -------------------------------------------------------------------- */
 /*  Read Table Header info                                              */
 /* -------------------------------------------------------------------- */
-    pabyBuf = (unsigned char *) malloc(500);
+    pabyBuf = (unsigned char *) malloc(nBufSize);
     if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
     {
         psDBF->sHooks.FClose( psDBF->fp );
+        if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
         free( pabyBuf );
         free( psDBF );
         return NULL;
     }
 
-    psDBF->nRecords = 
-     pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
+    DBFSetLastModifiedDate(psDBF, pabyBuf[1], pabyBuf[2], pabyBuf[3]);
 
+    psDBF->nRecords =
+     pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + (pabyBuf[7] & 0x7f) *256*256*256;
+
     psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
     psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
-    
+    psDBF->iLanguageDriver = pabyBuf[29];
+
+    if (psDBF->nRecordLength == 0 || nHeadLen < 32)
+    {
+        psDBF->sHooks.FClose( psDBF->fp );
+        if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
+        free( pabyBuf );
+        free( psDBF );
+        return NULL;
+    }
+
     psDBF->nFields = nFields = (nHeadLen - 32) / 32;
 
     psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
 
 /* -------------------------------------------------------------------- */
+/*  Figure out the code page from the LDID and CPG                      */
+/* -------------------------------------------------------------------- */
+
+    psDBF->pszCodePage = NULL;
+    if( pfCPG )
+    {
+        size_t n;
+        memset( pabyBuf, 0, nBufSize);
+        psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
+        n = strcspn( (char *) pabyBuf, "\n\r" );
+        if( n > 0 )
+        {
+            pabyBuf[n] = '\0';
+            psDBF->pszCodePage = (char *) malloc(n + 1);
+            memcpy( psDBF->pszCodePage, pabyBuf, n + 1 );
+        }
+		psDBF->sHooks.FClose( pfCPG );
+    }
+    if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 )
+    {
+        snprintf( (char *) pabyBuf, nBufSize, "LDID/%d", psDBF->iLanguageDriver );
+        psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1);
+        strcpy( psDBF->pszCodePage, (char *) pabyBuf );
+    }
+
+/* -------------------------------------------------------------------- */
 /*  Read in Field Definitions                                           */
 /* -------------------------------------------------------------------- */
-    
+
     pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
     psDBF->pszHeader = (char *) pabyBuf;
 
@@ -474,7 +603,7 @@
 	if( iField == 0 )
 	    psDBF->panFieldOffset[iField] = 1;
 	else
-	    psDBF->panFieldOffset[iField] = 
+	    psDBF->panFieldOffset[iField] =
 	      psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
     }
 
@@ -488,13 +617,16 @@
 void SHPAPI_CALL
 DBFClose(DBFHandle psDBF)
 {
+    if( psDBF == NULL )
+        return;
+
 /* -------------------------------------------------------------------- */
 /*      Write out header if not already written.                        */
 /* -------------------------------------------------------------------- */
     if( psDBF->bNoHeader )
         DBFWriteHeader( psDBF );
 
-    DBFFlushRecord( psDBF );
+    CPL_IGNORE_RET_VAL_INT(DBFFlushRecord( psDBF ));
 
 /* -------------------------------------------------------------------- */
 /*      Update last access date, and number of records if we have	*/
@@ -521,6 +653,7 @@
 
     free( psDBF->pszHeader );
     free( psDBF->pszCurrentRecord );
+    free( psDBF->pszCodePage );
 
     free( psDBF );
 }
@@ -528,18 +661,31 @@
 /************************************************************************/
 /*                             DBFCreate()                              */
 /*                                                                      */
-/*      Create a new .dbf file.                                         */
+/* Create a new .dbf file with default code page LDID/87 (0x57)         */
 /************************************************************************/
 
 DBFHandle SHPAPI_CALL
 DBFCreate( const char * pszFilename )
 
 {
+    return DBFCreateEx( pszFilename, "LDID/87" ); // 0x57
+}
+
+/************************************************************************/
+/*                            DBFCreateEx()                             */
+/*                                                                      */
+/*      Create a new .dbf file.                                         */
+/************************************************************************/
+
+DBFHandle SHPAPI_CALL
+DBFCreateEx( const char * pszFilename, const char* pszCodePage )
+
+{
     SAHooks sHooks;
 
     SASetupDefaultHooks( &sHooks );
 
-    return DBFCreateLL( pszFilename, &sHooks );
+    return DBFCreateLL( pszFilename, pszCodePage , &sHooks );
 }
 
 /************************************************************************/
@@ -549,14 +695,15 @@
 /************************************************************************/
 
 DBFHandle SHPAPI_CALL
-DBFCreateLL( const char * pszFilename, SAHooks *psHooks )
+DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks )
 
 {
     DBFHandle	psDBF;
     SAFile	fp;
     char	*pszFullname, *pszBasename;
-    int		i;
+    int		i, ldid = -1;
     char chZero = '\0';
+    size_t      nFullnameLen;
 
 /* -------------------------------------------------------------------- */
 /*	Compute the base (layer) name.  If there is any extension	*/
@@ -564,7 +711,7 @@
 /* -------------------------------------------------------------------- */
     pszBasename = (char *) malloc(strlen(pszFilename)+5);
     strcpy( pszBasename, pszFilename );
-    for( i = strlen(pszBasename)-1; 
+    for( i = (int)strlen(pszBasename)-1;
 	 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
 	       && pszBasename[i] != '\\';
 	 i-- ) {}
@@ -572,24 +719,54 @@
     if( pszBasename[i] == '.' )
         pszBasename[i] = '\0';
 
-    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
-    sprintf( pszFullname, "%s.dbf", pszBasename );
-    free( pszBasename );
+    nFullnameLen = strlen(pszBasename) + 5;
+    pszFullname = (char *) malloc(nFullnameLen);
+    snprintf( pszFullname, nFullnameLen, "%s.dbf", pszBasename );
 
 /* -------------------------------------------------------------------- */
 /*      Create the file.                                                */
 /* -------------------------------------------------------------------- */
     fp = psHooks->FOpen( pszFullname, "wb" );
     if( fp == NULL )
+    {
+        free( pszBasename );
+        free( pszFullname );
         return( NULL );
-    
+    }
+
     psHooks->FWrite( &chZero, 1, 1, fp );
     psHooks->FClose( fp );
 
     fp = psHooks->FOpen( pszFullname, "rb+" );
     if( fp == NULL )
+    {
+        free( pszBasename );
+        free( pszFullname );
         return( NULL );
+    }
 
+    snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
+    if( pszCodePage != NULL )
+    {
+        if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
+        {
+            ldid = atoi( pszCodePage + 5 );
+            if( ldid > 255 )
+                ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one
+        }
+        if( ldid < 0 )
+        {
+            SAFile fpCPG = psHooks->FOpen( pszFullname, "w" );
+            psHooks->FWrite( (char*) pszCodePage, strlen(pszCodePage), 1, fpCPG );
+            psHooks->FClose( fpCPG );
+        }
+    }
+    if( pszCodePage == NULL || ldid >= 0 )
+    {
+        psHooks->Remove( pszFullname );
+    }
+
+    free( pszBasename );
     free( pszFullname );
 
 /* -------------------------------------------------------------------- */
@@ -603,7 +780,7 @@
     psDBF->nFields = 0;
     psDBF->nRecordLength = 1;
     psDBF->nHeaderLength = 33;
-    
+
     psDBF->panFieldOffset = NULL;
     psDBF->panFieldSize = NULL;
     psDBF->panFieldDecimals = NULL;
@@ -616,18 +793,26 @@
 
     psDBF->bNoHeader = TRUE;
 
+    psDBF->iLanguageDriver = ldid > 0 ? ldid : 0;
+    psDBF->pszCodePage = NULL;
+    if( pszCodePage )
+    {
+        psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
+        strcpy( psDBF->pszCodePage, pszCodePage );
+    }
+    DBFSetLastModifiedDate(psDBF, 95, 7, 26); /* dummy date */
+
     return( psDBF );
 }
 
 /************************************************************************/
 /*                            DBFAddField()                             */
 /*                                                                      */
-/*      Add a field to a newly created .dbf file before any records     */
-/*      are written.                                                    */
+/*      Add a field to a newly created .dbf or to an existing one       */
 /************************************************************************/
 
 int SHPAPI_CALL
-DBFAddField(DBFHandle psDBF, const char * pszFieldName, 
+DBFAddField(DBFHandle psDBF, const char * pszFieldName,
             DBFFieldType eType, int nWidth, int nDecimals )
 
 {
@@ -640,11 +825,31 @@
     else
         chNativeType = 'N';
 
-    return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType, 
+    return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
                                   nWidth, nDecimals );
 }
 
 /************************************************************************/
+/*                        DBFGetNullCharacter()                         */
+/************************************************************************/
+
+static char DBFGetNullCharacter(char chType)
+{
+    switch (chType)
+    {
+      case 'N':
+      case 'F':
+        return '*';
+      case 'D':
+        return '0';
+      case 'L':
+       return '?';
+      default:
+       return ' ';
+    }
+}
+
+/************************************************************************/
 /*                            DBFAddField()                             */
 /*                                                                      */
 /*      Add a field to a newly created .dbf file before any records     */
@@ -652,44 +857,49 @@
 /************************************************************************/
 
 int SHPAPI_CALL
-DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, 
+DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
                       char chType, int nWidth, int nDecimals )
 
 {
     char	*pszFInfo;
     int		i;
+    int         nOldRecordLength, nOldHeaderLength;
+    char        *pszRecord;
+    char        chFieldFill;
+    SAOffset    nRecordOffset;
 
+    /* make sure that everything is written in .dbf */
+    if( !DBFFlushRecord( psDBF ) )
+        return -1;
+
 /* -------------------------------------------------------------------- */
 /*      Do some checking to ensure we can add records to this file.     */
 /* -------------------------------------------------------------------- */
-    if( psDBF->nRecords > 0 )
-        return( -1 );
-
-    if( !psDBF->bNoHeader )
-        return( -1 );
-
     if( nWidth < 1 )
         return -1;
 
     if( nWidth > 255 )
         nWidth = 255;
 
+    nOldRecordLength = psDBF->nRecordLength;
+    nOldHeaderLength = psDBF->nHeaderLength;
+
 /* -------------------------------------------------------------------- */
 /*      SfRealloc all the arrays larger to hold the additional field      */
 /*      information.                                                    */
 /* -------------------------------------------------------------------- */
     psDBF->nFields++;
 
-    psDBF->panFieldOffset = (int *) 
+    psDBF->panFieldOffset = (int *)
         SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
 
-    psDBF->panFieldSize = (int *) 
+    psDBF->panFieldSize = (int *)
         SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
 
-    psDBF->panFieldDecimals = (int *) 
+    psDBF->panFieldDecimals = (int *)
         SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
 
-    psDBF->pachFieldType = (char *) 
+    psDBF->pachFieldType = (char *)
         SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
 
 /* -------------------------------------------------------------------- */
@@ -731,13 +941,55 @@
         pszFInfo[16] = (unsigned char) nWidth;
         pszFInfo[17] = (unsigned char) nDecimals;
     }
-    
+
 /* -------------------------------------------------------------------- */
 /*      Make the current record buffer appropriately larger.            */
 /* -------------------------------------------------------------------- */
     psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
                                                  psDBF->nRecordLength);
 
+    /* we're done if dealing with new .dbf */
+    if( psDBF->bNoHeader )
+        return( psDBF->nFields - 1 );
+
+/* -------------------------------------------------------------------- */
+/*      For existing .dbf file, shift records                           */
+/* -------------------------------------------------------------------- */
+
+    /* alloc record */
+    pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
+
+    chFieldFill = DBFGetNullCharacter(chType);
+
+    for (i = psDBF->nRecords-1; i >= 0; --i)
+    {
+        nRecordOffset = nOldRecordLength * (SAOffset) i + nOldHeaderLength;
+
+        /* load record */
+        psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+        psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
+
+        /* set new field's value to NULL */
+        memset(pszRecord + nOldRecordLength, chFieldFill, nWidth);
+
+        nRecordOffset = psDBF->nRecordLength * (SAOffset) i + psDBF->nHeaderLength;
+
+        /* move record to the new place*/
+        psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+        psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
+    }
+
+    /* free record */
+    free(pszRecord);
+
+    /* force update of header with new header, record length and new field */
+    psDBF->bNoHeader = TRUE;
+    DBFUpdateHeader( psDBF );
+
+    psDBF->nCurrentRecord = -1;
+    psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
+
     return( psDBF->nFields-1 );
 }
 
@@ -787,7 +1039,7 @@
 /* -------------------------------------------------------------------- */
 /*	Extract the requested field.					*/
 /* -------------------------------------------------------------------- */
-    strncpy( psDBF->pszWorkField,
+    memcpy( psDBF->pszWorkField,
 	     ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
 	     psDBF->panFieldSize[iField] );
     psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
@@ -797,13 +1049,19 @@
 /* -------------------------------------------------------------------- */
 /*      Decode the field.                                               */
 /* -------------------------------------------------------------------- */
-    if( chReqType == 'N' )
+    if( chReqType == 'I' )
     {
-        psDBF->dfDoubleField = atof(psDBF->pszWorkField);
+        psDBF->fieldValue.nIntField = atoi(psDBF->pszWorkField);
 
-	pReturnField = &(psDBF->dfDoubleField);
+        pReturnField = &(psDBF->fieldValue.nIntField);
     }
+    else if( chReqType == 'N' )
+    {
+        psDBF->fieldValue.dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
 
+        pReturnField = &(psDBF->fieldValue.dfDoubleField);
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Should we trim white space off the string attribute value?      */
 /* -------------------------------------------------------------------- */
@@ -824,7 +1082,7 @@
             *pchDst = '\0';
     }
 #endif
-    
+
     return( pReturnField );
 }
 
@@ -838,14 +1096,14 @@
 DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
 
 {
-    double	*pdValue;
+    int	*pnValue;
 
-    pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
+    pnValue = (int *) DBFReadAttribute( psDBF, iRecord, iField, 'I' );
 
-    if( pdValue == NULL )
+    if( pnValue == NULL )
         return 0;
     else
-        return( (int) *pdValue );
+        return( *pnValue );
 }
 
 /************************************************************************/
@@ -894,34 +1152,28 @@
     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
 }
 
+
 /************************************************************************/
-/*                         DBFIsAttributeNULL()                         */
+/*                         DBFIsValueNULL()                             */
 /*                                                                      */
-/*      Return TRUE if value for field is NULL.                         */
-/*                                                                      */
-/*      Contributed by Jim Matthews.                                    */
+/*      Return TRUE if the passed string is NULL.                       */
 /************************************************************************/
 
-int SHPAPI_CALL
-DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
-
+static int DBFIsValueNULL( char chType, const char* pszValue )
 {
-    const char	*pszValue;
     int i;
 
-    pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
-
     if( pszValue == NULL )
         return TRUE;
 
-    switch(psDBF->pachFieldType[iField])
+    switch(chType)
     {
       case 'N':
       case 'F':
         /*
-        ** We accept all asterisks or all blanks as NULL 
-        ** though according to the spec I think it should be all 
-        ** asterisks. 
+        ** We accept all asterisks or all blanks as NULL
+        ** though according to the spec I think it should be all
+        ** asterisks.
         */
         if( pszValue[0] == '*' )
             return TRUE;
@@ -938,7 +1190,7 @@
         return strncmp(pszValue,"00000000",8) == 0;
 
       case 'L':
-        /* NULL boolean fields have value "?" */ 
+        /* NULL boolean fields have value "?" */
         return pszValue[0] == '?';
 
       default:
@@ -948,6 +1200,28 @@
 }
 
 /************************************************************************/
+/*                         DBFIsAttributeNULL()                         */
+/*                                                                      */
+/*      Return TRUE if value for field is NULL.                         */
+/*                                                                      */
+/*      Contributed by Jim Matthews.                                    */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
+
+{
+    const char	*pszValue;
+
+    pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
+
+    if( pszValue == NULL )
+        return TRUE;
+
+    return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue );
+}
+
+/************************************************************************/
 /*                          DBFGetFieldCount()                          */
 /*                                                                      */
 /*      Return the number of fields in this table.                      */
@@ -1006,11 +1280,11 @@
     if ( psDBF->pachFieldType[iField] == 'L' )
 	return( FTLogical);
 
-    else if( psDBF->pachFieldType[iField] == 'N' 
+    else if( psDBF->pachFieldType[iField] == 'N'
              || psDBF->pachFieldType[iField] == 'F' )
     {
 	if( psDBF->panFieldDecimals[iField] > 0 )
-/*            || psDBF->panFieldSize[iField] > 10 ) */ /* GDAL bug #809 */
+/*            || psDBF->panFieldSize[iField] >= 10 ) */ /* GDAL bug #809 */
 	    return( FTDouble );
 	else
 	    return( FTInteger );
@@ -1078,33 +1352,9 @@
 /* -------------------------------------------------------------------- */
     if( pValue == NULL )
     {
-        switch(psDBF->pachFieldType[iField])
-        {
-          case 'N':
-          case 'F':
-	    /* NULL numeric fields have value "****************" */
-            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*', 
-                    psDBF->panFieldSize[iField] );
-            break;
-
-          case 'D':
-	    /* NULL date fields have value "00000000" */
-            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0', 
-                    psDBF->panFieldSize[iField] );
-            break;
-
-          case 'L':
-	    /* NULL boolean fields have value "?" */ 
-            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?', 
-                    psDBF->panFieldSize[iField] );
-            break;
-
-          default:
-            /* empty string fields are considered NULL */
-            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), ' ', 
-                    psDBF->panFieldSize[iField] );
-            break;
-        }
+        memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]),
+                DBFGetNullCharacter(psDBF->pachFieldType[iField]),
+                psDBF->panFieldSize[iField] );
         return TRUE;
     }
 
@@ -1116,46 +1366,27 @@
       case 'D':
       case 'N':
       case 'F':
-	if( psDBF->panFieldDecimals[iField] == 0 )
-	{
-            int		nWidth = psDBF->panFieldSize[iField];
+      {
+        int		nWidth = psDBF->panFieldSize[iField];
 
-            if( (int) sizeof(szSField)-2 < nWidth )
-                nWidth = sizeof(szSField)-2;
+        if( (int) sizeof(szSField)-2 < nWidth )
+            nWidth = sizeof(szSField)-2;
 
-	    sprintf( szFormat, "%%%dd", nWidth );
-	    sprintf(szSField, szFormat, (int) *((double *) pValue) );
-	    if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
-            {
-	        szSField[psDBF->panFieldSize[iField]] = '\0';
-                nRetResult = FALSE;
-            }
+        snprintf( szFormat, sizeof(szFormat), "%%%d.%df",
+                    nWidth, psDBF->panFieldDecimals[iField] );
+        CPLsnprintf(szSField, sizeof(szSField), szFormat, *((double *) pValue) );
+        if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
+        {
+            szSField[psDBF->panFieldSize[iField]] = '\0';
+            nRetResult = FALSE;
+        }
+        strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
+            szSField, strlen(szSField) );
+        break;
+      }
 
-	    strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
-		    szSField, strlen(szSField) );
-	}
-	else
-	{
-            int		nWidth = psDBF->panFieldSize[iField];
-
-            if( (int) sizeof(szSField)-2 < nWidth )
-                nWidth = sizeof(szSField)-2;
-
-	    sprintf( szFormat, "%%%d.%df", 
-                     nWidth, psDBF->panFieldDecimals[iField] );
-	    sprintf(szSField, szFormat, *((double *) pValue) );
-	    if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
-            {
-	        szSField[psDBF->panFieldSize[iField]] = '\0';
-                nRetResult = FALSE;
-            }
-	    strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
-		    szSField, strlen(szSField) );
-	}
-	break;
-
       case 'L':
-        if (psDBF->panFieldSize[iField] >= 1  && 
+        if (psDBF->panFieldSize[iField] >= 1  &&
             (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
             *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
         break;
@@ -1170,7 +1401,7 @@
         {
             memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
                     psDBF->panFieldSize[iField] );
-	    j = strlen((char *) pValue);
+	    j = (int)strlen((char *) pValue);
         }
 
 	strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
@@ -1239,7 +1470,7 @@
     {
         memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
                 psDBF->panFieldSize[iField] );
-        j = strlen((char *) pValue);
+        j = (int)strlen((char *) pValue);
     }
 
     strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
@@ -1403,21 +1634,24 @@
 /************************************************************************/
 
 DBFHandle SHPAPI_CALL
-DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) 
+DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
 {
     DBFHandle	newDBF;
 
-   newDBF = DBFCreate ( pszFilename );
-   if ( newDBF == NULL ) return ( NULL ); 
-   
+   newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
+   if ( newDBF == NULL ) return ( NULL );
+
    newDBF->nFields = psDBF->nFields;
    newDBF->nRecordLength = psDBF->nRecordLength;
    newDBF->nHeaderLength = psDBF->nHeaderLength;
-    
-   newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength );
-   memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength );
-   
-   newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); 
+
+   if( psDBF->pszHeader )
+   {
+        newDBF->pszHeader = (char *) malloc ( XBASE_FLDHDR_SZ * psDBF->nFields );
+        memcpy ( newDBF->pszHeader, psDBF->pszHeader, XBASE_FLDHDR_SZ * psDBF->nFields );
+   }
+
+   newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
    memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
    newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
    memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
@@ -1428,10 +1662,10 @@
 
    newDBF->bNoHeader = TRUE;
    newDBF->bUpdated = TRUE;
-   
+
    DBFWriteHeader ( newDBF );
    DBFClose ( newDBF );
-   
+
    newDBF = DBFOpen ( pszFilename, "rb+" );
 
    return ( newDBF );
@@ -1465,9 +1699,9 @@
 static void str_to_upper (char *string)
 {
     int len;
-    short i = -1;
+    int i = -1;
 
-    len = strlen (string);
+    len = (int)strlen (string);
 
     while (++i < len)
         if (isalpha(string[i]) && islower(string[i]))
@@ -1537,7 +1771,7 @@
 /*                        DBFMarkRecordDeleted()                        */
 /************************************************************************/
 
-int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, 
+int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
                                       int bIsDeleted )
 
 {
@@ -1561,7 +1795,7 @@
 /* -------------------------------------------------------------------- */
     if( bIsDeleted )
         chNewFlag = '*';
-    else 
+    else
         chNewFlag = ' ';
 
     if( psDBF->pszCurrentRecord[0] != chNewFlag )
@@ -1573,3 +1807,459 @@
 
     return TRUE;
 }
+
+/************************************************************************/
+/*                            DBFGetCodePage                            */
+/************************************************************************/
+
+const char SHPAPI_CALL1(*)
+DBFGetCodePage(DBFHandle psDBF )
+{
+    if( psDBF == NULL )
+        return NULL;
+    return psDBF->pszCodePage;
+}
+
+/************************************************************************/
+/*                          DBFDeleteField()                            */
+/*                                                                      */
+/*      Remove a field from a .dbf file                                 */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFDeleteField(DBFHandle psDBF, int iField)
+{
+    int nOldRecordLength, nOldHeaderLength;
+    int nDeletedFieldOffset, nDeletedFieldSize;
+    SAOffset nRecordOffset;
+    char* pszRecord;
+    int i, iRecord;
+
+    if (iField < 0 || iField >= psDBF->nFields)
+        return FALSE;
+
+    /* make sure that everything is written in .dbf */
+    if( !DBFFlushRecord( psDBF ) )
+        return FALSE;
+
+    /* get information about field to be deleted */
+    nOldRecordLength = psDBF->nRecordLength;
+    nOldHeaderLength = psDBF->nHeaderLength;
+    nDeletedFieldOffset = psDBF->panFieldOffset[iField];
+    nDeletedFieldSize = psDBF->panFieldSize[iField];
+
+    /* update fields info */
+    for (i = iField + 1; i < psDBF->nFields; i++)
+    {
+        psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize;
+        psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i];
+        psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i];
+        psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i];
+    }
+
+    /* resize fields arrays */
+    psDBF->nFields--;
+
+    psDBF->panFieldOffset = (int *)
+        SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
+
+    psDBF->panFieldSize = (int *)
+        SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
+
+    psDBF->panFieldDecimals = (int *)
+        SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
+
+    psDBF->pachFieldType = (char *)
+        SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
+
+    /* update header information */
+    psDBF->nHeaderLength -= 32;
+    psDBF->nRecordLength -= nDeletedFieldSize;
+
+    /* overwrite field information in header */
+    memmove(psDBF->pszHeader + iField*32,
+           psDBF->pszHeader + (iField+1)*32,
+           sizeof(char) * (psDBF->nFields - iField)*32);
+
+    psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
+
+    /* update size of current record appropriately */
+    psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
+                                                 psDBF->nRecordLength);
+
+    /* we're done if we're dealing with not yet created .dbf */
+    if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
+        return TRUE;
+
+    /* force update of header with new header and record length */
+    psDBF->bNoHeader = TRUE;
+    DBFUpdateHeader( psDBF );
+
+    /* alloc record */
+    pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
+
+    /* shift records to their new positions */
+    for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
+    {
+        nRecordOffset =
+            nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength;
+
+        /* load record */
+        psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+        psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
+
+        nRecordOffset =
+            psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+        /* move record in two steps */
+        psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+        psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp );
+        psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize,
+                              nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize,
+                              1, psDBF->fp );
+
+    }
+
+    /* TODO: truncate file */
+
+    /* free record */
+    free(pszRecord);
+
+    psDBF->nCurrentRecord = -1;
+    psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                          DBFReorderFields()                          */
+/*                                                                      */
+/*      Reorder the fields of a .dbf file                               */
+/*                                                                      */
+/* panMap must be exactly psDBF->nFields long and be a permutation      */
+/* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/
+/* code of DBFReorderFields.                                            */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFReorderFields( DBFHandle psDBF, int* panMap )
+{
+    SAOffset nRecordOffset;
+    int      i, iRecord;
+    int     *panFieldOffsetNew;
+    int     *panFieldSizeNew;
+    int     *panFieldDecimalsNew;
+    char    *pachFieldTypeNew;
+    char    *pszHeaderNew;
+    char    *pszRecord;
+    char    *pszRecordNew;
+
+    if ( psDBF->nFields == 0 )
+        return TRUE;
+
+    /* make sure that everything is written in .dbf */
+    if( !DBFFlushRecord( psDBF ) )
+        return FALSE;
+
+    /* a simple malloc() would be enough, but calloc() helps clang static analyzer */
+    panFieldOffsetNew = (int *) calloc(sizeof(int), psDBF->nFields);
+    panFieldSizeNew = (int *) malloc(sizeof(int) *  psDBF->nFields);
+    panFieldDecimalsNew = (int *) malloc(sizeof(int) *  psDBF->nFields);
+    pachFieldTypeNew = (char *) malloc(sizeof(char) *  psDBF->nFields);
+    pszHeaderNew = (char*) malloc(sizeof(char) * 32 *  psDBF->nFields);
+
+    /* shuffle fields definitions */
+    for(i=0; i < psDBF->nFields; i++)
+    {
+        panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
+        panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
+        pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
+        memcpy(pszHeaderNew + i * 32,
+               psDBF->pszHeader + panMap[i] * 32, 32);
+    }
+    panFieldOffsetNew[0] = 1;
+    for(i=1; i < psDBF->nFields; i++)
+    {
+        panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
+    }
+
+    free(psDBF->pszHeader);
+    psDBF->pszHeader = pszHeaderNew;
+
+    /* we're done if we're dealing with not yet created .dbf */
+    if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) )
+    {
+        /* force update of header with new header and record length */
+        psDBF->bNoHeader = TRUE;
+        DBFUpdateHeader( psDBF );
+
+        /* alloc record */
+        pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
+        pszRecordNew = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
+
+        /* shuffle fields in records */
+        for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
+        {
+            nRecordOffset =
+                psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+            /* load record */
+            psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+            psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
+
+            pszRecordNew[0] = pszRecord[0];
+
+            for(i=0; i < psDBF->nFields; i++)
+            {
+                memcpy(pszRecordNew + panFieldOffsetNew[i],
+                       pszRecord + psDBF->panFieldOffset[panMap[i]],
+                       psDBF->panFieldSize[panMap[i]]);
+            }
+
+            /* write record */
+            psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+            psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp );
+        }
+
+        /* free record */
+        free(pszRecord);
+        free(pszRecordNew);
+    }
+
+    free(psDBF->panFieldOffset);
+    free(psDBF->panFieldSize);
+    free(psDBF->panFieldDecimals);
+    free(psDBF->pachFieldType);
+
+    psDBF->panFieldOffset = panFieldOffsetNew;
+    psDBF->panFieldSize = panFieldSizeNew;
+    psDBF->panFieldDecimals =panFieldDecimalsNew;
+    psDBF->pachFieldType = pachFieldTypeNew;
+
+    psDBF->nCurrentRecord = -1;
+    psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
+
+    return TRUE;
+}
+
+
+/************************************************************************/
+/*                          DBFAlterFieldDefn()                         */
+/*                                                                      */
+/*      Alter a field definition in a .dbf file                         */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
+                    char chType, int nWidth, int nDecimals )
+{
+    int   i;
+    int   iRecord;
+    int   nOffset;
+    int   nOldWidth;
+    int   nOldRecordLength;
+    SAOffset  nRecordOffset;
+    char* pszFInfo;
+    char  chOldType;
+    int   bIsNULL;
+    char chFieldFill;
+
+    if (iField < 0 || iField >= psDBF->nFields)
+        return FALSE;
+
+    /* make sure that everything is written in .dbf */
+    if( !DBFFlushRecord( psDBF ) )
+        return FALSE;
+
+    chFieldFill = DBFGetNullCharacter(chType);
+
+    chOldType = psDBF->pachFieldType[iField];
+    nOffset = psDBF->panFieldOffset[iField];
+    nOldWidth = psDBF->panFieldSize[iField];
+    nOldRecordLength = psDBF->nRecordLength;
+
+/* -------------------------------------------------------------------- */
+/*      Do some checking to ensure we can add records to this file.     */
+/* -------------------------------------------------------------------- */
+    if( nWidth < 1 )
+        return -1;
+
+    if( nWidth > 255 )
+        nWidth = 255;
+
+/* -------------------------------------------------------------------- */
+/*      Assign the new field information fields.                        */
+/* -------------------------------------------------------------------- */
+    psDBF->panFieldSize[iField] = nWidth;
+    psDBF->panFieldDecimals[iField] = nDecimals;
+    psDBF->pachFieldType[iField] = chType;
+
+/* -------------------------------------------------------------------- */
+/*      Update the header information.                                  */
+/* -------------------------------------------------------------------- */
+    pszFInfo = psDBF->pszHeader + 32 * iField;
+
+    for( i = 0; i < 32; i++ )
+        pszFInfo[i] = '\0';
+
+    if( (int) strlen(pszFieldName) < 10 )
+        strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
+    else
+        strncpy( pszFInfo, pszFieldName, 10);
+
+    pszFInfo[11] = psDBF->pachFieldType[iField];
+
+    if( chType == 'C' )
+    {
+        pszFInfo[16] = (unsigned char) (nWidth % 256);
+        pszFInfo[17] = (unsigned char) (nWidth / 256);
+    }
+    else
+    {
+        pszFInfo[16] = (unsigned char) nWidth;
+        pszFInfo[17] = (unsigned char) nDecimals;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Update offsets                                                  */
+/* -------------------------------------------------------------------- */
+    if (nWidth != nOldWidth)
+    {
+        for (i = iField + 1; i < psDBF->nFields; i++)
+             psDBF->panFieldOffset[i] += nWidth - nOldWidth;
+        psDBF->nRecordLength += nWidth - nOldWidth;
+
+        psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
+                                                     psDBF->nRecordLength);
+    }
+
+    /* we're done if we're dealing with not yet created .dbf */
+    if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
+        return TRUE;
+
+    /* force update of header with new header and record length */
+    psDBF->bNoHeader = TRUE;
+    DBFUpdateHeader( psDBF );
+
+    if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType))
+    {
+        char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
+        char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
+
+        pszOldField[nOldWidth] = 0;
+
+        /* move records to their new positions */
+        for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
+        {
+            nRecordOffset =
+                nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+            /* load record */
+            psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+            psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
+
+            memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
+            bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
+
+            if (nWidth != nOldWidth)
+            {
+                if ((chOldType == 'N' || chOldType == 'F') && pszOldField[0] == ' ')
+                {
+                    /* Strip leading spaces when truncating a numeric field */
+                    memmove( pszRecord + nOffset,
+                            pszRecord + nOffset + nOldWidth - nWidth,
+                            nWidth );
+                }
+                if (nOffset + nOldWidth < nOldRecordLength)
+                {
+                    memmove( pszRecord + nOffset + nWidth,
+                            pszRecord + nOffset + nOldWidth,
+                            nOldRecordLength - (nOffset + nOldWidth));
+                }
+            }
+
+            /* Convert null value to the appropriate value of the new type */
+            if (bIsNULL)
+            {
+                memset( pszRecord + nOffset, chFieldFill, nWidth);
+            }
+
+            nRecordOffset =
+                psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+            /* write record */
+            psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+            psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
+        }
+
+        free(pszRecord);
+        free(pszOldField);
+    }
+    else if (nWidth > nOldWidth)
+    {
+        char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
+        char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
+
+        pszOldField[nOldWidth] = 0;
+
+        /* move records to their new positions */
+        for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
+        {
+            nRecordOffset =
+                nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+            /* load record */
+            psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+            psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
+
+            memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
+            bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
+
+            if (nOffset + nOldWidth < nOldRecordLength)
+            {
+                memmove( pszRecord + nOffset + nWidth,
+                         pszRecord + nOffset + nOldWidth,
+                         nOldRecordLength - (nOffset + nOldWidth));
+            }
+
+            /* Convert null value to the appropriate value of the new type */
+            if (bIsNULL)
+            {
+                memset( pszRecord + nOffset, chFieldFill, nWidth);
+            }
+            else
+            {
+                if ((chOldType == 'N' || chOldType == 'F'))
+                {
+                    /* Add leading spaces when expanding a numeric field */
+                    memmove( pszRecord + nOffset + nWidth - nOldWidth,
+                             pszRecord + nOffset, nOldWidth );
+                    memset( pszRecord + nOffset, ' ', nWidth - nOldWidth );
+                }
+                else
+                {
+                    /* Add trailing spaces */
+                    memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth);
+                }
+            }
+
+            nRecordOffset =
+                psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+            /* write record */
+            psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+            psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
+        }
+
+        free(pszRecord);
+        free(pszOldField);
+    }
+
+    psDBF->nCurrentRecord = -1;
+    psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
+
+    return TRUE;
+}

Modified: grass/trunk/lib/external/shapelib/safileio.c
===================================================================
--- grass/trunk/lib/external/shapelib/safileio.c	2016-11-24 06:37:41 UTC (rev 69889)
+++ grass/trunk/lib/external/shapelib/safileio.c	2016-11-24 09:57:15 UTC (rev 69890)
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: safileio.c,v 1.4 2008/01/16 20:05:14 bram Exp $
+ * $Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $
  *
  * Project:  Shapelib
  * Purpose:  Default implementation of file io based on stdio.
@@ -34,7 +34,7 @@
  ******************************************************************************
  *
  * $Log: safileio.c,v $
- * Revision 1.4  2008/01/16 20:05:14  bram
+ * Revision 1.4  2008-01-16 20:05:14  bram
  * Add file hooks that accept UTF-8 encoded filenames on some platforms.  Use SASetupUtf8Hooks
  *  tosetup the hooks and check SHPAPI_UTF8_HOOKS for its availability.  Currently, this
  *  is only available on the Windows platform that decodes the UTF-8 filenames to wide
@@ -56,7 +56,7 @@
  *
  */
 
-#include "shapefil.h"
+#include <grass/shapefil.h>
 
 #include <math.h>
 #include <limits.h>
@@ -65,7 +65,7 @@
 #include <string.h>
 #include <stdio.h>
 
-SHP_CVSID("$Id: safileio.c,v 1.4 2008/01/16 20:05:14 bram Exp $");
+SHP_CVSID("$Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $");
 
 #ifdef SHPAPI_UTF8_HOOKS
 #   ifdef SHPAPI_WINDOWS
@@ -182,8 +182,10 @@
     psHooks->FTell   = SADFTell;
     psHooks->FFlush  = SADFFlush;
     psHooks->FClose  = SADFClose;
+    psHooks->Remove  = SADRemove;
 
     psHooks->Error   = SADError;
+    psHooks->Atof    = atof;
 }
 
 

Modified: grass/trunk/lib/external/shapelib/shapefil.h
===================================================================
--- grass/trunk/lib/external/shapelib/shapefil.h	2016-11-24 06:37:41 UTC (rev 69889)
+++ grass/trunk/lib/external/shapelib/shapefil.h	2016-11-24 09:57:15 UTC (rev 69890)
@@ -1,5 +1,5 @@
-#ifndef _SHAPEFILE_H_INCLUDED
-#define _SHAPEFILE_H_INCLUDED
+#ifndef SHAPEFILE_H_INCLUDED
+#define SHAPEFILE_H_INCLUDED
 
 /******************************************************************************
  * $Id$
@@ -10,13 +10,14 @@
  *
  ******************************************************************************
  * Copyright (c) 1999, Frank Warmerdam
+ * Copyright (c) 2012-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * This software is available under the following "MIT Style" license,
  * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
  * option is discussed in more detail in shapelib.html.
  *
  * --
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
@@ -37,6 +38,50 @@
  ******************************************************************************
  *
  * $Log: shapefil.h,v $
+ * Revision 1.52  2011-12-11 22:26:46  fwarmerdam
+ * upgrade .qix access code to use SAHooks (gdal #3365)
+ *
+ * Revision 1.51  2011-07-24 05:59:25  fwarmerdam
+ * minimize use of CPLError in favor of SAHooks.Error()
+ *
+ * Revision 1.50  2011-05-13 17:35:17  fwarmerdam
+ * added DBFReorderFields() and DBFAlterFields() functions (from Even)
+ *
+ * Revision 1.49  2011-04-16 14:38:21  fwarmerdam
+ * avoid warnings with gcc on SHP_CVSID
+ *
+ * Revision 1.48  2010-08-27 23:42:52  fwarmerdam
+ * add SHPAPI_CALL attribute in code
+ *
+ * Revision 1.47  2010-01-28 11:34:34  fwarmerdam
+ * handle the shape file length limits more gracefully (#3236)
+ *
+ * Revision 1.46  2008-11-12 14:28:15  fwarmerdam
+ * DBFCreateField() now works on files with records
+ *
+ * Revision 1.45  2008/11/11 17:47:10  fwarmerdam
+ * added DBFDeleteField() function
+ *
+ * Revision 1.44  2008/01/16 20:05:19  bram
+ * Add file hooks that accept UTF-8 encoded filenames on some platforms.  Use SASetupUtf8Hooks
+ *  tosetup the hooks and check SHPAPI_UTF8_HOOKS for its availability.  Currently, this
+ *  is only available on the Windows platform that decodes the UTF-8 filenames to wide
+ *  character strings and feeds them to _wfopen and _wremove.
+ *
+ * Revision 1.43  2008/01/10 16:35:30  fwarmerdam
+ * avoid _ prefix on #defined symbols (bug 1840)
+ *
+ * Revision 1.42  2007/12/18 18:28:14  bram
+ * - create hook for client specific atof (bugzilla ticket 1615)
+ * - check for NULL handle before closing cpCPG file, and close after reading.
+ *
+ * Revision 1.41  2007/12/15 20:25:32  bram
+ * dbfopen.c now reads the Code Page information from the DBF file, and exports
+ * this information as a string through the DBFGetCodePage function.  This is
+ * either the number from the LDID header field ("LDID/<number>") or as the
+ * content of an accompanying .CPG file.  When creating a DBF file, the code can
+ * be set using DBFCreateEx.
+ *
  * Revision 1.40  2007/12/06 07:00:25  fwarmerdam
  * dbfopen now using SAHooks for fileio
  *
@@ -103,8 +148,7 @@
 #endif
 
 #ifdef USE_CPL
-#include "cpl_error.h"
-#include "cpl_vsi.h"
+#include "cpl_conv.h"
 #endif
 
 #ifdef __cplusplus
@@ -127,7 +171,7 @@
 /*      is disabled.                                                    */
 /* -------------------------------------------------------------------- */
 #define DISABLE_MULTIPATCH_MEASURE
-    
+
 /* -------------------------------------------------------------------- */
 /*      SHPAPI_CALL                                                     */
 /*                                                                      */
@@ -151,7 +195,7 @@
 /*        #define SHPAPI_CALL __declspec(dllexport) __stdcall           */
 /*        #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall        */
 /*                                                                      */
-/*      The complexity of the situtation is partly caused by the        */
+/*      The complexity of the situation is partly caused by the        */
 /*      peculiar requirement of Visual C++ that __stdcall appear        */
 /*      after any "*"'s in the return value of a function while the     */
 /*      __declspec(dllexport) must appear before them.                  */
@@ -174,19 +218,32 @@
 #ifndef SHPAPI_CALL1
 #  define SHPAPI_CALL1(x)      x SHPAPI_CALL
 #endif
-    
+
 /* -------------------------------------------------------------------- */
 /*      Macros for controlling CVSID and ensuring they don't appear     */
 /*      as unreferenced variables resulting in lots of warnings.        */
 /* -------------------------------------------------------------------- */
 #ifndef DISABLE_CVSID
-#  define SHP_CVSID(string)     static char cpl_cvsid[] = string; \
-static char *cvsid_aw() { return( cvsid_aw() ? ((char *) NULL) : cpl_cvsid ); }
+#  if defined(__GNUC__) && __GNUC__ >= 4
+#    define SHP_CVSID(string)     static const char cpl_cvsid[] __attribute__((used)) = string;
+#  else
+#    define SHP_CVSID(string)     static const char cpl_cvsid[] = string; \
+static const char *cvsid_aw() { return( cvsid_aw() ? NULL : cpl_cvsid ); }
+#  endif
 #else
 #  define SHP_CVSID(string)
 #endif
-    
+
 /* -------------------------------------------------------------------- */
+/*      On some platforms, additional file IO hooks are defined that    */
+/*      UTF-8 encoded filenames Unicode filenames                       */
+/* -------------------------------------------------------------------- */
+#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+#	define SHPAPI_WINDOWS
+#	define SHPAPI_UTF8_HOOKS
+#endif
+
+/* -------------------------------------------------------------------- */
 /*      IO/Error hook functions.                                        */
 /* -------------------------------------------------------------------- */
 typedef int *SAFile;
@@ -196,23 +253,30 @@
 #endif
 
 typedef struct {
-    SAFile     (*FOpen) ( const char *filename, const char *path);
+    SAFile     (*FOpen) ( const char *filename, const char *access);
     SAOffset   (*FRead) ( void *p, SAOffset size, SAOffset nmemb, SAFile file);
     SAOffset   (*FWrite)( void *p, SAOffset size, SAOffset nmemb, SAFile file);
     SAOffset   (*FSeek) ( SAFile file, SAOffset offset, int whence );
     SAOffset   (*FTell) ( SAFile file );
     int        (*FFlush)( SAFile file );
     int        (*FClose)( SAFile file );
+    int        (*Remove) ( const char *filename );
 
     void       (*Error) ( const char *message );
+    double     (*Atof)  ( const char *str );
 } SAHooks;
 
 void SHPAPI_CALL SASetupDefaultHooks( SAHooks *psHooks );
+#ifdef SHPAPI_UTF8_HOOKS
+void SHPAPI_CALL SASetupUtf8Hooks( SAHooks *psHooks );
+#endif
 
 /************************************************************************/
 /*                             SHP Support.                             */
 /************************************************************************/
-typedef	struct
+typedef struct tagSHPObject SHPObject;
+
+typedef struct
 {
     SAHooks sHooks;
 
@@ -220,13 +284,13 @@
     SAFile 	fpSHX;
 
     int		nShapeType;				/* SHPT_* */
-    
-    int		nFileSize;				/* SHP file */
 
+    unsigned int 	nFileSize;				/* SHP file */
+
     int         nRecords;
     int		nMaxRecords;
-    int		*panRecOffset;
-    int		*panRecSize;
+    unsigned int		*panRecOffset;
+    unsigned int		*panRecSize;
 
     double	adBoundsMin[4];
     double	adBoundsMax[4];
@@ -235,6 +299,11 @@
 
     unsigned char *pabyRec;
     int         nBufSize;
+
+    int            bFastModeReadObject;
+    unsigned char *pabyObjectBuf;
+    int            nObjectBufSize;
+    SHPObject*     psCachedObject;
 } SHPInfo;
 
 typedef SHPInfo * SHPHandle;
@@ -274,7 +343,7 @@
 /*      SHPObject - represents on shape (without attributes) read       */
 /*      from the .shp file.                                             */
 /* -------------------------------------------------------------------- */
-typedef struct
+struct tagSHPObject
 {
     int		nSHPType;
 
@@ -283,7 +352,7 @@
     int		nParts;
     int		*panPartStart;
     int		*panPartType;
-    
+
     int		nVertices;
     double	*padfX;
     double	*padfY;
@@ -301,7 +370,8 @@
     double	dfMMax;
 
     int		bMeasureIsUsed;
-} SHPObject;
+    int     bFastModeReadObject;
+};
 
 /* -------------------------------------------------------------------- */
 /*      SHP API Prototypes                                              */
@@ -312,9 +382,23 @@
 SHPHandle SHPAPI_CALL
       SHPOpen( const char * pszShapeFile, const char * pszAccess );
 SHPHandle SHPAPI_CALL
-      SHPOpenLL( const char *pszShapeFile, const char *pszAccess, 
+      SHPOpenLL( const char *pszShapeFile, const char *pszAccess,
                  SAHooks *psHooks );
 SHPHandle SHPAPI_CALL
+      SHPOpenLLEx( const char *pszShapeFile, const char *pszAccess,
+                  SAHooks *psHooks, int bRestoreSHX );
+
+int       SHPAPI_CALL
+      SHPRestoreSHX( const char *pszShapeFile, const char *pszAccess,
+                  SAHooks *psHooks );
+
+/* If setting bFastMode = TRUE, the content of SHPReadObject() is owned by the SHPHandle. */
+/* So you cannot have 2 valid instances of SHPReadObject() simultaneously. */
+/* The SHPObject padfZ and padfM members may be NULL depending on the geometry */
+/* type. It is illegal to free at hand any of the pointer members of the SHPObject structure */
+void SHPAPI_CALL SHPSetFastModeReadObject( SHPHandle hSHP, int bFastMode );
+
+SHPHandle SHPAPI_CALL
       SHPCreate( const char * pszShapeFile, int nShapeType );
 SHPHandle SHPAPI_CALL
       SHPCreateLL( const char * pszShapeFile, int nShapeType,
@@ -333,15 +417,15 @@
 void SHPAPI_CALL
       SHPComputeExtents( SHPObject * psObject );
 SHPObject SHPAPI_CALL1(*)
-      SHPCreateObject( int nSHPType, int nShapeId, int nParts, 
+      SHPCreateObject( int nSHPType, int nShapeId, int nParts,
                        const int * panPartStart, const int * panPartType,
-                       int nVertices, 
+                       int nVertices,
                        const double * padfX, const double * padfY,
                        const double * padfZ, const double * padfM );
 SHPObject SHPAPI_CALL1(*)
       SHPCreateSimpleObject( int nSHPType, int nVertices,
-                             const double * padfX, 
-                             const double * padfY, 
+                             const double * padfX,
+                             const double * padfY,
                              const double * padfZ );
 
 int SHPAPI_CALL
@@ -379,17 +463,17 @@
 
     int		nSubNodes;
     struct shape_tree_node *apsSubNode[MAX_SUBNODE];
-    
+
 } SHPTreeNode;
 
 typedef struct
 {
     SHPHandle   hSHP;
-    
+
     int		nMaxDepth;
     int		nDimension;
     int         nTotalCount;
-    
+
     SHPTreeNode	*psRoot;
 } SHPTree;
 
@@ -401,12 +485,8 @@
 
 int	SHPAPI_CALL
       SHPWriteTree( SHPTree *hTree, const char * pszFilename );
-SHPTree SHPAPI_CALL
-      SHPReadTree( const char * pszFilename );
 
 int	SHPAPI_CALL
-      SHPTreeAddObject( SHPTree * hTree, SHPObject * psObject );
-int	SHPAPI_CALL
       SHPTreeAddShapeId( SHPTree * hTree, SHPObject * psObject );
 int	SHPAPI_CALL
       SHPTreeRemoveShapeId( SHPTree * hTree, int nShapeId );
@@ -422,11 +502,55 @@
 int     SHPAPI_CALL
       SHPCheckBoundsOverlap( double *, double *, double *, double *, int );
 
-int SHPAPI_CALL1(*) 
-SHPSearchDiskTree( FILE *fp, 
+int SHPAPI_CALL1(*)
+SHPSearchDiskTree( FILE *fp,
                    double *padfBoundsMin, double *padfBoundsMax,
                    int *pnShapeCount );
 
+
+typedef struct SHPDiskTreeInfo* SHPTreeDiskHandle;
+
+SHPTreeDiskHandle SHPAPI_CALL
+    SHPOpenDiskTree( const char* pszQIXFilename,
+                     SAHooks *psHooks );
+
+void SHPAPI_CALL
+    SHPCloseDiskTree( SHPTreeDiskHandle hDiskTree );
+
+int SHPAPI_CALL1(*)
+SHPSearchDiskTreeEx( SHPTreeDiskHandle hDiskTree,
+                   double *padfBoundsMin, double *padfBoundsMax,
+                   int *pnShapeCount );
+
+int SHPAPI_CALL
+    SHPWriteTreeLL(SHPTree *hTree, const char *pszFilename, SAHooks *psHooks );
+
+
+/* -------------------------------------------------------------------- */
+/*      SBN Search API                                                  */
+/* -------------------------------------------------------------------- */
+
+typedef struct SBNSearchInfo* SBNSearchHandle;
+
+SBNSearchHandle SHPAPI_CALL
+    SBNOpenDiskTree( const char* pszSBNFilename,
+                 SAHooks *psHooks );
+
+void SHPAPI_CALL
+    SBNCloseDiskTree( SBNSearchHandle hSBN );
+
+int SHPAPI_CALL1(*)
+SBNSearchDiskTree( SBNSearchHandle hSBN,
+                   double *padfBoundsMin, double *padfBoundsMax,
+                   int *pnShapeCount );
+
+int SHPAPI_CALL1(*)
+SBNSearchDiskTreeInteger( SBNSearchHandle hSBN,
+                          int bMinX, int bMinY, int bMaxX, int bMaxY,
+                          int *pnShapeCount );
+
+void SHPAPI_CALL SBNSearchFreeIds( int* panShapeId );
+
 /************************************************************************/
 /*                             DBF Support.                             */
 /************************************************************************/
@@ -454,11 +578,22 @@
 
     int         nWorkFieldLength;
     char        *pszWorkField;
-    
+
     int		bNoHeader;
     int		bUpdated;
 
-    double      dfDoubleField;
+    union
+    {
+        double      dfDoubleField;
+        int         nIntField;
+    } fieldValue;
+
+    int         iLanguageDriver;
+    char        *pszCodePage;
+
+    int         nUpdateYearSince1900; /* 0-255 */
+    int         nUpdateMonth; /* 1-12 */
+    int         nUpdateDay; /* 1-31 */
 } DBFInfo;
 
 typedef DBFInfo * DBFHandle;
@@ -482,7 +617,9 @@
 DBFHandle SHPAPI_CALL
       DBFCreate( const char * pszDBFFile );
 DBFHandle SHPAPI_CALL
-      DBFCreateLL( const char * pszDBFFile, SAHooks *psHooks );
+      DBFCreateEx( const char * pszDBFFile, const char * pszCodePage );
+DBFHandle SHPAPI_CALL
+      DBFCreateLL( const char * pszDBFFile, const char * pszCodePage, SAHooks *psHooks );
 
 int	SHPAPI_CALL
       DBFGetFieldCount( DBFHandle psDBF );
@@ -496,8 +633,18 @@
       DBFAddNativeFieldType( DBFHandle hDBF, const char * pszFieldName,
                              char chType, int nWidth, int nDecimals );
 
+int	SHPAPI_CALL
+      DBFDeleteField( DBFHandle hDBF, int iField );
+
+int SHPAPI_CALL
+      DBFReorderFields( DBFHandle psDBF, int* panMap );
+
+int SHPAPI_CALL
+      DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
+                         char chType, int nWidth, int nDecimals );
+
 DBFFieldType SHPAPI_CALL
-      DBFGetFieldInfo( DBFHandle psDBF, int iField, 
+      DBFGetFieldInfo( DBFHandle psDBF, int iField,
                        char * pszFieldName, int * pnWidth, int * pnDecimals );
 
 int SHPAPI_CALL
@@ -515,7 +662,7 @@
       DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField );
 
 int SHPAPI_CALL
-      DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField, 
+      DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
                                 int nFieldValue );
 int SHPAPI_CALL
       DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,
@@ -538,12 +685,12 @@
       DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple );
 
 int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape );
-int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, 
+int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
                                       int bIsDeleted );
 
 DBFHandle SHPAPI_CALL
       DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename );
- 
+
 void	SHPAPI_CALL
       DBFClose( DBFHandle hDBF );
 void    SHPAPI_CALL
@@ -551,8 +698,14 @@
 char    SHPAPI_CALL
       DBFGetNativeFieldType( DBFHandle hDBF, int iField );
 
+const char SHPAPI_CALL1(*)
+      DBFGetCodePage(DBFHandle psDBF );
+
+void SHPAPI_CALL
+    DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD );
+
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* ndef _SHAPEFILE_H_INCLUDED */
+#endif /* ndef SHAPEFILE_H_INCLUDED */

Modified: grass/trunk/lib/external/shapelib/shpopen.c
===================================================================
--- grass/trunk/lib/external/shapelib/shpopen.c	2016-11-24 06:37:41 UTC (rev 69889)
+++ grass/trunk/lib/external/shapelib/shpopen.c	2016-11-24 09:57:15 UTC (rev 69890)
@@ -7,13 +7,14 @@
  *
  ******************************************************************************
  * Copyright (c) 1999, 2001, Frank Warmerdam
+ * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * This software is available under the following "MIT Style" license,
  * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
  * option is discussed in more detail in shapelib.html.
  *
  * --
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
@@ -34,7 +35,49 @@
  ******************************************************************************
  *
  * $Log: shpopen.c,v $
- * Revision 1.59  2008/03/14 05:25:31  fwarmerdam
+ * Revision 1.73  2012-01-24 22:33:01  fwarmerdam
+ * fix memory leak on failure to open .shp (gdal #4410)
+ *
+ * Revision 1.72  2011-12-11 22:45:28  fwarmerdam
+ * fix failure return from SHPOpenLL.
+ *
+ * Revision 1.71  2011-09-15 03:33:58  fwarmerdam
+ * fix missing cast (#2344)
+ *
+ * Revision 1.70  2011-07-24 05:59:25  fwarmerdam
+ * minimize use of CPLError in favor of SAHooks.Error()
+ *
+ * Revision 1.69  2011-07-24 03:24:22  fwarmerdam
+ * fix memory leaks in error cases creating shapefiles (#2061)
+ *
+ * Revision 1.68  2010-08-27 23:42:52  fwarmerdam
+ * add SHPAPI_CALL attribute in code
+ *
+ * Revision 1.67  2010-07-01 08:15:48  fwarmerdam
+ * do not error out on an object with zero vertices
+ *
+ * Revision 1.66  2010-07-01 07:58:57  fwarmerdam
+ * minor cleanup of error handling
+ *
+ * Revision 1.65  2010-07-01 07:27:13  fwarmerdam
+ * white space formatting adjustments
+ *
+ * Revision 1.64  2010-01-28 11:34:34  fwarmerdam
+ * handle the shape file length limits more gracefully (#3236)
+ *
+ * Revision 1.63  2010-01-28 04:04:40  fwarmerdam
+ * improve numerical accuracy of SHPRewind() algs (gdal #3363)
+ *
+ * Revision 1.62  2010-01-17 05:34:13  fwarmerdam
+ * Remove asserts on x/y being null (#2148).
+ *
+ * Revision 1.61  2010-01-16 05:07:42  fwarmerdam
+ * allow 0/nulls in shpcreateobject (#2148)
+ *
+ * Revision 1.60  2009-09-17 20:50:02  bram
+ * on Win32, define snprintf as alias to _snprintf
+ *
+ * Revision 1.59  2008-03-14 05:25:31  fwarmerdam
  * Correct crash on buggy geometries (gdal #2218)
  *
  * Revision 1.58  2008/01/08 23:28:26  bram
@@ -117,7 +160,7 @@
  * move pabyRec into SHPInfo for thread safety
  *
  * Revision 1.33  2001/07/03 12:18:15  warmerda
- * Improved cleanup if SHX not found, provied by Riccardo Cohen.
+ * Improved cleanup if SHX not found, provided by Riccardo Cohen.
  *
  * Revision 1.32  2001/06/22 01:58:07  warmerda
  * be more careful about establishing initial bounds in face of NULL shapes
@@ -233,12 +276,16 @@
 
 SHP_CVSID("$Id$")
 
+#ifndef CPL_UNUSED
+#define CPL_UNUSED
+#endif
+
 typedef unsigned char uchar;
 
 #if UINT_MAX == 65535
-typedef long	      int32;
+typedef unsigned long	      int32;
 #else
-typedef int	      int32;
+typedef unsigned int	      int32;
 #endif
 
 #ifndef FALSE
@@ -252,9 +299,20 @@
 #  define MAX(a,b)      ((a>b) ? a : b)
 #endif
 
+#if defined(WIN32) || defined(_WIN32)
+#  ifndef snprintf
+#     define snprintf _snprintf
+#  endif
+#endif
+
+#if defined(CPL_LSB)
+#define bBigEndian FALSE
+#elif defined(CPL_MSB)
+#define bBigEndian TRUE
+#else
 static int 	bBigEndian;
+#endif
 
-
 /************************************************************************/
 /*                              SwapWord()                              */
 /*                                                                      */
@@ -298,7 +356,7 @@
 /*	contents of the index (.shx) file.				*/
 /************************************************************************/
 
-void SHPWriteHeader( SHPHandle psSHP )
+void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
 
 {
     uchar     	abyHeader[100];
@@ -306,7 +364,7 @@
     int32	i32;
     double	dValue;
     int32	*panSHX;
-    
+
     if (psSHP->fpSHX == NULL)
     {
         psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed");
@@ -317,7 +375,7 @@
 /*      Prepare header block for .shp file.                             */
 /* -------------------------------------------------------------------- */
     for( i = 0; i < 100; i++ )
-      abyHeader[i] = 0;
+        abyHeader[i] = 0;
 
     abyHeader[2] = 0x27;				/* magic cookie */
     abyHeader[3] = 0x0a;
@@ -325,11 +383,11 @@
     i32 = psSHP->nFileSize/2;				/* file size */
     ByteCopy( &i32, abyHeader+24, 4 );
     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-    
+
     i32 = 1000;						/* version */
     ByteCopy( &i32, abyHeader+28, 4 );
     if( bBigEndian ) SwapWord( 4, abyHeader+28 );
-    
+
     i32 = psSHP->nShapeType;				/* shape type */
     ByteCopy( &i32, abyHeader+32, 4 );
     if( bBigEndian ) SwapWord( 4, abyHeader+32 );
@@ -369,7 +427,7 @@
 /* -------------------------------------------------------------------- */
 /*      Write .shp file header.                                         */
 /* -------------------------------------------------------------------- */
-    if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0 
+    if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0
         || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
     {
         psSHP->sHooks.Error( "Failure writing .shp header" );
@@ -382,8 +440,8 @@
     i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2;   /* file size */
     ByteCopy( &i32, abyHeader+24, 4 );
     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-    
-    if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0 
+
+    if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0
         || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
     {
         psSHP->sHooks.Error( "Failure writing .shx header" );
@@ -394,16 +452,21 @@
 /*      Write out the .shx contents.                                    */
 /* -------------------------------------------------------------------- */
     panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
+    if( panSHX == NULL )
+    {
+        psSHP->sHooks.Error( "Failure allocatin panSHX" );
+        return;
+    }
 
     for( i = 0; i < psSHP->nRecords; i++ )
     {
-	panSHX[i*2  ] = psSHP->panRecOffset[i]/2;
-	panSHX[i*2+1] = psSHP->panRecSize[i]/2;
-	if( !bBigEndian ) SwapWord( 4, panSHX+i*2 );
-	if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
+        panSHX[i*2  ] = psSHP->panRecOffset[i]/2;
+        panSHX[i*2+1] = psSHP->panRecSize[i]/2;
+        if( !bBigEndian ) SwapWord( 4, panSHX+i*2 );
+        if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
     }
 
-    if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX ) 
+    if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX )
         != psSHP->nRecords )
     {
         psSHP->sHooks.Error( "Failure writing .shx contents" );
@@ -439,18 +502,20 @@
 /*      Open the .shp and .shx files based on the basename of the       */
 /*      files or either file name.                                      */
 /************************************************************************/
-   
+
 SHPHandle SHPAPI_CALL
 SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
 
 {
-    char		*pszFullname, *pszBasename;
-    SHPHandle		psSHP;
-    
-    uchar		*pabyBuf;
-    int			i;
-    double		dValue;
-    
+    char        *pszFullname, *pszBasename;
+    SHPHandle       psSHP;
+
+    uchar       *pabyBuf;
+    int         i;
+    double      dValue;
+    int         bLazySHXLoading = FALSE;
+    size_t nFullnameLen;
+
 /* -------------------------------------------------------------------- */
 /*      Ensure the access string is one of the legal ones.  We          */
 /*      ensure the result string indicates binary to avoid common       */
@@ -460,19 +525,24 @@
         || strcmp(pszAccess,"r+") == 0 )
         pszAccess = "r+b";
     else
+    {
+        bLazySHXLoading = strchr(pszAccess, 'l') != NULL;
         pszAccess = "rb";
-    
+    }
+
 /* -------------------------------------------------------------------- */
-/*	Establish the byte order on this machine.			*/
+/*  Establish the byte order on this machine.           */
 /* -------------------------------------------------------------------- */
+#if !defined(bBigEndian)
     i = 1;
     if( *((uchar *) &i) == 1 )
         bBigEndian = FALSE;
     else
         bBigEndian = TRUE;
+#endif
 
 /* -------------------------------------------------------------------- */
-/*	Initialize the info structure.					*/
+/*  Initialize the info structure.                  */
 /* -------------------------------------------------------------------- */
     psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
 
@@ -480,60 +550,67 @@
     memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) );
 
 /* -------------------------------------------------------------------- */
-/*	Compute the base (layer) name.  If there is any extension	*/
-/*	on the passed in filename we will strip it off.			*/
+/*  Compute the base (layer) name.  If there is any extension   */
+/*  on the passed in filename we will strip it off.         */
 /* -------------------------------------------------------------------- */
     pszBasename = (char *) malloc(strlen(pszLayer)+5);
     strcpy( pszBasename, pszLayer );
-    for( i = strlen(pszBasename)-1; 
-	 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
-	       && pszBasename[i] != '\\';
-	 i-- ) {}
+    for( i = (int)strlen(pszBasename)-1;
+         i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+             && pszBasename[i] != '\\';
+         i-- ) {}
 
     if( pszBasename[i] == '.' )
         pszBasename[i] = '\0';
 
 /* -------------------------------------------------------------------- */
-/*	Open the .shp and .shx files.  Note that files pulled from	*/
-/*	a PC to Unix with upper case filenames won't work!		*/
+/*  Open the .shp and .shx files.  Note that files pulled from  */
+/*  a PC to Unix with upper case filenames won't work!      */
 /* -------------------------------------------------------------------- */
-    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
-    sprintf( pszFullname, "%s.shp", pszBasename ) ;
+    nFullnameLen = strlen(pszBasename) + 5;
+    pszFullname = (char *) malloc(nFullnameLen);
+    snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename ) ;
     psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
     if( psSHP->fpSHP == NULL )
     {
-        sprintf( pszFullname, "%s.SHP", pszBasename );
+        snprintf( pszFullname, nFullnameLen, "%s.SHP", pszBasename );
         psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
     }
-    
+
     if( psSHP->fpSHP == NULL )
     {
-#ifdef USE_CPL
-        CPLError( CE_Failure, CPLE_OpenFailed, 
-                  "Unable to open %s.shp or %s.SHP.", 
+        size_t nMessageLen = strlen(pszBasename)*2+256;
+        char *pszMessage = (char *) malloc(nMessageLen);
+        snprintf( pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
                   pszBasename, pszBasename );
-#endif
+        psHooks->Error( pszMessage );
+        free( pszMessage );
+
         free( psSHP );
         free( pszBasename );
         free( pszFullname );
-        return( NULL );
+
+        return NULL;
     }
 
-    sprintf( pszFullname, "%s.shx", pszBasename );
+    snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
     psSHP->fpSHX =  psSHP->sHooks.FOpen(pszFullname, pszAccess );
     if( psSHP->fpSHX == NULL )
     {
-        sprintf( pszFullname, "%s.SHX", pszBasename );
+        snprintf( pszFullname, nFullnameLen, "%s.SHX", pszBasename );
         psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
     }
-    
+
     if( psSHP->fpSHX == NULL )
     {
-#ifdef USE_CPL
-        CPLError( CE_Failure, CPLE_OpenFailed, 
-                  "Unable to open %s.shx or %s.SHX.", 
+        size_t nMessageLen = strlen(pszBasename)*2+256;
+        char *pszMessage = (char *) malloc(nMessageLen);
+        snprintf( pszMessage, nMessageLen, "Unable to open %s.shx or %s.SHX."
+                  "Try --config SHAPE_RESTORE_SHX true to restore or create it",
                   pszBasename, pszBasename );
-#endif
+        psHooks->Error( pszMessage );
+        free( pszMessage );
+
         psSHP->sHooks.FClose( psSHP->fpSHP );
         free( psSHP );
         free( pszBasename );
@@ -545,56 +622,75 @@
     free( pszBasename );
 
 /* -------------------------------------------------------------------- */
-/*  Read the file size from the SHP file.				*/
+/*  Read the file size from the SHP file.               */
 /* -------------------------------------------------------------------- */
     pabyBuf = (uchar *) malloc(100);
     psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP );
 
-    psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256
-			+ pabyBuf[25] * 256 * 256
-			+ pabyBuf[26] * 256
-			+ pabyBuf[27]) * 2;
+    psSHP->nFileSize = ((unsigned int)pabyBuf[24] * 256 * 256 * 256
+                        + (unsigned int)pabyBuf[25] * 256 * 256
+                        + (unsigned int)pabyBuf[26] * 256
+                        + (unsigned int)pabyBuf[27]);
+    if( psSHP->nFileSize < 0xFFFFFFFFU / 2 )
+        psSHP->nFileSize *= 2;
+    else
+        psSHP->nFileSize = 0xFFFFFFFEU;
 
 /* -------------------------------------------------------------------- */
 /*  Read SHX file Header info                                           */
 /* -------------------------------------------------------------------- */
-    if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1 
-        || pabyBuf[0] != 0 
-        || pabyBuf[1] != 0 
-        || pabyBuf[2] != 0x27 
+    if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
+        || pabyBuf[0] != 0
+        || pabyBuf[1] != 0
+        || pabyBuf[2] != 0x27
         || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
     {
         psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." );
-	psSHP->sHooks.FClose( psSHP->fpSHP );
-	psSHP->sHooks.FClose( psSHP->fpSHX );
-	free( psSHP );
+        psSHP->sHooks.FClose( psSHP->fpSHP );
+        psSHP->sHooks.FClose( psSHP->fpSHX );
+        free( psSHP );
 
-	return( NULL );
+        return( NULL );
     }
 
     psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
-      + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
-    psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
+        + pabyBuf[25] * 256 * 256 + (pabyBuf[24] & 0x7F) * 256 * 256 * 256;
+    psSHP->nRecords = (psSHP->nRecords - 50) / 4;
 
     psSHP->nShapeType = pabyBuf[32];
 
     if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
     {
         char szError[200];
-        
-        sprintf( szError, 
+
+        snprintf( szError, sizeof(szError),
                  "Record count in .shp header is %d, which seems\n"
                  "unreasonable.  Assuming header is corrupt.",
-                  psSHP->nRecords );
-        psSHP->sHooks.Error( szError );				       
-	psSHP->sHooks.FClose( psSHP->fpSHP );
-	psSHP->sHooks.FClose( psSHP->fpSHX );
-	free( psSHP );
+                 psSHP->nRecords );
+        psSHP->sHooks.Error( szError );
+        psSHP->sHooks.FClose( psSHP->fpSHP );
+        psSHP->sHooks.FClose( psSHP->fpSHX );
+        free( psSHP );
         free(pabyBuf);
 
-	return( NULL );
+        return( NULL );
     }
 
+    /* If a lot of records are advertized, check that the file is big enough */
+    /* to hold them */
+    if( psSHP->nRecords >= 1024 * 1024 )
+    {
+        SAOffset nFileSize;
+        psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 2 );
+        nFileSize = psSHP->sHooks.FTell( psSHP->fpSHX );
+        if( nFileSize > 100 &&
+            nFileSize/2 < (SAOffset)(psSHP->nRecords * 4 + 50) )
+        {
+            psSHP->nRecords = (int)((nFileSize - 100) / 8);
+        }
+        psSHP->sHooks.FSeek( psSHP->fpSHX, 100, 0 );
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Read the bounds.                                                */
 /* -------------------------------------------------------------------- */
@@ -614,15 +710,15 @@
     memcpy( &dValue, pabyBuf+60, 8 );
     psSHP->adBoundsMax[1] = dValue;
 
-    if( bBigEndian ) SwapWord( 8, pabyBuf+68 );		/* z */
+    if( bBigEndian ) SwapWord( 8, pabyBuf+68 );     /* z */
     memcpy( &dValue, pabyBuf+68, 8 );
     psSHP->adBoundsMin[2] = dValue;
-    
+
     if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
     memcpy( &dValue, pabyBuf+76, 8 );
     psSHP->adBoundsMax[2] = dValue;
-    
-    if( bBigEndian ) SwapWord( 8, pabyBuf+84 );		/* z */
+
+    if( bBigEndian ) SwapWord( 8, pabyBuf+84 );     /* z */
     memcpy( &dValue, pabyBuf+84, 8 );
     psSHP->adBoundsMin[3] = dValue;
 
@@ -633,30 +729,33 @@
     free( pabyBuf );
 
 /* -------------------------------------------------------------------- */
-/*	Read the .shx file to get the offsets to each record in 	*/
-/*	the .shp file.							*/
+/*  Read the .shx file to get the offsets to each record in     */
+/*  the .shp file.                          */
 /* -------------------------------------------------------------------- */
     psSHP->nMaxRecords = psSHP->nRecords;
 
-    psSHP->panRecOffset =
-        (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
-    psSHP->panRecSize =
-        (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
-    pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
+    psSHP->panRecOffset = (unsigned int *)
+        malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
+    psSHP->panRecSize = (unsigned int *)
+        malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
+    if( bLazySHXLoading )
+        pabyBuf = NULL;
+    else
+        pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
 
     if (psSHP->panRecOffset == NULL ||
         psSHP->panRecSize == NULL ||
-        pabyBuf == NULL)
+        (!bLazySHXLoading && pabyBuf == NULL))
     {
         char szError[200];
 
-        sprintf(szError, 
+        snprintf( szError, sizeof(szError),
                 "Not enough memory to allocate requested memory (nRecords=%d).\n"
-                "Probably broken SHP file", 
+                "Probably broken SHP file",
                 psSHP->nRecords );
         psSHP->sHooks.Error( szError );
-	psSHP->sHooks.FClose( psSHP->fpSHP );
-	psSHP->sHooks.FClose( psSHP->fpSHX );
+        psSHP->sHooks.FClose( psSHP->fpSHP );
+        psSHP->sHooks.FClose( psSHP->fpSHX );
         if (psSHP->panRecOffset) free( psSHP->panRecOffset );
         if (psSHP->panRecSize) free( psSHP->panRecSize );
         if (pabyBuf) free( pabyBuf );
@@ -664,27 +763,34 @@
         return( NULL );
     }
 
-    if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ) 
-			!= psSHP->nRecords )
+    if( bLazySHXLoading )
     {
+        memset(psSHP->panRecOffset, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
+        memset(psSHP->panRecSize, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
+        return( psSHP );
+    }
+
+    if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX )
+        != psSHP->nRecords )
+    {
         char szError[200];
 
-        sprintf( szError, 
+        snprintf( szError, sizeof(szError),
                  "Failed to read all values for %d records in .shx file.",
                  psSHP->nRecords );
         psSHP->sHooks.Error( szError );
 
         /* SHX is short or unreadable for some reason. */
-	psSHP->sHooks.FClose( psSHP->fpSHP );
-	psSHP->sHooks.FClose( psSHP->fpSHX );
+        psSHP->sHooks.FClose( psSHP->fpSHP );
+        psSHP->sHooks.FClose( psSHP->fpSHX );
         free( psSHP->panRecOffset );
         free( psSHP->panRecSize );
         free( pabyBuf );
-	free( psSHP );
+        free( psSHP );
 
-	return( NULL );
+        return( NULL );
     }
-    
+
     /* In read-only mode, we can close the SHX now */
     if (strcmp(pszAccess, "rb") == 0)
     {
@@ -694,16 +800,38 @@
 
     for( i = 0; i < psSHP->nRecords; i++ )
     {
-	int32		nOffset, nLength;
+        unsigned int        nOffset, nLength;
 
-	memcpy( &nOffset, pabyBuf + i * 8, 4 );
-	if( !bBigEndian ) SwapWord( 4, &nOffset );
+        memcpy( &nOffset, pabyBuf + i * 8, 4 );
+        if( !bBigEndian ) SwapWord( 4, &nOffset );
 
-	memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
-	if( !bBigEndian ) SwapWord( 4, &nLength );
+        memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
+        if( !bBigEndian ) SwapWord( 4, &nLength );
 
-	psSHP->panRecOffset[i] = nOffset*2;
-	psSHP->panRecSize[i] = nLength*2;
+        if( nOffset > (unsigned int)INT_MAX )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Invalid offset for entity %d", i);
+
+            psSHP->sHooks.Error( str );
+            SHPClose(psSHP);
+            free( pabyBuf );
+            return NULL;
+        }
+        if( nLength > (unsigned int)(INT_MAX / 2 - 4) )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Invalid length for entity %d", i);
+
+            psSHP->sHooks.Error( str );
+            SHPClose(psSHP);
+            free( pabyBuf );
+            return NULL;
+        }
+        psSHP->panRecOffset[i] = nOffset*2;
+        psSHP->panRecSize[i] = nLength*2;
     }
     free( pabyBuf );
 
@@ -711,6 +839,231 @@
 }
 
 /************************************************************************/
+/*                              SHPOpenLLEx()                           */
+/*                                                                      */
+/*      Open the .shp and .shx files based on the basename of the       */
+/*      files or either file name. It generally invokes SHPRestoreSHX() */
+/*      in case when bRestoreSHX equals true.                           */
+/************************************************************************/
+
+SHPHandle SHPAPI_CALL
+SHPOpenLLEx( const char * pszLayer, const char * pszAccess, SAHooks *psHooks,
+            int bRestoreSHX )
+
+{
+    if ( !bRestoreSHX ) return SHPOpenLL ( pszLayer, pszAccess, psHooks );
+    else
+    {
+        if ( SHPRestoreSHX ( pszLayer, pszAccess, psHooks ) )
+        {
+            return SHPOpenLL ( pszLayer, pszAccess, psHooks );
+        }
+    }
+
+    return( NULL );
+}
+
+/************************************************************************/
+/*                              SHPRestoreSHX()                         */
+/*                                                                      */
+/*      Restore .SHX file using associated .SHP file.                   */
+/*                                                                      */
+/************************************************************************/
+
+int       SHPAPI_CALL
+SHPRestoreSHX ( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
+
+{
+    char            *pszFullname, *pszBasename;
+    SAFile          fpSHP, fpSHX;
+
+
+    uchar           *pabyBuf;
+    int             i;
+    size_t          nFullnameLen;
+    unsigned int    nSHPFilesize;
+
+    size_t          nMessageLen;
+    char            *pszMessage;
+
+    unsigned int    nCurrentRecordOffset = 0;
+    unsigned int    nCurrentSHPOffset = 100;
+    size_t          nRealSHXContentSize = 100;
+
+    const char      pszSHXAccess[] = "w+b";
+    char            *pabySHXHeader;
+    char            abyReadedRecord[8];
+    unsigned int    niRecord = 0;
+    unsigned int    nRecordLength = 0;
+    unsigned int    nRecordOffset = 50;
+
+/* -------------------------------------------------------------------- */
+/*      Ensure the access string is one of the legal ones.  We          */
+/*      ensure the result string indicates binary to avoid common       */
+/*      problems on Windows.                                            */
+/* -------------------------------------------------------------------- */
+    if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
+        || strcmp(pszAccess,"r+") == 0 )
+        pszAccess = "r+b";
+    else
+    {
+        pszAccess = "rb";
+    }
+
+/* -------------------------------------------------------------------- */
+/*  Establish the byte order on this machine.                           */
+/* -------------------------------------------------------------------- */
+#if !defined(bBigEndian)
+    i = 1;
+    if( *((uchar *) &i) == 1 )
+        bBigEndian = FALSE;
+    else
+        bBigEndian = TRUE;
+#endif
+
+/* -------------------------------------------------------------------- */
+/*  Compute the base (layer) name.  If there is any extension           */
+/*  on the passed in filename we will strip it off.                     */
+/* -------------------------------------------------------------------- */
+    pszBasename = (char *) malloc(strlen(pszLayer)+5);
+    strcpy( pszBasename, pszLayer );
+    for( i = (int)strlen(pszBasename)-1;
+         i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+             && pszBasename[i] != '\\';
+         i-- ) {}
+
+    if( pszBasename[i] == '.' )
+        pszBasename[i] = '\0';
+
+/* -------------------------------------------------------------------- */
+/*  Open the .shp file.  Note that files pulled from                    */
+/*  a PC to Unix with upper case filenames won't work!                  */
+/* -------------------------------------------------------------------- */
+    nFullnameLen = strlen(pszBasename) + 5;
+    pszFullname = (char *) malloc(nFullnameLen);
+    snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename ) ;
+    fpSHP = psHooks->FOpen(pszFullname, pszAccess );
+    if( fpSHP == NULL )
+    {
+        snprintf( pszFullname, nFullnameLen, "%s.SHP", pszBasename );
+        fpSHP = psHooks->FOpen(pszFullname, pszAccess );
+    }
+
+    if( fpSHP == NULL )
+    {
+        nMessageLen = strlen(pszBasename)*2+256;
+        pszMessage = (char *) malloc(nMessageLen);
+        snprintf( pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
+                  pszBasename, pszBasename );
+        psHooks->Error( pszMessage );
+        free( pszMessage );
+
+        free( pszBasename );
+        free( pszFullname );
+
+        return( 0 );
+    }
+
+/* -------------------------------------------------------------------- */
+/*  Read the file size from the SHP file.                               */
+/* -------------------------------------------------------------------- */
+    pabyBuf = (uchar *) malloc(100);
+    psHooks->FRead( pabyBuf, 100, 1, fpSHP );
+
+    nSHPFilesize = ((unsigned int)pabyBuf[24] * 256 * 256 * 256
+                        + (unsigned int)pabyBuf[25] * 256 * 256
+                        + (unsigned int)pabyBuf[26] * 256
+                        + (unsigned int)pabyBuf[27]);
+    if( nSHPFilesize < 0xFFFFFFFFU / 2 )
+        nSHPFilesize *= 2;
+    else
+        nSHPFilesize = 0xFFFFFFFEU;
+
+    snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
+    fpSHX = psHooks->FOpen( pszFullname, pszSHXAccess );
+
+    if( fpSHX == NULL )
+    {
+        nMessageLen = strlen( pszBasename ) * 2 + 256;
+        pszMessage = (char *) malloc( nMessageLen );
+        snprintf( pszMessage, nMessageLen, "Error opening file %s.shx for writing",
+                 pszBasename );
+        psHooks->Error( pszMessage );
+        free( pszMessage );
+
+        psHooks->FClose( fpSHX );
+
+        free( pabyBuf );
+        free( pszBasename );
+        free( pszFullname );
+
+        return( 0 );
+    }
+
+/* -------------------------------------------------------------------- */
+/*  Open SHX and create it using SHP file content.                      */
+/* -------------------------------------------------------------------- */
+    psHooks->FSeek( fpSHP, 100, 0 );
+    pabySHXHeader = (char *) malloc ( 100 );
+    memcpy( pabySHXHeader, pabyBuf, 100 );
+    psHooks->FWrite( pabySHXHeader, 100, 1, fpSHX );
+
+    while( nCurrentSHPOffset < nSHPFilesize )
+    {
+        if( psHooks->FRead( &niRecord, 4, 1, fpSHP ) == 1 &&
+            psHooks->FRead( &nRecordLength, 4, 1, fpSHP ) == 1)
+        {
+            if( !bBigEndian ) SwapWord( 4, &nRecordOffset );
+            memcpy( abyReadedRecord, &nRecordOffset, 4 );
+            memcpy( abyReadedRecord + 4, &nRecordLength, 4 );
+
+            psHooks->FWrite( abyReadedRecord, 8, 1, fpSHX );
+
+            if ( !bBigEndian ) SwapWord( 4, &nRecordOffset );
+            if ( !bBigEndian ) SwapWord( 4, &nRecordLength );
+            nRecordOffset += nRecordLength + 4;
+            nCurrentRecordOffset += 8;
+            nCurrentSHPOffset += 8 + nRecordLength * 2;
+
+            psHooks->FSeek( fpSHP, nCurrentSHPOffset, 0 );
+            nRealSHXContentSize += 8;
+        }
+        else
+        {
+            nMessageLen = strlen( pszBasename ) * 2 + 256;
+            pszMessage = (char *) malloc( nMessageLen );
+            snprintf( pszMessage, nMessageLen, "Error parsing .shp to restore .shx" );
+            psHooks->Error( pszMessage );
+            free( pszMessage );
+
+            psHooks->FClose( fpSHX );
+            psHooks->FClose( fpSHP );
+
+            free( pabySHXHeader );
+            free( pszBasename );
+            free( pszFullname );
+
+            return( 0 );
+        }
+    }
+
+    nRealSHXContentSize /= 2; // Bytes counted -> WORDs
+    if( !bBigEndian ) SwapWord( 4, &nRealSHXContentSize );
+    psHooks->FSeek( fpSHX, 24, 0 );
+    psHooks->FWrite( &nRealSHXContentSize, 4, 1, fpSHX );
+
+    psHooks->FClose( fpSHP );
+    psHooks->FClose( fpSHX );
+
+    free ( pabyBuf );
+    free ( pszFullname );
+    free ( pszBasename );
+    free ( pabySHXHeader );
+
+    return( 1 );
+}
+
+/************************************************************************/
 /*                              SHPClose()                              */
 /*								       	*/
 /*	Close the .shp and .shx files.					*/
@@ -743,11 +1096,42 @@
     {
         free( psSHP->pabyRec );
     }
-    
+
+    if( psSHP->pabyObjectBuf != NULL )
+    {
+        free( psSHP->pabyObjectBuf );
+    }
+    if( psSHP->psCachedObject != NULL )
+    {
+        free( psSHP->psCachedObject );
+    }
+
     free( psSHP );
 }
 
 /************************************************************************/
+/*                    SHPSetFastModeReadObject()                        */
+/************************************************************************/
+
+/* If setting bFastMode = TRUE, the content of SHPReadObject() is owned by the SHPHandle. */
+/* So you cannot have 2 valid instances of SHPReadObject() simultaneously. */
+/* The SHPObject padfZ and padfM members may be NULL depending on the geometry */
+/* type. It is illegal to free at hand any of the pointer members of the SHPObject structure */
+void SHPAPI_CALL SHPSetFastModeReadObject( SHPHandle hSHP, int bFastMode )
+{
+    if( bFastMode )
+    {
+        if( hSHP->psCachedObject == NULL )
+        {
+            hSHP->psCachedObject = (SHPObject*) calloc(1, sizeof(SHPObject));
+            assert( hSHP->psCachedObject != NULL );
+        }
+    }
+
+    hSHP->bFastModeReadObject = bFastMode;
+}
+
+/************************************************************************/
 /*                             SHPGetInfo()                             */
 /*                                                                      */
 /*      Fetch general information about the shape file.                 */
@@ -762,7 +1146,7 @@
 
     if( psSHP == NULL )
         return;
-    
+
     if( pnEntities != NULL )
         *pnEntities = psSHP->nRecords;
 
@@ -807,21 +1191,24 @@
 SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
 
 {
-    char	*pszBasename, *pszFullname;
+    char	*pszBasename = NULL, *pszFullname = NULL;
     int		i;
-    SAFile	fpSHP, fpSHX;
+    SAFile	fpSHP = NULL, fpSHX = NULL;
     uchar     	abyHeader[100];
     int32	i32;
     double	dValue;
-    
+    size_t      nFullnameLen;
+
 /* -------------------------------------------------------------------- */
 /*      Establish the byte order on this system.                        */
 /* -------------------------------------------------------------------- */
+#if !defined(bBigEndian)
     i = 1;
     if( *((uchar *) &i) == 1 )
         bBigEndian = FALSE;
     else
         bBigEndian = TRUE;
+#endif
 
 /* -------------------------------------------------------------------- */
 /*	Compute the base (layer) name.  If there is any extension	*/
@@ -829,10 +1216,10 @@
 /* -------------------------------------------------------------------- */
     pszBasename = (char *) malloc(strlen(pszLayer)+5);
     strcpy( pszBasename, pszLayer );
-    for( i = strlen(pszBasename)-1; 
-	 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
-	       && pszBasename[i] != '\\';
-	 i-- ) {}
+    for( i = (int)strlen(pszBasename)-1;
+         i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+             && pszBasename[i] != '\\';
+         i-- ) {}
 
     if( pszBasename[i] == '.' )
         pszBasename[i] = '\0';
@@ -840,35 +1227,32 @@
 /* -------------------------------------------------------------------- */
 /*      Open the two files so we can write their headers.               */
 /* -------------------------------------------------------------------- */
-    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
-    sprintf( pszFullname, "%s.shp", pszBasename );
+    nFullnameLen = strlen(pszBasename) + 5;
+    pszFullname = (char *) malloc(nFullnameLen);
+    snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename );
     fpSHP = psHooks->FOpen(pszFullname, "wb" );
     if( fpSHP == NULL )
     {
         psHooks->Error( "Failed to create file .shp file." );
-	free( pszFullname );
-	free( pszBasename );
-        return( NULL );
+        goto error;
     }
 
-    sprintf( pszFullname, "%s.shx", pszBasename );
+    snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
     fpSHX = psHooks->FOpen(pszFullname, "wb" );
     if( fpSHX == NULL )
     {
         psHooks->Error( "Failed to create file .shx file." );
-	free( pszFullname );
-	free( pszBasename );
-        return( NULL );
+        goto error;
     }
 
-    free( pszFullname );
-    free( pszBasename );
+    free( pszFullname ); pszFullname = NULL;
+    free( pszBasename ); pszBasename = NULL;
 
 /* -------------------------------------------------------------------- */
 /*      Prepare header block for .shp file.                             */
 /* -------------------------------------------------------------------- */
     for( i = 0; i < 100; i++ )
-      abyHeader[i] = 0;
+        abyHeader[i] = 0;
 
     abyHeader[2] = 0x27;				/* magic cookie */
     abyHeader[3] = 0x0a;
@@ -876,11 +1260,11 @@
     i32 = 50;						/* file size */
     ByteCopy( &i32, abyHeader+24, 4 );
     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-    
+
     i32 = 1000;						/* version */
     ByteCopy( &i32, abyHeader+28, 4 );
     if( bBigEndian ) SwapWord( 4, abyHeader+28 );
-    
+
     i32 = nShapeType;					/* shape type */
     ByteCopy( &i32, abyHeader+32, 4 );
     if( bBigEndian ) SwapWord( 4, abyHeader+32 );
@@ -897,7 +1281,7 @@
     if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
     {
         psHooks->Error( "Failed to write .shp header." );
-        return NULL;
+        goto error;
     }
 
 /* -------------------------------------------------------------------- */
@@ -906,11 +1290,11 @@
     i32 = 50;						/* file size */
     ByteCopy( &i32, abyHeader+24, 4 );
     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-    
+
     if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 )
     {
         psHooks->Error( "Failed to write .shx header." );
-        return NULL;
+        goto error;
     }
 
 /* -------------------------------------------------------------------- */
@@ -920,6 +1304,13 @@
     psHooks->FClose( fpSHX );
 
     return( SHPOpenLL( pszLayer, "r+b", psHooks ) );
+
+error:
+    if (pszFullname) free(pszFullname);
+    if (pszBasename) free(pszBasename);
+    if (fpSHP) psHooks->FClose( fpSHP );
+    if (fpSHX) psHooks->FClose( fpSHX );
+    return NULL;
 }
 
 /************************************************************************/
@@ -958,7 +1349,7 @@
 
 {
     int		i;
-    
+
 /* -------------------------------------------------------------------- */
 /*      Build extents for this object.                                  */
 /* -------------------------------------------------------------------- */
@@ -969,7 +1360,7 @@
         psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
         psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
     }
-    
+
     for( i = 0; i < psObject->nVertices; i++ )
     {
         psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
@@ -1044,16 +1435,17 @@
         psObject->nParts = MAX(1,nParts);
 
         psObject->panPartStart = (int *)
-            malloc(sizeof(int) * psObject->nParts);
+            calloc(sizeof(int), psObject->nParts);
         psObject->panPartType = (int *)
             malloc(sizeof(int) * psObject->nParts);
 
         psObject->panPartStart[0] = 0;
         psObject->panPartType[0] = SHPP_RING;
-        
+
         for( i = 0; i < nParts; i++ )
         {
-            psObject->panPartStart[i] = panPartStart[i];
+            if( panPartStart != NULL )
+                psObject->panPartStart[i] = panPartStart[i];
 
             if( panPartType != NULL )
                 psObject->panPartType[i] = panPartType[i];
@@ -1066,8 +1458,7 @@
     }
 
 /* -------------------------------------------------------------------- */
-/*      Capture vertices.  Note that Z and M are optional, but X and    */
-/*      Y are not.                                                      */
+/*      Capture vertices.  Note that X, Y, Z and M are optional.        */
 /* -------------------------------------------------------------------- */
     if( nVertices > 0 )
     {
@@ -1076,13 +1467,12 @@
         psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
         psObject->padfM = (double *) calloc(sizeof(double),nVertices);
 
-        assert( padfX != NULL );
-        assert( padfY != NULL );
-    
         for( i = 0; i < nVertices; i++ )
         {
-            psObject->padfX[i] = padfX[i];
-            psObject->padfY[i] = padfY[i];
+            if( padfX != NULL )
+                psObject->padfX[i] = padfX[i];
+            if( padfY != NULL )
+                psObject->padfY[i] = padfY[i];
             if( padfZ != NULL && bHasZ )
                 psObject->padfZ[i] = padfZ[i];
             if( padfM != NULL && bHasM )
@@ -1117,7 +1507,7 @@
     return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
                              nVertices, padfX, padfY, padfZ, NULL ) );
 }
-                                  
+
 /************************************************************************/
 /*                           SHPWriteObject()                           */
 /*                                                                      */
@@ -1127,11 +1517,13 @@
 
 int SHPAPI_CALL
 SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
-		      
+
 {
-    int	       	nRecordOffset, i, nRecordSize=0;
+    unsigned int	       	nRecordOffset, nRecordSize=0;
+    int i;
     uchar	*pabyRec;
     int32	i32;
+    int     bExtendFile = FALSE;
 
     psSHP->bUpdated = TRUE;
 
@@ -1139,7 +1531,7 @@
 /*      Ensure that shape object matches the type of the file it is     */
 /*      being written to.                                               */
 /* -------------------------------------------------------------------- */
-    assert( psObject->nSHPType == psSHP->nShapeType 
+    assert( psObject->nSHPType == psSHP->nShapeType
             || psObject->nSHPType == SHPT_NULL );
 
 /* -------------------------------------------------------------------- */
@@ -1147,7 +1539,7 @@
 /*      assertion, or if they are disabled, set the shapeid to -1       */
 /*      for appends.                                                    */
 /* -------------------------------------------------------------------- */
-    assert( nShapeId == -1 
+    assert( nShapeId == -1
             || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
 
     if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
@@ -1158,57 +1550,69 @@
 /* -------------------------------------------------------------------- */
     if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
     {
-	psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
+        int nNewMaxRecords = psSHP->nMaxRecords + psSHP->nMaxRecords / 3 + 100;
+        unsigned int* panRecOffsetNew;
+        unsigned int* panRecSizeNew;
 
-	psSHP->panRecOffset = (int *) 
-            SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords );
-	psSHP->panRecSize = (int *) 
-            SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords );
+        panRecOffsetNew = (unsigned int *)
+            SfRealloc(psSHP->panRecOffset,sizeof(unsigned int) * nNewMaxRecords );
+        if( panRecOffsetNew == NULL )
+            return -1;
+        psSHP->panRecOffset = panRecOffsetNew;
+
+        panRecSizeNew = (unsigned int *)
+            SfRealloc(psSHP->panRecSize,sizeof(unsigned int) * nNewMaxRecords );
+        if( panRecSizeNew == NULL )
+            return -1;
+        psSHP->panRecSize = panRecSizeNew;
+
+        psSHP->nMaxRecords = nNewMaxRecords;
     }
 
 /* -------------------------------------------------------------------- */
 /*      Initialize record.                                              */
 /* -------------------------------------------------------------------- */
-    pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double) 
-			       + psObject->nParts * 8 + 128);
-    
+    pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
+                               + psObject->nParts * 8 + 128);
+    if( pabyRec == NULL )
+        return -1;
+
 /* -------------------------------------------------------------------- */
 /*  Extract vertices for a Polygon or Arc.				*/
 /* -------------------------------------------------------------------- */
     if( psObject->nSHPType == SHPT_POLYGON
         || psObject->nSHPType == SHPT_POLYGONZ
         || psObject->nSHPType == SHPT_POLYGONM
-        || psObject->nSHPType == SHPT_ARC 
+        || psObject->nSHPType == SHPT_ARC
         || psObject->nSHPType == SHPT_ARCZ
         || psObject->nSHPType == SHPT_ARCM
         || psObject->nSHPType == SHPT_MULTIPATCH )
     {
-	int32		nPoints, nParts;
-	int    		i;
+        int32		nPoints, nParts;
 
-	nPoints = psObject->nVertices;
-	nParts = psObject->nParts;
+        nPoints = psObject->nVertices;
+        nParts = psObject->nParts;
 
-	_SHPSetBounds( pabyRec + 12, psObject );
+        _SHPSetBounds( pabyRec + 12, psObject );
 
-	if( bBigEndian ) SwapWord( 4, &nPoints );
-	if( bBigEndian ) SwapWord( 4, &nParts );
+        if( bBigEndian ) SwapWord( 4, &nPoints );
+        if( bBigEndian ) SwapWord( 4, &nParts );
 
-	ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
-	ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
+        ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
+        ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
 
         nRecordSize = 52;
 
         /*
          * Write part start positions.
          */
-	ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
+        ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
                   4 * psObject->nParts );
-	for( i = 0; i < psObject->nParts; i++ )
-	{
-	    if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
+        for( i = 0; i < psObject->nParts; i++ )
+        {
+            if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
             nRecordSize += 4;
-	}
+        }
 
         /*
          * Write multipatch part types if needed.
@@ -1227,19 +1631,19 @@
         /*
          * Write the (x,y) vertex values.
          */
-	for( i = 0; i < psObject->nVertices; i++ )
-	{
-	    ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
-	    ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
+        for( i = 0; i < psObject->nVertices; i++ )
+        {
+            ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
+            ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
 
-	    if( bBigEndian )
+            if( bBigEndian )
                 SwapWord( 8, pabyRec + nRecordSize );
-            
-	    if( bBigEndian )
+
+            if( bBigEndian )
                 SwapWord( 8, pabyRec + nRecordSize + 8 );
 
             nRecordSize += 2 * 8;
-	}
+        }
 
         /*
          * Write the Z coordinates (if any).
@@ -1251,7 +1655,7 @@
             ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
-            
+
             ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
@@ -1269,17 +1673,17 @@
          */
         if( psObject->bMeasureIsUsed
             && (psObject->nSHPType == SHPT_POLYGONM
-            || psObject->nSHPType == SHPT_ARCM
-#ifndef DISABLE_MULTIPATCH_MEASURE            
-            || psObject->nSHPType == SHPT_MULTIPATCH
-#endif            
-            || psObject->nSHPType == SHPT_POLYGONZ
-            || psObject->nSHPType == SHPT_ARCZ) )
+                || psObject->nSHPType == SHPT_ARCM
+#ifndef DISABLE_MULTIPATCH_MEASURE
+                || psObject->nSHPType == SHPT_MULTIPATCH
+#endif
+                || psObject->nSHPType == SHPT_POLYGONZ
+                || psObject->nSHPType == SHPT_ARCZ) )
         {
             ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
-            
+
             ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
@@ -1300,27 +1704,26 @@
              || psObject->nSHPType == SHPT_MULTIPOINTZ
              || psObject->nSHPType == SHPT_MULTIPOINTM )
     {
-	int32		nPoints;
-	int    		i;
+        int32		nPoints;
 
-	nPoints = psObject->nVertices;
+        nPoints = psObject->nVertices;
 
         _SHPSetBounds( pabyRec + 12, psObject );
 
-	if( bBigEndian ) SwapWord( 4, &nPoints );
-	ByteCopy( &nPoints, pabyRec + 44, 4 );
-	
-	for( i = 0; i < psObject->nVertices; i++ )
-	{
-	    ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
-	    ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
+        if( bBigEndian ) SwapWord( 4, &nPoints );
+        ByteCopy( &nPoints, pabyRec + 44, 4 );
 
-	    if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
-	    if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
-	}
+        for( i = 0; i < psObject->nVertices; i++ )
+        {
+            ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
+            ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
 
-	nRecordSize = 48 + 16 * psObject->nVertices;
+            if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
+            if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
+        }
 
+        nRecordSize = 48 + 16 * psObject->nVertices;
+
         if( psObject->nSHPType == SHPT_MULTIPOINTZ )
         {
             ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
@@ -1330,7 +1733,7 @@
             ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
-            
+
             for( i = 0; i < psObject->nVertices; i++ )
             {
                 ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
@@ -1341,7 +1744,7 @@
 
         if( psObject->bMeasureIsUsed
             && (psObject->nSHPType == SHPT_MULTIPOINTZ
-            || psObject->nSHPType == SHPT_MULTIPOINTM) )
+                || psObject->nSHPType == SHPT_MULTIPOINTM) )
         {
             ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
@@ -1350,7 +1753,7 @@
             ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
-            
+
             for( i = 0; i < psObject->nVertices; i++ )
             {
                 ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
@@ -1367,24 +1770,24 @@
              || psObject->nSHPType == SHPT_POINTZ
              || psObject->nSHPType == SHPT_POINTM )
     {
-	ByteCopy( psObject->padfX, pabyRec + 12, 8 );
-	ByteCopy( psObject->padfY, pabyRec + 20, 8 );
+        ByteCopy( psObject->padfX, pabyRec + 12, 8 );
+        ByteCopy( psObject->padfY, pabyRec + 20, 8 );
 
-	if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
-	if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
+        if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
+        if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
 
         nRecordSize = 28;
-        
+
         if( psObject->nSHPType == SHPT_POINTZ )
         {
             ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
         }
-        
+
         if( psObject->bMeasureIsUsed
             && (psObject->nSHPType == SHPT_POINTZ
-            || psObject->nSHPType == SHPT_POINTM) )
+                || psObject->nSHPType == SHPT_POINTM) )
         {
             ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
@@ -1413,23 +1816,30 @@
 /* -------------------------------------------------------------------- */
     if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
     {
-        if( nShapeId == -1 )
-            nShapeId = psSHP->nRecords++;
+        unsigned int nExpectedSize = psSHP->nFileSize + nRecordSize;
+        if( nExpectedSize < psSHP->nFileSize ) // due to unsigned int overflow
+        {
+            char str[128];
+            snprintf( str, sizeof(str), "Failed to write shape object. "
+                     "File size cannot reach %u + %u.",
+                     psSHP->nFileSize, nRecordSize );
+            psSHP->sHooks.Error( str );
+            free( pabyRec );
+            return -1;
+        }
 
-        psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
-        psSHP->panRecSize[nShapeId] = nRecordSize-8;
-        psSHP->nFileSize += nRecordSize;
+        bExtendFile = TRUE;
+        nRecordOffset = psSHP->nFileSize;
     }
     else
     {
         nRecordOffset = psSHP->panRecOffset[nShapeId];
-        psSHP->panRecSize[nShapeId] = nRecordSize-8;
     }
-    
+
 /* -------------------------------------------------------------------- */
 /*      Set the shape type, record number, and record size.             */
 /* -------------------------------------------------------------------- */
-    i32 = nShapeId+1;					/* record # */
+    i32 = (nShapeId < 0) ? psSHP->nRecords+1 : nShapeId+1;					/* record # */
     if( !bBigEndian ) SwapWord( 4, &i32 );
     ByteCopy( &i32, pabyRec, 4 );
 
@@ -1444,16 +1854,31 @@
 /* -------------------------------------------------------------------- */
 /*      Write out record.                                               */
 /* -------------------------------------------------------------------- */
-    if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0
-        || psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
+    if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0 )
     {
-        psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() or fwrite() writing object to .shp file." );
+        psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() while writing object to .shp file." );
         free( pabyRec );
         return -1;
     }
-    
+    if( psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
+    {
+        psSHP->sHooks.Error( "Error in psSHP->sHooks.Fwrite() while writing object to .shp file." );
+        free( pabyRec );
+        return -1;
+    }
+
     free( pabyRec );
 
+    if( bExtendFile )
+    {
+        if( nShapeId == -1 )
+            nShapeId = psSHP->nRecords++;
+
+        psSHP->panRecOffset[nShapeId] = psSHP->nFileSize;
+        psSHP->nFileSize += nRecordSize;
+    }
+    psSHP->panRecSize[nShapeId] = nRecordSize-8;
+
 /* -------------------------------------------------------------------- */
 /*	Expand file wide bounds based on this shape.			*/
 /* -------------------------------------------------------------------- */
@@ -1473,27 +1898,78 @@
         {
             psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
             psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
-            psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
-            psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
+            psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ ? psObject->padfZ[0] : 0.0;
+            psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM ? psObject->padfM[0] : 0.0;
         }
     }
 
     for( i = 0; i < psObject->nVertices; i++ )
     {
-	psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
-	psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
-	psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
-	psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
-	psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
-	psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
-	psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
-	psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
+        psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
+        psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
+        psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
+        psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
+        if( psObject->padfZ )
+        {
+            psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
+            psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
+        }
+        if( psObject->padfM )
+        {
+            psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
+            psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
+        }
     }
 
     return( nShapeId  );
 }
 
 /************************************************************************/
+/*                         SHPAllocBuffer()                             */
+/************************************************************************/
+
+static void* SHPAllocBuffer(unsigned char** pBuffer, int nSize)
+{
+    unsigned char* pRet;
+
+    if( pBuffer == NULL )
+        return calloc(1, nSize);
+
+    pRet = *pBuffer;
+    if( pRet == NULL )
+        return NULL;
+
+    (*pBuffer) += nSize;
+    return pRet;
+}
+
+/************************************************************************/
+/*                    SHPReallocObjectBufIfNecessary()                  */
+/************************************************************************/
+
+static unsigned char* SHPReallocObjectBufIfNecessary ( SHPHandle psSHP,
+                                                       int nObjectBufSize )
+{
+    unsigned char* pBuffer;
+    if( nObjectBufSize == 0 )
+    {
+        nObjectBufSize = 4 * sizeof(double);
+    }
+    if( nObjectBufSize > psSHP->nObjectBufSize )
+    {
+        pBuffer = (unsigned char*) realloc( psSHP->pabyObjectBuf, nObjectBufSize );
+        if( pBuffer != NULL )
+        {
+            psSHP->pabyObjectBuf = pBuffer;
+            psSHP->nObjectBufSize = nObjectBufSize;
+        }
+    }
+    else
+        pBuffer = psSHP->pabyObjectBuf;
+    return pBuffer;
+}
+
+/************************************************************************/
 /*                          SHPReadObject()                             */
 /*                                                                      */
 /*      Read the vertices, parts, and other non-attribute information	*/
@@ -1505,8 +1981,10 @@
 
 {
     int                  nEntitySize, nRequiredSize;
-    SHPObject		*psShape;
-    char                 pszErrorMsg[128];
+    SHPObject           *psShape;
+    char                 szErrorMsg[128];
+    int                  nSHPType;
+    int                  nBytesRead;
 
 /* -------------------------------------------------------------------- */
 /*      Validate the record/entity number.                              */
@@ -1515,28 +1993,105 @@
         return( NULL );
 
 /* -------------------------------------------------------------------- */
+/*      Read offset/length from SHX loading if necessary.               */
+/* -------------------------------------------------------------------- */
+    if( psSHP->panRecOffset[hEntity] == 0 && psSHP->fpSHX != NULL )
+    {
+        unsigned int       nOffset, nLength;
+
+        if( psSHP->sHooks.FSeek( psSHP->fpSHX, 100 + 8 * hEntity, 0 ) != 0 ||
+            psSHP->sHooks.FRead( &nOffset, 1, 4, psSHP->fpSHX ) != 4 ||
+            psSHP->sHooks.FRead( &nLength, 1, 4, psSHP->fpSHX ) != 4 )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Error in fseek()/fread() reading object from .shx file at offset %d",
+                    100 + 8 * hEntity);
+
+            psSHP->sHooks.Error( str );
+            return NULL;
+        }
+        if( !bBigEndian ) SwapWord( 4, &nOffset );
+        if( !bBigEndian ) SwapWord( 4, &nLength );
+
+        if( nOffset > (unsigned int)INT_MAX )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Invalid offset for entity %d", hEntity);
+
+            psSHP->sHooks.Error( str );
+            return NULL;
+        }
+        if( nLength > (unsigned int)(INT_MAX / 2 - 4) )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Invalid length for entity %d", hEntity);
+
+            psSHP->sHooks.Error( str );
+            return NULL;
+        }
+
+        psSHP->panRecOffset[hEntity] = nOffset*2;
+        psSHP->panRecSize[hEntity] = nLength*2;
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Ensure our record buffer is large enough.                       */
 /* -------------------------------------------------------------------- */
     nEntitySize = psSHP->panRecSize[hEntity]+8;
     if( nEntitySize > psSHP->nBufSize )
     {
-	psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize);
-        if (psSHP->pabyRec == NULL)
+        uchar* pabyRecNew;
+        int nNewBufSize = nEntitySize;
+        if( nNewBufSize < INT_MAX - nNewBufSize / 3 )
+            nNewBufSize += nNewBufSize / 3;
+        else
+            nNewBufSize = INT_MAX;
+
+        /* Before allocating too much memory, check that the file is big enough */
+        if( nEntitySize >= 10 * 1024 * 1024 &&
+            (psSHP->panRecOffset[hEntity] >= psSHP->nFileSize ||
+             (unsigned int)nEntitySize > psSHP->nFileSize - psSHP->panRecOffset[hEntity]) )
         {
+            /* We do as is we didn't trust the file size in the header */
+            SAOffset nFileSize;
+            psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 2 );
+            nFileSize = psSHP->sHooks.FTell(psSHP->fpSHP);
+            if( nFileSize >= 0xFFFFFFFFU )
+                psSHP->nFileSize = 0xFFFFFFFFU;
+            else
+                psSHP->nFileSize = (unsigned int)nFileSize;
+
+            if( psSHP->panRecOffset[hEntity] >= psSHP->nFileSize ||
+                (unsigned int)nEntitySize > psSHP->nFileSize - psSHP->panRecOffset[hEntity] )
+            {
+                char str[128];
+                snprintf( str, sizeof(str),
+                         "Error in fread() reading object of size %u at offset %u from .shp file",
+                         nEntitySize, psSHP->panRecOffset[hEntity] );
+
+                psSHP->sHooks.Error( str );
+                return NULL;
+            }
+        }
+
+        pabyRecNew = (uchar *) SfRealloc(psSHP->pabyRec,nNewBufSize);
+        if (pabyRecNew == NULL)
+        {
             char szError[200];
 
-            /* Reallocate previous successful size for following features */
-            psSHP->pabyRec = malloc(psSHP->nBufSize);
-
-            sprintf( szError, 
-                     "Not enough memory to allocate requested memory (nBufSize=%d). "
-                     "Probably broken SHP file", psSHP->nBufSize );
+            snprintf( szError, sizeof(szError),
+                     "Not enough memory to allocate requested memory (nNewBufSize=%d). "
+                     "Probably broken SHP file", nNewBufSize);
             psSHP->sHooks.Error( szError );
             return NULL;
         }
 
         /* Only set new buffer size after successful alloc */
-	psSHP->nBufSize = nEntitySize;
+        psSHP->pabyRec = pabyRecNew;
+        psSHP->nBufSize = nNewBufSize;
     }
 
     /* In case we were not able to reallocate the buffer on a previous step */
@@ -1548,38 +2103,97 @@
 /* -------------------------------------------------------------------- */
 /*      Read the record.                                                */
 /* -------------------------------------------------------------------- */
-    if( psSHP->sHooks.FSeek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0 
-        || psSHP->sHooks.FRead( psSHP->pabyRec, nEntitySize, 1, 
-                  psSHP->fpSHP ) != 1 )
+    if( psSHP->sHooks.FSeek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0 )
     {
         /*
          * TODO - mloskot: Consider detailed diagnostics of shape file,
          * for example to detect if file is truncated.
          */
+        char str[128];
+        snprintf( str, sizeof(str),
+                 "Error in fseek() reading object from .shp file at offset %u",
+                 psSHP->panRecOffset[hEntity]);
 
-        psSHP->sHooks.Error( "Error in fseek() or fread() reading object from .shp file." );
+        psSHP->sHooks.Error( str );
         return NULL;
     }
 
-/* -------------------------------------------------------------------- */
-/*	Allocate and minimally initialize the object.			*/
-/* -------------------------------------------------------------------- */
-    psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
-    psShape->nShapeId = hEntity;
-    psShape->bMeasureIsUsed = FALSE;
+    nBytesRead = (int)psSHP->sHooks.FRead( psSHP->pabyRec, 1, nEntitySize, psSHP->fpSHP );
 
+    /* Special case for a shapefile whose .shx content length field is not equal */
+    /* to the content length field of the .shp, which is a violation of "The */
+    /* content length stored in the index record is the same as the value stored in the main */
+    /* file record header." (http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf, page 24) */
+    /* Actually in that case the .shx content length is equal to the .shp content length + */
+    /* 4 (16 bit words), representing the 8 bytes of the record header... */
+    if( nBytesRead >= 8 && nBytesRead == nEntitySize - 8 )
+    {
+        /* Do a sanity check */
+        int nSHPContentLength;
+        memcpy( &nSHPContentLength, psSHP->pabyRec + 4, 4 );
+        if( !bBigEndian ) SwapWord( 4, &(nSHPContentLength) );
+        if( nSHPContentLength < 0 ||
+            nSHPContentLength > INT_MAX / 2 - 4 ||
+            2 * nSHPContentLength + 8 != nBytesRead )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Sanity check failed when trying to recover from inconsistent .shx/.shp with shape %d",
+                    hEntity );
+
+            psSHP->sHooks.Error( str );
+            return NULL;
+        }
+    }
+    else if( nBytesRead != nEntitySize )
+    {
+        /*
+         * TODO - mloskot: Consider detailed diagnostics of shape file,
+         * for example to detect if file is truncated.
+         */
+        char str[128];
+        snprintf( str, sizeof(str),
+                 "Error in fread() reading object of size %u at offset %u from .shp file",
+                 nEntitySize, psSHP->panRecOffset[hEntity] );
+
+        psSHP->sHooks.Error( str );
+        return NULL;
+    }
+
     if ( 8 + 4 > nEntitySize )
     {
-        snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
-                    hEntity, nEntitySize); 
-        psSHP->sHooks.Error( pszErrorMsg );
-        SHPDestroyObject(psShape);
+        snprintf(szErrorMsg, sizeof(szErrorMsg),
+                 "Corrupted .shp file : shape %d : nEntitySize = %d",
+                 hEntity, nEntitySize);
+        psSHP->sHooks.Error( szErrorMsg );
         return NULL;
     }
-    memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
+    memcpy( &nSHPType, psSHP->pabyRec + 8, 4 );
 
-    if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
+    if( bBigEndian ) SwapWord( 4, &(nSHPType) );
 
+/* -------------------------------------------------------------------- */
+/*	Allocate and minimally initialize the object.			*/
+/* -------------------------------------------------------------------- */
+    if( psSHP->bFastModeReadObject )
+    {
+        if( psSHP->psCachedObject->bFastModeReadObject )
+        {
+            psSHP->sHooks.Error( "Invalid read pattern in fast read mode. "
+                                 "SHPDestroyObject() should be called." );
+            return NULL;
+        }
+
+        psShape = psSHP->psCachedObject;
+        memset(psShape, 0, sizeof(SHPObject));
+    }
+    else
+        psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
+    psShape->nShapeId = hEntity;
+    psShape->nSHPType = nSHPType;
+    psShape->bMeasureIsUsed = FALSE;
+    psShape->bFastModeReadObject = psSHP->bFastModeReadObject;
+
 /* ==================================================================== */
 /*  Extract vertices for a Polygon or Arc.				*/
 /* ==================================================================== */
@@ -1590,14 +2204,17 @@
         || psShape->nSHPType == SHPT_ARCM
         || psShape->nSHPType == SHPT_MULTIPATCH )
     {
-	int32		nPoints, nParts;
-	int    		i, nOffset;
+        int32		nPoints, nParts;
+        int    		i, nOffset;
+        unsigned char* pBuffer = NULL;
+        unsigned char** ppBuffer = NULL;
 
         if ( 40 + 8 + 4 > nEntitySize )
         {
-            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
-                     hEntity, nEntitySize); 
-            psSHP->sHooks.Error( pszErrorMsg );
+            snprintf(szErrorMsg, sizeof(szErrorMsg),
+                     "Corrupted .shp file : shape %d : nEntitySize = %d",
+                     hEntity, nEntitySize);
+            psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
@@ -1609,38 +2226,40 @@
         memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
         memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
 
-	if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
-	if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
-	if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
-	if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
+        if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
+        if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
+        if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
+        if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
 
 /* -------------------------------------------------------------------- */
 /*      Extract part/point count, and build vertex and part arrays      */
 /*      to proper size.                                                 */
 /* -------------------------------------------------------------------- */
-	memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
-	memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
+        memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
+        memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
 
-	if( bBigEndian ) SwapWord( 4, &nPoints );
-	if( bBigEndian ) SwapWord( 4, &nParts );
+        if( bBigEndian ) SwapWord( 4, &nPoints );
+        if( bBigEndian ) SwapWord( 4, &nParts );
 
-        if (nPoints < 0 || nParts < 0 ||
+        /* nPoints and nParts are unsigned */
+        if (/* nPoints < 0 || nParts < 0 || */
             nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
         {
-            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
-                        hEntity, nPoints, nParts);
-            psSHP->sHooks.Error( pszErrorMsg );
+            snprintf(szErrorMsg, sizeof(szErrorMsg),
+                     "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
+                     hEntity, nPoints, nParts);
+            psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
-        
+
         /* With the previous checks on nPoints and nParts, */
         /* we should not overflow here and after */
         /* since 50 M * (16 + 8 + 8) = 1 600 MB */
         nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
         if ( psShape->nSHPType == SHPT_POLYGONZ
-            || psShape->nSHPType == SHPT_ARCZ
-            || psShape->nSHPType == SHPT_MULTIPATCH )
+             || psShape->nSHPType == SHPT_ARCZ
+             || psShape->nSHPType == SHPT_MULTIPATCH )
         {
             nRequiredSize += 16 + 8 * nPoints;
         }
@@ -1650,23 +2269,31 @@
         }
         if (nRequiredSize > nEntitySize)
         {
-            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
-                        hEntity, nPoints, nParts, nEntitySize);
-            psSHP->sHooks.Error( pszErrorMsg );
+            snprintf(szErrorMsg, sizeof(szErrorMsg),
+                     "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
+                     hEntity, nPoints, nParts, nEntitySize);
+            psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
 
-	psShape->nVertices = nPoints;
-        psShape->padfX = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfY = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfM = (double *) calloc(nPoints,sizeof(double));
+        if( psShape->bFastModeReadObject )
+        {
+            int nObjectBufSize = 4 * sizeof(double) * nPoints + 2 * sizeof(int) * nParts;
+            pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
+            ppBuffer = &pBuffer;
+        }
 
-	psShape->nParts = nParts;
-        psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
-        psShape->panPartType = (int *) calloc(nParts,sizeof(int));
-        
+        psShape->nVertices = nPoints;
+        psShape->padfX = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfY = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfZ = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfM = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+
+        psShape->nParts = nParts;
+        psShape->panPartStart = (int *) SHPAllocBuffer(ppBuffer, nParts * sizeof(int));
+        psShape->panPartType = (int *) SHPAllocBuffer(ppBuffer, nParts * sizeof(int));
+
         if (psShape->padfX == NULL ||
             psShape->padfY == NULL ||
             psShape->padfZ == NULL ||
@@ -1674,46 +2301,50 @@
             psShape->panPartStart == NULL ||
             psShape->panPartType == NULL)
         {
-            snprintf(pszErrorMsg, 128,
-                     "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. "
-                     "Probably broken SHP file", hEntity, nPoints, nParts );
-            psSHP->sHooks.Error( pszErrorMsg );
+            snprintf(szErrorMsg, sizeof(szErrorMsg),
+                    "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. "
+                    "Probably broken SHP file", hEntity, nPoints, nParts );
+            psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
 
-        for( i = 0; i < nParts; i++ )
+        for( i = 0; (int32)i < nParts; i++ )
             psShape->panPartType[i] = SHPP_RING;
 
 /* -------------------------------------------------------------------- */
 /*      Copy out the part array from the record.                        */
 /* -------------------------------------------------------------------- */
-	memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
-	for( i = 0; i < nParts; i++ )
-	{
-	    if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
+        memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
+        for( i = 0; (int32)i < nParts; i++ )
+        {
+            if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
 
             /* We check that the offset is inside the vertex array */
-            if (psShape->panPartStart[i] < 0 ||
-                psShape->panPartStart[i] >= psShape->nVertices)
+            if (psShape->panPartStart[i] < 0
+                || (psShape->panPartStart[i] >= psShape->nVertices
+                    && psShape->nVertices > 0)
+                || (psShape->panPartStart[i] > 0 && psShape->nVertices == 0) )
             {
-                snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
-                         hEntity, i, psShape->panPartStart[i], psShape->nVertices); 
-                psSHP->sHooks.Error( pszErrorMsg );
+                snprintf(szErrorMsg, sizeof(szErrorMsg),
+                         "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
+                         hEntity, i, psShape->panPartStart[i], psShape->nVertices);
+                psSHP->sHooks.Error( szErrorMsg );
                 SHPDestroyObject(psShape);
                 return NULL;
             }
             if (i > 0 && psShape->panPartStart[i] <= psShape->panPartStart[i-1])
             {
-                snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d",
-                         hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]); 
-                psSHP->sHooks.Error( pszErrorMsg );
+                snprintf(szErrorMsg, sizeof(szErrorMsg),
+                         "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d",
+                         hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]);
+                psSHP->sHooks.Error( szErrorMsg );
                 SHPDestroyObject(psShape);
                 return NULL;
             }
-	}
+        }
 
-	nOffset = 44 + 8 + 4*nParts;
+        nOffset = 44 + 8 + 4*nParts;
 
 /* -------------------------------------------------------------------- */
 /*      If this is a multipatch, we will also have parts types.         */
@@ -1721,33 +2352,33 @@
         if( psShape->nSHPType == SHPT_MULTIPATCH )
         {
             memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
-            for( i = 0; i < nParts; i++ )
+            for( i = 0; (int32)i < nParts; i++ )
             {
                 if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
             }
 
             nOffset += 4*nParts;
         }
-        
+
 /* -------------------------------------------------------------------- */
 /*      Copy out the vertices from the record.                          */
 /* -------------------------------------------------------------------- */
-	for( i = 0; i < nPoints; i++ )
-	{
-	    memcpy(psShape->padfX + i,
-		   psSHP->pabyRec + nOffset + i * 16,
-		   8 );
+        for( i = 0; (int32)i < nPoints; i++ )
+        {
+            memcpy(psShape->padfX + i,
+                   psSHP->pabyRec + nOffset + i * 16,
+                   8 );
 
-	    memcpy(psShape->padfY + i,
-		   psSHP->pabyRec + nOffset + i * 16 + 8,
-		   8 );
+            memcpy(psShape->padfY + i,
+                   psSHP->pabyRec + nOffset + i * 16 + 8,
+                   8 );
 
-	    if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
-	    if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
-	}
+            if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
+            if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
+        }
 
         nOffset += 16*nPoints;
-        
+
 /* -------------------------------------------------------------------- */
 /*      If we have a Z coordinate, collect that now.                    */
 /* -------------------------------------------------------------------- */
@@ -1757,11 +2388,11 @@
         {
             memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
-            
-            for( i = 0; i < nPoints; i++ )
+
+            for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfZ + i,
                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
@@ -1770,6 +2401,10 @@
 
             nOffset += 16 + 8*nPoints;
         }
+        else if( psShape->bFastModeReadObject )
+        {
+            psShape->padfZ = NULL;
+        }
 
 /* -------------------------------------------------------------------- */
 /*      If we have a M measure value, then read it now.  We assume      */
@@ -1777,15 +2412,15 @@
 /*      big enough, but really it will only occur for the Z shapes      */
 /*      (options), and the M shapes.                                    */
 /* -------------------------------------------------------------------- */
-        if( nEntitySize >= nOffset + 16 + 8*nPoints )
+        if( nEntitySize >= (int)(nOffset + 16 + 8*nPoints) )
         {
             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
-            
-            for( i = 0; i < nPoints; i++ )
+
+            for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfM + i,
                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
@@ -1793,6 +2428,10 @@
             }
             psShape->bMeasureIsUsed = TRUE;
         }
+        else if( psShape->bFastModeReadObject )
+        {
+            psShape->padfM = NULL;
+        }
     }
 
 /* ==================================================================== */
@@ -1802,26 +2441,31 @@
              || psShape->nSHPType == SHPT_MULTIPOINTM
              || psShape->nSHPType == SHPT_MULTIPOINTZ )
     {
-	int32		nPoints;
-	int    		i, nOffset;
+        int32		nPoints;
+        int    		i, nOffset;
+        unsigned char* pBuffer = NULL;
+        unsigned char** ppBuffer = NULL;
 
         if ( 44 + 4 > nEntitySize )
         {
-            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
-                     hEntity, nEntitySize); 
-            psSHP->sHooks.Error( pszErrorMsg );
+            snprintf(szErrorMsg, sizeof(szErrorMsg),
+                     "Corrupted .shp file : shape %d : nEntitySize = %d",
+                     hEntity, nEntitySize);
+            psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
-	memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
+        memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
 
-	if( bBigEndian ) SwapWord( 4, &nPoints );
+        if( bBigEndian ) SwapWord( 4, &nPoints );
 
-        if (nPoints < 0 || nPoints > 50 * 1000 * 1000)
+        /* nPoints is unsigned */
+        if (/* nPoints < 0 || */ nPoints > 50 * 1000 * 1000)
         {
-            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nPoints = %d",
-                     hEntity, nPoints); 
-            psSHP->sHooks.Error( pszErrorMsg );
+            snprintf(szErrorMsg, sizeof(szErrorMsg),
+                     "Corrupted .shp file : shape %d : nPoints = %d",
+                     hEntity, nPoints);
+            psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
@@ -1833,43 +2477,52 @@
         }
         if (nRequiredSize > nEntitySize)
         {
-            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
-                     hEntity, nPoints, nEntitySize); 
-            psSHP->sHooks.Error( pszErrorMsg );
+            snprintf(szErrorMsg, sizeof(szErrorMsg),
+                     "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
+                     hEntity, nPoints, nEntitySize);
+            psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
-        
-	psShape->nVertices = nPoints;
-        psShape->padfX = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfY = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfM = (double *) calloc(nPoints,sizeof(double));
 
+        if( psShape->bFastModeReadObject )
+        {
+            int nObjectBufSize = 4 * sizeof(double) * nPoints;
+            pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
+            ppBuffer = &pBuffer;
+        }
+
+        psShape->nVertices = nPoints;
+
+        psShape->padfX = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfY = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfZ = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfM = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+
         if (psShape->padfX == NULL ||
             psShape->padfY == NULL ||
             psShape->padfZ == NULL ||
             psShape->padfM == NULL)
         {
-            snprintf(pszErrorMsg, 128,
+            snprintf(szErrorMsg, sizeof(szErrorMsg),
                      "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. "
                      "Probably broken SHP file", hEntity, nPoints );
-            psSHP->sHooks.Error( pszErrorMsg );
+            psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
 
-	for( i = 0; i < nPoints; i++ )
-	{
-	    memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
-	    memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
+        for( i = 0; (int32)i < nPoints; i++ )
+        {
+            memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
+            memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
 
-	    if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
-	    if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
-	}
+            if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
+            if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
+        }
 
         nOffset = 48 + 16*nPoints;
-        
+
 /* -------------------------------------------------------------------- */
 /*	Get the X/Y bounds.						*/
 /* -------------------------------------------------------------------- */
@@ -1878,10 +2531,10 @@
         memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
         memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
 
-	if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
-	if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
-	if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
-	if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
+        if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
+        if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
+        if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
+        if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
 
 /* -------------------------------------------------------------------- */
 /*      If we have a Z coordinate, collect that now.                    */
@@ -1890,11 +2543,11 @@
         {
             memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
-            
-            for( i = 0; i < nPoints; i++ )
+
+            for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfZ + i,
                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
@@ -1903,6 +2556,8 @@
 
             nOffset += 16 + 8*nPoints;
         }
+        else if( psShape->bFastModeReadObject )
+            psShape->padfZ = NULL;
 
 /* -------------------------------------------------------------------- */
 /*      If we have a M measure value, then read it now.  We assume      */
@@ -1910,15 +2565,15 @@
 /*      big enough, but really it will only occur for the Z shapes      */
 /*      (options), and the M shapes.                                    */
 /* -------------------------------------------------------------------- */
-        if( nEntitySize >= nOffset + 16 + 8*nPoints )
+        if( nEntitySize >= (int)(nOffset + 16 + 8*nPoints) )
         {
             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
-            
-            for( i = 0; i < nPoints; i++ )
+
+            for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfM + i,
                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
@@ -1926,6 +2581,8 @@
             }
             psShape->bMeasureIsUsed = TRUE;
         }
+        else if( psShape->bFastModeReadObject )
+            psShape->padfM = NULL;
     }
 
 /* ==================================================================== */
@@ -1936,38 +2593,51 @@
              || psShape->nSHPType == SHPT_POINTZ )
     {
         int	nOffset;
-        
-	psShape->nVertices = 1;
-        psShape->padfX = (double *) calloc(1,sizeof(double));
-        psShape->padfY = (double *) calloc(1,sizeof(double));
-        psShape->padfZ = (double *) calloc(1,sizeof(double));
-        psShape->padfM = (double *) calloc(1,sizeof(double));
 
+        psShape->nVertices = 1;
+        if( psShape->bFastModeReadObject )
+        {
+            psShape->padfX = &(psShape->dfXMin);
+            psShape->padfY = &(psShape->dfYMin);
+            psShape->padfZ = &(psShape->dfZMin);
+            psShape->padfM = &(psShape->dfMMin);
+            psShape->padfZ[0] = 0.0;
+            psShape->padfM[0] = 0.0;
+        }
+        else
+        {
+            psShape->padfX = (double *) calloc(1,sizeof(double));
+            psShape->padfY = (double *) calloc(1,sizeof(double));
+            psShape->padfZ = (double *) calloc(1,sizeof(double));
+            psShape->padfM = (double *) calloc(1,sizeof(double));
+        }
+
         if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize)
         {
-            snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
-                     hEntity, nEntitySize); 
-            psSHP->sHooks.Error( pszErrorMsg );
+            snprintf(szErrorMsg, sizeof(szErrorMsg),
+                     "Corrupted .shp file : shape %d : nEntitySize = %d",
+                     hEntity, nEntitySize);
+            psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
-	memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
-	memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
+        memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
+        memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
 
-	if( bBigEndian ) SwapWord( 8, psShape->padfX );
-	if( bBigEndian ) SwapWord( 8, psShape->padfY );
+        if( bBigEndian ) SwapWord( 8, psShape->padfX );
+        if( bBigEndian ) SwapWord( 8, psShape->padfY );
 
         nOffset = 20 + 8;
-        
+
 /* -------------------------------------------------------------------- */
 /*      If we have a Z coordinate, collect that now.                    */
 /* -------------------------------------------------------------------- */
         if( psShape->nSHPType == SHPT_POINTZ )
         {
             memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
-        
+
             if( bBigEndian ) SwapWord( 8, psShape->padfZ );
-            
+
             nOffset += 8;
         }
 
@@ -1980,7 +2650,7 @@
         if( nEntitySize >= nOffset + 8 )
         {
             memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
-        
+
             if( bBigEndian ) SwapWord( 8, psShape->padfM );
             psShape->bMeasureIsUsed = TRUE;
         }
@@ -2022,7 +2692,7 @@
 
       case SHPT_MULTIPOINT:
         return "MultiPoint";
-        
+
       case SHPT_POINTZ:
         return "PointZ";
 
@@ -2034,7 +2704,7 @@
 
       case SHPT_MULTIPOINTZ:
         return "MultiPointZ";
-        
+
       case SHPT_POINTM:
         return "PointM";
 
@@ -2067,7 +2737,7 @@
     {
       case SHPP_TRISTRIP:
         return "TriangleStrip";
-        
+
       case SHPP_TRIFAN:
         return "TriangleFan";
 
@@ -2098,7 +2768,13 @@
 {
     if( psShape == NULL )
         return;
-    
+
+    if( psShape->bFastModeReadObject )
+    {
+        psShape->bFastModeReadObject = FALSE;
+        return;
+    }
+
     if( psShape->padfX != NULL )
         free( psShape->padfX );
     if( psShape->padfY != NULL )
@@ -2124,8 +2800,8 @@
 /************************************************************************/
 
 int SHPAPI_CALL
-SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
-
+SHPRewindObject( CPL_UNUSED SHPHandle hSHP,
+                 SHPObject * psObject )
 {
     int  iOpRing, bAltered = 0;
 
@@ -2172,14 +2848,14 @@
 
             if( iCheckRing == iOpRing )
                 continue;
-            
+
             nVertStart = psObject->panPartStart[iCheckRing];
 
             if( iCheckRing == psObject->nParts-1 )
-                nVertCount = psObject->nVertices 
+                nVertCount = psObject->nVertices
                     - psObject->panPartStart[iCheckRing];
             else
-                nVertCount = psObject->panPartStart[iCheckRing+1] 
+                nVertCount = psObject->panPartStart[iCheckRing+1]
                     - psObject->panPartStart[iCheckRing];
 
             for( iEdge = 0; iEdge < nVertCount; iEdge++ )
@@ -2193,19 +2869,19 @@
 
                 /* Rule #1:
                  * Test whether the edge 'straddles' the horizontal ray from the test point (dfTestY,dfTestY)
-                 * The rule #1 also excludes edges collinear with the ray.
+                 * The rule #1 also excludes edges colinear with the ray.
                  */
                 if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY
                        && dfTestY <= psObject->padfY[iNext+nVertStart] )
-                    || ( psObject->padfY[iNext+nVertStart] < dfTestY
-                         && dfTestY <= psObject->padfY[iEdge+nVertStart] ) )
+                     || ( psObject->padfY[iNext+nVertStart] < dfTestY
+                          && dfTestY <= psObject->padfY[iEdge+nVertStart] ) )
                 {
                     /* Rule #2:
-                    * Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY)
-                    */
-                    double const intersect = 
+                     * Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY)
+                     */
+                    double const intersect =
                         ( psObject->padfX[iEdge+nVertStart]
-                          + ( dfTestY - psObject->padfY[iEdge+nVertStart] ) 
+                          + ( dfTestY - psObject->padfY[iEdge+nVertStart] )
                           / ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] )
                           * ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) );
 
@@ -2213,7 +2889,7 @@
                     {
                         bInner = !bInner;
                     }
-                }    
+                }
             }
         } /* for iCheckRing */
 
@@ -2226,18 +2902,19 @@
         if( iOpRing == psObject->nParts-1 )
             nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
         else
-            nVertCount = psObject->panPartStart[iOpRing+1] 
+            nVertCount = psObject->panPartStart[iOpRing+1]
                 - psObject->panPartStart[iOpRing];
 
-        dfSum = 0.0;
-        for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ )
+        if (nVertCount < 2)
+            continue;
+
+        dfSum = psObject->padfX[nVertStart] * (psObject->padfY[nVertStart+1] - psObject->padfY[nVertStart+nVertCount-1]);
+        for( iVert = nVertStart + 1; iVert < nVertStart+nVertCount-1; iVert++ )
         {
-            dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1]
-                - psObject->padfY[iVert] * psObject->padfX[iVert+1];
+            dfSum += psObject->padfX[iVert] * (psObject->padfY[iVert+1] - psObject->padfY[iVert-1]);
         }
 
-        dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart]
-               - psObject->padfY[iVert] * psObject->padfX[nVertStart];
+        dfSum += psObject->padfX[iVert] * (psObject->padfY[nVertStart] - psObject->padfY[iVert-1]);
 
 /* -------------------------------------------------------------------- */
 /*      Reverse if necessary.                                           */
@@ -2253,13 +2930,13 @@
 
                 /* Swap X */
                 dfSaved = psObject->padfX[nVertStart+i];
-                psObject->padfX[nVertStart+i] = 
+                psObject->padfX[nVertStart+i] =
                     psObject->padfX[nVertStart+nVertCount-i-1];
                 psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
 
                 /* Swap Y */
                 dfSaved = psObject->padfY[nVertStart+i];
-                psObject->padfY[nVertStart+i] = 
+                psObject->padfY[nVertStart+i] =
                     psObject->padfY[nVertStart+nVertCount-i-1];
                 psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
 
@@ -2267,7 +2944,7 @@
                 if( psObject->padfZ )
                 {
                     dfSaved = psObject->padfZ[nVertStart+i];
-                    psObject->padfZ[nVertStart+i] = 
+                    psObject->padfZ[nVertStart+i] =
                         psObject->padfZ[nVertStart+nVertCount-i-1];
                     psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
                 }
@@ -2276,7 +2953,7 @@
                 if( psObject->padfM )
                 {
                     dfSaved = psObject->padfM[nVertStart+i];
-                    psObject->padfM[nVertStart+i] = 
+                    psObject->padfM[nVertStart+i] =
                         psObject->padfM[nVertStart+nVertCount-i-1];
                     psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
                 }



More information about the grass-commit mailing list