[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