summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Grandin <grandinp@gmail.com>2017-07-17 23:29:18 -0700
committerPierre Grandin <grandinp@gmail.com>2017-07-17 23:29:18 -0700
commit6adbfd4e522828b8b81172b89d14b89f61d5d482 (patch)
tree6b1aae5a080fd34123ef3cad830c345b721921b7
parent00f3bd8da313368fe432bd00069ffaa1bbf95a16 (diff)
downloadnavit-shapefile.tar.gz
Updated shapefile drivershapefile
-rw-r--r--navit/support/shapefile/dbfopen.c1028
-rw-r--r--navit/support/shapefile/shapefil.h394
-rw-r--r--navit/support/shapefile/shpopen.c1615
-rw-r--r--navit/support/shapefile/shptree.c472
4 files changed, 2573 insertions, 936 deletions
diff --git a/navit/support/shapefile/dbfopen.c b/navit/support/shapefile/dbfopen.c
index 51944fc53..148e593a4 100644
--- a/navit/support/shapefile/dbfopen.c
+++ b/navit/support/shapefile/dbfopen.c
@@ -1,5 +1,5 @@
/******************************************************************************
- * $Id: dbfopen.c,v 1.83 2008/11/12 14:28:15 fwarmerdam Exp $
+ * $Id: dbfopen.c,v 1.92 2016-12-05 18:44:08 erouault Exp $
*
* Project: Shapelib
* Purpose: Implementation of .dbf access API documented in dbf_api.html.
@@ -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
+ * or at the option of the licensee under the LGPL (see COPYING). 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,51 @@
******************************************************************************
*
* $Log: dbfopen.c,v $
+ * Revision 1.92 2016-12-05 18:44:08 erouault
+ * * dbfopen.c, shapefil.h: write DBF end-of-file character 0x1A by default.
+ * This behaviour can be controlled with the DBFSetWriteEndOfFileChar()
+ * function.
+ *
+ * Revision 1.91 2016-12-05 12:44:05 erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
+ * Revision 1.90 2016-12-04 15:30:15 erouault
+ * * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
+ * GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
+ * structures extended with new members. New functions:
+ * DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
+ * SHPSetFastModeReadObject
+ *
+ * * sbnsearch.c: new file to implement original ESRI .sbn spatial
+ * index reading. (no write support). New functions:
+ * SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
+ * SBNSearchDiskTreeInteger, SBNSearchFreeIds
+ *
+ * * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
+ * with new file and symbols.
+ *
+ * * commit: helper script to cvs commit
+ *
+ * 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
*
@@ -57,8 +103,8 @@
*
* 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
+ * 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.
*
@@ -145,11 +191,45 @@
#include <ctype.h>
#include <string.h>
+#ifdef USE_CPL
+#include "cpl_string.h"
+#else
+
+#if defined(_MSC_VER)
+# if _MSC_VER < 1900
+# define snprintf _snprintf
+# endif
+#elif defined(WIN32) || defined(_WIN32)
+# ifndef snprintf
+# define snprintf _snprintf
+# endif
+#endif
+
+#define CPLsprintf sprintf
+#define CPLsnprintf snprintf
+#endif
+
+SHP_CVSID("$Id: dbfopen.c,v 1.92 2016-12-05 18:44:08 erouault Exp $")
+
#ifndef FALSE
# define FALSE 0
# define TRUE 1
#endif
+/* File header size */
+#define XBASE_FILEHDR_SZ 32
+
+#define HEADER_RECORD_TERMINATOR 0x0D
+
+/* See http://www.manmrk.net/tutorials/database/xbase/dbf.html */
+#define END_OF_FILE_CHARACTER 0x1A
+
+#ifdef USE_CPL
+CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused) {}
+#else
+#define CPL_IGNORE_RET_VAL_INT(x) x
+#endif
+
/************************************************************************/
/* SfRealloc() */
/* */
@@ -178,8 +258,7 @@ static void * SfRealloc( void * pMem, int nNewSize )
static void DBFWriteHeader(DBFHandle psDBF)
{
- unsigned char abyHeader[XBASE_FLDHDR_SZ];
- int i;
+ unsigned char abyHeader[XBASE_FILEHDR_SZ] = { 0 };
if( !psDBF->bNoHeader )
return;
@@ -189,21 +268,18 @@ static void DBFWriteHeader(DBFHandle psDBF)
/* -------------------------------------------------------------------- */
/* Initialize the file header information. */
/* -------------------------------------------------------------------- */
- for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
- abyHeader[i] = 0;
-
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);
@@ -214,20 +290,31 @@ static void DBFWriteHeader(DBFHandle psDBF)
/* 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( abyHeader, XBASE_FILEHDR_SZ, 1, psDBF->fp );
+ psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
psDBF->fp );
/* -------------------------------------------------------------------- */
/* Write out the newline character if there is room for it. */
/* -------------------------------------------------------------------- */
- if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
+ if( psDBF->nHeaderLength > XBASE_FLDHDR_SZ*psDBF->nFields +
+ XBASE_FLDHDR_SZ )
{
char cNewline;
- cNewline = 0x0d;
+ cNewline = HEADER_RECORD_TERMINATOR;
psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
}
+
+/* -------------------------------------------------------------------- */
+/* If the file is new, add a EOF character. */
+/* -------------------------------------------------------------------- */
+ if( psDBF->nRecords == 0 && psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
}
/************************************************************************/
@@ -245,25 +332,30 @@ static int DBFFlushRecord( DBFHandle psDBF )
{
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;
}
+
+ if( psDBF->nCurrentRecord == psDBF->nRecords - 1 )
+ {
+ if( psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
+ }
}
return TRUE;
@@ -283,33 +375,25 @@ static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
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.",
(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.",
psDBF->nRecordLength );
-#endif
+ psDBF->sHooks.Error( szMessage );
return FALSE;
}
@@ -327,33 +411,49 @@ void SHPAPI_CALL
DBFUpdateHeader( DBFHandle psDBF )
{
- unsigned char abyFileHeader[32];
+ unsigned char abyFileHeader[XBASE_FILEHDR_SZ];
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 );
-
+ psDBF->sHooks.FRead( abyFileHeader, sizeof(abyFileHeader), 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 );
+ psDBF->sHooks.FWrite( abyFileHeader, sizeof(abyFileHeader), 1, psDBF->fp );
psDBF->sHooks.FFlush( psDBF->fp );
}
/************************************************************************/
+/* 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 )
@@ -370,7 +470,7 @@ DBFOpen( const char * pszFilename, const char * pszAccess )
/* */
/* Open a .dbf file. */
/************************************************************************/
-
+
DBFHandle SHPAPI_CALL
DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
@@ -381,18 +481,19 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
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+";
@@ -402,7 +503,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
/* -------------------------------------------------------------------- */
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-- ) {}
@@ -410,30 +511,31 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
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 );
}
- sprintf( pszFullname, "%s.cpg", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
pfCPG = psHooks->FOpen( pszFullname, "r" );
if( pfCPG == NULL )
{
- sprintf( pszFullname, "%s.CPG", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.CPG", pszBasename );
pfCPG = psHooks->FOpen( pszFullname, "r" );
}
free( pszBasename );
free( pszFullname );
-
+
if( psDBF->fp == NULL )
{
free( psDBF );
@@ -449,7 +551,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
/* Read Table Header info */
/* -------------------------------------------------------------------- */
pabyBuf = (unsigned char *) malloc(nBufSize);
- if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
+ if( psDBF->sHooks.FRead( pabyBuf, XBASE_FILEHDR_SZ, 1, psDBF->fp ) != 1 )
{
psDBF->sHooks.FClose( psDBF->fp );
if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
@@ -458,14 +560,25 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
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];
- psDBF->nFields = nFields = (nHeadLen - 32) / 32;
+ if (psDBF->nRecordLength == 0 || nHeadLen < XBASE_FILEHDR_SZ)
+ {
+ psDBF->sHooks.FClose( psDBF->fp );
+ if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
+ free( pabyBuf );
+ free( psDBF );
+ return NULL;
+ }
+
+ psDBF->nFields = nFields = (nHeadLen - XBASE_FILEHDR_SZ) / XBASE_FLDHDR_SZ;
psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
@@ -477,8 +590,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
if( pfCPG )
{
size_t n;
- char *buffer = (char *) pabyBuf;
- buffer[0] = '\0';
+ memset( pabyBuf, 0, nBufSize);
psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
n = strcspn( (char *) pabyBuf, "\n\r" );
if( n > 0 )
@@ -491,7 +603,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
}
if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 )
{
- sprintf( (char *) pabyBuf, "LDID/%d", psDBF->iLanguageDriver );
+ snprintf( (char *) pabyBuf, nBufSize, "LDID/%d", psDBF->iLanguageDriver );
psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1);
strcpy( psDBF->pszCodePage, (char *) pabyBuf );
}
@@ -499,12 +611,13 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
/* -------------------------------------------------------------------- */
/* Read in Field Definitions */
/* -------------------------------------------------------------------- */
-
+
pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
psDBF->pszHeader = (char *) pabyBuf;
- psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
- if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
+ psDBF->sHooks.FSeek( psDBF->fp, XBASE_FILEHDR_SZ, 0 );
+ if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-XBASE_FILEHDR_SZ, 1,
+ psDBF->fp ) != 1 )
{
psDBF->sHooks.FClose( psDBF->fp );
free( pabyBuf );
@@ -522,7 +635,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
{
unsigned char *pabyFInfo;
- pabyFInfo = pabyBuf+iField*32;
+ pabyFInfo = pabyBuf+iField*XBASE_FLDHDR_SZ;
if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
{
@@ -548,10 +661,12 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
if( iField == 0 )
psDBF->panFieldOffset[iField] = 1;
else
- psDBF->panFieldOffset[iField] =
+ psDBF->panFieldOffset[iField] =
psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
}
+ DBFSetWriteEndOfFileChar( psDBF, TRUE );
+
return( psDBF );
}
@@ -571,7 +686,7 @@ DBFClose(DBFHandle psDBF)
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 */
@@ -648,6 +763,7 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
char *pszFullname, *pszBasename;
int i, ldid = -1;
char chZero = '\0';
+ size_t nFullnameLen;
/* -------------------------------------------------------------------- */
/* Compute the base (layer) name. If there is any extension */
@@ -655,7 +771,7 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
/* -------------------------------------------------------------------- */
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-- ) {}
@@ -663,25 +779,33 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
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 );
/* -------------------------------------------------------------------- */
/* 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 );
+ }
-
- sprintf( pszFullname, "%s.cpg", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
if( pszCodePage != NULL )
{
if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
@@ -715,8 +839,8 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
psDBF->nRecords = 0;
psDBF->nFields = 0;
psDBF->nRecordLength = 1;
- psDBF->nHeaderLength = 33;
-
+ psDBF->nHeaderLength = XBASE_FILEHDR_SZ + 1; /* + 1 for HEADER_RECORD_TERMINATOR */
+
psDBF->panFieldOffset = NULL;
psDBF->panFieldSize = NULL;
psDBF->panFieldDecimals = NULL;
@@ -736,6 +860,9 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
strcpy( psDBF->pszCodePage, pszCodePage );
}
+ DBFSetLastModifiedDate(psDBF, 95, 7, 26); /* dummy date */
+
+ DBFSetWriteEndOfFileChar(psDBF, TRUE);
return( psDBF );
}
@@ -747,7 +874,7 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
/************************************************************************/
int SHPAPI_CALL
-DBFAddField(DBFHandle psDBF, const char * pszFieldName,
+DBFAddField(DBFHandle psDBF, const char * pszFieldName,
DBFFieldType eType, int nWidth, int nDecimals )
{
@@ -760,11 +887,31 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName,
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 */
@@ -772,7 +919,7 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName,
/************************************************************************/
int SHPAPI_CALL
-DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
+DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
char chType, int nWidth, int nDecimals )
{
@@ -783,14 +930,40 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
char chFieldFill;
SAOffset nRecordOffset;
+ /* make sure that everything is written in .dbf */
+ if( !DBFFlushRecord( psDBF ) )
+ return -1;
+
+ if( psDBF->nHeaderLength + XBASE_FLDHDR_SZ > 65535 )
+ {
+ char szMessage[128];
+ snprintf( szMessage, sizeof(szMessage),
+ "Cannot add field %s. Header length limit reached "
+ "(max 65535 bytes, 2046 fields).",
+ pszFieldName );
+ psDBF->sHooks.Error( szMessage );
+ return -1;
+ }
+
/* -------------------------------------------------------------------- */
/* Do some checking to ensure we can add records to this file. */
/* -------------------------------------------------------------------- */
if( nWidth < 1 )
return -1;
- if( nWidth > 255 )
- nWidth = 255;
+ if( nWidth > XBASE_FLD_MAX_WIDTH )
+ nWidth = XBASE_FLD_MAX_WIDTH;
+
+ if( psDBF->nRecordLength + nWidth > 65535 )
+ {
+ char szMessage[128];
+ snprintf( szMessage, sizeof(szMessage),
+ "Cannot add field %s. Record length limit reached "
+ "(max 65535 bytes).",
+ pszFieldName );
+ psDBF->sHooks.Error( szMessage );
+ return -1;
+ }
nOldRecordLength = psDBF->nRecordLength;
nOldHeaderLength = psDBF->nHeaderLength;
@@ -801,16 +974,16 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
/* -------------------------------------------------------------------- */
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 );
/* -------------------------------------------------------------------- */
@@ -825,20 +998,18 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
/* -------------------------------------------------------------------- */
/* Extend the required header information. */
/* -------------------------------------------------------------------- */
- psDBF->nHeaderLength += 32;
+ psDBF->nHeaderLength += XBASE_FLDHDR_SZ;
psDBF->bUpdated = FALSE;
- psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
+ psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,
+ psDBF->nFields*XBASE_FLDHDR_SZ);
- pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
+ pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * (psDBF->nFields-1);
- for( i = 0; i < 32; i++ )
+ for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
pszFInfo[i] = '\0';
- if( (int) strlen(pszFieldName) < 10 )
- strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
- else
- strncpy( pszFInfo, pszFieldName, 10);
+ strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
@@ -852,7 +1023,7 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
pszFInfo[16] = (unsigned char) nWidth;
pszFInfo[17] = (unsigned char) nDecimals;
}
-
+
/* -------------------------------------------------------------------- */
/* Make the current record buffer appropriately larger. */
/* -------------------------------------------------------------------- */
@@ -870,22 +1041,7 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
/* alloc record */
pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
- switch (chType)
- {
- case 'N':
- case 'F':
- chFieldFill = '*';
- break;
- case 'D':
- chFieldFill = '0';
- break;
- case 'L':
- chFieldFill = '?';
- break;
- default:
- chFieldFill = ' ';
- break;
- }
+ chFieldFill = DBFGetNullCharacter(chType);
for (i = psDBF->nRecords-1; i >= 0; --i)
{
@@ -905,6 +1061,17 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
}
+ if( psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) psDBF->nRecords + psDBF->nHeaderLength;
+
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
+
/* free record */
free(pszRecord);
@@ -912,6 +1079,10 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
psDBF->bNoHeader = TRUE;
DBFUpdateHeader( psDBF );
+ psDBF->nCurrentRecord = -1;
+ psDBF->bCurrentRecordModified = FALSE;
+ psDBF->bUpdated = TRUE;
+
return( psDBF->nFields-1 );
}
@@ -961,7 +1132,7 @@ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
/* -------------------------------------------------------------------- */
/* 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';
@@ -971,11 +1142,17 @@ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
/* -------------------------------------------------------------------- */
/* Decode the field. */
/* -------------------------------------------------------------------- */
- if( chReqType == 'N' )
+ if( chReqType == 'I' )
+ {
+ psDBF->fieldValue.nIntField = atoi(psDBF->pszWorkField);
+
+ pReturnField = &(psDBF->fieldValue.nIntField);
+ }
+ else if( chReqType == 'N' )
{
- psDBF->dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
+ psDBF->fieldValue.dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
- pReturnField = &(psDBF->dfDoubleField);
+ pReturnField = &(psDBF->fieldValue.dfDoubleField);
}
/* -------------------------------------------------------------------- */
@@ -998,7 +1175,7 @@ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
*pchDst = '\0';
}
#endif
-
+
return( pReturnField );
}
@@ -1012,14 +1189,14 @@ int SHPAPI_CALL
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 );
}
/************************************************************************/
@@ -1068,34 +1245,28 @@ DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
}
+
/************************************************************************/
-/* DBFIsAttributeNULL() */
-/* */
-/* Return TRUE if value for field is NULL. */
+/* DBFIsValueNULL() */
/* */
-/* 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;
@@ -1112,7 +1283,7 @@ DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
return strncmp(pszValue,"00000000",8) == 0;
case 'L':
- /* NULL boolean fields have value "?" */
+ /* NULL boolean fields have value "?" */
return pszValue[0] == '?';
default:
@@ -1122,6 +1293,28 @@ DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
}
/************************************************************************/
+/* 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. */
@@ -1151,6 +1344,8 @@ DBFGetRecordCount( DBFHandle psDBF )
/* DBFGetFieldInfo() */
/* */
/* Return any requested information about the field. */
+/* pszFieldName must be at least XBASE_FLDNAME_LEN_READ+1 (=12) */
+/* bytes long. */
/************************************************************************/
DBFFieldType SHPAPI_CALL
@@ -1171,20 +1366,21 @@ DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
{
int i;
- strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
- pszFieldName[11] = '\0';
- for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
+ strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*XBASE_FLDHDR_SZ,
+ XBASE_FLDNAME_LEN_READ );
+ pszFieldName[XBASE_FLDNAME_LEN_READ] = '\0';
+ for( i = XBASE_FLDNAME_LEN_READ - 1; i > 0 && pszFieldName[i] == ' '; i-- )
pszFieldName[i] = '\0';
}
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 )
+ if( psDBF->panFieldDecimals[iField] > 0
+ || psDBF->panFieldSize[iField] >= 10 )
return( FTDouble );
else
return( FTInteger );
@@ -1207,7 +1403,7 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
{
int i, j, nRetResult = TRUE;
unsigned char *pabyRec;
- char szSField[400], szFormat[20];
+ char szSField[XBASE_FLD_MAX_WIDTH+1], szFormat[20];
/* -------------------------------------------------------------------- */
/* Is this a valid record? */
@@ -1252,33 +1448,9 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
/* -------------------------------------------------------------------- */
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;
}
@@ -1290,46 +1462,27 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
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;
- }
-
- 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;
+ 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;
+ }
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;
@@ -1344,7 +1497,7 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
{
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
psDBF->panFieldSize[iField] );
- j = strlen((char *) pValue);
+ j = (int)strlen((char *) pValue);
}
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
@@ -1413,7 +1566,7 @@ DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
{
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
psDBF->panFieldSize[iField] );
- j = strlen((char *) pValue);
+ j = (int)strlen((char *) pValue);
}
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
@@ -1577,21 +1730,24 @@ DBFReadTuple(DBFHandle psDBF, int hEntity )
/************************************************************************/
DBFHandle SHPAPI_CALL
-DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
+DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
{
DBFHandle newDBF;
newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
- if ( newDBF == NULL ) return ( NULL );
-
+ 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 );
@@ -1602,11 +1758,13 @@ DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
newDBF->bNoHeader = TRUE;
newDBF->bUpdated = TRUE;
-
+ newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
+
DBFWriteHeader ( newDBF );
DBFClose ( newDBF );
-
+
newDBF = DBFOpen ( pszFilename, "rb+" );
+ newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
return ( newDBF );
}
@@ -1639,9 +1797,9 @@ DBFGetNativeFieldType( DBFHandle psDBF, int iField )
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]))
@@ -1660,20 +1818,23 @@ int SHPAPI_CALL
DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
{
- char name[12], name1[12], name2[12];
+ char name[XBASE_FLDNAME_LEN_READ+1],
+ name1[XBASE_FLDNAME_LEN_READ+1],
+ name2[XBASE_FLDNAME_LEN_READ+1];
int i;
- strncpy(name1, pszFieldName,11);
- name1[11] = '\0';
+ strncpy(name1, pszFieldName,XBASE_FLDNAME_LEN_READ);
+ name1[XBASE_FLDNAME_LEN_READ] = '\0';
str_to_upper(name1);
for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
{
DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
- strncpy(name2,name,11);
+ strncpy(name2,name,XBASE_FLDNAME_LEN_READ);
+ name2[XBASE_FLDNAME_LEN_READ] = '\0';
str_to_upper(name2);
- if(!strncmp(name1,name2,10))
+ if(!strcmp(name1,name2))
return(i);
}
return(-1);
@@ -1711,7 +1872,7 @@ int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
/* DBFMarkRecordDeleted() */
/************************************************************************/
-int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
+int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
int bIsDeleted )
{
@@ -1735,7 +1896,7 @@ int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
/* -------------------------------------------------------------------- */
if( bIsDeleted )
chNewFlag = '*';
- else
+ else
chNewFlag = ' ';
if( psDBF->pszCurrentRecord[0] != chNewFlag )
@@ -1800,28 +1961,29 @@ DBFDeleteField(DBFHandle psDBF, int iField)
/* resize fields arrays */
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 );
/* update header information */
- psDBF->nHeaderLength -= 32;
+ psDBF->nHeaderLength -= XBASE_FLDHDR_SZ;
psDBF->nRecordLength -= nDeletedFieldSize;
/* overwrite field information in header */
- memcpy(psDBF->pszHeader + iField*32,
- psDBF->pszHeader + (iField+1)*32,
- sizeof(char) * (psDBF->nFields - iField)*32);
+ memmove(psDBF->pszHeader + iField*XBASE_FLDHDR_SZ,
+ psDBF->pszHeader + (iField+1)*XBASE_FLDHDR_SZ,
+ sizeof(char) * (psDBF->nFields - iField)*XBASE_FLDHDR_SZ);
- psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
+ psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,
+ psDBF->nFields*XBASE_FLDHDR_SZ);
/* update size of current record appropriately */
psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
@@ -1841,14 +2003,14 @@ DBFDeleteField(DBFHandle psDBF, int iField)
/* shift records to their new positions */
for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
{
- nRecordOffset =
+ nRecordOffset =
nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength;
/* load record */
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
- nRecordOffset =
+ nRecordOffset =
psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
/* move record in two steps */
@@ -1860,10 +2022,384 @@ DBFDeleteField(DBFHandle psDBF, int iField)
}
+ if( psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+ psDBF->sHooks.FWrite( &ch, 1, 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 *) calloc(sizeof(int), psDBF->nFields);
+ panFieldDecimalsNew = (int *) calloc(sizeof(int), psDBF->nFields);
+ pachFieldTypeNew = (char *) calloc(sizeof(char), psDBF->nFields);
+ pszHeaderNew = (char*) malloc(sizeof(char) * XBASE_FLDHDR_SZ *
+ 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 * XBASE_FLDHDR_SZ,
+ psDBF->pszHeader + panMap[i] * XBASE_FLDHDR_SZ, XBASE_FLDHDR_SZ);
+ }
+ 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 > XBASE_FLD_MAX_WIDTH )
+ nWidth = XBASE_FLD_MAX_WIDTH;
+
+/* -------------------------------------------------------------------- */
+/* 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 + XBASE_FLDHDR_SZ * iField;
+
+ for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
+ pszFInfo[i] = '\0';
+
+ strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
+
+ 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));
+
+ /* cppcheck-suppress uninitdata */
+ 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 );
+ }
+
+ if( psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) psDBF->nRecords + psDBF->nHeaderLength;
+
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
+ /* TODO: truncate file */
+
+ free(pszRecord);
+ free(pszOldField);
+ }
+ else if (nWidth > nOldWidth)
+ {
+ char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
+ char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
+
+ /* cppcheck-suppress uninitdata */
+ 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 );
+ }
+
+ if( psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) psDBF->nRecords + psDBF->nHeaderLength;
+
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
+
+ free(pszRecord);
+ free(pszOldField);
+ }
+
+ psDBF->nCurrentRecord = -1;
+ psDBF->bCurrentRecordModified = FALSE;
+ psDBF->bUpdated = TRUE;
+
+ return TRUE;
+}
+
+/************************************************************************/
+/* DBFSetWriteEndOfFileChar() */
+/************************************************************************/
+
+void SHPAPI_CALL DBFSetWriteEndOfFileChar( DBFHandle psDBF, int bWriteFlag )
+{
+ psDBF->bWriteEndOfFileChar = bWriteFlag;
+}
diff --git a/navit/support/shapefile/shapefil.h b/navit/support/shapefile/shapefil.h
index 059244b03..08c645996 100644
--- a/navit/support/shapefile/shapefil.h
+++ b/navit/support/shapefile/shapefil.h
@@ -2,7 +2,7 @@
#define SHAPEFILE_H_INCLUDED
/******************************************************************************
- * $Id: shapefil.h 15715 2008-11-12 15:15:21Z warmerdam $
+ * $Id: shapefil.h,v 1.55 2016-12-05 18:44:08 erouault Exp $
*
* Project: Shapelib
* Purpose: Primary include file for Shapelib.
@@ -10,13 +10,14 @@
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
+ * Copyright (c) 2012-2016, 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
+ * or at the option of the licensee under the LGPL (see COPYING). 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,7 +38,52 @@
******************************************************************************
*
* $Log: shapefil.h,v $
- * Revision 1.46 2008/11/12 14:28:15 fwarmerdam
+ * Revision 1.55 2016-12-05 18:44:08 erouault
+ * * dbfopen.c, shapefil.h: write DBF end-of-file character 0x1A by default.
+ * This behaviour can be controlled with the DBFSetWriteEndOfFileChar()
+ * function.
+ *
+ * Revision 1.54 2016-12-05 12:44:05 erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
+ * Revision 1.53 2016-12-04 15:30:15 erouault
+ * * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
+ * GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
+ * structures extended with new members. New functions:
+ * DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
+ * SHPSetFastModeReadObject
+ *
+ * * sbnsearch.c: new file to implement original ESRI .sbn spatial
+ * index reading. (no write support). New functions:
+ * SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
+ * SBNSearchDiskTreeInteger, SBNSearchFreeIds
+ *
+ * * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
+ * with new file and symbols.
+ *
+ * * commit: helper script to cvs commit
+ *
+ * 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
@@ -129,8 +175,7 @@
#endif
#ifdef USE_CPL
-#include "cpl_error.h"
-#include "cpl_vsi.h"
+#include "cpl_conv.h"
#endif
#ifdef __cplusplus
@@ -153,7 +198,7 @@ extern "C" {
/* is disabled. */
/* -------------------------------------------------------------------- */
#define DISABLE_MULTIPATCH_MEASURE
-
+
/* -------------------------------------------------------------------- */
/* SHPAPI_CALL */
/* */
@@ -177,7 +222,7 @@ extern "C" {
/* #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. */
@@ -200,14 +245,18 @@ extern "C" {
#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
@@ -217,8 +266,8 @@ static char *cvsid_aw() { return( cvsid_aw() ? ((char *) NULL) : cpl_cvsid ); }
/* UTF-8 encoded filenames Unicode filenames */
/* -------------------------------------------------------------------- */
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
-# define SHPAPI_WINDOWS
-# define SHPAPI_UTF8_HOOKS
+# define SHPAPI_WINDOWS
+# define SHPAPI_UTF8_HOOKS
#endif
/* -------------------------------------------------------------------- */
@@ -252,29 +301,36 @@ void SHPAPI_CALL SASetupUtf8Hooks( SAHooks *psHooks );
/************************************************************************/
/* SHP Support. */
/************************************************************************/
-typedef struct
+typedef struct tagSHPObject SHPObject;
+
+typedef struct
{
SAHooks sHooks;
SAFile fpSHP;
- SAFile fpSHX;
+ SAFile fpSHX;
+
+ int nShapeType; /* SHPT_* */
- int nShapeType; /* SHPT_* */
-
- int nFileSize; /* SHP file */
+ unsigned int nFileSize; /* SHP file */
int nRecords;
- int nMaxRecords;
- int *panRecOffset;
- int *panRecSize;
+ int nMaxRecords;
+ unsigned int*panRecOffset;
+ unsigned int *panRecSize;
- double adBoundsMin[4];
- double adBoundsMax[4];
+ double adBoundsMin[4];
+ double adBoundsMax[4];
- int bUpdated;
+ int bUpdated;
unsigned char *pabyRec;
int nBufSize;
+
+ int bFastModeReadObject;
+ unsigned char *pabyObjectBuf;
+ int nObjectBufSize;
+ SHPObject* psCachedObject;
} SHPInfo;
typedef SHPInfo * SHPHandle;
@@ -282,66 +338,66 @@ typedef SHPInfo * SHPHandle;
/* -------------------------------------------------------------------- */
/* Shape types (nSHPType) */
/* -------------------------------------------------------------------- */
-#define SHPT_NULL 0
-#define SHPT_POINT 1
-#define SHPT_ARC 3
-#define SHPT_POLYGON 5
-#define SHPT_MULTIPOINT 8
-#define SHPT_POINTZ 11
-#define SHPT_ARCZ 13
-#define SHPT_POLYGONZ 15
+#define SHPT_NULL 0
+#define SHPT_POINT 1
+#define SHPT_ARC 3
+#define SHPT_POLYGON 5
+#define SHPT_MULTIPOINT 8
+#define SHPT_POINTZ 11
+#define SHPT_ARCZ 13
+#define SHPT_POLYGONZ 15
#define SHPT_MULTIPOINTZ 18
-#define SHPT_POINTM 21
-#define SHPT_ARCM 23
-#define SHPT_POLYGONM 25
+#define SHPT_POINTM 21
+#define SHPT_ARCM 23
+#define SHPT_POLYGONM 25
#define SHPT_MULTIPOINTM 28
#define SHPT_MULTIPATCH 31
-
/* -------------------------------------------------------------------- */
/* Part types - everything but SHPT_MULTIPATCH just uses */
/* SHPP_RING. */
/* -------------------------------------------------------------------- */
-#define SHPP_TRISTRIP 0
-#define SHPP_TRIFAN 1
-#define SHPP_OUTERRING 2
-#define SHPP_INNERRING 3
-#define SHPP_FIRSTRING 4
-#define SHPP_RING 5
+#define SHPP_TRISTRIP 0
+#define SHPP_TRIFAN 1
+#define SHPP_OUTERRING 2
+#define SHPP_INNERRING 3
+#define SHPP_FIRSTRING 4
+#define SHPP_RING 5
/* -------------------------------------------------------------------- */
/* SHPObject - represents on shape (without attributes) read */
/* from the .shp file. */
/* -------------------------------------------------------------------- */
-typedef struct
+struct tagSHPObject
{
- int nSHPType;
+ int nSHPType;
- int nShapeId; /* -1 is unknown/unassigned */
+ int nShapeId; /* -1 is unknown/unassigned */
- int nParts;
- int *panPartStart;
- int *panPartType;
-
- int nVertices;
- double *padfX;
- double *padfY;
- double *padfZ;
- double *padfM;
+ int nParts;
+ int *panPartStart;
+ int *panPartType;
- double dfXMin;
- double dfYMin;
- double dfZMin;
- double dfMMin;
+ int nVertices;
+ double *padfX;
+ double *padfY;
+ double *padfZ;
+ double *padfM;
- double dfXMax;
- double dfYMax;
- double dfZMax;
- double dfMMax;
+ double dfXMin;
+ double dfYMin;
+ double dfZMin;
+ double dfMMin;
- int bMeasureIsUsed;
-} SHPObject;
+ double dfXMax;
+ double dfYMax;
+ double dfZMax;
+ double dfMMax;
+
+ int bMeasureIsUsed;
+ int bFastModeReadObject;
+};
/* -------------------------------------------------------------------- */
/* SHP API Prototypes */
@@ -352,9 +408,23 @@ typedef struct
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,
@@ -373,15 +443,15 @@ void SHPAPI_CALL
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
@@ -400,7 +470,7 @@ const char SHPAPI_CALL1(*)
/* -------------------------------------------------------------------- */
/* this can be two or four for binary or quad tree */
-#define MAX_SUBNODE 4
+#define MAX_SUBNODE 4
/* upper limit of tree levels for automatic estimation */
#define MAX_DEFAULT_TREE_DEPTH 12
@@ -408,100 +478,150 @@ const char SHPAPI_CALL1(*)
typedef struct shape_tree_node
{
/* region covered by this node */
- double adfBoundsMin[4];
- double adfBoundsMax[4];
+ double adfBoundsMin[4];
+ double adfBoundsMax[4];
/* list of shapes stored at this node. The papsShapeObj pointers
or the whole list can be NULL */
- int nShapeCount;
- int *panShapeIds;
+ int nShapeCount;
+ int *panShapeIds;
SHPObject **papsShapeObj;
- int nSubNodes;
+ int nSubNodes;
struct shape_tree_node *apsSubNode[MAX_SUBNODE];
-
+
} SHPTreeNode;
typedef struct
{
SHPHandle hSHP;
-
- int nMaxDepth;
- int nDimension;
+
+ int nMaxDepth;
+ int nDimension;
int nTotalCount;
-
- SHPTreeNode *psRoot;
+
+ SHPTreeNode *psRoot;
} SHPTree;
SHPTree SHPAPI_CALL1(*)
SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
double *padfBoundsMin, double *padfBoundsMax );
-void SHPAPI_CALL
+void SHPAPI_CALL
SHPDestroyTree( SHPTree * hTree );
-int SHPAPI_CALL
+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
+int SHPAPI_CALL
SHPTreeAddShapeId( SHPTree * hTree, SHPObject * psObject );
-int SHPAPI_CALL
+int SHPAPI_CALL
SHPTreeRemoveShapeId( SHPTree * hTree, int nShapeId );
-void SHPAPI_CALL
+void SHPAPI_CALL
SHPTreeTrimExtraNodes( SHPTree * hTree );
-int SHPAPI_CALL1(*)
+int SHPAPI_CALL1(*)
SHPTreeFindLikelyShapes( SHPTree * hTree,
double * padfBoundsMin,
double * padfBoundsMax,
int * );
-int SHPAPI_CALL
+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. */
/************************************************************************/
-typedef struct
+typedef struct
{
SAHooks sHooks;
- SAFile fp;
+ SAFile fp;
int nRecords;
- int nRecordLength;
- int nHeaderLength;
- int nFields;
- int *panFieldOffset;
- int *panFieldSize;
- int *panFieldDecimals;
- char *pachFieldType;
+ int nRecordLength; /* Must fit on uint16 */
+ int nHeaderLength; /* File header length (32) + field
+ descriptor length + spare space.
+ Must fit on uint16 */
+ int nFields;
+ int *panFieldOffset;
+ int *panFieldSize;
+ int *panFieldDecimals;
+ char *pachFieldType;
- char *pszHeader;
+ char *pszHeader; /* Field descriptors */
- int nCurrentRecord;
- int bCurrentRecordModified;
- char *pszCurrentRecord;
+ int nCurrentRecord;
+ int bCurrentRecordModified;
+ char *pszCurrentRecord;
int nWorkFieldLength;
char *pszWorkField;
-
- int bNoHeader;
- int bUpdated;
- double dfDoubleField;
+ int bNoHeader;
+ int bUpdated;
+
+ union
+ {
+ double dfDoubleField;
+ int nIntField;
+ } fieldValue;
int iLanguageDriver;
char *pszCodePage;
+
+ int nUpdateYearSince1900; /* 0-255 */
+ int nUpdateMonth; /* 1-12 */
+ int nUpdateDay; /* 1-31 */
+
+ int bWriteEndOfFileChar; /* defaults to TRUE */
} DBFInfo;
typedef DBFInfo * DBFHandle;
@@ -514,8 +634,14 @@ typedef enum {
FTInvalid
} DBFFieldType;
-#define XBASE_FLDHDR_SZ 32
-
+/* Field descriptor/header size */
+#define XBASE_FLDHDR_SZ 32
+/* Shapelib read up to 11 characters, even if only 10 should normally be used */
+#define XBASE_FLDNAME_LEN_READ 11
+/* On writing, we limit to 10 characters */
+#define XBASE_FLDNAME_LEN_WRITE 10
+/* Normally only 254 characters should be used. We tolerate 255 historically */
+#define XBASE_FLD_MAX_WIDTH 255
DBFHandle SHPAPI_CALL
DBFOpen( const char * pszDBFFile, const char * pszAccess );
@@ -529,41 +655,48 @@ DBFHandle SHPAPI_CALL
DBFHandle SHPAPI_CALL
DBFCreateLL( const char * pszDBFFile, const char * pszCodePage, SAHooks *psHooks );
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFGetFieldCount( DBFHandle psDBF );
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFGetRecordCount( DBFHandle psDBF );
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFAddField( DBFHandle hDBF, const char * pszFieldName,
DBFFieldType eType, int nWidth, int nDecimals );
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFAddNativeFieldType( DBFHandle hDBF, const char * pszFieldName,
char chType, int nWidth, int nDecimals );
-int SHPAPI_CALL
+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
DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName);
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );
-double SHPAPI_CALL
+double SHPAPI_CALL
DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
const char SHPAPI_CALL1(*)
DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
const char SHPAPI_CALL1(*)
DBFReadLogicalAttribute( DBFHandle hDBF, int iShape, int iField );
-int SHPAPI_CALL
+int SHPAPI_CALL
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,
@@ -576,7 +709,7 @@ int SHPAPI_CALL
int SHPAPI_CALL
DBFWriteLogicalAttribute( DBFHandle hDBF, int iShape, int iField,
- const char lFieldValue);
+ const char lFieldValue);
int SHPAPI_CALL
DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
void * pValue );
@@ -586,22 +719,27 @@ int SHPAPI_CALL
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
+
+void SHPAPI_CALL
DBFClose( DBFHandle hDBF );
void SHPAPI_CALL
DBFUpdateHeader( DBFHandle hDBF );
-char SHPAPI_CALL
+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 );
+
+void SHPAPI_CALL DBFSetWriteEndOfFileChar( DBFHandle psDBF, int bWriteFlag );
+
#ifdef __cplusplus
}
#endif
diff --git a/navit/support/shapefile/shpopen.c b/navit/support/shapefile/shpopen.c
index da5365281..2ace6843b 100644
--- a/navit/support/shapefile/shpopen.c
+++ b/navit/support/shapefile/shpopen.c
@@ -1,5 +1,5 @@
/******************************************************************************
- * $Id: shpopen.c,v 1.59 2008/03/14 05:25:31 fwarmerdam Exp $
+ * $Id: shpopen.c,v 1.75 2016-12-05 12:44:05 erouault Exp $
*
* Project: Shapelib
* Purpose: Implementation of core Shapefile read/write functions.
@@ -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
+ * or at the option of the licensee under the LGPL (see COPYING). 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,71 @@
******************************************************************************
*
* $Log: shpopen.c,v $
- * Revision 1.59 2008/03/14 05:25:31 fwarmerdam
+ * Revision 1.75 2016-12-05 12:44:05 erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
+ * Revision 1.74 2016-12-04 15:30:15 erouault
+ * * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
+ * GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
+ * structures extended with new members. New functions:
+ * DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
+ * SHPSetFastModeReadObject
+ *
+ * * sbnsearch.c: new file to implement original ESRI .sbn spatial
+ * index reading. (no write support). New functions:
+ * SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
+ * SBNSearchDiskTreeInteger, SBNSearchFreeIds
+ *
+ * * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
+ * with new file and symbols.
+ *
+ * * commit: helper script to cvs commit
+ *
+ * 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 +182,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
@@ -230,14 +295,16 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
-#include <glib.h>
+#include <errno.h>
+
+SHP_CVSID("$Id: shpopen.c,v 1.75 2016-12-05 12:44:05 erouault Exp $")
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
@@ -251,8 +318,33 @@ typedef int int32;
# define MAX(a,b) ((a>b) ? a : b)
#endif
-static int bBigEndian;
+#ifndef USE_CPL
+#if defined(_MSC_VER)
+# if _MSC_VER < 1900
+# define snprintf _snprintf
+# endif
+#elif defined(WIN32) || defined(_WIN32)
+# ifndef snprintf
+# define snprintf _snprintf
+# endif
+#endif
+#endif
+#ifndef CPL_UNUSED
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define CPL_UNUSED __attribute((__unused__))
+#else
+# define CPL_UNUSED
+#endif
+#endif
+
+#if defined(CPL_LSB)
+#define bBigEndian FALSE
+#elif defined(CPL_MSB)
+#define bBigEndian TRUE
+#else
+static int bBigEndian;
+#endif
/************************************************************************/
/* SwapWord() */
@@ -297,15 +389,15 @@ static void * SfRealloc( void * pMem, int nNewSize )
/* contents of the index (.shx) file. */
/************************************************************************/
-void SHPWriteHeader( SHPHandle psSHP )
+void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
{
- uchar abyHeader[100];
+ uchar abyHeader[100] = { 0 };
int i;
int32 i32;
double dValue;
int32 *panSHX;
-
+
if (psSHP->fpSHX == NULL)
{
psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed");
@@ -315,8 +407,6 @@ void SHPWriteHeader( SHPHandle psSHP )
/* -------------------------------------------------------------------- */
/* Prepare header block for .shp file. */
/* -------------------------------------------------------------------- */
- for( i = 0; i < 100; i++ )
- abyHeader[i] = 0;
abyHeader[2] = 0x27; /* magic cookie */
abyHeader[3] = 0x0a;
@@ -324,11 +414,11 @@ void SHPWriteHeader( SHPHandle psSHP )
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 );
@@ -368,10 +458,14 @@ void SHPWriteHeader( SHPHandle psSHP )
/* -------------------------------------------------------------------- */
/* 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" );
+ char szError[200];
+
+ snprintf( szError, sizeof(szError),
+ "Failure writing .shp header: %s", strerror(errno) );
+ psSHP->sHooks.Error( szError );
return;
}
@@ -381,11 +475,16 @@ void SHPWriteHeader( SHPHandle psSHP )
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" );
+ char szError[200];
+
+ snprintf( szError, sizeof(szError),
+ "Failure writing .shx header: %s", strerror(errno) );
+ psSHP->sHooks.Error( szError );
+
return;
}
@@ -393,19 +492,28 @@ void SHPWriteHeader( SHPHandle psSHP )
/* 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" );
+ char szError[200];
+
+ snprintf( szError, sizeof(szError),
+ "Failure writing .shx contents: %s", strerror(errno) );
+ psSHP->sHooks.Error( szError );
}
free( panSHX );
@@ -438,18 +546,20 @@ SHPOpen( const char * pszLayer, const char * pszAccess )
/* 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 */
@@ -459,19 +569,24 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
|| 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);
@@ -479,60 +594,67 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
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 );
@@ -544,54 +666,73 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
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 );
}
/* -------------------------------------------------------------------- */
@@ -613,15 +754,15 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
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;
@@ -632,30 +773,33 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
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 );
@@ -663,27 +807,34 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
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,
- "Failed to read all values for %d records in .shx file.",
- psSHP->nRecords );
+ snprintf( szError, sizeof(szError),
+ "Failed to read all values for %d records in .shx file: %s.",
+ psSHP->nRecords, strerror(errno) );
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)
{
@@ -693,16 +844,38 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
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 );
+ if( nOffset > (unsigned int)INT_MAX )
+ {
+ char str[128];
+ snprintf( str, sizeof(str),
+ "Invalid offset for entity %d", i);
- psSHP->panRecOffset[i] = nOffset*2;
- psSHP->panRecSize[i] = nLength*2;
+ 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 );
@@ -710,6 +883,231 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
}
/************************************************************************/
+/* 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. */
@@ -742,11 +1140,42 @@ SHPClose(SHPHandle psSHP )
{
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. */
@@ -761,7 +1190,7 @@ SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
if( psSHP == NULL )
return;
-
+
if( pnEntities != NULL )
*pnEntities = psSHP->nRecords;
@@ -806,21 +1235,24 @@ SHPHandle SHPAPI_CALL
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 */
@@ -828,10 +1260,10 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
/* -------------------------------------------------------------------- */
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';
@@ -839,31 +1271,31 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
/* -------------------------------------------------------------------- */
/* 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." );
- 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." );
- 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;
+ memset( abyHeader, 0, sizeof(abyHeader) );
abyHeader[2] = 0x27; /* magic cookie */
abyHeader[3] = 0x0a;
@@ -871,11 +1303,11 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
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 );
@@ -891,8 +1323,13 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
/* -------------------------------------------------------------------- */
if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
{
- psHooks->Error( "Failed to write .shp header." );
- return NULL;
+ char szError[200];
+
+ snprintf( szError, sizeof(szError),
+ "Failed to write .shp header: %s", strerror(errno) );
+ psHooks->Error( szError );
+
+ goto error;
}
/* -------------------------------------------------------------------- */
@@ -901,11 +1338,16 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
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;
+ char szError[200];
+
+ snprintf( szError, sizeof(szError),
+ "Failure writing .shx header: %s", strerror(errno) );
+ psHooks->Error( szError );
+
+ goto error;
}
/* -------------------------------------------------------------------- */
@@ -915,6 +1357,13 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
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;
}
/************************************************************************/
@@ -953,7 +1402,7 @@ SHPComputeExtents( SHPObject * psObject )
{
int i;
-
+
/* -------------------------------------------------------------------- */
/* Build extents for this object. */
/* -------------------------------------------------------------------- */
@@ -964,7 +1413,7 @@ SHPComputeExtents( SHPObject * psObject )
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]);
@@ -1039,16 +1488,17 @@ SHPCreateObject( int nSHPType, int nShapeId, int nParts,
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];
@@ -1061,8 +1511,7 @@ SHPCreateObject( int nSHPType, int nShapeId, int nParts,
}
/* -------------------------------------------------------------------- */
-/* 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 )
{
@@ -1071,13 +1520,12 @@ SHPCreateObject( int nSHPType, int nShapeId, int nParts,
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 )
@@ -1112,7 +1560,7 @@ SHPCreateSimpleObject( int nSHPType, int nVertices,
return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
nVertices, padfX, padfY, padfZ, NULL ) );
}
-
+
/************************************************************************/
/* SHPWriteObject() */
/* */
@@ -1122,11 +1570,13 @@ SHPCreateSimpleObject( int nSHPType, int nVertices,
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;
@@ -1134,7 +1584,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
/* 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 );
/* -------------------------------------------------------------------- */
@@ -1142,7 +1592,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
/* 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 )
@@ -1153,57 +1603,69 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
/* -------------------------------------------------------------------- */
if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
{
- psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
-
- psSHP->panRecOffset = (int *)
- SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords );
- psSHP->panRecSize = (int *)
- SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords );
+ int nNewMaxRecords = psSHP->nMaxRecords + psSHP->nMaxRecords / 3 + 100;
+ unsigned int* panRecOffsetNew;
+ unsigned int* panRecSizeNew;
+
+ 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.
@@ -1222,19 +1684,19 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
/*
* 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).
@@ -1246,7 +1708,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
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;
@@ -1264,17 +1726,17 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
*/
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;
@@ -1295,26 +1757,25 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
|| 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 );
+
+ if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
+ }
- nRecordSize = 48 + 16 * psObject->nVertices;
+ nRecordSize = 48 + 16 * psObject->nVertices;
if( psObject->nSHPType == SHPT_MULTIPOINTZ )
{
@@ -1325,7 +1786,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
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 );
@@ -1336,7 +1797,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
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 );
@@ -1345,7 +1806,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
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 );
@@ -1362,24 +1823,24 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
|| 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 );
@@ -1408,23 +1869,30 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
/* -------------------------------------------------------------------- */
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 );
@@ -1439,16 +1907,43 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
/* -------------------------------------------------------------------- */
/* 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." );
+ char szError[200];
+
+ snprintf( szError, sizeof(szError),
+ "Error in psSHP->sHooks.FSeek() while writing object to .shp file: %s",
+ strerror(errno) );
+ psSHP->sHooks.Error( szError );
+
+ free( pabyRec );
+ return -1;
+ }
+ if( psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
+ {
+ char szError[200];
+
+ snprintf( szError, sizeof(szError),
+ "Error in psSHP->sHooks.FWrite() while writing object of %u bytes to .shp file: %s",
+ nRecordSize, strerror(errno) );
+ psSHP->sHooks.Error( szError );
+
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. */
/* -------------------------------------------------------------------- */
@@ -1468,27 +1963,78 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
{
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 */
@@ -1500,8 +2046,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
{
int nEntitySize, nRequiredSize;
- SHPObject *psShape;
- char pszErrorMsg[128];
+ SHPObject *psShape;
+ char szErrorMsg[128];
+ int nSHPType;
+ int nBytesRead;
/* -------------------------------------------------------------------- */
/* Validate the record/entity number. */
@@ -1510,28 +2058,105 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
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]) )
{
- char szError[200];
+ /* 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 %d at offset %u from .shp file",
+ nEntitySize, psSHP->panRecOffset[hEntity] );
+
+ psSHP->sHooks.Error( str );
+ return NULL;
+ }
+ }
- /* Reallocate previous successfull size for following features */
- psSHP->pabyRec = malloc(psSHP->nBufSize);
+ pabyRecNew = (uchar *) SfRealloc(psSHP->pabyRec,nNewBufSize);
+ if (pabyRecNew == NULL)
+ {
+ char szError[200];
- 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 successfull alloc */
- psSHP->nBufSize = nEntitySize;
+ /* Only set new buffer size after successful alloc */
+ psSHP->pabyRec = pabyRecNew;
+ psSHP->nBufSize = nNewBufSize;
}
/* In case we were not able to reallocate the buffer on a previous step */
@@ -1543,37 +2168,96 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
/* -------------------------------------------------------------------- */
/* 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 %d at offset %u from .shp file",
+ nEntitySize, psSHP->panRecOffset[hEntity] );
+
+ psSHP->sHooks.Error( str );
+ return NULL;
+ }
if ( 8 + 4 > nEntitySize )
{
- g_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, &(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;
+ }
- if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
+ 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. */
@@ -1585,14 +2269,17 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
|| 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 )
{
- g_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;
}
@@ -1604,38 +2291,40 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
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)
{
- g_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=%u, nParts=%u.",
+ 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;
}
@@ -1645,23 +2334,31 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
}
if (nRequiredSize > nEntitySize)
{
- g_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=%u, nParts=%u, 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->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));
- psShape->nParts = nParts;
- psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
- psShape->panPartType = (int *) calloc(nParts,sizeof(int));
-
if (psShape->padfX == NULL ||
psShape->padfY == NULL ||
psShape->padfZ == NULL ||
@@ -1669,46 +2366,50 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
psShape->panPartStart == NULL ||
psShape->panPartType == NULL)
{
- g_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=%u, nParts=%u) for shape %d. "
+ "Probably broken SHP file", nPoints, nParts, hEntity );
+ 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) )
{
- g_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])
{
- g_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. */
@@ -1716,33 +2417,33 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
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. */
/* -------------------------------------------------------------------- */
@@ -1752,11 +2453,11 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
{
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 );
@@ -1765,6 +2466,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
nOffset += 16 + 8*nPoints;
}
+ else if( psShape->bFastModeReadObject )
+ {
+ psShape->padfZ = NULL;
+ }
/* -------------------------------------------------------------------- */
/* If we have a M measure value, then read it now. We assume */
@@ -1772,15 +2477,15 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
/* 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 );
@@ -1788,6 +2493,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
}
psShape->bMeasureIsUsed = TRUE;
}
+ else if( psShape->bFastModeReadObject )
+ {
+ psShape->padfM = NULL;
+ }
}
/* ==================================================================== */
@@ -1797,26 +2506,31 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
|| 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 )
{
- g_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)
{
- g_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 = %u",
+ hEntity, nPoints);
+ psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
}
@@ -1828,43 +2542,52 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
}
if (nRequiredSize > nEntitySize)
{
- g_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 = %u, 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)
{
- g_snprintf(pszErrorMsg, 128,
- "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. "
- "Probably broken SHP file", hEntity, nPoints );
- psSHP->sHooks.Error( pszErrorMsg );
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
+ "Not enough memory to allocate requested memory (nPoints=%u) for shape %d. "
+ "Probably broken SHP file", nPoints, hEntity );
+ 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. */
/* -------------------------------------------------------------------- */
@@ -1873,10 +2596,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
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. */
@@ -1885,11 +2608,11 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
{
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 );
@@ -1898,6 +2621,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
nOffset += 16 + 8*nPoints;
}
+ else if( psShape->bFastModeReadObject )
+ psShape->padfZ = NULL;
/* -------------------------------------------------------------------- */
/* If we have a M measure value, then read it now. We assume */
@@ -1905,15 +2630,15 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
/* 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 );
@@ -1921,6 +2646,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
}
psShape->bMeasureIsUsed = TRUE;
}
+ else if( psShape->bFastModeReadObject )
+ psShape->padfM = NULL;
}
/* ==================================================================== */
@@ -1931,38 +2658,51 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
|| 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)
{
- g_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;
}
@@ -1975,7 +2715,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
if( nEntitySize >= nOffset + 8 )
{
memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
-
+
if( bBigEndian ) SwapWord( 8, psShape->padfM );
psShape->bMeasureIsUsed = TRUE;
}
@@ -2017,7 +2757,7 @@ SHPTypeName( int nSHPType )
case SHPT_MULTIPOINT:
return "MultiPoint";
-
+
case SHPT_POINTZ:
return "PointZ";
@@ -2029,7 +2769,7 @@ SHPTypeName( int nSHPType )
case SHPT_MULTIPOINTZ:
return "MultiPointZ";
-
+
case SHPT_POINTM:
return "PointM";
@@ -2062,7 +2802,7 @@ SHPPartTypeName( int nPartType )
{
case SHPP_TRISTRIP:
return "TriangleStrip";
-
+
case SHPP_TRIFAN:
return "TriangleFan";
@@ -2093,7 +2833,13 @@ SHPDestroyObject( SHPObject * psShape )
{
if( psShape == NULL )
return;
-
+
+ if( psShape->bFastModeReadObject )
+ {
+ psShape->bFastModeReadObject = FALSE;
+ return;
+ }
+
if( psShape->padfX != NULL )
free( psShape->padfX );
if( psShape->padfY != NULL )
@@ -2119,8 +2865,8 @@ SHPDestroyObject( SHPObject * psShape )
/************************************************************************/
int SHPAPI_CALL
-SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
-
+SHPRewindObject( CPL_UNUSED SHPHandle hSHP,
+ SHPObject * psObject )
{
int iOpRing, bAltered = 0;
@@ -2167,14 +2913,14 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
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++ )
@@ -2188,19 +2934,19 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
/* 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] ) );
@@ -2208,7 +2954,7 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
{
bInner = !bInner;
}
- }
+ }
}
} /* for iCheckRing */
@@ -2221,18 +2967,19 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
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. */
@@ -2248,13 +2995,13 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
/* 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;
@@ -2262,7 +3009,7 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
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;
}
@@ -2271,7 +3018,7 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
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;
}
diff --git a/navit/support/shapefile/shptree.c b/navit/support/shapefile/shptree.c
index 56d33b227..d81533c95 100644
--- a/navit/support/shapefile/shptree.c
+++ b/navit/support/shapefile/shptree.c
@@ -1,5 +1,5 @@
/******************************************************************************
- * $Id: shptree.c,v 1.12 2008/11/12 15:39:50 fwarmerdam Exp $
+ * $Id: shptree.c,v 1.19 2016-12-05 12:44:06 erouault Exp $
*
* Project: Shapelib
* Purpose: Implementation of quadtree building and searching functions.
@@ -7,13 +7,14 @@
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
+ * Copyright (c) 2012, 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
+ * or at the option of the licensee under the LGPL (see COPYING). 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,44 @@
******************************************************************************
*
* $Log: shptree.c,v $
- * Revision 1.12 2008/11/12 15:39:50 fwarmerdam
+ * Revision 1.19 2016-12-05 12:44:06 erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
+ * Revision 1.18 2016-12-04 15:30:15 erouault
+ * * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
+ * GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
+ * structures extended with new members. New functions:
+ * DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
+ * SHPSetFastModeReadObject
+ *
+ * * sbnsearch.c: new file to implement original ESRI .sbn spatial
+ * index reading. (no write support). New functions:
+ * SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
+ * SBNSearchDiskTreeInteger, SBNSearchFreeIds
+ *
+ * * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
+ * with new file and symbols.
+ *
+ * * commit: helper script to cvs commit
+ *
+ * Revision 1.17 2012-01-27 21:09:26 fwarmerdam
+ * optimize .qix output (gdal #4472)
+ *
+ * Revision 1.16 2011-12-11 22:26:46 fwarmerdam
+ * upgrade .qix access code to use SAHooks (gdal #3365)
+ *
+ * Revision 1.15 2011-07-24 05:59:25 fwarmerdam
+ * minimize use of CPLError in favor of SAHooks.Error()
+ *
+ * Revision 1.14 2010-08-27 23:43:27 fwarmerdam
+ * add SHPAPI_CALL attribute in code
+ *
+ * Revision 1.13 2010-06-29 05:50:15 fwarmerdam
+ * fix sign of Z/M comparisons in SHPCheckObjectContained (#2223)
+ *
+ * Revision 1.12 2008-11-12 15:39:50 fwarmerdam
* improve safety in face of buggy .shp file.
*
* Revision 1.11 2007/10/27 03:31:14 fwarmerdam
@@ -78,13 +116,13 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
+
#ifdef USE_CPL
-#include <cpl_error.h>
+#include "cpl_error.h"
#endif
-#if 0
-SHP_CVSID("$Id: shptree.c,v 1.12 2008/11/12 15:39:50 fwarmerdam Exp $")
-#endif
+SHP_CVSID("$Id: shptree.c,v 1.19 2016-12-05 12:44:06 erouault Exp $")
#ifndef TRUE
# define TRUE 1
@@ -93,9 +131,6 @@ SHP_CVSID("$Id: shptree.c,v 1.12 2008/11/12 15:39:50 fwarmerdam Exp $")
static int bBigEndian = 0;
-void SHPAPI_CALL SHPTreeSplitBounds( double *padfBoundsMinIn, double *padfBoundsMaxIn, double *padfBoundsMin1, double * padfBoundsMax1, double *padfBoundsMin2, double * padfBoundsMax2 );
-void SHPAPI_CALL SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode, double * padfBoundsMin, double * padfBoundsMax, int * pnShapeCount, int * pnMaxShapes, int ** ppanShapeList );
-
/* -------------------------------------------------------------------- */
/* If the following is 0.5, nodes will be split in half. If it */
@@ -136,13 +171,8 @@ static SHPTreeNode *SHPTreeNodeCreate( double * padfBoundsMin,
SHPTreeNode *psTreeNode;
psTreeNode = (SHPTreeNode *) malloc(sizeof(SHPTreeNode));
- if( NULL == psTreeNode )
- {
-#ifdef USE_CPL
- CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure");
-#endif
- return NULL;
- }
+ if( NULL == psTreeNode )
+ return NULL;
psTreeNode->nShapeCount = 0;
psTreeNode->panShapeIds = NULL;
@@ -165,8 +195,8 @@ static SHPTreeNode *SHPTreeNodeCreate( double * padfBoundsMin,
/************************************************************************/
SHPTree SHPAPI_CALL1(*)
-SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
- double *padfBoundsMin, double *padfBoundsMax )
+ SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
+ double *padfBoundsMin, double *padfBoundsMax )
{
SHPTree *psTree;
@@ -178,13 +208,10 @@ SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
/* Allocate the tree object */
/* -------------------------------------------------------------------- */
psTree = (SHPTree *) malloc(sizeof(SHPTree));
- if( NULL == psTree )
- {
-#ifdef USE_CPL
- CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure");
-#endif
- return NULL;
- }
+ if( NULL == psTree )
+ {
+ return NULL;
+ }
psTree->hSHP = hSHP;
psTree->nMaxDepth = nMaxDepth;
@@ -222,9 +249,9 @@ SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
psTree->nMaxDepth = MAX_DEFAULT_TREE_DEPTH;
#ifdef USE_CPL
- CPLDebug( "Shape",
- "Falling back to max number of allowed index tree levels (%d).",
- MAX_DEFAULT_TREE_DEPTH );
+ CPLDebug( "Shape",
+ "Falling back to max number of allowed index tree levels (%d).",
+ MAX_DEFAULT_TREE_DEPTH );
#endif
}
}
@@ -233,23 +260,21 @@ SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
/* Allocate the root node. */
/* -------------------------------------------------------------------- */
psTree->psRoot = SHPTreeNodeCreate( padfBoundsMin, padfBoundsMax );
- if( NULL == psTree->psRoot )
- {
- return NULL;
- }
+ if( NULL == psTree->psRoot )
+ {
+ free( psTree );
+ return NULL;
+ }
/* -------------------------------------------------------------------- */
/* Assign the bounds to the root node. If none are passed in, */
/* use the bounds of the provided file otherwise the create */
/* function will have already set the bounds. */
/* -------------------------------------------------------------------- */
- assert( NULL != psTree );
- assert( NULL != psTree->psRoot );
-
- if( padfBoundsMin == NULL )
+ if( padfBoundsMin == NULL )
{
SHPGetInfo( hSHP, NULL, NULL,
- psTree->psRoot->adfBoundsMin,
+ psTree->psRoot->adfBoundsMin,
psTree->psRoot->adfBoundsMax );
}
@@ -259,13 +284,13 @@ SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
if( hSHP != NULL )
{
int iShape, nShapeCount;
-
+
SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL );
for( iShape = 0; iShape < nShapeCount; iShape++ )
{
SHPObject *psShape;
-
+
psShape = SHPReadObject( hSHP, iShape );
if( psShape != NULL )
{
@@ -273,7 +298,7 @@ SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
SHPDestroyObject( psShape );
}
}
- }
+ }
return psTree;
}
@@ -286,7 +311,7 @@ static void SHPDestroyTreeNode( SHPTreeNode * psTreeNode )
{
int i;
-
+
assert( NULL != psTreeNode );
for( i = 0; i < psTreeNode->nSubNodes; i++ )
@@ -294,7 +319,7 @@ static void SHPDestroyTreeNode( SHPTreeNode * psTreeNode )
if( psTreeNode->apsSubNode[i] != NULL )
SHPDestroyTreeNode( psTreeNode->apsSubNode[i] );
}
-
+
if( psTreeNode->panShapeIds != NULL )
free( psTreeNode->panShapeIds );
@@ -342,7 +367,7 @@ SHPCheckBoundsOverlap( double * padfBox1Min, double * padfBox1Max,
{
if( padfBox2Max[iDim] < padfBox1Min[iDim] )
return FALSE;
-
+
if( padfBox1Max[iDim] < padfBox2Min[iDim] )
return FALSE;
}
@@ -363,23 +388,23 @@ static int SHPCheckObjectContained( SHPObject * psObject, int nDimension,
if( psObject->dfXMin < padfBoundsMin[0]
|| psObject->dfXMax > padfBoundsMax[0] )
return FALSE;
-
+
if( psObject->dfYMin < padfBoundsMin[1]
|| psObject->dfYMax > padfBoundsMax[1] )
return FALSE;
if( nDimension == 2 )
return TRUE;
-
+
if( psObject->dfZMin < padfBoundsMin[2]
- || psObject->dfZMax < padfBoundsMax[2] )
+ || psObject->dfZMax > padfBoundsMax[2] )
return FALSE;
-
+
if( nDimension == 3 )
return TRUE;
if( psObject->dfMMin < padfBoundsMin[3]
- || psObject->dfMMax < padfBoundsMax[3] )
+ || psObject->dfMMax > padfBoundsMax[3] )
return FALSE;
return TRUE;
@@ -392,7 +417,7 @@ static int SHPCheckObjectContained( SHPObject * psObject, int nDimension,
/* longest dimension. */
/************************************************************************/
-void SHPAPI_CALL
+static void
SHPTreeSplitBounds( double *padfBoundsMinIn, double *padfBoundsMaxIn,
double *padfBoundsMin1, double * padfBoundsMax1,
double *padfBoundsMin2, double * padfBoundsMax2 )
@@ -406,7 +431,7 @@ SHPTreeSplitBounds( double *padfBoundsMinIn, double *padfBoundsMaxIn,
memcpy( padfBoundsMax1, padfBoundsMaxIn, sizeof(double) * 4 );
memcpy( padfBoundsMin2, padfBoundsMinIn, sizeof(double) * 4 );
memcpy( padfBoundsMax2, padfBoundsMaxIn, sizeof(double) * 4 );
-
+
/* -------------------------------------------------------------------- */
/* Split in X direction. */
/* -------------------------------------------------------------------- */
@@ -441,9 +466,9 @@ SHPTreeNodeAddShapeId( SHPTreeNode * psTreeNode, SHPObject * psObject,
{
int i;
-
+
/* -------------------------------------------------------------------- */
-/* If there are subnodes, then consider wiether this object */
+/* If there are subnodes, then consider whether this object */
/* will fit in them. */
/* -------------------------------------------------------------------- */
if( nMaxDepth > 1 && psTreeNode->nSubNodes > 0 )
@@ -560,7 +585,7 @@ SHPTreeNodeAddShapeId( SHPTreeNode * psTreeNode, SHPObject * psObject,
/* -------------------------------------------------------------------- */
psTreeNode->nShapeCount++;
- psTreeNode->panShapeIds = (int *)
+ psTreeNode->panShapeIds = (int *)
SfRealloc( psTreeNode->panShapeIds,
sizeof(int) * psTreeNode->nShapeCount );
psTreeNode->panShapeIds[psTreeNode->nShapeCount-1] = psObject->nShapeId;
@@ -600,7 +625,7 @@ SHPTreeAddShapeId( SHPTree * psTree, SHPObject * psObject )
/* tree node by tree node basis. */
/************************************************************************/
-void SHPAPI_CALL
+static void
SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode,
double * padfBoundsMin, double * padfBoundsMax,
int * pnShapeCount, int * pnMaxShapes,
@@ -608,7 +633,7 @@ SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode,
{
int i;
-
+
/* -------------------------------------------------------------------- */
/* Does this node overlap the area of interest at all? If not, */
/* return without adding to the list at all. */
@@ -637,7 +662,7 @@ SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode,
{
(*ppanShapeList)[(*pnShapeCount)++] = psTreeNode->panShapeIds[i];
}
-
+
/* -------------------------------------------------------------------- */
/* Recurse to subnodes if they exist. */
/* -------------------------------------------------------------------- */
@@ -690,7 +715,8 @@ SHPTreeFindLikelyShapes( SHPTree * hTree,
/* Sort the id array */
/* -------------------------------------------------------------------- */
- qsort(panShapeList, *pnShapeCount, sizeof(int), compare_ints);
+ if( panShapeList != NULL )
+ qsort(panShapeList, *pnShapeCount, sizeof(int), compare_ints);
return panShapeList;
}
@@ -698,7 +724,7 @@ SHPTreeFindLikelyShapes( SHPTree * hTree,
/************************************************************************/
/* SHPTreeNodeTrim() */
/* */
-/* This is the recurve version of SHPTreeTrimExtraNodes() that */
+/* This is the recursive version of SHPTreeTrimExtraNodes() that */
/* walks the tree cleaning it up. */
/************************************************************************/
@@ -726,6 +752,29 @@ static int SHPTreeNodeTrim( SHPTreeNode * psTreeNode )
}
/* -------------------------------------------------------------------- */
+/* If the current node has 1 subnode and no shapes, promote that */
+/* subnode to the current node position. */
+/* -------------------------------------------------------------------- */
+ if( psTreeNode->nSubNodes == 1 && psTreeNode->nShapeCount == 0)
+ {
+ SHPTreeNode* psSubNode = psTreeNode->apsSubNode[0];
+
+ memcpy(psTreeNode->adfBoundsMin, psSubNode->adfBoundsMin,
+ sizeof(psSubNode->adfBoundsMin));
+ memcpy(psTreeNode->adfBoundsMax, psSubNode->adfBoundsMax,
+ sizeof(psSubNode->adfBoundsMax));
+ psTreeNode->nShapeCount = psSubNode->nShapeCount;
+ assert(psTreeNode->panShapeIds == NULL);
+ psTreeNode->panShapeIds = psSubNode->panShapeIds;
+ assert(psTreeNode->papsShapeObj == NULL);
+ psTreeNode->papsShapeObj = psSubNode->papsShapeObj;
+ psTreeNode->nSubNodes = psSubNode->nSubNodes;
+ for( i = 0; i < psSubNode->nSubNodes; i++ )
+ psTreeNode->apsSubNode[i] = psSubNode->apsSubNode[i];
+ free(psSubNode);
+ }
+
+/* -------------------------------------------------------------------- */
/* We should be trimmed if we have no subnodes, and no shapes. */
/* -------------------------------------------------------------------- */
return( psTreeNode->nSubNodes == 0 && psTreeNode->nShapeCount == 0 );
@@ -765,29 +814,76 @@ static void SwapWord( int length, void * wordP )
}
}
+
+struct SHPDiskTreeInfo
+{
+ SAHooks sHooks;
+ SAFile fpQIX;
+};
+
+/************************************************************************/
+/* SHPOpenDiskTree() */
+/************************************************************************/
+
+SHPTreeDiskHandle SHPOpenDiskTree( const char* pszQIXFilename,
+ SAHooks *psHooks )
+{
+ SHPTreeDiskHandle hDiskTree;
+
+ hDiskTree = (SHPTreeDiskHandle) calloc(sizeof(struct SHPDiskTreeInfo),1);
+
+ if (psHooks == NULL)
+ SASetupDefaultHooks( &(hDiskTree->sHooks) );
+ else
+ memcpy( &(hDiskTree->sHooks), psHooks, sizeof(SAHooks) );
+
+ hDiskTree->fpQIX = hDiskTree->sHooks.FOpen(pszQIXFilename, "rb");
+ if (hDiskTree->fpQIX == NULL)
+ {
+ free(hDiskTree);
+ return NULL;
+ }
+
+ return hDiskTree;
+}
+
+/***********************************************************************/
+/* SHPCloseDiskTree() */
+/************************************************************************/
+
+void SHPCloseDiskTree( SHPTreeDiskHandle hDiskTree )
+{
+ if (hDiskTree == NULL)
+ return;
+
+ hDiskTree->sHooks.FClose(hDiskTree->fpQIX);
+ free(hDiskTree);
+}
+
/************************************************************************/
/* SHPSearchDiskTreeNode() */
/************************************************************************/
static int
-SHPSearchDiskTreeNode( FILE *fp, double *padfBoundsMin, double *padfBoundsMax,
- int **ppanResultBuffer, int *pnBufferMax,
- int *pnResultCount, int bNeedSwap )
+SHPSearchDiskTreeNode( SHPTreeDiskHandle hDiskTree, double *padfBoundsMin, double *padfBoundsMax,
+ int **ppanResultBuffer, int *pnBufferMax,
+ int *pnResultCount, int bNeedSwap, int nRecLevel )
{
- int i;
- int offset;
- int numshapes, numsubnodes;
+ unsigned int i;
+ unsigned int offset;
+ unsigned int numshapes, numsubnodes;
double adfNodeBoundsMin[2], adfNodeBoundsMax[2];
+ int nFReadAcc;
/* -------------------------------------------------------------------- */
/* Read and unswap first part of node info. */
/* -------------------------------------------------------------------- */
- fread( &offset, 4, 1, fp );
+ nFReadAcc = (int)hDiskTree->sHooks.FRead( &offset, 4, 1, hDiskTree->fpQIX );
if ( bNeedSwap ) SwapWord ( 4, &offset );
- fread( adfNodeBoundsMin, sizeof(double), 2, fp );
- fread( adfNodeBoundsMax, sizeof(double), 2, fp );
+ nFReadAcc += (int)hDiskTree->sHooks.FRead( adfNodeBoundsMin, sizeof(double), 2, hDiskTree->fpQIX );
+ nFReadAcc += (int)hDiskTree->sHooks.FRead( adfNodeBoundsMax, sizeof(double), 2, hDiskTree->fpQIX );
if ( bNeedSwap )
{
SwapWord( 8, adfNodeBoundsMin + 0 );
@@ -795,36 +891,75 @@ SHPSearchDiskTreeNode( FILE *fp, double *padfBoundsMin, double *padfBoundsMax,
SwapWord( 8, adfNodeBoundsMax + 0 );
SwapWord( 8, adfNodeBoundsMax + 1 );
}
-
- fread( &numshapes, 4, 1, fp );
+
+ nFReadAcc += (int)hDiskTree->sHooks.FRead( &numshapes, 4, 1, hDiskTree->fpQIX );
if ( bNeedSwap ) SwapWord ( 4, &numshapes );
+ /* Check that we could read all previous values */
+ if( nFReadAcc != 1 + 2 + 2 + 1 )
+ {
+ hDiskTree->sHooks.Error("I/O error");
+ return FALSE;
+ }
+
+ /* Sanity checks to avoid int overflows in later computation */
+ if( offset > INT_MAX - sizeof(int) )
+ {
+ hDiskTree->sHooks.Error("Invalid value for offset");
+ return FALSE;
+ }
+
+ if( numshapes > (INT_MAX - offset - sizeof(int)) / sizeof(int) ||
+ numshapes > INT_MAX / sizeof(int) - *pnResultCount )
+ {
+ hDiskTree->sHooks.Error("Invalid value for numshapes");
+ return FALSE;
+ }
+
/* -------------------------------------------------------------------- */
/* If we don't overlap this node at all, we can just fseek() */
/* pass this node info and all subnodes. */
/* -------------------------------------------------------------------- */
- if( !SHPCheckBoundsOverlap( adfNodeBoundsMin, adfNodeBoundsMax,
+ if( !SHPCheckBoundsOverlap( adfNodeBoundsMin, adfNodeBoundsMax,
padfBoundsMin, padfBoundsMax, 2 ) )
{
offset += numshapes*sizeof(int) + sizeof(int);
- fseek(fp, offset, SEEK_CUR);
+ hDiskTree->sHooks.FSeek(hDiskTree->fpQIX, offset, SEEK_CUR);
return TRUE;
}
/* -------------------------------------------------------------------- */
/* Add all the shapeids at this node to our list. */
/* -------------------------------------------------------------------- */
- if(numshapes > 0)
+ if(numshapes > 0)
{
- if( *pnResultCount + numshapes > *pnBufferMax )
+ if( *pnResultCount + numshapes > (unsigned int)*pnBufferMax )
{
- *pnBufferMax = (int) ((*pnResultCount + numshapes + 100) * 1.25);
- *ppanResultBuffer = (int *)
+ int* pNewBuffer;
+
+ *pnBufferMax = (*pnResultCount + numshapes + 100) * 5 / 4;
+
+ if( (size_t)*pnBufferMax > INT_MAX / sizeof(int) )
+ *pnBufferMax = *pnResultCount + numshapes;
+
+ pNewBuffer = (int *)
SfRealloc( *ppanResultBuffer, *pnBufferMax * sizeof(int) );
+
+ if( pNewBuffer == NULL )
+ {
+ hDiskTree->sHooks.Error("Out of memory error");
+ return FALSE;
+ }
+
+ *ppanResultBuffer = pNewBuffer;
}
- fread( *ppanResultBuffer + *pnResultCount,
- sizeof(int), numshapes, fp );
+ if( hDiskTree->sHooks.FRead( *ppanResultBuffer + *pnResultCount,
+ sizeof(int), numshapes, hDiskTree->fpQIX ) != numshapes )
+ {
+ hDiskTree->sHooks.Error("I/O error");
+ return FALSE;
+ }
if (bNeedSwap )
{
@@ -832,20 +967,29 @@ SHPSearchDiskTreeNode( FILE *fp, double *padfBoundsMin, double *padfBoundsMax,
SwapWord( 4, *ppanResultBuffer + *pnResultCount + i );
}
- *pnResultCount += numshapes;
- }
+ *pnResultCount += numshapes;
+ }
/* -------------------------------------------------------------------- */
/* Process the subnodes. */
/* -------------------------------------------------------------------- */
- fread( &numsubnodes, 4, 1, fp );
+ if( hDiskTree->sHooks.FRead( &numsubnodes, 4, 1, hDiskTree->fpQIX ) != 1 )
+ {
+ hDiskTree->sHooks.Error("I/O error");
+ return FALSE;
+ }
if ( bNeedSwap ) SwapWord ( 4, &numsubnodes );
+ if( numsubnodes > 0 && nRecLevel == 32 )
+ {
+ hDiskTree->sHooks.Error("Shape tree is too deep");
+ return FALSE;
+ }
for(i=0; i<numsubnodes; i++)
{
- if( !SHPSearchDiskTreeNode( fp, padfBoundsMin, padfBoundsMax,
- ppanResultBuffer, pnBufferMax,
- pnResultCount, bNeedSwap ) )
+ if( !SHPSearchDiskTreeNode( hDiskTree, padfBoundsMin, padfBoundsMax,
+ ppanResultBuffer, pnBufferMax,
+ pnResultCount, bNeedSwap, nRecLevel + 1 ) )
return FALSE;
}
@@ -853,13 +997,58 @@ SHPSearchDiskTreeNode( FILE *fp, double *padfBoundsMin, double *padfBoundsMax,
}
/************************************************************************/
+/* SHPTreeReadLibc() */
+/************************************************************************/
+
+static
+SAOffset SHPTreeReadLibc( void *p, SAOffset size, SAOffset nmemb, SAFile file )
+
+{
+ return (SAOffset) fread( p, (size_t) size, (size_t) nmemb,
+ (FILE *) file );
+}
+
+/************************************************************************/
+/* SHPTreeSeekLibc() */
+/************************************************************************/
+
+static
+SAOffset SHPTreeSeekLibc( SAFile file, SAOffset offset, int whence )
+
+{
+ return (SAOffset) fseek( (FILE *) file, (long) offset, whence );
+}
+
+/************************************************************************/
/* SHPSearchDiskTree() */
/************************************************************************/
-int SHPAPI_CALL1(*)
-SHPSearchDiskTree( FILE *fp,
+int SHPAPI_CALL1(*)
+SHPSearchDiskTree( FILE *fp,
double *padfBoundsMin, double *padfBoundsMax,
int *pnShapeCount )
+{
+ struct SHPDiskTreeInfo sDiskTree;
+ memset(&sDiskTree.sHooks, 0, sizeof(sDiskTree.sHooks));
+
+ /* We do not use SASetupDefaultHooks() because the FILE* */
+ /* is a libc FILE* */
+ sDiskTree.sHooks.FSeek = SHPTreeSeekLibc;
+ sDiskTree.sHooks.FRead = SHPTreeReadLibc;
+
+ sDiskTree.fpQIX = (SAFile)fp;
+
+ return SHPSearchDiskTreeEx( &sDiskTree, padfBoundsMin, padfBoundsMax,
+ pnShapeCount );
+}
+
+/***********************************************************************/
+/* SHPSearchDiskTreeEx() */
+/************************************************************************/
+
+int* SHPSearchDiskTreeEx( SHPTreeDiskHandle hDiskTree,
+ double *padfBoundsMin, double *padfBoundsMax,
+ int *pnShapeCount )
{
int i, bNeedSwap, nBufferMax = 0;
@@ -880,8 +1069,8 @@ SHPSearchDiskTree( FILE *fp,
/* -------------------------------------------------------------------- */
/* Read the header. */
/* -------------------------------------------------------------------- */
- fseek( fp, 0, SEEK_SET );
- fread( abyBuf, 16, 1, fp );
+ hDiskTree->sHooks.FSeek( hDiskTree->fpQIX, 0, SEEK_SET );
+ hDiskTree->sHooks.FRead( abyBuf, 16, 1, hDiskTree->fpQIX );
if( memcmp( abyBuf, "SQT", 3 ) != 0 )
return NULL;
@@ -893,11 +1082,11 @@ SHPSearchDiskTree( FILE *fp,
bNeedSwap = TRUE;
/* -------------------------------------------------------------------- */
-/* Search through root node and it's decendents. */
+/* Search through root node and it's descendants. */
/* -------------------------------------------------------------------- */
- if( !SHPSearchDiskTreeNode( fp, padfBoundsMin, padfBoundsMax,
- &panResultBuffer, &nBufferMax,
- pnShapeCount, bNeedSwap ) )
+ if( !SHPSearchDiskTreeNode( hDiskTree, padfBoundsMin, padfBoundsMax,
+ &panResultBuffer, &nBufferMax,
+ pnShapeCount, bNeedSwap, 0 ) )
{
if( panResultBuffer != NULL )
free( panResultBuffer );
@@ -907,8 +1096,14 @@ SHPSearchDiskTree( FILE *fp,
/* -------------------------------------------------------------------- */
/* Sort the id array */
/* -------------------------------------------------------------------- */
- qsort(panResultBuffer, *pnShapeCount, sizeof(int), compare_ints);
-
+
+ /* To distinguish between empty intersection from error case */
+ if( panResultBuffer == NULL )
+ panResultBuffer = (int*) calloc(1, sizeof(int));
+ else
+ qsort(panResultBuffer, *pnShapeCount, sizeof(int), compare_ints);
+
+
return panResultBuffer;
}
@@ -920,16 +1115,16 @@ SHPSearchDiskTree( FILE *fp,
/* seek past them all efficiently. */
/************************************************************************/
-static int SHPGetSubNodeOffset( SHPTreeNode *node)
+static int SHPGetSubNodeOffset( SHPTreeNode *node)
{
int i;
- long offset=0;
+ int offset=0;
- for(i=0; i<node->nSubNodes; i++ )
+ for(i=0; i<node->nSubNodes; i++ )
{
- if(node->apsSubNode[i])
+ if(node->apsSubNode[i])
{
- offset += 4*sizeof(double)
+ offset += 4*sizeof(double)
+ (node->apsSubNode[i]->nShapeCount+3)*sizeof(int);
offset += SHPGetSubNodeOffset(node->apsSubNode[i]);
}
@@ -942,26 +1137,26 @@ static int SHPGetSubNodeOffset( SHPTreeNode *node)
/* SHPWriteTreeNode() */
/************************************************************************/
-static void SHPWriteTreeNode( FILE *fp, SHPTreeNode *node)
+static void SHPWriteTreeNode( SAFile fp, SHPTreeNode *node, SAHooks* psHooks)
{
int i,j;
int offset;
unsigned char *pabyRec = NULL;
- assert( NULL != node );
+ assert( NULL != node );
offset = SHPGetSubNodeOffset(node);
-
- pabyRec = (unsigned char *)
+
+ pabyRec = (unsigned char *)
malloc(sizeof(double) * 4
+ (3 * sizeof(int)) + (node->nShapeCount * sizeof(int)) );
- if( NULL == pabyRec )
- {
+ if( NULL == pabyRec )
+ {
#ifdef USE_CPL
- CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure");
+ CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure");
#endif
- assert( 0 );
- }
- assert( NULL != pabyRec );
+ assert( 0 );
+ return;
+ }
memcpy( pabyRec, &offset, 4);
@@ -973,16 +1168,17 @@ static void SHPWriteTreeNode( FILE *fp, SHPTreeNode *node)
memcpy( pabyRec+36, &node->nShapeCount, 4);
j = node->nShapeCount * sizeof(int);
- memcpy( pabyRec+40, node->panShapeIds, j);
+ if( j )
+ memcpy( pabyRec+40, node->panShapeIds, j);
memcpy( pabyRec+j+40, &node->nSubNodes, 4);
- fwrite( pabyRec, 44+j, 1, fp );
+ psHooks->FWrite( pabyRec, 44+j, 1, fp );
free (pabyRec);
-
- for(i=0; i<node->nSubNodes; i++ )
+
+ for(i=0; i<node->nSubNodes; i++ )
{
if(node->apsSubNode[i])
- SHPWriteTreeNode( fp, node->apsSubNode[i]);
+ SHPWriteTreeNode( fp, node->apsSubNode[i], psHooks);
}
}
@@ -990,18 +1186,38 @@ static void SHPWriteTreeNode( FILE *fp, SHPTreeNode *node)
/* SHPWriteTree() */
/************************************************************************/
-int SHPWriteTree(SHPTree *tree, const char *filename )
+int SHPAPI_CALL SHPWriteTree(SHPTree *tree, const char *filename )
+{
+ SAHooks sHooks;
+
+ SASetupDefaultHooks( &sHooks );
+
+ return SHPWriteTreeLL(tree, filename, &sHooks);
+}
+
+/************************************************************************/
+/* SHPWriteTreeLL() */
+/************************************************************************/
+
+int SHPWriteTreeLL(SHPTree *tree, const char *filename, SAHooks* psHooks )
{
char signature[4] = "SQT";
int i;
char abyBuf[32];
- FILE *fp;
-
+ SAFile fp;
+
+ SAHooks sHooks;
+ if (psHooks == NULL)
+ {
+ SASetupDefaultHooks( &sHooks );
+ psHooks = &sHooks;
+ }
+
/* -------------------------------------------------------------------- */
/* Open the output file. */
/* -------------------------------------------------------------------- */
- fp = fopen(filename, "wb");
- if( fp == NULL )
+ fp = psHooks->FOpen(filename, "wb");
+ if( fp == NULL )
{
return FALSE;
}
@@ -1014,12 +1230,12 @@ int SHPWriteTree(SHPTree *tree, const char *filename )
bBigEndian = FALSE;
else
bBigEndian = TRUE;
-
+
/* -------------------------------------------------------------------- */
/* Write the header. */
/* -------------------------------------------------------------------- */
memcpy( abyBuf+0, signature, 3 );
-
+
if( bBigEndian )
abyBuf[3] = 2; /* New MSB */
else
@@ -1030,21 +1246,21 @@ int SHPWriteTree(SHPTree *tree, const char *filename )
abyBuf[6] = 0;
abyBuf[7] = 0;
- fwrite( abyBuf, 8, 1, fp );
+ psHooks->FWrite( abyBuf, 8, 1, fp );
- fwrite( &(tree->nTotalCount), 4, 1, fp );
+ psHooks->FWrite( &(tree->nTotalCount), 4, 1, fp );
/* write maxdepth */
- fwrite( &(tree->nMaxDepth), 4, 1, fp );
+ psHooks->FWrite( &(tree->nMaxDepth), 4, 1, fp );
/* -------------------------------------------------------------------- */
/* Write all the nodes "in order". */
/* -------------------------------------------------------------------- */
- SHPWriteTreeNode( fp, tree->psRoot );
-
- fclose( fp );
+ SHPWriteTreeNode( fp, tree->psRoot, psHooks );
+
+ psHooks->FClose( fp );
return TRUE;
}