[Thuban-commits] r2796 - in branches/WIP-pyshapelib-Unicode/thuban: . libraries/pyshapelib libraries/shapelib
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Wed Dec 12 23:32:37 CET 2007
Author: bramz
Date: 2007-12-12 23:32:34 +0100 (Wed, 12 Dec 2007)
New Revision: 2796
Added:
branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/safileio.c
Modified:
branches/WIP-pyshapelib-Unicode/thuban/ChangeLog
branches/WIP-pyshapelib-Unicode/thuban/libraries/pyshapelib/setup.py
branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/dbfopen.c
branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shapefil.h
branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shpopen.c
branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shptree.c
branches/WIP-pyshapelib-Unicode/thuban/setup.py
Log:
Porting shapelib from maptools source cvs.maptools.org.
Currently, this will have no support for code pages and wide
character filenames (Win32), and might miss some bugfixes
from our side, but we'll get that back in later. See ChangeLog.
Modified: branches/WIP-pyshapelib-Unicode/thuban/ChangeLog
===================================================================
--- branches/WIP-pyshapelib-Unicode/thuban/ChangeLog 2007-12-12 20:35:20 UTC (rev 2795)
+++ branches/WIP-pyshapelib-Unicode/thuban/ChangeLog 2007-12-12 22:32:34 UTC (rev 2796)
@@ -1,3 +1,19 @@
+2007-12-12 Bram de Greve <bram.degreve at gmail.com>
+
+ Porting shapelib from maptools source cvs.maptools.org.
+ Currently, this will have no support for code pages and wide
+ character filenames (Win32), but we'll get that back in later,
+ parallel with the cvs.maptools.org source tree. There might be
+ some bugfixes from our side missing, but we'll sort that out later
+ as well.
+
+ * libraries/shapelib: Revisions on cvs.maptools.org that have been
+ ported from: shapefil.h v1.40, shpopen.c v1.57, dbfopen.c v1.76,
+ shptree.c v1.11, safileio.c v1.1.
+
+ * setup.py, libraries/pyshapelib/setup.py: add safileio.c to build
+ process and use the dbf_macros() in setup.py as well.
+
2007-12-09 Bernhard Reiter <bernhard at intevation.de>
WMS Extention improvements: Better logging for problem analysis.
Modified: branches/WIP-pyshapelib-Unicode/thuban/libraries/pyshapelib/setup.py
===================================================================
--- branches/WIP-pyshapelib-Unicode/thuban/libraries/pyshapelib/setup.py 2007-12-12 20:35:20 UTC (rev 2795)
+++ branches/WIP-pyshapelib-Unicode/thuban/libraries/pyshapelib/setup.py 2007-12-12 22:32:34 UTC (rev 2796)
@@ -39,7 +39,7 @@
DBFUpdateHeader function and '0' otherwise. To check whether
DBFUpdateHeader is available, we scan shapefil.h for the string
'DBFUpdateHeader'.
- - HAVE_LANGUAGE_DRIVER, whics is '1' if the dbflib version we will
+ - HAVE_LANGUAGE_DRIVER, which is '1' if the dbflib version we will
compiling with has the nLanguageDriver field in DBFInfo and '0' otherwise.
Again, shapefil.h is scanned to check this.
"""
@@ -50,7 +50,7 @@
def have(keyword):
if keyword in contents:
return "1"
- return 0
+ return "0"
return [
("HAVE_UPDATE_HEADER", have("DBFUpdateHeader")),
@@ -59,14 +59,16 @@
extensions = [Extension("shapelib",
["shapelibmodule.c",
shp_dir + "/shpopen.c",
- shp_dir + "/shptree.c"],
+ shp_dir + "/shptree.c",
+ shp_dir + "/safileio.c"],
include_dirs = [shp_dir]),
Extension("shptree",
["shptreemodule.c"],
include_dirs = [shp_dir]),
Extension("dbflib",
["dbflibmodule.c",
- shp_dir + "/dbfopen.c"],
+ shp_dir + "/dbfopen.c",
+ shp_dir + "/safileio.c"],
include_dirs = [shp_dir],
define_macros = dbf_macros())]
Modified: branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/dbfopen.c
===================================================================
--- branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/dbfopen.c 2007-12-12 20:35:20 UTC (rev 2795)
+++ branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/dbfopen.c 2007-12-12 22:32:34 UTC (rev 2796)
@@ -33,212 +33,83 @@
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
- * $Log$
- * Revision 1.3 2004/05/17 15:47:57 bh
- * Update to newest shapelib and get rid of Thuban specific extensions,
- * i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge
+ * $Log: dbfopen.c,v $
+ * Revision 1.76 2007/12/12 22:21:32 bram
+ * DBFClose: check for NULL psDBF handle before trying to close it.
*
- * * libraries/shapelib/shpopen.c: Update to version from current
- * shapelib CVS.
+ * Revision 1.75 2007/12/06 13:58:19 fwarmerdam
+ * make sure file offset calculations are done in as SAOffset
*
- * * libraries/shapelib/shapefil.h: Update to version from current
- * shapelib CVS.
+ * Revision 1.74 2007/12/06 07:00:25 fwarmerdam
+ * dbfopen now using SAHooks for fileio
*
- * * libraries/shapelib/dbfopen.c: Update to version from current
- * shapelib CVS.
- * (DBFCommit): Effectively removed since shapelib itself has
- * DBFUpdateHeader now which is better for what DBFCommit wanted to
- * achieve.
- * We're now using an unmodified version of dbfopen.
+ * Revision 1.73 2007/09/03 19:48:11 fwarmerdam
+ * move DBFReadAttribute() static dDoubleField into dbfinfo
*
- * * libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
- * Update from dbflib.i
+ * Revision 1.72 2007/09/03 19:34:06 fwarmerdam
+ * Avoid use of static tuple buffer in DBFReadTuple()
*
- * * libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
- * the commit method. This new indirection is necessary because we use the
- * DBFUpdateHeader function now which is not available in shapelib <=
- * 1.2.10
- * (DBFFile::commit): Use DBFInfo_commit as implementation
- * (pragma __class__): New. Kludge to remove the commit method when
- * the DBFUpdateHeader function isn't available
- * (_have_commit): New. Helper for the pragma kludge.
+ * Revision 1.71 2006/06/22 14:37:18 fwarmerdam
+ * avoid memory leak if dbfopen fread fails
*
- * * libraries/pyshapelib/setup.py (dbf_macros): New. Return the
- * preprocessor macros needed to compile the dbflib wrapper. Determine
- * whether DBFUpdateHeader is available and define the right value of
- * HAVE_UPDATE_HEADER
- * (extensions): Use dbf_macros for the dbflibc extension
+ * Revision 1.70 2006/06/17 17:47:05 fwarmerdam
+ * use calloc() for dbfinfo in DBFCreate
*
- * * setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
- * value '1' to the Lib.dbflibc extension. This simply reflects the
- * shapelib and pyshapelib updates
+ * Revision 1.69 2006/06/17 15:34:32 fwarmerdam
+ * disallow creating fields wider than 255
*
- * Revision 1.53 2003/12/29 00:00:30 fwarmerdam
- * mark DBFWriteAttributeDirectly as SHPAPI_CALL
+ * Revision 1.68 2006/06/17 15:12:40 fwarmerdam
+ * Fixed C++ style comments.
*
- * Revision 1.52 2003/07/08 15:20:03 warmerda
- * avoid warnings about downcasting to unsigned char
+ * Revision 1.67 2006/06/17 00:24:53 fwarmerdam
+ * Don't treat non-zero decimals values as high order byte for length
+ * for strings. It causes serious corruption for some files.
+ * http://bugzilla.remotesensing.org/show_bug.cgi?id=1202
*
- * Revision 1.51 2003/07/08 13:50:15 warmerda
- * DBFIsAttributeNULL check for pszValue==NULL - bug 360
+ * Revision 1.66 2006/03/29 18:26:20 fwarmerdam
+ * fixed bug with size of pachfieldtype in dbfcloneempty
*
- * Revision 1.50 2003/04/21 18:58:25 warmerda
- * ensure current record is flushed at same time as header is updated
+ * Revision 1.65 2006/02/15 01:14:30 fwarmerdam
+ * added DBFAddNativeFieldType
*
- * Revision 1.49 2003/04/21 18:30:37 warmerda
- * added header write/update public methods
+ * Revision 1.64 2006/02/09 00:29:04 fwarmerdam
+ * Changed to put spaces into string fields that are NULL as
+ * per http://bugzilla.maptools.org/show_bug.cgi?id=316.
*
- * Revision 1.48 2003/03/10 14:51:27 warmerda
- * DBFWrite* calls now return FALSE if they have to truncate
+ * Revision 1.63 2006/01/25 15:35:43 fwarmerdam
+ * check success on DBFFlushRecord
*
- * Revision 1.47 2002/11/20 03:32:22 warmerda
- * Ensure field name in DBFGetFieldIndex() is properly terminated.
+ * Revision 1.62 2006/01/10 16:28:03 fwarmerdam
+ * Fixed typo in CPLError.
*
- * Revision 1.46 2002/10/09 13:10:21 warmerda
- * Added check that width is positive.
+ * Revision 1.61 2006/01/10 16:26:29 fwarmerdam
+ * Push loading record buffer into DBFLoadRecord.
+ * Implement CPL error reporting if USE_CPL defined.
*
- * Revision 1.45 2002/09/29 00:00:08 warmerda
- * added FTLogical and logical attribute read/write calls
+ * Revision 1.60 2006/01/05 01:27:27 fwarmerdam
+ * added dbf deletion mark/fetch
*
- * Revision 1.44 2002/05/07 13:46:11 warmerda
- * Added DBFWriteAttributeDirectly().
+ * Revision 1.59 2005/03/14 15:20:28 fwarmerdam
+ * Fixed last change.
*
- * Revision 1.43 2002/02/13 19:39:21 warmerda
- * Fix casting issues in DBFCloneEmpty().
+ * Revision 1.58 2005/03/14 15:18:54 fwarmerdam
+ * Treat very wide fields with no decimals as double. This is
+ * more than 32bit integer fields.
*
- * Revision 1.42 2002/01/15 14:36:07 warmerda
- * updated email address
+ * Revision 1.57 2005/02/10 20:16:54 fwarmerdam
+ * Make the pszStringField buffer for DBFReadAttribute() static char [256]
+ * as per bug 306.
*
- * Revision 1.41 2002/01/15 14:31:49 warmerda
- * compute rather than copying nHeaderLength in DBFCloneEmpty()
+ * Revision 1.56 2005/02/10 20:07:56 fwarmerdam
+ * Fixed bug 305 in DBFCloneEmpty() - header length problem.
*
- * Revision 1.40 2002/01/09 04:32:35 warmerda
- * fixed to read correct amount of header
+ * Revision 1.55 2004/09/26 20:23:46 fwarmerdam
+ * avoid warnings with rcsid and signed/unsigned stuff
*
- * Revision 1.39 2001/12/11 22:41:03 warmerda
- * improve io related error checking when reading header
- *
- * Revision 1.38 2001/11/28 16:07:31 warmerda
- * Cleanup to avoid compiler warnings as suggested by Richard Hash.
- *
- * Revision 1.37 2001/07/04 05:18:09 warmerda
- * do last fix properly
- *
- * Revision 1.36 2001/07/04 05:16:09 warmerda
- * fixed fieldname comparison in DBFGetFieldIndex
- *
- * Revision 1.35 2001/06/22 02:10:06 warmerda
- * fixed NULL shape support with help from Jim Matthews
- *
- * Revision 1.33 2001/05/31 19:20:13 warmerda
- * added DBFGetFieldIndex()
- *
- * Revision 1.32 2001/05/31 18:15:40 warmerda
- * Added support for NULL fields in DBF files
- *
- * Revision 1.31 2001/05/23 13:36:52 warmerda
- * added use of SHPAPI_CALL
- *
- * Revision 1.30 2000/12/05 14:43:38 warmerda
- * DBReadAttribute() white space trimming bug fix
- *
- * Revision 1.29 2000/10/05 14:36:44 warmerda
- * fix bug with writing very wide numeric fields
- *
- * Revision 1.28 2000/09/25 14:18:07 warmerda
- * Added some casts of strlen() return result to fix warnings on some
- * systems, as submitted by Daniel.
- *
- * Revision 1.27 2000/09/25 14:15:51 warmerda
- * added DBFGetNativeFieldType()
- *
- * Revision 1.26 2000/07/07 13:39:45 warmerda
- * removed unused variables, and added system include files
- *
- * Revision 1.25 2000/05/29 18:19:13 warmerda
- * avoid use of uchar, and adding casting fix
- *
- * Revision 1.24 2000/05/23 13:38:27 warmerda
- * Added error checks on return results of fread() and fseek().
- *
- * Revision 1.23 2000/05/23 13:25:49 warmerda
- * Avoid crashing if field or record are out of range in dbfread*attribute().
- *
- * Revision 1.22 1999/12/15 13:47:24 warmerda
- * Added stdlib.h to ensure that atof() is prototyped.
- *
- * Revision 1.21 1999/12/13 17:25:46 warmerda
- * Added support for upper case .DBF extention.
- *
- * Revision 1.20 1999/11/30 16:32:11 warmerda
- * Use atof() instead of sscanf().
- *
- * Revision 1.19 1999/11/05 14:12:04 warmerda
- * updated license terms
- *
- * Revision 1.18 1999/07/27 00:53:28 warmerda
- * ensure that whole old field value clear on write of string
- *
- * Revision 1.1 1999/07/05 18:58:07 warmerda
- * New
- *
- * Revision 1.17 1999/06/11 19:14:12 warmerda
- * Fixed some memory leaks.
- *
- * Revision 1.16 1999/06/11 19:04:11 warmerda
- * Remoted some unused variables.
- *
- * Revision 1.15 1999/05/11 03:19:28 warmerda
- * added new Tuple api, and improved extension handling - add from candrsn
- *
- * Revision 1.14 1999/05/04 15:01:48 warmerda
- * Added 'F' support.
- *
- * Revision 1.13 1999/03/23 17:38:59 warmerda
- * DBFAddField() now actually does return the new field number, or -1 if
- * it fails.
- *
- * Revision 1.12 1999/03/06 02:54:46 warmerda
- * Added logic to convert shapefile name to dbf filename in DBFOpen()
- * for convenience.
- *
- * Revision 1.11 1998/12/31 15:30:34 warmerda
- * Improved the interchangability of numeric and string attributes. Add
- * white space trimming option for attributes.
- *
- * Revision 1.10 1998/12/03 16:36:44 warmerda
- * Use r+b instead of rb+ for binary access.
- *
- * Revision 1.9 1998/12/03 15:34:23 warmerda
- * Updated copyright message.
- *
- * Revision 1.8 1997/12/04 15:40:15 warmerda
- * Added newline character after field definitions.
- *
- * Revision 1.7 1997/03/06 14:02:10 warmerda
- * Ensure bUpdated is initialized.
- *
- * Revision 1.6 1996/02/12 04:54:41 warmerda
- * Ensure that DBFWriteAttribute() returns TRUE if it succeeds.
- *
- * Revision 1.5 1995/10/21 03:15:12 warmerda
- * Changed to use binary file access, and ensure that the
- * field name field is zero filled, and limited to 10 chars.
- *
- * Revision 1.4 1995/08/24 18:10:42 warmerda
- * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such
- * as on the Sun.
- *
- * Revision 1.3 1995/08/04 03:15:16 warmerda
- * Fixed up header.
- *
- * Revision 1.2 1995/08/04 03:14:43 warmerda
- * Added header.
+ * Revision 1.54 2004/09/15 16:26:10 fwarmerdam
+ * Treat all blank numeric fields as null too.
*/
-static char rcsid[] =
- "$Id$";
-
#include "shapefil.h"
#include <math.h>
@@ -246,43 +117,14 @@
#include <ctype.h>
#include <string.h>
+SHP_CVSID("$Id$")
+
#ifndef FALSE
# define FALSE 0
# define TRUE 1
#endif
-#if defined(_WIN32) || defined(_WIN64)
-# define MS_WINDOWS
-#endif
-
-static int nStringFieldLen = 0;
-static char * pszStringField = NULL;
-
/************************************************************************/
-/* DBFSet_atof_function() */
-/* */
-/* This makes it possible to initialise a different atof() function */
-/* which might be necessary because the standard atof() might be */
-/* sensitive to locale settings. */
-/* */
-/* If the calling application uses a locale with different decimal_point*/
-/* it should better also give us a locale agnostic atof() function. */
-/* */
-/* As far as I can see from Python PEP331 and GNU libc documentation */
-/* there is no standard for such a function yet. */
-/* */
-/* bernhard.reiter at intevation.de 20060924 */
-/************************************************************************/
-
-static double (* atof_function)(const char *nptr) = &atof;
-
-void SHPAPI_CALL
- DBFSetatof_function( double (* new_atof_function)(const char *nptr))
-{
- atof_function = new_atof_function;
-}
-
-/************************************************************************/
/* SfRealloc() */
/* */
/* A realloc cover function that will access a NULL pointer as */
@@ -339,15 +181,14 @@
abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
- abyHeader[29] = (unsigned char) (psDBF->nLanguageDriver);
-
/* -------------------------------------------------------------------- */
/* Write the initial 32 byte file header, and all the field */
/* descriptions. */
/* -------------------------------------------------------------------- */
- fseek( psDBF->fp, 0, 0 );
- fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
- fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );
+ 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->fp );
/* -------------------------------------------------------------------- */
/* Write out the newline character if there is room for it. */
@@ -357,7 +198,7 @@
char cNewline;
cNewline = 0x0d;
- fwrite( &cNewline, 1, 1, psDBF->fp );
+ psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
}
}
@@ -367,24 +208,90 @@
/* Write out the current record if there is one. */
/************************************************************************/
-static void DBFFlushRecord( DBFHandle psDBF )
+static int DBFFlushRecord( DBFHandle psDBF )
{
- int nRecordOffset;
+ SAOffset nRecordOffset;
if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
{
psDBF->bCurrentRecordModified = FALSE;
- nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord
- + psDBF->nHeaderLength;
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord
+ + psDBF->nHeaderLength;
- fseek( psDBF->fp, nRecordOffset, 0 );
- fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
+ 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.",
+ psDBF->nCurrentRecord );
+#endif
+ return FALSE;
+ }
}
+
+ return TRUE;
}
/************************************************************************/
+/* DBFLoadRecord() */
+/************************************************************************/
+
+static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
+
+{
+ if( psDBF->nCurrentRecord != iRecord )
+ {
+ SAOffset nRecordOffset;
+
+ if( !DBFFlushRecord( psDBF ) )
+ return FALSE;
+
+ 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",
+ (long) nRecordOffset );
+#endif
+ return FALSE;
+ }
+
+ 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",
+ psDBF->nRecordLength );
+#endif
+ return FALSE;
+ }
+
+ psDBF->nCurrentRecord = iRecord;
+ }
+
+ return TRUE;
+}
+
+/************************************************************************/
/* DBFUpdateHeader() */
/************************************************************************/
@@ -399,18 +306,18 @@
DBFFlushRecord( psDBF );
- fseek( psDBF->fp, 0, 0 );
- fread( abyFileHeader, 32, 1, psDBF->fp );
+ psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
+ psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
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);
- fseek( psDBF->fp, 0, 0 );
- fwrite( abyFileHeader, 32, 1, psDBF->fp );
+ psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
+ psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
- fflush( psDBF->fp );
+ psDBF->sHooks.FFlush( psDBF->fp );
}
/************************************************************************/
@@ -423,8 +330,26 @@
DBFOpen( const char * pszFilename, const char * pszAccess )
{
- FILE* fp;
- int i;
+ SAHooks sHooks;
+
+ SASetupDefaultHooks( &sHooks );
+
+ return DBFOpenLL( pszFilename, pszAccess, &sHooks );
+}
+
+/************************************************************************/
+/* DBFOpen() */
+/* */
+/* Open a .dbf file. */
+/************************************************************************/
+
+DBFHandle SHPAPI_CALL
+DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
+
+{
+ DBFHandle psDBF;
+ unsigned char *pabyBuf;
+ int nFields, nHeadLen, iField, i;
char *pszBasename, *pszFullname;
/* -------------------------------------------------------------------- */
@@ -458,109 +383,25 @@
pszFullname = (char *) malloc(strlen(pszBasename) + 5);
sprintf( pszFullname, "%s.dbf", pszBasename );
- fp = fopen( pszFullname, pszAccess );
+ psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
+ psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
+ memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
- if( fp == NULL )
+ if( psDBF->fp == NULL )
{
sprintf( pszFullname, "%s.DBF", pszBasename );
- fp = fopen(pszFullname, pszAccess );
+ psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
}
free( pszBasename );
free( pszFullname );
-
- return DBFOpenEx( fp );
-}
-
-
-
-/************************************************************************/
-/* DBFOpenW() */
-/* */
-/* Open a .dbf file with a wide character filename */
-/************************************************************************/
-
-#ifdef SHPAPI_HAS_WIDE
-
-DBFHandle SHPAPI_CALL
-DBFOpenW( const wchar_t * pszFilename, const wchar_t * pszAccess )
-
-{
- FILE* fp;
- int i;
- wchar_t *pszBasename, *pszFullname;
-
-/* -------------------------------------------------------------------- */
-/* We only allow the access strings "rb" and "r+". */
-/* -------------------------------------------------------------------- */
- if( wcscmp(pszAccess,L"r") != 0 && wcscmp(pszAccess,L"r+") != 0
- && wcscmp(pszAccess,L"rb") != 0 && wcscmp(pszAccess,L"rb+") != 0
- && wcscmp(pszAccess,L"r+b") != 0 )
- return( NULL );
-
- if( wcscmp(pszAccess,L"r") == 0 )
- pszAccess = L"rb";
-
- if( wcscmp(pszAccess,L"r+") == 0 )
- pszAccess = L"rb+";
-
-/* -------------------------------------------------------------------- */
-/* Compute the base (layer) name. If there is any extension */
-/* on the passed in filename we will strip it off. */
-/* -------------------------------------------------------------------- */
- pszBasename = (wchar_t *) malloc(sizeof(wchar_t)*(wcslen(pszFilename)+5));
- wcscpy( pszBasename, pszFilename );
- for( i = wcslen(pszBasename)-1;
- i > 0 && pszBasename[i] != L'.' && pszBasename[i] != L'/'
- && pszBasename[i] != L'\\';
- i-- ) {}
-
- if( pszBasename[i] == L'.' )
- pszBasename[i] = L'\0';
-
- pszFullname = (wchar_t *) malloc(sizeof(wchar_t)*(wcslen(pszBasename) + 5));
- swprintf( pszFullname, L"%s.dbf", pszBasename );
-
- fp = _wfopen( pszFullname, pszAccess );
-
- if( fp == NULL )
+
+ if( psDBF->fp == NULL )
{
- swprintf( pszFullname, L"%s.DBF", pszBasename );
- fp = _wfopen(pszFullname, pszAccess );
+ free( psDBF );
+ return( NULL );
}
-
- free( pszBasename );
- free( pszFullname );
- return DBFOpenEx( fp );
-}
-
-#endif
-
-
-
-/************************************************************************/
-/* DBFOpenEx() */
-/* */
-/* Open a .dbf file from a freshly opened FILE */
-/************************************************************************/
-
-DBFHandle SHPAPI_CALL
-DBFOpenEx( FILE* fp )
-
-{
- unsigned char *pabyBuf;
- int nFields, nHeadLen, nRecLen, iField;
- DBFHandle psDBF = NULL;
-
- if( fp == NULL )
- {
- return( NULL );
- }
-
- psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
- psDBF->fp = fp;
-
psDBF->bNoHeader = FALSE;
psDBF->nCurrentRecord = -1;
psDBF->bCurrentRecordModified = FALSE;
@@ -569,9 +410,9 @@
/* Read Table Header info */
/* -------------------------------------------------------------------- */
pabyBuf = (unsigned char *) malloc(500);
- if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
+ if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
{
- fclose( psDBF->fp );
+ psDBF->sHooks.FClose( psDBF->fp );
free( pabyBuf );
free( psDBF );
return NULL;
@@ -581,12 +422,11 @@
pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
- psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;
- psDBF->nLanguageDriver = pabyBuf[29];
+ psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
psDBF->nFields = nFields = (nHeadLen - 32) / 32;
- psDBF->pszCurrentRecord = (char *) malloc(nRecLen);
+ psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
/* -------------------------------------------------------------------- */
/* Read in Field Definitions */
@@ -595,11 +435,12 @@
pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
psDBF->pszHeader = (char *) pabyBuf;
- fseek( psDBF->fp, 32, 0 );
- if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
+ psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
+ if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
{
- fclose( psDBF->fp );
+ psDBF->sHooks.FClose( psDBF->fp );
free( pabyBuf );
+ free( psDBF->pszCurrentRecord );
free( psDBF );
return NULL;
}
@@ -622,8 +463,17 @@
}
else
{
+ psDBF->panFieldSize[iField] = pabyFInfo[16];
+ psDBF->panFieldDecimals[iField] = 0;
+
+/*
+** The following seemed to be used sometimes to handle files with long
+** string fields, but in other cases (such as bug 1202) the decimals field
+** just seems to indicate some sort of preferred formatting, not very
+** wide fields. So I have disabled this code. FrankW.
psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
psDBF->panFieldDecimals[iField] = 0;
+*/
}
psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
@@ -644,9 +494,9 @@
void SHPAPI_CALL
DBFClose(DBFHandle psDBF)
{
- if( psDBF == NULL )
- return;
-
+ if( psDBF == NULL )
+ return;
+
/* -------------------------------------------------------------------- */
/* Write out header if not already written. */
/* -------------------------------------------------------------------- */
@@ -665,7 +515,7 @@
/* -------------------------------------------------------------------- */
/* Close, and free resources. */
/* -------------------------------------------------------------------- */
- fclose( psDBF->fp );
+ psDBF->sHooks.FClose( psDBF->fp );
if( psDBF->panFieldOffset != NULL )
{
@@ -675,17 +525,13 @@
free( psDBF->pachFieldType );
}
+ if( psDBF->pszWorkField != NULL )
+ free( psDBF->pszWorkField );
+
free( psDBF->pszHeader );
free( psDBF->pszCurrentRecord );
free( psDBF );
-
- if( pszStringField != NULL )
- {
- free( pszStringField );
- pszStringField = NULL;
- nStringFieldLen = 0;
- }
}
/************************************************************************/
@@ -698,122 +544,69 @@
DBFCreate( const char * pszFilename )
{
- FILE *fp;
- char *pszFullname, *pszBasename;
- int i;
+ SAHooks sHooks;
-/* -------------------------------------------------------------------- */
-/* Compute the base (layer) name. If there is any extension */
-/* on the passed in filename we will strip it off. */
-/* -------------------------------------------------------------------- */
- pszBasename = (char *) malloc(strlen(pszFilename)+5);
- strcpy( pszBasename, pszFilename );
- for( i = strlen(pszBasename)-1;
- i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
- && pszBasename[i] != '\\';
- i-- ) {}
+ SASetupDefaultHooks( &sHooks );
- if( pszBasename[i] == '.' )
- pszBasename[i] = '\0';
-
- pszFullname = (char *) malloc(strlen(pszBasename) + 5);
- sprintf( pszFullname, "%s.dbf", pszBasename );
- free( pszBasename );
-
-/* -------------------------------------------------------------------- */
-/* Create the file. */
-/* -------------------------------------------------------------------- */
- fp = fopen( pszFullname, "wb" );
- if( fp == NULL )
- return( NULL );
-
- fputc( 0, fp );
- fclose( fp );
-
- fp = fopen( pszFullname, "rb+" );
- if( fp == NULL )
- return( NULL );
-
- free( pszFullname );
-
- return DBFCreateEx( fp );
+ return DBFCreateLL( pszFilename, &sHooks );
}
-
-
/************************************************************************/
-/* DBFCreateW() */
+/* DBFCreate() */
/* */
-/* Create a new .dbf file with a wide character filename */
+/* Create a new .dbf file. */
/************************************************************************/
-#ifdef SHPAPI_HAS_WIDE
-
DBFHandle SHPAPI_CALL
-DBFCreateW( const wchar_t * pszFilename )
+DBFCreateLL( const char * pszFilename, SAHooks *psHooks )
{
- FILE *fp;
- wchar_t *pszFullname, *pszBasename;
+ DBFHandle psDBF;
+ SAFile fp;
+ char *pszFullname, *pszBasename;
int i;
+ char chZero = '\0';
/* -------------------------------------------------------------------- */
/* Compute the base (layer) name. If there is any extension */
/* on the passed in filename we will strip it off. */
/* -------------------------------------------------------------------- */
- pszBasename = (wchar_t *) malloc(sizeof(wchar_t)*(wcslen(pszFilename)+5));
- wcscpy( pszBasename, pszFilename );
- for( i = wcslen(pszBasename)-1;
- i > 0 && pszBasename[i] != L'.' && pszBasename[i] != L'/'
- && pszBasename[i] != L'\\';
+ pszBasename = (char *) malloc(strlen(pszFilename)+5);
+ strcpy( pszBasename, pszFilename );
+ for( i = strlen(pszBasename)-1;
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+ && pszBasename[i] != '\\';
i-- ) {}
- if( pszBasename[i] == L'.' )
- pszBasename[i] = L'\0';
+ if( pszBasename[i] == '.' )
+ pszBasename[i] = '\0';
- pszFullname = (wchar_t *) malloc(sizeof(wchar_t)*(wcslen(pszBasename) + 5));
- swprintf( pszFullname, L"%s.dbf", pszBasename );
+ pszFullname = (char *) malloc(strlen(pszBasename) + 5);
+ sprintf( pszFullname, "%s.dbf", pszBasename );
free( pszBasename );
/* -------------------------------------------------------------------- */
/* Create the file. */
/* -------------------------------------------------------------------- */
- fp = _wfopen( pszFullname, L"wb" );
+ fp = psHooks->FOpen( pszFullname, "wb" );
if( fp == NULL )
return( NULL );
+
+ psHooks->FWrite( &chZero, 1, 1, fp );
+ psHooks->FClose( fp );
- fputc( 0, fp );
- fclose( fp );
-
- fp = _wfopen( pszFullname, L"rb+" );
+ fp = psHooks->FOpen( pszFullname, "rb+" );
if( fp == NULL )
return( NULL );
free( pszFullname );
- return DBFCreateEx( fp );
-}
-
-#endif
-
-
-/************************************************************************/
-/* DBFCreateEx() */
-/* */
-/* Create a new .dbf file from a freshly created file */
-/************************************************************************/
-
-DBFHandle SHPAPI_CALL
-DBFCreateEx( FILE* fp )
-
-{
- DBFHandle psDBF;
-
/* -------------------------------------------------------------------- */
/* Create the info structure. */
/* -------------------------------------------------------------------- */
- psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
+ psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo));
+ memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
psDBF->fp = fp;
psDBF->nRecords = 0;
psDBF->nFields = 0;
@@ -831,13 +624,10 @@
psDBF->pszCurrentRecord = NULL;
psDBF->bNoHeader = TRUE;
- psDBF->nLanguageDriver = 0x03; // ANSI
return( psDBF );
}
-
-
/************************************************************************/
/* DBFAddField() */
/* */
@@ -850,6 +640,31 @@
DBFFieldType eType, int nWidth, int nDecimals )
{
+ char chNativeType = 'C';
+
+ if( eType == FTLogical )
+ chNativeType = 'L';
+ else if( eType == FTString )
+ chNativeType = 'C';
+ else
+ chNativeType = 'N';
+
+ return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
+ nWidth, nDecimals );
+}
+
+/************************************************************************/
+/* DBFAddField() */
+/* */
+/* Add a field to a newly created .dbf file before any records */
+/* are written. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
+ char chType, int nWidth, int nDecimals )
+
+{
char *pszFInfo;
int i;
@@ -862,12 +677,12 @@
if( !psDBF->bNoHeader )
return( -1 );
- if( eType != FTDouble && nDecimals != 0 )
- return( -1 );
-
if( nWidth < 1 )
return -1;
+ if( nWidth > 255 )
+ nWidth = 255;
+
/* -------------------------------------------------------------------- */
/* SfRealloc all the arrays larger to hold the additional field */
/* information. */
@@ -875,16 +690,16 @@
psDBF->nFields++;
psDBF->panFieldOffset = (int *)
- SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
+ SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
psDBF->panFieldSize = (int *)
- SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
+ SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
psDBF->panFieldDecimals = (int *)
- SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
+ SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
psDBF->pachFieldType = (char *)
- SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
+ SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
/* -------------------------------------------------------------------- */
/* Assign the new field information fields. */
@@ -893,14 +708,8 @@
psDBF->nRecordLength += nWidth;
psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
+ psDBF->pachFieldType[psDBF->nFields-1] = chType;
- if( eType == FTLogical )
- psDBF->pachFieldType[psDBF->nFields-1] = 'L';
- else if( eType == FTString )
- psDBF->pachFieldType[psDBF->nFields-1] = 'C';
- else
- psDBF->pachFieldType[psDBF->nFields-1] = 'N';
-
/* -------------------------------------------------------------------- */
/* Extend the required header information. */
/* -------------------------------------------------------------------- */
@@ -921,7 +730,7 @@
pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
- if( eType == FTString )
+ if( chType == 'C' )
{
pszFInfo[16] = (unsigned char) (nWidth % 256);
pszFInfo[17] = (unsigned char) (nWidth / 256);
@@ -936,7 +745,7 @@
/* Make the current record buffer appropriately larger. */
/* -------------------------------------------------------------------- */
psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
- psDBF->nRecordLength);
+ psDBF->nRecordLength);
return( psDBF->nFields-1 );
}
@@ -951,12 +760,9 @@
char chReqType )
{
- int nRecordOffset;
unsigned char *pabyRec;
void *pReturnField = NULL;
- static double dDoubleField;
-
/* -------------------------------------------------------------------- */
/* Verify selection. */
/* -------------------------------------------------------------------- */
@@ -969,59 +775,42 @@
/* -------------------------------------------------------------------- */
/* Have we read the record? */
/* -------------------------------------------------------------------- */
- if( psDBF->nCurrentRecord != hEntity )
- {
- DBFFlushRecord( psDBF );
+ if( !DBFLoadRecord( psDBF, hEntity ) )
+ return NULL;
- nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
-
- if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
- {
- fprintf( stderr, "fseek(%d) failed on DBF file.\n",
- nRecordOffset );
- return NULL;
- }
-
- if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength,
- 1, psDBF->fp ) != 1 )
- {
- fprintf( stderr, "fread(%d) failed on DBF file.\n",
- psDBF->nRecordLength );
- return NULL;
- }
-
- psDBF->nCurrentRecord = hEntity;
- }
-
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
/* -------------------------------------------------------------------- */
-/* Ensure our field buffer is large enough to hold this buffer. */
+/* Ensure we have room to extract the target field. */
/* -------------------------------------------------------------------- */
- if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
+ if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
{
- nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
- pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
+ psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
+ if( psDBF->pszWorkField == NULL )
+ psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength);
+ else
+ psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField,
+ psDBF->nWorkFieldLength);
}
/* -------------------------------------------------------------------- */
/* Extract the requested field. */
/* -------------------------------------------------------------------- */
- strncpy( pszStringField,
+ strncpy( psDBF->pszWorkField,
((const char *) pabyRec) + psDBF->panFieldOffset[iField],
psDBF->panFieldSize[iField] );
- pszStringField[psDBF->panFieldSize[iField]] = '\0';
+ psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
- pReturnField = pszStringField;
+ pReturnField = psDBF->pszWorkField;
/* -------------------------------------------------------------------- */
/* Decode the field. */
/* -------------------------------------------------------------------- */
if( chReqType == 'N' )
{
- dDoubleField = (*atof_function)(pszStringField);
+ psDBF->dfDoubleField = atof(psDBF->pszWorkField);
- pReturnField = &dDoubleField;
+ pReturnField = &(psDBF->dfDoubleField);
}
/* -------------------------------------------------------------------- */
@@ -1032,7 +821,7 @@
{
char *pchSrc, *pchDst;
- pchDst = pchSrc = pszStringField;
+ pchDst = pchSrc = psDBF->pszWorkField;
while( *pchSrc == ' ' )
pchSrc++;
@@ -1040,7 +829,7 @@
*(pchDst++) = *(pchSrc++);
*pchDst = '\0';
- while( pchDst != pszStringField && *(--pchDst) == ' ' )
+ while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
*pchDst = '\0';
}
#endif
@@ -1127,6 +916,7 @@
{
const char *pszValue;
+ int i;
pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
@@ -1137,9 +927,21 @@
{
case 'N':
case 'F':
- /* NULL numeric fields have value "****************" */
- return pszValue[0] == '*';
+ /*
+ ** 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;
+ for( i = 0; pszValue[i] != '\0'; i++ )
+ {
+ if( pszValue[i] != ' ' )
+ return FALSE;
+ }
+ return TRUE;
+
case 'D':
/* NULL date fields have value "00000000" */
return strncmp(pszValue,"00000000",8) == 0;
@@ -1214,10 +1016,10 @@
return( FTLogical);
else if( psDBF->pachFieldType[iField] == 'N'
- || psDBF->pachFieldType[iField] == 'F'
- || psDBF->pachFieldType[iField] == 'D' )
+ || psDBF->pachFieldType[iField] == 'F' )
{
- if( psDBF->panFieldDecimals[iField] > 0 )
+ if( psDBF->panFieldDecimals[iField] > 0
+ || psDBF->panFieldSize[iField] > 10 )
return( FTDouble );
else
return( FTInteger );
@@ -1238,7 +1040,7 @@
void * pValue )
{
- int nRecordOffset, i, j, nRetResult = TRUE;
+ int i, j, nRetResult = TRUE;
unsigned char *pabyRec;
char szSField[400], szFormat[20];
@@ -1256,7 +1058,8 @@
/* -------------------------------------------------------------------- */
if( hEntity == psDBF->nRecords )
{
- DBFFlushRecord( psDBF );
+ if( !DBFFlushRecord( psDBF ) )
+ return FALSE;
psDBF->nRecords++;
for( i = 0; i < psDBF->nRecordLength; i++ )
@@ -1269,18 +1072,9 @@
/* Is this an existing record, but different than the last one */
/* we accessed? */
/* -------------------------------------------------------------------- */
- if( psDBF->nCurrentRecord != hEntity )
- {
- DBFFlushRecord( psDBF );
+ if( !DBFLoadRecord( psDBF, hEntity ) )
+ return FALSE;
- nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
-
- fseek( psDBF->fp, nRecordOffset, 0 );
- fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
-
- psDBF->nCurrentRecord = hEntity;
- }
-
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
psDBF->bCurrentRecordModified = TRUE;
@@ -1316,7 +1110,7 @@
default:
/* empty string fields are considered NULL */
- memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0',
+ memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), ' ',
psDBF->panFieldSize[iField] );
break;
}
@@ -1335,7 +1129,7 @@
{
int nWidth = psDBF->panFieldSize[iField];
- if( sizeof(szSField)-2 < nWidth )
+ if( (int) sizeof(szSField)-2 < nWidth )
nWidth = sizeof(szSField)-2;
sprintf( szFormat, "%%%dd", nWidth );
@@ -1353,7 +1147,7 @@
{
int nWidth = psDBF->panFieldSize[iField];
- if( sizeof(szSField)-2 < nWidth )
+ if( (int) sizeof(szSField)-2 < nWidth )
nWidth = sizeof(szSField)-2;
sprintf( szFormat, "%%%d.%df",
@@ -1409,7 +1203,7 @@
void * pValue )
{
- int nRecordOffset, i, j;
+ int i, j;
unsigned char *pabyRec;
/* -------------------------------------------------------------------- */
@@ -1426,7 +1220,8 @@
/* -------------------------------------------------------------------- */
if( hEntity == psDBF->nRecords )
{
- DBFFlushRecord( psDBF );
+ if( !DBFFlushRecord( psDBF ) )
+ return FALSE;
psDBF->nRecords++;
for( i = 0; i < psDBF->nRecordLength; i++ )
@@ -1439,18 +1234,9 @@
/* Is this an existing record, but different than the last one */
/* we accessed? */
/* -------------------------------------------------------------------- */
- if( psDBF->nCurrentRecord != hEntity )
- {
- DBFFlushRecord( psDBF );
+ if( !DBFLoadRecord( psDBF, hEntity ) )
+ return FALSE;
- nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
-
- fseek( psDBF->fp, nRecordOffset, 0 );
- fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
-
- psDBF->nCurrentRecord = hEntity;
- }
-
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
/* -------------------------------------------------------------------- */
@@ -1555,7 +1341,7 @@
DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
{
- int nRecordOffset, i;
+ int i;
unsigned char *pabyRec;
/* -------------------------------------------------------------------- */
@@ -1572,7 +1358,8 @@
/* -------------------------------------------------------------------- */
if( hEntity == psDBF->nRecords )
{
- DBFFlushRecord( psDBF );
+ if( !DBFFlushRecord( psDBF ) )
+ return FALSE;
psDBF->nRecords++;
for( i = 0; i < psDBF->nRecordLength; i++ )
@@ -1585,18 +1372,9 @@
/* Is this an existing record, but different than the last one */
/* we accessed? */
/* -------------------------------------------------------------------- */
- if( psDBF->nCurrentRecord != hEntity )
- {
- DBFFlushRecord( psDBF );
+ if( !DBFLoadRecord( psDBF, hEntity ) )
+ return FALSE;
- nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
-
- fseek( psDBF->fp, nRecordOffset, 0 );
- fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
-
- psDBF->nCurrentRecord = hEntity;
- }
-
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
@@ -1608,49 +1386,23 @@
}
/************************************************************************/
-/* DBFReadTuple() */
+/* DBFReadTuple() */
/* */
-/* Read one of the attribute fields of a record. */
+/* Read a complete record. Note that the result is only valid */
+/* till the next record read for any reason. */
/************************************************************************/
const char SHPAPI_CALL1(*)
DBFReadTuple(DBFHandle psDBF, int hEntity )
{
- int nRecordOffset;
- unsigned char *pabyRec;
- static char *pReturnTuple = NULL;
-
- static int nTupleLen = 0;
-
-/* -------------------------------------------------------------------- */
-/* Have we read the record? */
-/* -------------------------------------------------------------------- */
if( hEntity < 0 || hEntity >= psDBF->nRecords )
return( NULL );
- if( psDBF->nCurrentRecord != hEntity )
- {
- DBFFlushRecord( psDBF );
+ if( !DBFLoadRecord( psDBF, hEntity ) )
+ return NULL;
- nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
-
- fseek( psDBF->fp, nRecordOffset, 0 );
- fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
-
- psDBF->nCurrentRecord = hEntity;
- }
-
- pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
-
- if ( nTupleLen < psDBF->nRecordLength) {
- nTupleLen = psDBF->nRecordLength;
- pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
- }
-
- memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
-
- return( pReturnTuple );
+ return (const char *) psDBF->pszCurrentRecord;
}
/************************************************************************/
@@ -1665,76 +1417,33 @@
DBFHandle newDBF;
newDBF = DBFCreate ( pszFilename );
- if ( newDBF == NULL ) return ( NULL );
-
- DBFCloneEmptyEx( psDBF, newDBF );
-
- DBFClose( newDBF );
- newDBF = DBFOpen ( pszFilename, "rb+" );
-
- return ( newDBF );
-}
-
-
-
-
-/************************************************************************/
-/* DBFCloneEmptyW */
-/* */
-/* Read one of the attribute fields of a record. */
-/************************************************************************/
-
-#ifdef SHPAPI_HAS_WIDE
-
-DBFHandle SHPAPI_CALL
-DBFCloneEmptyW(DBFHandle psDBF, const wchar_t * pszFilename )
-{
- DBFHandle newDBF;
-
- newDBF = DBFCreateW ( pszFilename );
- if ( newDBF == NULL ) return ( NULL );
-
- DBFCloneEmptyEx( psDBF, newDBF );
-
- DBFClose( newDBF );
- newDBF = DBFOpenW ( pszFilename, L"rb+" );
-
- return ( newDBF );
-}
-
-#endif
-
-/************************************************************************/
-/* DBFCloneEmptyEx() */
-/* */
-/* Read one of the attribute fields of a record. */
-/************************************************************************/
-
-void SHPAPI_CALL
-DBFCloneEmptyEx(DBFHandle psDBF, DBFHandle newDBF)
-{
- if ( newDBF == NULL ) return;
+ if ( newDBF == NULL ) return ( NULL );
- newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
- memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
-
newDBF->nFields = psDBF->nFields;
newDBF->nRecordLength = psDBF->nRecordLength;
- newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
+ 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 );
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 );
newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
- newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
- memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
+ newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields );
+ memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
newDBF->bNoHeader = TRUE;
newDBF->bUpdated = TRUE;
DBFWriteHeader ( newDBF );
+ DBFClose ( newDBF );
+
+ newDBF = DBFOpen ( pszFilename, "rb+" );
+
+ return ( newDBF );
}
/************************************************************************/
@@ -1804,3 +1513,72 @@
}
return(-1);
}
+
+/************************************************************************/
+/* DBFIsRecordDeleted() */
+/* */
+/* Returns TRUE if the indicated record is deleted, otherwise */
+/* it returns FALSE. */
+/************************************************************************/
+
+int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
+
+{
+/* -------------------------------------------------------------------- */
+/* Verify selection. */
+/* -------------------------------------------------------------------- */
+ if( iShape < 0 || iShape >= psDBF->nRecords )
+ return TRUE;
+
+/* -------------------------------------------------------------------- */
+/* Have we read the record? */
+/* -------------------------------------------------------------------- */
+ if( !DBFLoadRecord( psDBF, iShape ) )
+ return FALSE;
+
+/* -------------------------------------------------------------------- */
+/* '*' means deleted. */
+/* -------------------------------------------------------------------- */
+ return psDBF->pszCurrentRecord[0] == '*';
+}
+
+/************************************************************************/
+/* DBFMarkRecordDeleted() */
+/************************************************************************/
+
+int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
+ int bIsDeleted )
+
+{
+ char chNewFlag;
+
+/* -------------------------------------------------------------------- */
+/* Verify selection. */
+/* -------------------------------------------------------------------- */
+ if( iShape < 0 || iShape >= psDBF->nRecords )
+ return FALSE;
+
+/* -------------------------------------------------------------------- */
+/* Is this an existing record, but different than the last one */
+/* we accessed? */
+/* -------------------------------------------------------------------- */
+ if( !DBFLoadRecord( psDBF, iShape ) )
+ return FALSE;
+
+/* -------------------------------------------------------------------- */
+/* Assign value, marking record as dirty if it changes. */
+/* -------------------------------------------------------------------- */
+ if( bIsDeleted )
+ chNewFlag = '*';
+ else
+ chNewFlag = ' ';
+
+ if( psDBF->pszCurrentRecord[0] != chNewFlag )
+ {
+ psDBF->bCurrentRecordModified = TRUE;
+ psDBF->bUpdated = TRUE;
+ psDBF->pszCurrentRecord[0] = chNewFlag;
+ }
+
+ return TRUE;
+}
Added: branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/safileio.c
===================================================================
--- branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/safileio.c 2007-12-12 20:35:20 UTC (rev 2795)
+++ branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/safileio.c 2007-12-12 22:32:34 UTC (rev 2796)
@@ -0,0 +1,151 @@
+/******************************************************************************
+ * $Id: safileio.c,v 1.1 2007/12/06 06:56:41 fwarmerdam Exp $
+ *
+ * Project: Shapelib
+ * Purpose: Default implementation of file io based on stdio.
+ * Author: Frank Warmerdam, warmerdam at pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2007, Frank Warmerdam
+ *
+ * This software is available under the following "MIT Style" license,
+ * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
+ * option is discussed in more detail in shapelib.html.
+ *
+ * --
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ *
+ * $Log: safileio.c,v $
+ * Revision 1.1 2007/12/06 06:56:41 fwarmerdam
+ * new
+ *
+ */
+
+#include "shapefil.h"
+
+#include <math.h>
+#include <limits.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+SHP_CVSID("$Id: safileio.c,v 1.1 2007/12/06 06:56:41 fwarmerdam Exp $");
+
+/************************************************************************/
+/* SADFOpen() */
+/************************************************************************/
+
+SAFile SADFOpen( const char *pszFilename, const char *pszAccess )
+
+{
+ return (SAFile) fopen( pszFilename, pszAccess );
+}
+
+/************************************************************************/
+/* SADFRead() */
+/************************************************************************/
+
+SAOffset SADFRead( void *p, SAOffset size, SAOffset nmemb, SAFile file )
+
+{
+ return (SAOffset) fread( p, (size_t) size, (size_t) nmemb,
+ (FILE *) file );
+}
+
+/************************************************************************/
+/* SADFWrite() */
+/************************************************************************/
+
+SAOffset SADFWrite( void *p, SAOffset size, SAOffset nmemb, SAFile file )
+
+{
+ return (SAOffset) fwrite( p, (size_t) size, (size_t) nmemb,
+ (FILE *) file );
+}
+
+/************************************************************************/
+/* SADFSeek() */
+/************************************************************************/
+
+SAOffset SADFSeek( SAFile file, SAOffset offset, int whence )
+
+{
+ return (SAOffset) fseek( (FILE *) file, (long) offset, whence );
+}
+
+/************************************************************************/
+/* SADFTell() */
+/************************************************************************/
+
+SAOffset SADFTell( SAFile file )
+
+{
+ return (SAOffset) ftell( (FILE *) file );
+}
+
+/************************************************************************/
+/* SADFFlush() */
+/************************************************************************/
+
+int SADFFlush( SAFile file )
+
+{
+ return fflush( (FILE *) file );
+}
+
+/************************************************************************/
+/* SADFClose() */
+/************************************************************************/
+
+int SADFClose( SAFile file )
+
+{
+ return fclose( (FILE *) file );
+}
+
+/************************************************************************/
+/* SADError() */
+/************************************************************************/
+
+void SADError( const char *message )
+
+{
+ fprintf( stderr, "%s\n", message );
+}
+
+/************************************************************************/
+/* SASetupDefaultHooks() */
+/************************************************************************/
+
+void SASetupDefaultHooks( SAHooks *psHooks )
+
+{
+ psHooks->FOpen = SADFOpen;
+ psHooks->FRead = SADFRead;
+ psHooks->FWrite = SADFWrite;
+ psHooks->FSeek = SADFSeek;
+ psHooks->FTell = SADFTell;
+ psHooks->FFlush = SADFFlush;
+ psHooks->FClose = SADFClose;
+
+ psHooks->Error = SADError;
+}
Modified: branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shapefil.h
===================================================================
--- branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shapefil.h 2007-12-12 20:35:20 UTC (rev 2795)
+++ branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shapefil.h 2007-12-12 22:32:34 UTC (rev 2796)
@@ -36,46 +36,44 @@
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
- * $Log$
- * Revision 1.3 2004/05/17 15:47:57 bh
- * Update to newest shapelib and get rid of Thuban specific extensions,
- * i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge
+ * $Log: shapefil.h,v $
+ * Revision 1.40 2007/12/06 07:00:25 fwarmerdam
+ * dbfopen now using SAHooks for fileio
*
- * * libraries/shapelib/shpopen.c: Update to version from current
- * shapelib CVS.
+ * Revision 1.39 2007/12/04 20:37:56 fwarmerdam
+ * preliminary implementation of hooks api for io and errors
*
- * * libraries/shapelib/shapefil.h: Update to version from current
- * shapelib CVS.
+ * Revision 1.38 2007/11/21 22:39:56 fwarmerdam
+ * close shx file in readonly mode (GDAL #1956)
*
- * * libraries/shapelib/dbfopen.c: Update to version from current
- * shapelib CVS.
- * (DBFCommit): Effectively removed since shapelib itself has
- * DBFUpdateHeader now which is better for what DBFCommit wanted to
- * achieve.
- * We're now using an unmodified version of dbfopen.
+ * Revision 1.37 2007/10/27 03:31:14 fwarmerdam
+ * limit default depth of tree to 12 levels (gdal ticket #1594)
*
- * * libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
- * Update from dbflib.i
+ * Revision 1.36 2007/09/10 23:33:15 fwarmerdam
+ * Upstreamed support for visibility flag in SHPAPI_CALL for the needs
+ * of GDAL (gdal ticket #1810).
*
- * * libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
- * the commit method. This new indirection is necessary because we use the
- * DBFUpdateHeader function now which is not available in shapelib <=
- * 1.2.10
- * (DBFFile::commit): Use DBFInfo_commit as implementation
- * (pragma __class__): New. Kludge to remove the commit method when
- * the DBFUpdateHeader function isn't available
- * (_have_commit): New. Helper for the pragma kludge.
+ * Revision 1.35 2007/09/03 19:48:10 fwarmerdam
+ * move DBFReadAttribute() static dDoubleField into dbfinfo
*
- * * libraries/pyshapelib/setup.py (dbf_macros): New. Return the
- * preprocessor macros needed to compile the dbflib wrapper. Determine
- * whether DBFUpdateHeader is available and define the right value of
- * HAVE_UPDATE_HEADER
- * (extensions): Use dbf_macros for the dbflibc extension
+ * Revision 1.34 2006/06/17 15:33:32 fwarmerdam
+ * added pszWorkField - bug 1202 (rso)
*
- * * setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
- * value '1' to the Lib.dbflibc extension. This simply reflects the
- * shapelib and pyshapelib updates
+ * Revision 1.33 2006/02/15 01:14:30 fwarmerdam
+ * added DBFAddNativeFieldType
*
+ * Revision 1.32 2006/01/26 15:07:32 fwarmerdam
+ * add bMeasureIsUsed flag from Craig Bruce: Bug 1249
+ *
+ * Revision 1.31 2006/01/05 01:27:27 fwarmerdam
+ * added dbf deletion mark/fetch
+ *
+ * Revision 1.30 2005/01/03 22:30:13 fwarmerdam
+ * added support for saved quadtrees
+ *
+ * Revision 1.29 2004/09/26 20:09:35 fwarmerdam
+ * avoid rcsid warnings
+ *
* Revision 1.28 2003/12/29 06:02:18 fwarmerdam
* added cpl_error.h option
*
@@ -96,67 +94,6 @@
*
* Revision 1.22 2002/01/15 14:32:00 warmerda
* try to improve SHPAPI_CALL docs
- *
- * Revision 1.21 2001/11/01 16:29:55 warmerda
- * move pabyRec into SHPInfo for thread safety
- *
- * Revision 1.20 2001/07/20 13:06:02 warmerda
- * fixed SHPAPI attribute for SHPTreeFindLikelyShapes
- *
- * Revision 1.19 2001/05/31 19:20:13 warmerda
- * added DBFGetFieldIndex()
- *
- * Revision 1.18 2001/05/31 18:15:40 warmerda
- * Added support for NULL fields in DBF files
- *
- * Revision 1.17 2001/05/23 13:36:52 warmerda
- * added use of SHPAPI_CALL
- *
- * Revision 1.16 2000/09/25 14:15:59 warmerda
- * added DBFGetNativeFieldType()
- *
- * Revision 1.15 2000/02/16 16:03:51 warmerda
- * added null shape support
- *
- * Revision 1.14 1999/11/05 14:12:05 warmerda
- * updated license terms
- *
- * Revision 1.13 1999/06/02 18:24:21 warmerda
- * added trimming code
- *
- * Revision 1.12 1999/06/02 17:56:12 warmerda
- * added quad'' subnode support for trees
- *
- * Revision 1.11 1999/05/18 19:11:11 warmerda
- * Added example searching capability
- *
- * Revision 1.10 1999/05/18 17:49:38 warmerda
- * added initial quadtree support
- *
- * Revision 1.9 1999/05/11 03:19:28 warmerda
- * added new Tuple api, and improved extension handling - add from candrsn
- *
- * Revision 1.8 1999/03/23 17:22:27 warmerda
- * Added extern "C" protection for C++ users of shapefil.h.
- *
- * Revision 1.7 1998/12/31 15:31:07 warmerda
- * Added the TRIM_DBF_WHITESPACE and DISABLE_MULTIPATCH_MEASURE options.
- *
- * Revision 1.6 1998/12/03 15:48:15 warmerda
- * Added SHPCalculateExtents().
- *
- * Revision 1.5 1998/11/09 20:57:16 warmerda
- * Altered SHPGetInfo() call.
- *
- * Revision 1.4 1998/11/09 20:19:33 warmerda
- * Added 3D support, and use of SHPObject.
- *
- * Revision 1.3 1995/08/23 02:24:05 warmerda
- * Added support for reading bounds.
- *
- * Revision 1.2 1995/08/04 03:17:39 warmerda
- * Added header.
- *
*/
#include <stdio.h>
@@ -173,10 +110,6 @@
extern "C" {
#endif
-#if defined(_WIN32) || defined(_WIN64)
-#define SHPAPI_HAS_WIDE
-#endif
-
/************************************************************************/
/* Configuration options. */
/************************************************************************/
@@ -193,7 +126,7 @@
/* is disabled. */
/* -------------------------------------------------------------------- */
#define DISABLE_MULTIPATCH_MEASURE
-
+
/* -------------------------------------------------------------------- */
/* SHPAPI_CALL */
/* */
@@ -229,21 +162,62 @@
#endif
#ifndef SHPAPI_CALL
-# define SHPAPI_CALL
+# if defined(USE_GCC_VISIBILITY_FLAG)
+# define SHPAPI_CALL __attribute__ ((visibility("default")))
+# define SHPAPI_CALL1(x) __attribute__ ((visibility("default"))) x
+# else
+# define SHPAPI_CALL
+# endif
#endif
#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 ); }
+#else
+# define SHP_CVSID(string)
+#endif
+
+/* -------------------------------------------------------------------- */
+/* IO/Error hook functions. */
+/* -------------------------------------------------------------------- */
+typedef int *SAFile;
+
+#ifndef SAOffset
+typedef unsigned long SAOffset;
+#endif
+
+typedef struct {
+ SAFile (*FOpen) ( const char *filename, const char *path);
+ SAOffset (*FRead) ( void *p, SAOffset size, SAOffset nmemb, SAFile file);
+ SAOffset (*FWrite)( void *p, SAOffset size, SAOffset nmemb, SAFile file);
+ SAOffset (*FSeek) ( SAFile file, SAOffset offset, int whence );
+ SAOffset (*FTell) ( SAFile file );
+ int (*FFlush)( SAFile file );
+ int (*FClose)( SAFile file );
+
+ void (*Error) ( const char *message );
+} SAHooks;
+
+void SHPAPI_CALL SASetupDefaultHooks( SAHooks *psHooks );
+
/************************************************************************/
/* SHP Support. */
/************************************************************************/
typedef struct
{
- FILE *fpSHP;
- FILE *fpSHX;
+ SAHooks sHooks;
+ SAFile fpSHP;
+ SAFile fpSHX;
+
int nShapeType; /* SHPT_* */
int nFileSize; /* SHP file */
@@ -324,27 +298,27 @@
double dfYMax;
double dfZMax;
double dfMMax;
+
+ int bMeasureIsUsed;
} SHPObject;
/* -------------------------------------------------------------------- */
/* SHP API Prototypes */
/* -------------------------------------------------------------------- */
+
+/* If pszAccess is read-only, the fpSHX field of the returned structure */
+/* will be NULL as it is not necessary to keep the SHX file open */
SHPHandle SHPAPI_CALL
SHPOpen( const char * pszShapeFile, const char * pszAccess );
SHPHandle SHPAPI_CALL
+ SHPOpenLL( const char *pszShapeFile, const char *pszAccess,
+ SAHooks *psHooks );
+SHPHandle SHPAPI_CALL
SHPCreate( const char * pszShapeFile, int nShapeType );
-#ifdef SHPAPI_HAS_WIDE
SHPHandle SHPAPI_CALL
- SHPOpenW( const wchar_t * pszShapeFile, const wchar_t * pszAccess );
-SHPHandle SHPAPI_CALL
- SHPCreateW( const wchar_t * pszShapeFile, int nShapeType );
-#endif
-SHPHandle SHPAPI_CALL
- SHPOpenEx( FILE * pfSHP, FILE * pfSHX );
+ SHPCreateLL( const char * pszShapeFile, int nShapeType,
+ SAHooks *psHooks );
void SHPAPI_CALL
- SHPCreateEx( FILE * pfSHP, FILE * pfSHX, int nShapeType );
-
-void SHPAPI_CALL
SHPGetInfo( SHPHandle hSHP, int * pnEntities, int * pnShapeType,
double * padfMinBound, double * padfMaxBound );
@@ -358,13 +332,16 @@
void SHPAPI_CALL
SHPComputeExtents( SHPObject * psObject );
SHPObject SHPAPI_CALL1(*)
- SHPCreateObject( int nSHPType, int nShapeId,
- int nParts, int * panPartStart, int * panPartType,
- int nVertices, double * padfX, double * padfY,
- double * padfZ, double * padfM );
+ SHPCreateObject( int nSHPType, int nShapeId, int nParts,
+ const int * panPartStart, const int * panPartType,
+ int nVertices,
+ const double * padfX, const double * padfY,
+ const double * padfZ, const double * padfM );
SHPObject SHPAPI_CALL1(*)
SHPCreateSimpleObject( int nSHPType, int nVertices,
- double * padfX, double * padfY, double * padfZ );
+ const double * padfX,
+ const double * padfY,
+ const double * padfZ );
int SHPAPI_CALL
SHPRewindObject( SHPHandle hSHP, SHPObject * psObject );
@@ -384,6 +361,9 @@
/* this can be two or four for binary or quad tree */
#define MAX_SUBNODE 4
+/* upper limit of tree levels for automatic estimation */
+#define MAX_DEFAULT_TREE_DEPTH 12
+
typedef struct shape_tree_node
{
/* region covered by this node */
@@ -407,6 +387,7 @@
int nMaxDepth;
int nDimension;
+ int nTotalCount;
SHPTreeNode *psRoot;
} SHPTree;
@@ -421,12 +402,6 @@
SHPWriteTree( SHPTree *hTree, const char * pszFilename );
SHPTree SHPAPI_CALL
SHPReadTree( const char * pszFilename );
-#ifdef SHPAPI_HAS_WIDE
-int SHPAPI_CALL
- SHPWriteTreeW( SHPTree *hTree, const wchar_t * pszFilename );
-SHPTree SHPAPI_CALL
- SHPReadTreeW( const wchar_t * pszFilename );
-#endif
int SHPAPI_CALL
SHPTreeAddObject( SHPTree * hTree, SHPObject * psObject );
@@ -446,13 +421,20 @@
int SHPAPI_CALL
SHPCheckBoundsOverlap( double *, double *, double *, double *, int );
+int SHPAPI_CALL1(*)
+SHPSearchDiskTree( FILE *fp,
+ double *padfBoundsMin, double *padfBoundsMax,
+ int *pnShapeCount );
+
/************************************************************************/
/* DBF Support. */
/************************************************************************/
typedef struct
{
- FILE *fp;
+ SAHooks sHooks;
+ SAFile fp;
+
int nRecords;
int nRecordLength;
@@ -468,10 +450,14 @@
int nCurrentRecord;
int bCurrentRecordModified;
char *pszCurrentRecord;
+
+ int nWorkFieldLength;
+ char *pszWorkField;
int bNoHeader;
int bUpdated;
- int nLanguageDriver;
+
+ double dfDoubleField;
} DBFInfo;
typedef DBFInfo * DBFHandle;
@@ -486,24 +472,16 @@
#define XBASE_FLDHDR_SZ 32
-/* to hand over a locale agnostic atof function, if decimal_point != ".\0" */
-void SHPAPI_CALL
- DBFSetatof_function( double (* new_atof_function)(const char *nptr));
DBFHandle SHPAPI_CALL
DBFOpen( const char * pszDBFFile, const char * pszAccess );
DBFHandle SHPAPI_CALL
+ DBFOpenLL( const char * pszDBFFile, const char * pszAccess,
+ SAHooks *psHooks );
+DBFHandle SHPAPI_CALL
DBFCreate( const char * pszDBFFile );
-#ifdef SHPAPI_HAS_WIDE
DBFHandle SHPAPI_CALL
- DBFOpenW( const wchar_t * pszDBFFile, const wchar_t * pszAccess );
-DBFHandle SHPAPI_CALL
- DBFCreateW( const wchar_t * pszDBFFile );
-#endif
-DBFHandle SHPAPI_CALL
- DBFOpenEx( FILE* pf );
-DBFHandle SHPAPI_CALL
- DBFCreateEx( FILE* pf );
+ DBFCreateLL( const char * pszDBFFile, SAHooks *psHooks );
int SHPAPI_CALL
DBFGetFieldCount( DBFHandle psDBF );
@@ -513,6 +491,10 @@
DBFAddField( DBFHandle hDBF, const char * pszFieldName,
DBFFieldType eType, int nWidth, int nDecimals );
+int SHPAPI_CALL
+ DBFAddNativeFieldType( DBFHandle hDBF, const char * pszFieldName,
+ char chType, int nWidth, int nDecimals );
+
DBFFieldType SHPAPI_CALL
DBFGetFieldInfo( DBFHandle psDBF, int iField,
char * pszFieldName, int * pnWidth, int * pnDecimals );
@@ -554,15 +536,13 @@
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 bIsDeleted );
+
DBFHandle SHPAPI_CALL
DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename );
-#ifdef DBFAPI_HAS_WIDE
-DBFHandle SHPAPI_CALL
- DBFCloneEmptyW(DBFHandle psDBF, const wchar_t * pszFilename );
-#endif
-void SHPAPI_CALL
- DBFCloneEmptyEx(DBFHandle psDBF, DBFHandle newDBF );
-
+
void SHPAPI_CALL
DBFClose( DBFHandle hDBF );
void SHPAPI_CALL
Modified: branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shpopen.c
===================================================================
--- branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shpopen.c 2007-12-12 20:35:20 UTC (rev 2795)
+++ branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shpopen.c 2007-12-12 22:32:34 UTC (rev 2796)
@@ -33,46 +33,50 @@
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
- * $Log$
- * Revision 1.3 2004/05/17 15:47:57 bh
- * Update to newest shapelib and get rid of Thuban specific extensions,
- * i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge
+ * $Log: shpopen.c,v $
+ * Revision 1.57 2007/12/06 07:00:25 fwarmerdam
+ * dbfopen now using SAHooks for fileio
*
- * * libraries/shapelib/shpopen.c: Update to version from current
- * shapelib CVS.
+ * Revision 1.56 2007/12/04 20:37:56 fwarmerdam
+ * preliminary implementation of hooks api for io and errors
*
- * * libraries/shapelib/shapefil.h: Update to version from current
- * shapelib CVS.
+ * Revision 1.55 2007/11/21 22:39:56 fwarmerdam
+ * close shx file in readonly mode (GDAL #1956)
*
- * * libraries/shapelib/dbfopen.c: Update to version from current
- * shapelib CVS.
- * (DBFCommit): Effectively removed since shapelib itself has
- * DBFUpdateHeader now which is better for what DBFCommit wanted to
- * achieve.
- * We're now using an unmodified version of dbfopen.
+ * Revision 1.54 2007/11/15 00:12:47 mloskot
+ * Backported recent changes from GDAL (Ticket #1415) to Shapelib.
*
- * * libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
- * Update from dbflib.i
+ * Revision 1.53 2007/11/14 22:31:08 fwarmerdam
+ * checks after mallocs to detect for corrupted/voluntary broken shapefiles.
+ * http://trac.osgeo.org/gdal/ticket/1991
*
- * * libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
- * the commit method. This new indirection is necessary because we use the
- * DBFUpdateHeader function now which is not available in shapelib <=
- * 1.2.10
- * (DBFFile::commit): Use DBFInfo_commit as implementation
- * (pragma __class__): New. Kludge to remove the commit method when
- * the DBFUpdateHeader function isn't available
- * (_have_commit): New. Helper for the pragma kludge.
+ * Revision 1.52 2007/06/21 15:58:33 fwarmerdam
+ * fix for SHPRewindObject when rings touch at one vertex (gdal #976)
*
- * * libraries/pyshapelib/setup.py (dbf_macros): New. Return the
- * preprocessor macros needed to compile the dbflib wrapper. Determine
- * whether DBFUpdateHeader is available and define the right value of
- * HAVE_UPDATE_HEADER
- * (extensions): Use dbf_macros for the dbflibc extension
+ * Revision 1.51 2006/09/04 15:24:01 fwarmerdam
+ * Fixed up log message for 1.49.
*
- * * setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
- * value '1' to the Lib.dbflibc extension. This simply reflects the
- * shapelib and pyshapelib updates
+ * Revision 1.50 2006/09/04 15:21:39 fwarmerdam
+ * fix of last fix
*
+ * Revision 1.49 2006/09/04 15:21:00 fwarmerdam
+ * MLoskot: Added stronger test of Shapefile reading failures, e.g. truncated
+ * files. The problem was discovered by Tim Sutton and reported here
+ * https://svn.qgis.org/trac/ticket/200
+ *
+ * Revision 1.48 2006/01/26 15:07:32 fwarmerdam
+ * add bMeasureIsUsed flag from Craig Bruce: Bug 1249
+ *
+ * Revision 1.47 2006/01/04 20:07:23 fwarmerdam
+ * In SHPWriteObject() make sure that the record length is updated
+ * when rewriting an existing record.
+ *
+ * Revision 1.46 2005/02/11 17:17:46 fwarmerdam
+ * added panPartStart[0] validation
+ *
+ * Revision 1.45 2004/09/26 20:09:48 fwarmerdam
+ * const correctness changes
+ *
* Revision 1.44 2003/12/29 00:18:39 fwarmerdam
* added error checking for failed IO and optional CPL error reporting
*
@@ -212,9 +216,6 @@
*
*/
-static char rcsid[] =
- "$Id$";
-
#include "shapefil.h"
#include <math.h>
@@ -222,7 +223,10 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <stdio.h>
+SHP_CVSID("$Id$")
+
typedef unsigned char uchar;
#if UINT_MAX == 65535
@@ -296,6 +300,12 @@
int32 i32;
double dValue;
int32 *panSHX;
+
+ if (psSHP->fpSHX == NULL)
+ {
+ psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed");
+ return;
+ }
/* -------------------------------------------------------------------- */
/* Prepare header block for .shp file. */
@@ -353,13 +363,10 @@
/* -------------------------------------------------------------------- */
/* Write .shp file header. */
/* -------------------------------------------------------------------- */
- if( fseek( psSHP->fpSHP, 0, 0 ) != 0
- || fwrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
+ if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0
+ || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_OpenFailed,
- "Failure writing .shp header." );
-#endif
+ psSHP->sHooks.Error( "Failure writing .shp header" );
return;
}
@@ -370,13 +377,10 @@
ByteCopy( &i32, abyHeader+24, 4 );
if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
- if( fseek( psSHP->fpSHX, 0, 0 ) != 0
- || fwrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
+ if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0
+ || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_OpenFailed,
- "Failure writing .shx header." );
-#endif
+ psSHP->sHooks.Error( "Failure writing .shx header" );
return;
}
@@ -393,13 +397,10 @@
if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
}
- if( fwrite( panSHX, sizeof(int32) * 2, psSHP->nRecords, psSHP->fpSHX )
+ if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX )
!= psSHP->nRecords )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_OpenFailed,
- "Failure writing .shx contents." );
-#endif
+ psSHP->sHooks.Error( "Failure writing .shx contents" );
}
free( panSHX );
@@ -407,24 +408,42 @@
/* -------------------------------------------------------------------- */
/* Flush to disk. */
/* -------------------------------------------------------------------- */
- fflush( psSHP->fpSHP );
- fflush( psSHP->fpSHX );
+ psSHP->sHooks.FFlush( psSHP->fpSHP );
+ psSHP->sHooks.FFlush( psSHP->fpSHX );
}
/************************************************************************/
-/* shpopen() */
+/* SHPOpen() */
+/************************************************************************/
+
+SHPHandle SHPAPI_CALL
+SHPOpen( const char * pszLayer, const char * pszAccess )
+
+{
+ SAHooks sHooks;
+
+ SASetupDefaultHooks( &sHooks );
+
+ return SHPOpenLL( pszLayer, pszAccess, &sHooks );
+}
+
+/************************************************************************/
+/* SHPOpen() */
/* */
/* Open the .shp and .shx files based on the basename of the */
/* files or either file name. */
/************************************************************************/
SHPHandle SHPAPI_CALL
-SHPOpen( const char * pszLayer, const char * pszAccess )
+SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
{
char *pszFullname, *pszBasename;
- FILE *fpSHP, *fpSHX;
+ SHPHandle psSHP;
+
+ uchar *pabyBuf;
int i;
+ double dValue;
/* -------------------------------------------------------------------- */
/* Ensure the access string is one of the legal ones. We */
@@ -447,6 +466,14 @@
bBigEndian = TRUE;
/* -------------------------------------------------------------------- */
+/* Initialize the info structure. */
+/* -------------------------------------------------------------------- */
+ psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
+
+ psSHP->bUpdated = FALSE;
+ 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. */
/* -------------------------------------------------------------------- */
@@ -465,42 +492,44 @@
/* a PC to Unix with upper case filenames won't work! */
/* -------------------------------------------------------------------- */
pszFullname = (char *) malloc(strlen(pszBasename) + 5);
- sprintf( pszFullname, "%s.shp", pszBasename );
- fpSHP = fopen(pszFullname, pszAccess );
- if( fpSHP == NULL )
+ sprintf( pszFullname, "%s.shp", pszBasename ) ;
+ psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
+ if( psSHP->fpSHP == NULL )
{
sprintf( pszFullname, "%s.SHP", pszBasename );
- fpSHP = fopen(pszFullname, pszAccess );
+ psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
}
- if( fpSHP == NULL )
+ if( psSHP->fpSHP == NULL )
{
#ifdef USE_CPL
CPLError( CE_Failure, CPLE_OpenFailed,
"Unable to open %s.shp or %s.SHP.",
pszBasename, pszBasename );
#endif
+ free( psSHP );
free( pszBasename );
free( pszFullname );
return( NULL );
}
sprintf( pszFullname, "%s.shx", pszBasename );
- fpSHX = fopen(pszFullname, pszAccess );
- if( fpSHX == NULL )
+ psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
+ if( psSHP->fpSHX == NULL )
{
sprintf( pszFullname, "%s.SHX", pszBasename );
- fpSHX = fopen(pszFullname, pszAccess );
+ psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
}
- if( fpSHX == NULL )
+ if( psSHP->fpSHX == NULL )
{
#ifdef USE_CPL
CPLError( CE_Failure, CPLE_OpenFailed,
"Unable to open %s.shx or %s.SHX.",
pszBasename, pszBasename );
#endif
- fclose( fpSHP );
+ psSHP->sHooks.FClose( psSHP->fpSHP );
+ free( psSHP );
free( pszBasename );
free( pszFullname );
return( NULL );
@@ -509,143 +538,11 @@
free( pszFullname );
free( pszBasename );
- return SHPOpenEx( fpSHP, fpSHX );
-}
-
-
-/************************************************************************/
-/* SHPOpenW() */
-/* */
-/* Open the .shp and .shx files based on the basename of the */
-/* files or either file name, for wide character filenames */
-/************************************************************************/
-
-#ifdef SHPAPI_HAS_WIDE
-
-SHPHandle SHPAPI_CALL
-SHPOpenW( const wchar_t * pszLayer, const wchar_t * pszAccess )
-
-{
- wchar_t *pszFullname, *pszBasename;
- FILE *fpSHP, *fpSHX;
- int i;
-
/* -------------------------------------------------------------------- */
-/* Ensure the access string is one of the legal ones. We */
-/* ensure the result string indicates binary to avoid common */
-/* problems on Windows. */
-/* -------------------------------------------------------------------- */
- if( wcscmp(pszAccess,L"rb+") == 0 || wcscmp(pszAccess,L"r+b") == 0
- || wcscmp(pszAccess,L"r+") == 0 )
- pszAccess = L"r+b";
- else
- pszAccess = L"rb";
-
-/* -------------------------------------------------------------------- */
-/* Compute the base (layer) name. If there is any extension */
-/* on the passed in filename we will strip it off. */
-/* -------------------------------------------------------------------- */
- pszBasename = (wchar_t *) malloc(sizeof(wchar_t)*(wcslen(pszLayer)+5));
- wcscpy( pszBasename, pszLayer );
- for( i = wcslen(pszBasename)-1;
- i > 0 && pszBasename[i] != L'.' && pszBasename[i] != L'/'
- && pszBasename[i] != L'\\';
- i-- ) {}
-
- if( pszBasename[i] == L'.' )
- pszBasename[i] = L'\0';
-
-/* -------------------------------------------------------------------- */
-/* Open the .shp and .shx files. Note that files pulled from */
-/* a PC to Unix with upper case filenames won't work! */
-/* -------------------------------------------------------------------- */
- pszFullname = (wchar_t *) malloc(sizeof(wchar_t)*(wcslen(pszBasename) + 5));
- swprintf( pszFullname, L"%s.shp", pszBasename );
- fpSHP = _wfopen(pszFullname, pszAccess );
- if( fpSHP == NULL )
- {
- swprintf( pszFullname, L"%s.SHP", pszBasename );
- fpSHP = _wfopen(pszFullname, pszAccess );
- }
-
- if( fpSHP == NULL )
- {
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_OpenFailed,
- "Unable to open .shp file." );
-#endif
- free( pszBasename );
- free( pszFullname );
- return( NULL );
- }
-
- swprintf( pszFullname, L"%s.shx", pszBasename );
- fpSHX = _wfopen(pszFullname, pszAccess );
- if( fpSHX == NULL )
- {
- swprintf( pszFullname, L"%s.SHX", pszBasename );
- fpSHX = _wfopen(pszFullname, pszAccess );
- }
-
- if( fpSHX == NULL )
- {
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_OpenFailed,
- "Unable to open .shx file." );
-#endif
- fclose( fpSHP );
- free( pszBasename );
- free( pszFullname );
- return( NULL );
- }
-
- free( pszFullname );
- free( pszBasename );
-
- return SHPOpenEx( fpSHP, fpSHX );
-}
-
-#endif
-
-/************************************************************************/
-/* shpopen() */
-/* */
-/* Open the .shp and .shx files based on the basename of the */
-/* files or either file name. */
-/************************************************************************/
-
-SHPHandle SHPAPI_CALL
-SHPOpenEx( FILE * fpSHP, FILE * fpSHX )
-{
- SHPHandle psSHP;
- uchar *pabyBuf;
- int i;
- double dValue;
-
-/* -------------------------------------------------------------------- */
-/* Establish the byte order on this machine. */
-/* -------------------------------------------------------------------- */
- i = 1;
- if( *((uchar *) &i) == 1 )
- bBigEndian = FALSE;
- else
- bBigEndian = TRUE;
-
-/* -------------------------------------------------------------------- */
-/* Initialize the info structure. */
-/* -------------------------------------------------------------------- */
- psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
-
- psSHP->fpSHP = fpSHP;
- psSHP->fpSHX = fpSHX;
- psSHP->bUpdated = FALSE;
-
-
-/* -------------------------------------------------------------------- */
/* Read the file size from the SHP file. */
/* -------------------------------------------------------------------- */
pabyBuf = (uchar *) malloc(100);
- fread( pabyBuf, 100, 1, psSHP->fpSHP );
+ psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP );
psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256
+ pabyBuf[25] * 256 * 256
@@ -655,18 +552,15 @@
/* -------------------------------------------------------------------- */
/* Read SHX file Header info */
/* -------------------------------------------------------------------- */
- if( fread( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
+ 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) )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_AppDefined,
- ".shx file is unreadable, or corrupt." );
-#endif
- fclose( psSHP->fpSHP );
- fclose( psSHP->fpSHX );
+ psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." );
+ psSHP->sHooks.FClose( psSHP->fpSHP );
+ psSHP->sHooks.FClose( psSHP->fpSHX );
free( psSHP );
return( NULL );
@@ -680,15 +574,17 @@
if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_AppDefined,
- "Record count in .shp header is %d, which seems\n"
- "unreasonable. Assuming header is corrupt.",
+ char szError[200];
+
+ sprintf( szError,
+ "Record count in .shp header is %d, which seems\n"
+ "unreasonable. Assuming header is corrupt.",
psSHP->nRecords );
-#endif
- fclose( psSHP->fpSHP );
- fclose( psSHP->fpSHX );
+ psSHP->sHooks.Error( szError );
+ psSHP->sHooks.FClose( psSHP->fpSHP );
+ psSHP->sHooks.FClose( psSHP->fpSHX );
free( psSHP );
+ free(pabyBuf);
return( NULL );
}
@@ -740,24 +636,55 @@
(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) );
- if( fread( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ) != psSHP->nRecords )
+
+ if (psSHP->panRecOffset == NULL ||
+ psSHP->panRecSize == NULL ||
+ pabyBuf == NULL)
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_AppDefined,
- "Failed to read all values for %d records in .shx file.",
- psSHP->nRecords );
-#endif
+ char szError[200];
+
+ sprintf(szError,
+ "Not enough memory to allocate requested memory (nRecords=%d).\n"
+ "Probably broken SHP file",
+ psSHP->nRecords );
+ psSHP->sHooks.Error( szError );
+ 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 );
+ free( psSHP );
+ return( NULL );
+ }
+
+ 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 );
+ psSHP->sHooks.Error( szError );
+
/* SHX is short or unreadable for some reason. */
- fclose( psSHP->fpSHP );
- fclose( psSHP->fpSHX );
+ psSHP->sHooks.FClose( psSHP->fpSHP );
+ psSHP->sHooks.FClose( psSHP->fpSHX );
free( psSHP->panRecOffset );
free( psSHP->panRecSize );
+ free( pabyBuf );
free( psSHP );
return( NULL );
}
+
+ /* In read-only mode, we can close the SHX now */
+ if (strcmp(pszAccess, "rb") == 0)
+ {
+ psSHP->sHooks.FClose( psSHP->fpSHX );
+ psSHP->fpSHX = NULL;
+ }
for( i = 0; i < psSHP->nRecords; i++ )
{
@@ -802,8 +729,9 @@
free( psSHP->panRecOffset );
free( psSHP->panRecSize );
- fclose( psSHP->fpSHX );
- fclose( psSHP->fpSHP );
+ if ( psSHP->fpSHX != NULL)
+ psSHP->sHooks.FClose( psSHP->fpSHX );
+ psSHP->sHooks.FClose( psSHP->fpSHP );
if( psSHP->pabyRec != NULL )
{
@@ -855,68 +783,13 @@
SHPCreate( const char * pszLayer, int nShapeType )
{
- char *pszBasename, *pszFullname;
- int i;
- FILE *fpSHP, *fpSHX;
+ SAHooks sHooks;
-/* -------------------------------------------------------------------- */
-/* 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-- ) {}
+ SASetupDefaultHooks( &sHooks );
- if( pszBasename[i] == '.' )
- pszBasename[i] = '\0';
-
-/* -------------------------------------------------------------------- */
-/* Open the two files so we can write their headers. */
-/* -------------------------------------------------------------------- */
- pszFullname = (char *) malloc(strlen(pszBasename) + 5);
- sprintf( pszFullname, "%s.shp", pszBasename );
- fpSHP = fopen(pszFullname, "wb" );
- if( fpSHP == NULL )
- {
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_AppDefined,
- "Failed to create file %s.",
- pszFullname );
-#endif
- return( NULL );
- }
-
- sprintf( pszFullname, "%s.shx", pszBasename );
- fpSHX = fopen(pszFullname, "wb" );
- if( fpSHX == NULL )
- {
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_AppDefined,
- "Failed to create file %s.",
- pszFullname );
-#endif
- return( NULL );
- }
-
- free( pszFullname );
- free( pszBasename );
-
- SHPCreateEx( fpSHP, fpSHX, nShapeType );
-
-/* -------------------------------------------------------------------- */
-/* Close the files, and then open them as regular existing files. */
-/* -------------------------------------------------------------------- */
- fclose( fpSHP );
- fclose( fpSHX );
-
- return( SHPOpen( pszLayer, "r+b" ) );
+ return SHPCreateLL( pszLayer, nShapeType, &sHooks );
}
-#ifdef SHPAPI_HAS_WIDE
-
/************************************************************************/
/* SHPCreate() */
/* */
@@ -925,95 +798,63 @@
/************************************************************************/
SHPHandle SHPAPI_CALL
-SHPCreateW( const wchar_t * pszLayer, int nShapeType )
+SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
{
- wchar_t *pszBasename, *pszFullname;
+ char *pszBasename, *pszFullname;
int i;
- FILE *fpSHP, *fpSHX;
+ SAFile fpSHP, fpSHX;
+ uchar abyHeader[100];
+ int32 i32;
+ double dValue;
+
+/* -------------------------------------------------------------------- */
+/* Establish the byte order on this system. */
+/* -------------------------------------------------------------------- */
+ i = 1;
+ if( *((uchar *) &i) == 1 )
+ bBigEndian = FALSE;
+ else
+ bBigEndian = TRUE;
/* -------------------------------------------------------------------- */
/* Compute the base (layer) name. If there is any extension */
/* on the passed in filename we will strip it off. */
/* -------------------------------------------------------------------- */
- pszBasename = (wchar_t *) malloc(sizeof(wchar_t)*(wcslen(pszLayer)+5));
- wcscpy( pszBasename, pszLayer );
- for( i = wcslen(pszBasename)-1;
- i > 0 && pszBasename[i] != L'.' && pszBasename[i] != L'/'
- && pszBasename[i] != L'\\';
+ pszBasename = (char *) malloc(strlen(pszLayer)+5);
+ strcpy( pszBasename, pszLayer );
+ for( i = strlen(pszBasename)-1;
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+ && pszBasename[i] != '\\';
i-- ) {}
- if( pszBasename[i] == L'.' )
- pszBasename[i] = L'\0';
+ if( pszBasename[i] == '.' )
+ pszBasename[i] = '\0';
/* -------------------------------------------------------------------- */
/* Open the two files so we can write their headers. */
/* -------------------------------------------------------------------- */
- pszFullname = (wchar_t *) malloc(sizeof(wchar_t)*(wcslen(pszBasename) + 5));
- swprintf( pszFullname, L"%s.shp", pszBasename );
- fpSHP = _wfopen(pszFullname, L"wb" );
+ pszFullname = (char *) malloc(strlen(pszBasename) + 5);
+ sprintf( pszFullname, "%s.shp", pszBasename );
+ fpSHP = psHooks->FOpen(pszFullname, "wb" );
if( fpSHP == NULL )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_AppDefined,
- "Failed to create file." );
-#endif
+ psHooks->Error( "Failed to create file .shp file." );
return( NULL );
}
- swprintf( pszFullname, L"%s.shx", pszBasename );
- fpSHX = _wfopen(pszFullname, L"wb" );
+ sprintf( pszFullname, "%s.shx", pszBasename );
+ fpSHX = psHooks->FOpen(pszFullname, "wb" );
if( fpSHX == NULL )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_AppDefined,
- "Failed to create file." );
-#endif
+ psHooks->Error( "Failed to create file .shx file." );
return( NULL );
}
free( pszFullname );
free( pszBasename );
- SHPCreateEx( fpSHP, fpSHX, nShapeType );
-
/* -------------------------------------------------------------------- */
-/* Close the files, and then open them as regular existing files. */
-/* -------------------------------------------------------------------- */
- fclose( fpSHP );
- fclose( fpSHX );
-
- return( SHPOpenW( pszLayer, L"r+b" ) );
-}
-
-#endif
-
-/************************************************************************/
-/* SHPCreateEx() */
-/* */
-/* Create a new shape file and return a handle to the open */
-/* shape file with read/write access. */
-/************************************************************************/
-
-void SHPAPI_CALL
-SHPCreateEx( FILE * fpSHP, FILE * fpSHX, int nShapeType )
-
-{
- int i;
- uchar abyHeader[100];
- int32 i32;
- double dValue;
-
-/* -------------------------------------------------------------------- */
-/* Establish the byte order on this system. */
-/* -------------------------------------------------------------------- */
- i = 1;
- if( *((uchar *) &i) == 1 )
- bBigEndian = FALSE;
- else
- bBigEndian = TRUE;
-
-/* -------------------------------------------------------------------- */
/* Prepare header block for .shp file. */
/* -------------------------------------------------------------------- */
for( i = 0; i < 100; i++ )
@@ -1043,13 +884,10 @@
/* -------------------------------------------------------------------- */
/* Write .shp file header. */
/* -------------------------------------------------------------------- */
- if( fwrite( abyHeader, 100, 1, fpSHP ) != 1 )
+ if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_AppDefined,
- "Failed to write .shp header." );
-#endif
- return;
+ psHooks->Error( "Failed to write .shp header." );
+ return NULL;
}
/* -------------------------------------------------------------------- */
@@ -1059,17 +897,21 @@
ByteCopy( &i32, abyHeader+24, 4 );
if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
- if( fwrite( abyHeader, 100, 1, fpSHX ) != 1 )
+ if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_AppDefined,
- "Failed to write .shx header." );
-#endif
- return;
+ psHooks->Error( "Failed to write .shx header." );
+ return NULL;
}
-}
+/* -------------------------------------------------------------------- */
+/* Close the files, and then open them as regular existing files. */
+/* -------------------------------------------------------------------- */
+ psHooks->FClose( fpSHP );
+ psHooks->FClose( fpSHX );
+ return( SHPOpenLL( pszLayer, "r+b", psHooks ) );
+}
+
/************************************************************************/
/* _SHPSetBounds() */
/* */
@@ -1141,9 +983,9 @@
SHPObject SHPAPI_CALL1(*)
SHPCreateObject( int nSHPType, int nShapeId, int nParts,
- int * panPartStart, int * panPartType,
- int nVertices, double * padfX, double * padfY,
- double * padfZ, double * padfM )
+ const int * panPartStart, const int * panPartType,
+ int nVertices, const double *padfX, const double *padfY,
+ const double * padfZ, const double * padfM )
{
SHPObject *psObject;
@@ -1152,6 +994,7 @@
psObject = (SHPObject *) calloc(1,sizeof(SHPObject));
psObject->nSHPType = nSHPType;
psObject->nShapeId = nShapeId;
+ psObject->bMeasureIsUsed = FALSE;
/* -------------------------------------------------------------------- */
/* Establish whether this shape type has M, and Z values. */
@@ -1201,11 +1044,15 @@
for( i = 0; i < nParts; i++ )
{
psObject->panPartStart[i] = panPartStart[i];
+
if( panPartType != NULL )
psObject->panPartType[i] = panPartType[i];
else
psObject->panPartType[i] = SHPP_RING;
}
+
+ if( psObject->panPartStart[0] != 0 )
+ psObject->panPartStart[0] = 0;
}
/* -------------------------------------------------------------------- */
@@ -1231,6 +1078,8 @@
if( padfM != NULL && bHasM )
psObject->padfM[i] = padfM[i];
}
+ if( padfM != NULL && bHasM )
+ psObject->bMeasureIsUsed = TRUE;
}
/* -------------------------------------------------------------------- */
@@ -1251,8 +1100,8 @@
SHPObject SHPAPI_CALL1(*)
SHPCreateSimpleObject( int nSHPType, int nVertices,
- double * padfX, double * padfY,
- double * padfZ )
+ const double * padfX, const double * padfY,
+ const double * padfZ )
{
return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
@@ -1408,13 +1257,14 @@
/*
* Write the M values, if any.
*/
- if( psObject->nSHPType == SHPT_POLYGONM
+ 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_ARCZ) )
{
ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
@@ -1479,8 +1329,9 @@
}
}
- if( psObject->nSHPType == SHPT_MULTIPOINTZ
- || psObject->nSHPType == SHPT_MULTIPOINTM )
+ if( psObject->bMeasureIsUsed
+ && (psObject->nSHPType == SHPT_MULTIPOINTZ
+ || psObject->nSHPType == SHPT_MULTIPOINTM) )
{
ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
@@ -1521,8 +1372,9 @@
nRecordSize += 8;
}
- if( psObject->nSHPType == SHPT_POINTZ
- || psObject->nSHPType == SHPT_POINTM )
+ if( psObject->bMeasureIsUsed
+ && (psObject->nSHPType == SHPT_POINTZ
+ || psObject->nSHPType == SHPT_POINTM) )
{
ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
@@ -1561,6 +1413,7 @@
else
{
nRecordOffset = psSHP->panRecOffset[nShapeId];
+ psSHP->panRecSize[nShapeId] = nRecordSize-8;
}
/* -------------------------------------------------------------------- */
@@ -1581,13 +1434,10 @@
/* -------------------------------------------------------------------- */
/* Write out record. */
/* -------------------------------------------------------------------- */
- if( fseek( psSHP->fpSHP, nRecordOffset, 0 ) != 0
- || fwrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
+ if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0
+ || psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_FileIO,
- "Error in fseek() or fwrite() writing object to .shp file." );
-#endif
+ psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() or fwrite() writing object to .shp file." );
free( pabyRec );
return -1;
}
@@ -1659,19 +1509,31 @@
{
psSHP->nBufSize = psSHP->panRecSize[hEntity]+8;
psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize);
+ if (psSHP->pabyRec == NULL)
+ {
+ char szError[200];
+
+ sprintf( szError,
+ "Not enough memory to allocate requested memory (nBufSize=%d). "
+ "Probably broken SHP file", psSHP->nBufSize );
+ psSHP->sHooks.Error( szError );
+ return NULL;
+ }
}
/* -------------------------------------------------------------------- */
/* Read the record. */
/* -------------------------------------------------------------------- */
- if( fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0
- || fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1,
+ if( psSHP->sHooks.FSeek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0
+ || psSHP->sHooks.FRead( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1,
psSHP->fpSHP ) != 1 )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_FileIO,
- "Error in fseek() or fread() reading object from .shp file." );
-#endif
+ /*
+ * TODO - mloskot: Consider detailed diagnostics of shape file,
+ * for example to detect if file is truncated.
+ */
+
+ psSHP->sHooks.Error( "Error in fseek() or fread() reading object from .shp file." );
return NULL;
}
@@ -1680,6 +1542,7 @@
/* -------------------------------------------------------------------- */
psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
psShape->nShapeId = hEntity;
+ psShape->bMeasureIsUsed = FALSE;
memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
@@ -1720,6 +1583,16 @@
if( bBigEndian ) SwapWord( 4, &nPoints );
if( bBigEndian ) SwapWord( 4, &nParts );
+ if (nPoints < 0 || nParts < 0)
+ {
+#ifdef USE_CPL
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "nPoints=%d, nParts=%d : bad value(s). Probably broken SHP file", nPoints, nParts );
+#endif
+ SHPDestroyObject(psShape);
+ return NULL;
+ }
+
psShape->nVertices = nPoints;
psShape->padfX = (double *) calloc(nPoints,sizeof(double));
psShape->padfY = (double *) calloc(nPoints,sizeof(double));
@@ -1729,6 +1602,22 @@
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 ||
+ psShape->padfM == NULL ||
+ psShape->panPartStart == NULL ||
+ psShape->panPartType == NULL)
+ {
+#ifdef USE_CPL
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d). "
+ "Probably broken SHP file", nPoints, nParts );
+#endif
+ SHPDestroyObject(psShape);
+ return NULL;
+ }
for( i = 0; i < nParts; i++ )
psShape->panPartType[i] = SHPP_RING;
@@ -1820,8 +1709,8 @@
psSHP->pabyRec + nOffset + 16 + i*8, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
}
+ psShape->bMeasureIsUsed = TRUE;
}
-
}
/* ==================================================================== */
@@ -1837,12 +1726,36 @@
memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
if( bBigEndian ) SwapWord( 4, &nPoints );
+ if (nPoints < 0)
+ {
+#ifdef USE_CPL
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "nPoints=%d : bad value. Probably broken SHP file", nPoints );
+#endif
+ 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->padfX == NULL ||
+ psShape->padfY == NULL ||
+ psShape->padfZ == NULL ||
+ psShape->padfM == NULL)
+ {
+#ifdef USE_CPL
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Not enough memory to allocate requested memory (nPoints=%d). "
+ "Probably broken SHP file", nPoints );
+#endif
+ SHPDestroyObject(psShape);
+ return NULL;
+ }
+
for( i = 0; i < nPoints; i++ )
{
memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
@@ -1908,6 +1821,7 @@
psSHP->pabyRec + nOffset + 16 + i*8, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
}
+ psShape->bMeasureIsUsed = TRUE;
}
}
@@ -1957,6 +1871,7 @@
memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfM );
+ psShape->bMeasureIsUsed = TRUE;
}
/* -------------------------------------------------------------------- */
@@ -2128,10 +2043,17 @@
/* first ring is outer and all others are inner, but eventually */
/* we need to fix this to handle multiple island polygons and */
/* unordered sets of rings. */
+/* */
/* -------------------------------------------------------------------- */
- dfTestX = psObject->padfX[psObject->panPartStart[iOpRing]];
- dfTestY = psObject->padfY[psObject->panPartStart[iOpRing]];
+ /* Use point in the middle of segment to avoid testing
+ * common points of rings.
+ */
+ dfTestX = ( psObject->padfX[psObject->panPartStart[iOpRing]]
+ + psObject->padfX[psObject->panPartStart[iOpRing] + 1] ) / 2;
+ dfTestY = ( psObject->padfY[psObject->panPartStart[iOpRing]]
+ + psObject->padfY[psObject->panPartStart[iOpRing] + 1] ) / 2;
+
bInner = FALSE;
for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )
{
@@ -2158,21 +2080,31 @@
else
iNext = 0;
- if( (psObject->padfY[iEdge+nVertStart] < dfTestY
- && psObject->padfY[iNext+nVertStart] >= dfTestY)
- || (psObject->padfY[iNext+nVertStart] < dfTestY
- && psObject->padfY[iEdge+nVertStart] >= dfTestY) )
+ /* 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.
+ */
+ if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY
+ && dfTestY <= psObject->padfY[iNext+nVertStart] )
+ || ( psObject->padfY[iNext+nVertStart] < dfTestY
+ && dfTestY <= psObject->padfY[iEdge+nVertStart] ) )
{
- if( psObject->padfX[iEdge+nVertStart]
- + (dfTestY - psObject->padfY[iEdge+nVertStart])
- / (psObject->padfY[iNext+nVertStart]
- - psObject->padfY[iEdge+nVertStart])
- * (psObject->padfX[iNext+nVertStart]
- - psObject->padfX[iEdge+nVertStart]) < dfTestX )
+ /* Rule #2:
+ * Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY)
+ */
+ float const intersect =
+ ( psObject->padfX[iEdge+nVertStart]
+ + ( dfTestY - psObject->padfY[iEdge+nVertStart] )
+ / ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] )
+ * ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) );
+
+ if (intersect < dfTestX)
+ {
bInner = !bInner;
- }
+ }
+ }
}
- }
+ } /* for iCheckRing */
/* -------------------------------------------------------------------- */
/* Determine the current order of this ring so we will know if */
Modified: branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shptree.c
===================================================================
--- branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shptree.c 2007-12-12 20:35:20 UTC (rev 2795)
+++ branches/WIP-pyshapelib-Unicode/thuban/libraries/shapelib/shptree.c 2007-12-12 22:32:34 UTC (rev 2796)
@@ -33,10 +33,13 @@
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
- * $Log$
- * Revision 1.2 2003/10/02 15:15:16 bh
- * Update to shapelib 1.2.10
+ * $Log: shptree.c,v $
+ * Revision 1.11 2007/10/27 03:31:14 fwarmerdam
+ * limit default depth of tree to 12 levels (gdal ticket #1594)
*
+ * Revision 1.10 2005/01/03 22:30:13 fwarmerdam
+ * added support for saved quadtrees
+ *
* Revision 1.9 2003/01/28 15:53:41 warmerda
* Avoid build warnings.
*
@@ -66,22 +69,26 @@
*
*/
-static char rcsid[] =
- "$Id$";
-
#include "shapefil.h"
#include <math.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#ifdef USE_CPL
+#include <cpl_error.h>
+#endif
+SHP_CVSID("$Id$")
+
#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif
+static int bBigEndian = 0;
+
/* -------------------------------------------------------------------- */
/* If the following is 0.5, nodes will be split in half. If it */
/* is 0.6 then each subnode will contain 60% of the parent */
@@ -121,6 +128,13 @@
SHPTreeNode *psTreeNode;
psTreeNode = (SHPTreeNode *) malloc(sizeof(SHPTreeNode));
+ if( NULL == psTreeNode )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure");
+#endif
+ return NULL;
+ }
psTreeNode->nShapeCount = 0;
psTreeNode->panShapeIds = NULL;
@@ -156,10 +170,18 @@
/* 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;
+ }
psTree->hSHP = hSHP;
psTree->nMaxDepth = nMaxDepth;
psTree->nDimension = nDimension;
+ psTree->nTotalCount = 0;
/* -------------------------------------------------------------------- */
/* If no max depth was defined, try to select a reasonable one */
@@ -176,19 +198,47 @@
psTree->nMaxDepth += 1;
nMaxNodeCount = nMaxNodeCount * 2;
}
+
+#ifdef USE_CPL
+ CPLDebug( "Shape",
+ "Estimated spatial index tree depth: %d",
+ psTree->nMaxDepth );
+#endif
+
+ /* NOTE: Due to problems with memory allocation for deep trees,
+ * automatically estimated depth is limited up to 12 levels.
+ * See Ticket #1594 for detailed discussion.
+ */
+ if( psTree->nMaxDepth > MAX_DEFAULT_TREE_DEPTH )
+ {
+ 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 );
+#endif
+ }
}
/* -------------------------------------------------------------------- */
/* Allocate the root node. */
/* -------------------------------------------------------------------- */
psTree->psRoot = SHPTreeNodeCreate( padfBoundsMin, padfBoundsMax );
+ if( NULL == psTree->psRoot )
+ {
+ 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. */
/* -------------------------------------------------------------------- */
- if( padfBoundsMin == NULL )
+ assert( NULL != psTree );
+ assert( NULL != psTree->psRoot );
+
+ if( padfBoundsMin == NULL )
{
SHPGetInfo( hSHP, NULL, NULL,
psTree->psRoot->adfBoundsMin,
@@ -226,6 +276,8 @@
{
int i;
+ assert( NULL != psTreeNode );
+
for( i = 0; i < psTreeNode->nSubNodes; i++ )
{
if( psTreeNode->apsSubNode[i] != NULL )
@@ -497,14 +549,14 @@
/* -------------------------------------------------------------------- */
psTreeNode->nShapeCount++;
- psTreeNode->panShapeIds =
+ psTreeNode->panShapeIds = (int *)
SfRealloc( psTreeNode->panShapeIds,
sizeof(int) * psTreeNode->nShapeCount );
psTreeNode->panShapeIds[psTreeNode->nShapeCount-1] = psObject->nShapeId;
if( psTreeNode->papsShapeObj != NULL )
{
- psTreeNode->papsShapeObj =
+ psTreeNode->papsShapeObj = (SHPObject **)
SfRealloc( psTreeNode->papsShapeObj,
sizeof(void *) * psTreeNode->nShapeCount );
psTreeNode->papsShapeObj[psTreeNode->nShapeCount-1] = NULL;
@@ -524,6 +576,8 @@
SHPTreeAddShapeId( SHPTree * psTree, SHPObject * psObject )
{
+ psTree->nTotalCount++;
+
return( SHPTreeNodeAddShapeId( psTree->psRoot, psObject,
psTree->nMaxDepth, psTree->nDimension ) );
}
@@ -680,3 +734,306 @@
SHPTreeNodeTrim( hTree->psRoot );
}
+/************************************************************************/
+/* SwapWord() */
+/* */
+/* Swap a 2, 4 or 8 byte word. */
+/************************************************************************/
+
+static void SwapWord( int length, void * wordP )
+
+{
+ int i;
+ unsigned char temp;
+
+ for( i=0; i < length/2; i++ )
+ {
+ temp = ((unsigned char *) wordP)[i];
+ ((unsigned char *)wordP)[i] = ((unsigned char *) wordP)[length-i-1];
+ ((unsigned char *) wordP)[length-i-1] = temp;
+ }
+}
+
+/************************************************************************/
+/* SHPSearchDiskTreeNode() */
+/************************************************************************/
+
+static int
+SHPSearchDiskTreeNode( FILE *fp, double *padfBoundsMin, double *padfBoundsMax,
+ int **ppanResultBuffer, int *pnBufferMax,
+ int *pnResultCount, int bNeedSwap )
+
+{
+ int i;
+ int offset;
+ int numshapes, numsubnodes;
+ double adfNodeBoundsMin[2], adfNodeBoundsMax[2];
+
+/* -------------------------------------------------------------------- */
+/* Read and unswap first part of node info. */
+/* -------------------------------------------------------------------- */
+ fread( &offset, 4, 1, fp );
+ if ( bNeedSwap ) SwapWord ( 4, &offset );
+
+ fread( adfNodeBoundsMin, sizeof(double), 2, fp );
+ fread( adfNodeBoundsMax, sizeof(double), 2, fp );
+ if ( bNeedSwap )
+ {
+ SwapWord( 8, adfNodeBoundsMin + 0 );
+ SwapWord( 8, adfNodeBoundsMin + 1 );
+ SwapWord( 8, adfNodeBoundsMax + 0 );
+ SwapWord( 8, adfNodeBoundsMax + 1 );
+ }
+
+ fread( &numshapes, 4, 1, fp );
+ if ( bNeedSwap ) SwapWord ( 4, &numshapes );
+
+/* -------------------------------------------------------------------- */
+/* If we don't overlap this node at all, we can just fseek() */
+/* pass this node info and all subnodes. */
+/* -------------------------------------------------------------------- */
+ if( !SHPCheckBoundsOverlap( adfNodeBoundsMin, adfNodeBoundsMax,
+ padfBoundsMin, padfBoundsMax, 2 ) )
+ {
+ offset += numshapes*sizeof(int) + sizeof(int);
+ fseek(fp, offset, SEEK_CUR);
+ return TRUE;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Add all the shapeids at this node to our list. */
+/* -------------------------------------------------------------------- */
+ if(numshapes > 0)
+ {
+ if( *pnResultCount + numshapes > *pnBufferMax )
+ {
+ *pnBufferMax = (int) ((*pnResultCount + numshapes + 100) * 1.25);
+ *ppanResultBuffer = (int *)
+ SfRealloc( *ppanResultBuffer, *pnBufferMax * sizeof(int) );
+ }
+
+ fread( *ppanResultBuffer + *pnResultCount,
+ sizeof(int), numshapes, fp );
+
+ if (bNeedSwap )
+ {
+ for( i=0; i<numshapes; i++ )
+ SwapWord( 4, *ppanResultBuffer + *pnResultCount + i );
+ }
+
+ *pnResultCount += numshapes;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Process the subnodes. */
+/* -------------------------------------------------------------------- */
+ fread( &numsubnodes, 4, 1, fp );
+ if ( bNeedSwap ) SwapWord ( 4, &numsubnodes );
+
+ for(i=0; i<numsubnodes; i++)
+ {
+ if( !SHPSearchDiskTreeNode( fp, padfBoundsMin, padfBoundsMax,
+ ppanResultBuffer, pnBufferMax,
+ pnResultCount, bNeedSwap ) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/************************************************************************/
+/* SHPSearchDiskTree() */
+/************************************************************************/
+
+int SHPAPI_CALL1(*)
+SHPSearchDiskTree( FILE *fp,
+ double *padfBoundsMin, double *padfBoundsMax,
+ int *pnShapeCount )
+
+{
+ int i, bNeedSwap, nBufferMax = 0;
+ unsigned char abyBuf[16];
+ int *panResultBuffer = NULL;
+
+ *pnShapeCount = 0;
+
+/* -------------------------------------------------------------------- */
+/* Establish the byte order on this machine. */
+/* -------------------------------------------------------------------- */
+ i = 1;
+ if( *((unsigned char *) &i) == 1 )
+ bBigEndian = FALSE;
+ else
+ bBigEndian = TRUE;
+
+/* -------------------------------------------------------------------- */
+/* Read the header. */
+/* -------------------------------------------------------------------- */
+ fseek( fp, 0, SEEK_SET );
+ fread( abyBuf, 16, 1, fp );
+
+ if( memcmp( abyBuf, "SQT", 3 ) != 0 )
+ return NULL;
+
+ if( (abyBuf[3] == 2 && bBigEndian)
+ || (abyBuf[3] == 1 && !bBigEndian) )
+ bNeedSwap = FALSE;
+ else
+ bNeedSwap = TRUE;
+
+/* -------------------------------------------------------------------- */
+/* Search through root node and it's decendents. */
+/* -------------------------------------------------------------------- */
+ if( !SHPSearchDiskTreeNode( fp, padfBoundsMin, padfBoundsMax,
+ &panResultBuffer, &nBufferMax,
+ pnShapeCount, bNeedSwap ) )
+ {
+ if( panResultBuffer != NULL )
+ free( panResultBuffer );
+ *pnShapeCount = 0;
+ return NULL;
+ }
+/* -------------------------------------------------------------------- */
+/* Sort the id array */
+/* -------------------------------------------------------------------- */
+ qsort(panResultBuffer, *pnShapeCount, sizeof(int), compare_ints);
+
+ return panResultBuffer;
+}
+
+/************************************************************************/
+/* SHPGetSubNodeOffset() */
+/* */
+/* Determine how big all the subnodes of this node (and their */
+/* children) will be. This will allow disk based searchers to */
+/* seek past them all efficiently. */
+/************************************************************************/
+
+static int SHPGetSubNodeOffset( SHPTreeNode *node)
+{
+ int i;
+ long offset=0;
+
+ for(i=0; i<node->nSubNodes; i++ )
+ {
+ if(node->apsSubNode[i])
+ {
+ offset += 4*sizeof(double)
+ + (node->apsSubNode[i]->nShapeCount+3)*sizeof(int);
+ offset += SHPGetSubNodeOffset(node->apsSubNode[i]);
+ }
+ }
+
+ return(offset);
+}
+
+/************************************************************************/
+/* SHPWriteTreeNode() */
+/************************************************************************/
+
+static void SHPWriteTreeNode( FILE *fp, SHPTreeNode *node)
+{
+ int i,j;
+ int offset;
+ unsigned char *pabyRec = NULL;
+ assert( NULL != node );
+
+ offset = SHPGetSubNodeOffset(node);
+
+ pabyRec = (unsigned char *)
+ malloc(sizeof(double) * 4
+ + (3 * sizeof(int)) + (node->nShapeCount * sizeof(int)) );
+ if( NULL == pabyRec )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure");
+#endif
+ assert( 0 );
+ }
+ assert( NULL != pabyRec );
+
+ memcpy( pabyRec, &offset, 4);
+
+ /* minx, miny, maxx, maxy */
+ memcpy( pabyRec+ 4, node->adfBoundsMin+0, sizeof(double) );
+ memcpy( pabyRec+12, node->adfBoundsMin+1, sizeof(double) );
+ memcpy( pabyRec+20, node->adfBoundsMax+0, sizeof(double) );
+ memcpy( pabyRec+28, node->adfBoundsMax+1, sizeof(double) );
+
+ memcpy( pabyRec+36, &node->nShapeCount, 4);
+ j = node->nShapeCount * sizeof(int);
+ memcpy( pabyRec+40, node->panShapeIds, j);
+ memcpy( pabyRec+j+40, &node->nSubNodes, 4);
+
+ fwrite( pabyRec, 44+j, 1, fp );
+ free (pabyRec);
+
+ for(i=0; i<node->nSubNodes; i++ )
+ {
+ if(node->apsSubNode[i])
+ SHPWriteTreeNode( fp, node->apsSubNode[i]);
+ }
+}
+
+/************************************************************************/
+/* SHPWriteTree() */
+/************************************************************************/
+
+int SHPWriteTree(SHPTree *tree, const char *filename )
+{
+ char signature[4] = "SQT";
+ int i;
+ char abyBuf[32];
+ FILE *fp;
+
+/* -------------------------------------------------------------------- */
+/* Open the output file. */
+/* -------------------------------------------------------------------- */
+ fp = fopen(filename, "wb");
+ if( fp == NULL )
+ {
+ return FALSE;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Establish the byte order on this machine. */
+/* -------------------------------------------------------------------- */
+ i = 1;
+ if( *((unsigned char *) &i) == 1 )
+ bBigEndian = FALSE;
+ else
+ bBigEndian = TRUE;
+
+/* -------------------------------------------------------------------- */
+/* Write the header. */
+/* -------------------------------------------------------------------- */
+ memcpy( abyBuf+0, signature, 3 );
+
+ if( bBigEndian )
+ abyBuf[3] = 2; /* New MSB */
+ else
+ abyBuf[3] = 1; /* New LSB */
+
+ abyBuf[4] = 1; /* version */
+ abyBuf[5] = 0; /* next 3 reserved */
+ abyBuf[6] = 0;
+ abyBuf[7] = 0;
+
+ fwrite( abyBuf, 8, 1, fp );
+
+ fwrite( &(tree->nTotalCount), 4, 1, fp );
+
+ /* write maxdepth */
+
+ fwrite( &(tree->nMaxDepth), 4, 1, fp );
+
+/* -------------------------------------------------------------------- */
+/* Write all the nodes "in order". */
+/* -------------------------------------------------------------------- */
+
+ SHPWriteTreeNode( fp, tree->psRoot );
+
+ fclose( fp );
+
+ return TRUE;
+}
Modified: branches/WIP-pyshapelib-Unicode/thuban/setup.py
===================================================================
--- branches/WIP-pyshapelib-Unicode/thuban/setup.py 2007-12-12 20:35:20 UTC (rev 2795)
+++ branches/WIP-pyshapelib-Unicode/thuban/setup.py 2007-12-12 22:32:34 UTC (rev 2796)
@@ -269,19 +269,38 @@
# shapelib wrappers are also distributed with thuban
#
+def dbf_macros():
+ """determine the macros to define when compiling the dbflib wrapper.
+ """
+ f = open(convert_path(shp_dir + "/shapefil.h"))
+ contents = f.read()
+ f.close()
+
+ def have(keyword):
+ if keyword in contents:
+ return "1"
+ return "0"
+
+ return [
+ ("HAVE_UPDATE_HEADER", have("DBFUpdateHeader")),
+ ("HAVE_LANGUAGE_DRIVER", have("nLanguageDriver"))]
+
+
extensions.append(Extension("Lib.shapelib",
[ext_dir + "/pyshapelib/shapelibmodule.c",
shp_dir + "/shpopen.c",
- shp_dir + "/shptree.c"],
+ shp_dir + "/shptree.c",
+ shp_dir + "/safileio.c"],
include_dirs = [shp_dir]))
extensions.append(Extension("Lib.shptree",
[ext_dir + "/pyshapelib/shptreemodule.c"],
include_dirs = [shp_dir]))
extensions.append(Extension("Lib.dbflib",
[ext_dir + "/pyshapelib/dbflibmodule.c",
- shp_dir + "/dbfopen.c"],
+ shp_dir + "/dbfopen.c",
+ shp_dir + "/safileio.c"],
include_dirs = [shp_dir],
- define_macros = [("HAVE_UPDATE_HEADER", "1")]))
+ define_macros = dbf_macros()))
#
More information about the Thuban-commits
mailing list