*
* Project: Shapelib
* Purpose: Implementation of .dbf access API documented in dbf_api.html.
- * Author: Frank Warmerdam, warmerda@home.com
+ * Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
******************************************************************************
*
* $Log$
- * Revision 1.5 2002/10/17 17:06:39 chodgson
- * fixed the last compile warning on solaris/gcc
+ * Revision 1.6 2003/12/01 20:52:00 strk
+ * shapelib put in sync with gdal cvs
*
- * Revision 1.4 2002/10/17 16:45:04 chodgson
- * - cleaned up all the compiler warnings
- * - for getopt.c, this involved moving the line:
- * extern char *getenv(const char *name);
- * outside of the two nested #ifdefs that it was inside, as it is always required (the code that calls it isn't inside any #ifdefs) Perhaps this may break compilation in non-linux/gnu environments?
+ * Revision 1.52 2003/07/08 15:20:03 warmerda
+ * avoid warnings about downcasting to unsigned char
*
- * Revision 1.3 2002/05/04 22:44:04 pramsey
- * Update shapelib references to 1.2.9.
+ * Revision 1.51 2003/07/08 13:50:15 warmerda
+ * DBFIsAttributeNULL check for pszValue==NULL - bug 360
+ *
+ * Revision 1.50 2003/04/21 18:58:25 warmerda
+ * ensure current record is flushed at same time as header is updated
+ *
+ * Revision 1.49 2003/04/21 18:30:37 warmerda
+ * added header write/update public methods
+ *
+ * Revision 1.48 2003/03/10 14:51:27 warmerda
+ * DBFWrite* calls now return FALSE if they have to truncate
+ *
+ * Revision 1.47 2002/11/20 03:32:22 warmerda
+ * Ensure field name in DBFGetFieldIndex() is properly terminated.
+ *
+ * Revision 1.46 2002/10/09 13:10:21 warmerda
+ * Added check that width is positive.
+ *
+ * Revision 1.45 2002/09/29 00:00:08 warmerda
+ * added FTLogical and logical attribute read/write calls
+ *
+ * Revision 1.44 2002/05/07 13:46:11 warmerda
+ * Added DBFWriteAttributeDirectly().
+ *
+ * Revision 1.43 2002/02/13 19:39:21 warmerda
+ * Fix casting issues in DBFCloneEmpty().
+ *
+ * Revision 1.42 2002/01/15 14:36:07 warmerda
+ * updated email address
+ *
+ * Revision 1.41 2002/01/15 14:31:49 warmerda
+ * compute rather than copying nHeaderLength in DBFCloneEmpty()
+ *
+ * Revision 1.40 2002/01/09 04:32:35 warmerda
+ * fixed to read correct amount of header
+ *
+ * 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
* Added header.
*/
+static char rcsid[] =
+ "$Id$";
+
#include "shapefil.h"
#include <math.h>
abyHeader[0] = 0x03; /* memo field? - just copying */
- /* date updated on close, record count preset at zero */
+ /* write out a dummy date */
+ abyHeader[1] = 95; /* YY */
+ abyHeader[2] = 7; /* MM */
+ abyHeader[3] = 26; /* DD */
- abyHeader[8] = psDBF->nHeaderLength % 256;
- abyHeader[9] = psDBF->nHeaderLength / 256;
+ /* record count preset at zero */
+
+ abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
+ abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
- abyHeader[10] = psDBF->nRecordLength % 256;
- abyHeader[11] = psDBF->nRecordLength / 256;
+ abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
+ abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
/* -------------------------------------------------------------------- */
/* Write the initial 32 byte file header, and all the field */
}
}
+/************************************************************************/
+/* DBFUpdateHeader() */
+/************************************************************************/
+
+void SHPAPI_CALL
+DBFUpdateHeader( DBFHandle psDBF )
+
+{
+ unsigned char abyFileHeader[32];
+
+ if( psDBF->bNoHeader )
+ DBFWriteHeader( psDBF );
+
+ DBFFlushRecord( psDBF );
+
+ fseek( psDBF->fp, 0, 0 );
+ 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 );
+
+ fflush( psDBF->fp );
+}
+
/************************************************************************/
/* DBFOpen() */
/* */
{
DBFHandle psDBF;
unsigned char *pabyBuf;
- int nFields, nRecords, nHeadLen, nRecLen, iField, i;
+ int nFields, nHeadLen, nRecLen, iField, i;
char *pszBasename, *pszFullname;
/* -------------------------------------------------------------------- */
/* Read Table Header info */
/* -------------------------------------------------------------------- */
pabyBuf = (unsigned char *) malloc(500);
- fread( pabyBuf, 32, 1, psDBF->fp );
+ if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
+ {
+ fclose( psDBF->fp );
+ free( pabyBuf );
+ free( psDBF );
+ return NULL;
+ }
- psDBF->nRecords = nRecords =
+ psDBF->nRecords =
pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
psDBF->pszHeader = (char *) pabyBuf;
fseek( psDBF->fp, 32, 0 );
- fread( pabyBuf, nHeadLen, 1, psDBF->fp );
+ if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
+ {
+ fclose( psDBF->fp );
+ free( pabyBuf );
+ free( psDBF );
+ return NULL;
+ }
psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
/* write access. */
/* -------------------------------------------------------------------- */
if( psDBF->bUpdated )
- {
- unsigned char abyFileHeader[32];
-
- fseek( psDBF->fp, 0, 0 );
- fread( abyFileHeader, 32, 1, psDBF->fp );
-
- abyFileHeader[1] = 95; /* YY */
- abyFileHeader[2] = 7; /* MM */
- abyFileHeader[3] = 26; /* DD */
-
- abyFileHeader[4] = psDBF->nRecords % 256;
- abyFileHeader[5] = (psDBF->nRecords/256) % 256;
- abyFileHeader[6] = (psDBF->nRecords/(256*256)) % 256;
- abyFileHeader[7] = (psDBF->nRecords/(256*256*256)) % 256;
-
- fseek( psDBF->fp, 0, 0 );
- fwrite( abyFileHeader, 32, 1, psDBF->fp );
- }
+ DBFUpdateHeader( psDBF );
/* -------------------------------------------------------------------- */
/* Close, and free resources. */
if( eType != FTDouble && nDecimals != 0 )
return( -1 );
+ if( nWidth < 1 )
+ return -1;
+
/* -------------------------------------------------------------------- */
/* SfRealloc all the arrays larger to hold the additional field */
/* information. */
psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
- if( eType == FTString )
+ 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';
if( eType == FTString )
{
- pszFInfo[16] = nWidth % 256;
- pszFInfo[17] = nWidth / 256;
+ pszFInfo[16] = (unsigned char) (nWidth % 256);
+ pszFInfo[17] = (unsigned char) (nWidth / 256);
}
else
{
- pszFInfo[16] = nWidth;
- pszFInfo[17] = nDecimals;
+ pszFInfo[16] = (unsigned char) nWidth;
+ pszFInfo[17] = (unsigned char) nDecimals;
}
/* -------------------------------------------------------------------- */
return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
}
+/************************************************************************/
+/* DBFReadLogicalAttribute() */
+/* */
+/* Read a logical attribute. */
+/************************************************************************/
+
+const char SHPAPI_CALL1(*)
+DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
+
+{
+ return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
+}
+
/************************************************************************/
/* DBFIsAttributeNULL() */
/* */
pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
+ if( pszValue == NULL )
+ return TRUE;
+
switch(psDBF->pachFieldType[iField])
{
case 'N':
/* empty string fields are considered NULL */
return strlen(pszValue) == 0;
}
- return FALSE;
}
/************************************************************************/
pszFieldName[i] = '\0';
}
- if( psDBF->pachFieldType[iField] == 'N'
- || psDBF->pachFieldType[iField] == 'F'
- || psDBF->pachFieldType[iField] == 'D' )
+ if ( psDBF->pachFieldType[iField] == 'L' )
+ return( FTLogical);
+
+ else if( psDBF->pachFieldType[iField] == 'N'
+ || psDBF->pachFieldType[iField] == 'F'
+ || psDBF->pachFieldType[iField] == 'D' )
{
if( psDBF->panFieldDecimals[iField] > 0 )
return( FTDouble );
void * pValue )
{
- int nRecordOffset, i, j;
+ int nRecordOffset, i, j, nRetResult = TRUE;
unsigned char *pabyRec;
char szSField[400], szFormat[20];
sprintf( szFormat, "%%%dd", nWidth );
sprintf(szSField, szFormat, (int) *((double *) pValue) );
if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
+ {
szSField[psDBF->panFieldSize[iField]] = '\0';
+ nRetResult = FALSE;
+ }
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
szSField, strlen(szSField) );
nWidth, psDBF->panFieldDecimals[iField] );
sprintf(szSField, szFormat, *((double *) pValue) );
if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
+ {
szSField[psDBF->panFieldSize[iField]] = '\0';
+ nRetResult = FALSE;
+ }
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
szSField, strlen(szSField) );
}
break;
+ case 'L':
+ if (psDBF->panFieldSize[iField] >= 1 &&
+ (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
+ *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
+ break;
+
default:
if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
+ {
j = psDBF->panFieldSize[iField];
+ nRetResult = FALSE;
+ }
else
{
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
break;
}
+ return( nRetResult );
+}
+
+/************************************************************************/
+/* DBFWriteAttributeDirectly() */
+/* */
+/* Write an attribute record to the file, but without any */
+/* reformatting based on type. The provided buffer is written */
+/* as is to the field position in the record. */
+/************************************************************************/
+
+int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
+ void * pValue )
+
+{
+ int nRecordOffset, i, j;
+ unsigned char *pabyRec;
+
+/* -------------------------------------------------------------------- */
+/* Is this a valid record? */
+/* -------------------------------------------------------------------- */
+ if( hEntity < 0 || hEntity > psDBF->nRecords )
+ return( FALSE );
+
+ if( psDBF->bNoHeader )
+ DBFWriteHeader(psDBF);
+
+/* -------------------------------------------------------------------- */
+/* Is this a brand new record? */
+/* -------------------------------------------------------------------- */
+ if( hEntity == psDBF->nRecords )
+ {
+ DBFFlushRecord( psDBF );
+
+ psDBF->nRecords++;
+ for( i = 0; i < psDBF->nRecordLength; i++ )
+ psDBF->pszCurrentRecord[i] = ' ';
+
+ psDBF->nCurrentRecord = hEntity;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Is this an existing record, but different than the last one */
+/* we accessed? */
+/* -------------------------------------------------------------------- */
+ if( psDBF->nCurrentRecord != hEntity )
+ {
+ DBFFlushRecord( psDBF );
+
+ 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;
+
+/* -------------------------------------------------------------------- */
+/* Assign all the record fields. */
+/* -------------------------------------------------------------------- */
+ if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
+ j = psDBF->panFieldSize[iField];
+ else
+ {
+ memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
+ psDBF->panFieldSize[iField] );
+ j = strlen((char *) pValue);
+ }
+
+ strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
+ (char *) pValue, j );
+
+ psDBF->bCurrentRecordModified = TRUE;
+ psDBF->bUpdated = TRUE;
+
return( TRUE );
}
return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
}
+/************************************************************************/
+/* DBFWriteLogicalAttribute() */
+/* */
+/* Write a logical attribute. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
+ const char lValue)
+
+{
+ return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
+}
+
/************************************************************************/
/* DBFWriteTuple() */
/* */
newDBF = DBFCreate ( pszFilename );
if ( newDBF == NULL ) return ( NULL );
- newDBF->pszHeader = (void *) malloc ( 32 * psDBF->nFields );
+ 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 = psDBF->nHeaderLength;
+ newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
- newDBF->panFieldOffset = (void *) malloc ( sizeof(int) * psDBF->nFields );
+ newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
- newDBF->panFieldSize = (void *) malloc ( sizeof(int) * psDBF->nFields );
+ newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
- newDBF->panFieldDecimals = (void *) malloc ( sizeof(int) * psDBF->nFields );
+ newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
- newDBF->pachFieldType = (void *) malloc ( sizeof(int) * psDBF->nFields );
+ newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
newDBF->bNoHeader = TRUE;
len = strlen (string);
while (++i < len)
- if (isalpha((unsigned)string[i]) && islower((unsigned)string[i]))
- string[i] = toupper ((int)string[i]);
+ if (isalpha(string[i]) && islower(string[i]))
+ string[i] = (char) toupper ((int)string[i]);
}
/************************************************************************/
int i;
strncpy(name1, pszFieldName,11);
+ name1[11] = '\0';
str_to_upper(name1);
for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
*
* Project: Shapelib
* Purpose: Primary include file for Shapelib.
- * Author: Frank Warmerdam, warmerda@home.com
+ * Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
******************************************************************************
*
* $Log$
- * Revision 1.3 2002/05/04 22:44:04 pramsey
- * Update shapelib references to 1.2.9.
+ * Revision 1.4 2003/12/01 20:52:00 strk
+ * shapelib put in sync with gdal cvs
+ *
+ * Revision 1.27 2003/04/21 18:30:37 warmerda
+ * added header write/update public methods
+ *
+ * Revision 1.26 2002/09/29 00:00:08 warmerda
+ * added FTLogical and logical attribute read/write calls
+ *
+ * Revision 1.25 2002/05/07 13:46:30 warmerda
+ * added DBFWriteAttributeDirectly().
+ *
+ * Revision 1.24 2002/04/10 16:59:54 warmerda
+ * added SHPRewindObject
+ *
+ * Revision 1.23 2002/01/15 14:36:07 warmerda
+ * updated email address
+ *
+ * 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
extern "C" {
#endif
-#ifndef SHPAPI_CALL
-#define SHPAPI_CALL
-#endif
-
-#define SHPAPI_CALL1(x) * SHPAPI_CALL
-
/************************************************************************/
/* Configuration options. */
/************************************************************************/
/* -------------------------------------------------------------------- */
#define DISABLE_MULTIPATCH_MEASURE
+/* -------------------------------------------------------------------- */
+/* SHPAPI_CALL */
+/* */
+/* The following two macros are present to allow forcing */
+/* various calling conventions on the Shapelib API. */
+/* */
+/* To force __stdcall conventions (needed to call Shapelib */
+/* from Visual Basic and/or Dephi I believe) the makefile could */
+/* be modified to define: */
+/* */
+/* /DSHPAPI_CALL=__stdcall */
+/* */
+/* If it is desired to force export of the Shapelib API without */
+/* using the shapelib.def file, use the following definition. */
+/* */
+/* /DSHAPELIB_DLLEXPORT */
+/* */
+/* To get both at once it will be necessary to hack this */
+/* include file to define: */
+/* */
+/* #define SHPAPI_CALL __declspec(dllexport) __stdcall */
+/* #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall */
+/* */
+/* The complexity of the situtation is partly caused by the */
+/* peculiar requirement of Visual C++ that __stdcall appear */
+/* after any "*"'s in the return value of a function while the */
+/* __declspec(dllexport) must appear before them. */
+/* -------------------------------------------------------------------- */
+
+#ifdef SHAPELIB_DLLEXPORT
+# define SHPAPI_CALL __declspec(dllexport)
+# define SHPAPI_CALL1(x) __declspec(dllexport) x
+#endif
+
+#ifndef SHPAPI_CALL
+# define SHPAPI_CALL
+#endif
+
+#ifndef SHPAPI_CALL1
+# define SHPAPI_CALL1(x) x SHPAPI_CALL
+#endif
+
/************************************************************************/
/* SHP Support. */
/************************************************************************/
double adBoundsMax[4];
int bUpdated;
+
+ unsigned char *pabyRec;
+ int nBufSize;
} SHPInfo;
typedef SHPInfo * SHPHandle;
SHPCreateSimpleObject( int nSHPType, int nVertices,
double * padfX, double * padfY, double * padfZ );
-void SHPAPI_CALL
- SHPClose( SHPHandle hSHP );
+int SHPAPI_CALL
+ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject );
+
+void SHPAPI_CALL SHPClose( SHPHandle hSHP );
+void SHPAPI_CALL SHPWriteHeader( SHPHandle hSHP );
const char SHPAPI_CALL1(*)
SHPTypeName( int nSHPType );
FTString,
FTInteger,
FTDouble,
+ FTLogical,
FTInvalid
} DBFFieldType;
DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
const char SHPAPI_CALL1(*)
DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
+const char SHPAPI_CALL1(*)
+ DBFReadLogicalAttribute( DBFHandle hDBF, int iShape, int iField );
int SHPAPI_CALL
DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField );
int SHPAPI_CALL
DBFWriteNULLAttribute( DBFHandle hDBF, int iShape, int iField );
+int SHPAPI_CALL
+ DBFWriteLogicalAttribute( DBFHandle hDBF, int iShape, int iField,
+ const char lFieldValue);
+int SHPAPI_CALL
+ DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
+ void * pValue );
const char SHPAPI_CALL1(*)
DBFReadTuple(DBFHandle psDBF, int hEntity );
int SHPAPI_CALL
void SHPAPI_CALL
DBFClose( DBFHandle hDBF );
+void SHPAPI_CALL
+ DBFUpdateHeader( DBFHandle hDBF );
char SHPAPI_CALL
DBFGetNativeFieldType( DBFHandle hDBF, int iField );
******************************************************************************
*
* $Log$
- * Revision 1.4 2002/10/17 16:45:04 chodgson
- * - cleaned up all the compiler warnings
- * - for getopt.c, this involved moving the line:
- * extern char *getenv(const char *name);
- * outside of the two nested #ifdefs that it was inside, as it is always required (the code that calls it isn't inside any #ifdefs) Perhaps this may break compilation in non-linux/gnu environments?
+ * Revision 1.5 2003/12/01 20:52:00 strk
+ * shapelib put in sync with gdal cvs
*
- * Revision 1.3 2002/05/04 22:44:04 pramsey
- * Update shapelib references to 1.2.9.
+ * Revision 1.43 2003/12/01 16:20:08 warmerda
+ * be careful of zero vertex shapes
+ *
+ * Revision 1.42 2003/12/01 14:58:27 warmerda
+ * added degenerate object check in SHPRewindObject()
+ *
+ * Revision 1.41 2003/07/08 15:22:43 warmerda
+ * avoid warning
+ *
+ * Revision 1.40 2003/04/21 18:30:37 warmerda
+ * added header write/update public methods
+ *
+ * Revision 1.39 2002/08/26 06:46:56 warmerda
+ * avoid c++ comments
+ *
+ * Revision 1.38 2002/05/07 16:43:39 warmerda
+ * Removed debugging printf.
+ *
+ * Revision 1.37 2002/04/10 17:35:22 warmerda
+ * fixed bug in ring reversal code
+ *
+ * Revision 1.36 2002/04/10 16:59:54 warmerda
+ * added SHPRewindObject
+ *
+ * Revision 1.35 2001/12/07 15:10:44 warmerda
+ * fix if .shx fails to open
+ *
+ * Revision 1.34 2001/11/01 16:29:55 warmerda
+ * move pabyRec into SHPInfo for thread safety
*
* Revision 1.33 2001/07/03 12:18:15 warmerda
* Improved cleanup if SHX not found, provied by Riccardo Cohen.
*
*/
+static char rcsid[] =
+ "$Id$";
+
#include "shapefil.h"
#include <math.h>
#endif
static int bBigEndian;
-static uchar *pabyRec = NULL;
-static int nBufSize = 0;
/************************************************************************/
/* contents of the index (.shx) file. */
/************************************************************************/
-static void SHPWriteHeader( SHPHandle psSHP )
+void SHPWriteHeader( SHPHandle psSHP )
{
uchar abyHeader[100];
fwrite( panSHX, sizeof(int32) * 2, psSHP->nRecords, psSHP->fpSHX );
free( panSHX );
+
+/* -------------------------------------------------------------------- */
+/* Flush to disk. */
+/* -------------------------------------------------------------------- */
+ fflush( psSHP->fpSHP );
+ fflush( psSHP->fpSHX );
}
/************************************************************************/
/* -------------------------------------------------------------------- */
/* Initialize the info structure. */
/* -------------------------------------------------------------------- */
- psSHP = (SHPHandle) malloc(sizeof(SHPInfo));
+ psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
psSHP->bUpdated = FALSE;
if( psSHP->fpSHX == NULL )
{
- fclose( psSHP->fpSHX );
+ fclose( psSHP->fpSHP );
free( psSHP );
free( pszBasename );
free( pszFullname );
/* Update the header if we have modified anything. */
/* -------------------------------------------------------------------- */
if( psSHP->bUpdated )
- {
SHPWriteHeader( psSHP );
- }
/* -------------------------------------------------------------------- */
/* Free all resources, and close files. */
fclose( psSHP->fpSHX );
fclose( psSHP->fpSHP );
- free( psSHP );
-
- if( pabyRec != NULL )
+ if( psSHP->pabyRec != NULL )
{
- free( pabyRec );
- pabyRec = NULL;
- nBufSize = 0;
+ free( psSHP->pabyRec );
}
+
+ free( psSHP );
}
/************************************************************************/
SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
{
- int nRecordOffset, i, nRecordSize;
+ int nRecordOffset, i, nRecordSize=0;
uchar *pabyRec;
int32 i32;
if( psSHP->adBoundsMin[0] == 0.0
&& psSHP->adBoundsMax[0] == 0.0
&& psSHP->adBoundsMin[1] == 0.0
- && psSHP->adBoundsMax[1] == 0.0
- && psObject->nSHPType != SHPT_NULL )
+ && psSHP->adBoundsMax[1] == 0.0 )
{
- psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
- psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
- psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
- psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
+ if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 )
+ {
+ psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;
+ psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;
+ psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;
+ psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;
+ }
+ else
+ {
+ psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
+ psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
+ psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
+ psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
+ }
}
for( i = 0; i < psObject->nVertices; i++ )
/* -------------------------------------------------------------------- */
/* Ensure our record buffer is large enough. */
/* -------------------------------------------------------------------- */
- if( psSHP->panRecSize[hEntity]+8 > nBufSize )
+ if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize )
{
- nBufSize = psSHP->panRecSize[hEntity]+8;
- pabyRec = (uchar *) SfRealloc(pabyRec,nBufSize);
+ psSHP->nBufSize = psSHP->panRecSize[hEntity]+8;
+ psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize);
}
/* -------------------------------------------------------------------- */
/* Read the record. */
/* -------------------------------------------------------------------- */
fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 );
- fread( pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP );
+ fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP );
/* -------------------------------------------------------------------- */
/* Allocate and minimally initialize the object. */
psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
psShape->nShapeId = hEntity;
- memcpy( &psShape->nSHPType, pabyRec + 8, 4 );
+ memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
/* ==================================================================== */
/* -------------------------------------------------------------------- */
/* Get the X/Y bounds. */
/* -------------------------------------------------------------------- */
- memcpy( &(psShape->dfXMin), pabyRec + 8 + 4, 8 );
- memcpy( &(psShape->dfYMin), pabyRec + 8 + 12, 8 );
- memcpy( &(psShape->dfXMax), pabyRec + 8 + 20, 8 );
- memcpy( &(psShape->dfYMax), pabyRec + 8 + 28, 8 );
+ memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
+ memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
+ memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
+ memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
/* Extract part/point count, and build vertex and part arrays */
/* to proper size. */
/* -------------------------------------------------------------------- */
- memcpy( &nPoints, pabyRec + 40 + 8, 4 );
- memcpy( &nParts, pabyRec + 36 + 8, 4 );
+ memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
+ memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
if( bBigEndian ) SwapWord( 4, &nPoints );
if( bBigEndian ) SwapWord( 4, &nParts );
/* -------------------------------------------------------------------- */
/* Copy out the part array from the record. */
/* -------------------------------------------------------------------- */
- memcpy( psShape->panPartStart, pabyRec + 44 + 8, 4 * nParts );
+ memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
for( i = 0; i < nParts; i++ )
{
if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
/* -------------------------------------------------------------------- */
if( psShape->nSHPType == SHPT_MULTIPATCH )
{
- memcpy( psShape->panPartType, pabyRec + nOffset, 4*nParts );
+ memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
for( i = 0; i < nParts; i++ )
{
if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
for( i = 0; i < nPoints; i++ )
{
memcpy(psShape->padfX + i,
- pabyRec + nOffset + i * 16,
+ psSHP->pabyRec + nOffset + i * 16,
8 );
memcpy(psShape->padfY + i,
- pabyRec + nOffset + i * 16 + 8,
+ psSHP->pabyRec + nOffset + i * 16 + 8,
8 );
if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
|| psShape->nSHPType == SHPT_ARCZ
|| psShape->nSHPType == SHPT_MULTIPATCH )
{
- memcpy( &(psShape->dfZMin), pabyRec + nOffset, 8 );
- memcpy( &(psShape->dfZMax), pabyRec + nOffset + 8, 8 );
+ memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
+ memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
for( i = 0; i < nPoints; i++ )
{
memcpy( psShape->padfZ + i,
- pabyRec + nOffset + 16 + i*8, 8 );
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
}
/* -------------------------------------------------------------------- */
if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
{
- memcpy( &(psShape->dfMMin), pabyRec + nOffset, 8 );
- memcpy( &(psShape->dfMMax), pabyRec + nOffset + 8, 8 );
+ memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
+ memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
for( i = 0; i < nPoints; i++ )
{
memcpy( psShape->padfM + i,
- pabyRec + nOffset + 16 + i*8, 8 );
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
}
}
int32 nPoints;
int i, nOffset;
- memcpy( &nPoints, pabyRec + 44, 4 );
+ memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
if( bBigEndian ) SwapWord( 4, &nPoints );
psShape->nVertices = nPoints;
for( i = 0; i < nPoints; i++ )
{
- memcpy(psShape->padfX+i, pabyRec + 48 + 16 * i, 8 );
- memcpy(psShape->padfY+i, pabyRec + 48 + 16 * i + 8, 8 );
+ memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
+ memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
/* -------------------------------------------------------------------- */
/* Get the X/Y bounds. */
/* -------------------------------------------------------------------- */
- memcpy( &(psShape->dfXMin), pabyRec + 8 + 4, 8 );
- memcpy( &(psShape->dfYMin), pabyRec + 8 + 12, 8 );
- memcpy( &(psShape->dfXMax), pabyRec + 8 + 20, 8 );
- memcpy( &(psShape->dfYMax), pabyRec + 8 + 28, 8 );
+ memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
+ memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
+ memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
+ memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
/* -------------------------------------------------------------------- */
if( psShape->nSHPType == SHPT_MULTIPOINTZ )
{
- memcpy( &(psShape->dfZMin), pabyRec + nOffset, 8 );
- memcpy( &(psShape->dfZMax), pabyRec + nOffset + 8, 8 );
+ memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
+ memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
for( i = 0; i < nPoints; i++ )
{
memcpy( psShape->padfZ + i,
- pabyRec + nOffset + 16 + i*8, 8 );
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
}
/* -------------------------------------------------------------------- */
if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
{
- memcpy( &(psShape->dfMMin), pabyRec + nOffset, 8 );
- memcpy( &(psShape->dfMMax), pabyRec + nOffset + 8, 8 );
+ memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
+ memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
for( i = 0; i < nPoints; i++ )
{
memcpy( psShape->padfM + i,
- pabyRec + nOffset + 16 + i*8, 8 );
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
}
}
psShape->padfZ = (double *) calloc(1,sizeof(double));
psShape->padfM = (double *) calloc(1,sizeof(double));
- memcpy( psShape->padfX, pabyRec + 12, 8 );
- memcpy( psShape->padfY, pabyRec + 20, 8 );
+ memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
+ memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfX );
if( bBigEndian ) SwapWord( 8, psShape->padfY );
/* -------------------------------------------------------------------- */
if( psShape->nSHPType == SHPT_POINTZ )
{
- memcpy( psShape->padfZ, pabyRec + nOffset, 8 );
+ memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfZ );
/* -------------------------------------------------------------------- */
if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 )
{
- memcpy( psShape->padfM, pabyRec + nOffset, 8 );
+ memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
if( bBigEndian ) SwapWord( 8, psShape->padfM );
}
free( psShape );
}
+
+/************************************************************************/
+/* SHPRewindObject() */
+/* */
+/* Reset the winding of polygon objects to adhere to the */
+/* specification. */
+/************************************************************************/
+
+int SHPAPI_CALL
+SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
+
+{
+ int iOpRing, bAltered = 0;
+
+/* -------------------------------------------------------------------- */
+/* Do nothing if this is not a polygon object. */
+/* -------------------------------------------------------------------- */
+ if( psObject->nSHPType != SHPT_POLYGON
+ && psObject->nSHPType != SHPT_POLYGONZ
+ && psObject->nSHPType != SHPT_POLYGONM )
+ return 0;
+
+ if( psObject->nVertices == 0 || psObject->nParts == 0 )
+ return 0;
+
+/* -------------------------------------------------------------------- */
+/* Process each of the rings. */
+/* -------------------------------------------------------------------- */
+ for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ )
+ {
+ int bInner, iVert, nVertCount, nVertStart, iCheckRing;
+ double dfSum, dfTestX, dfTestY;
+
+/* -------------------------------------------------------------------- */
+/* Determine if this ring is an inner ring or an outer ring */
+/* relative to all the other rings. For now we assume the */
+/* 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]];
+
+ bInner = FALSE;
+ for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )
+ {
+ int iEdge;
+
+ if( iCheckRing == iOpRing )
+ continue;
+
+ nVertStart = psObject->panPartStart[iCheckRing];
+
+ if( iCheckRing == psObject->nParts-1 )
+ nVertCount = psObject->nVertices
+ - psObject->panPartStart[iCheckRing];
+ else
+ nVertCount = psObject->panPartStart[iCheckRing+1]
+ - psObject->panPartStart[iCheckRing];
+
+ for( iEdge = 0; iEdge < nVertCount; iEdge++ )
+ {
+ int iNext;
+
+ if( iEdge < nVertCount-1 )
+ iNext = iEdge+1;
+ else
+ iNext = 0;
+
+ if( (psObject->padfY[iEdge+nVertStart] < dfTestY
+ && psObject->padfY[iNext+nVertStart] >= dfTestY)
+ || (psObject->padfY[iNext+nVertStart] < dfTestY
+ && psObject->padfY[iEdge+nVertStart] >= dfTestY) )
+ {
+ 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 )
+ bInner = !bInner;
+ }
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Determine the current order of this ring so we will know if */
+/* it has to be reversed. */
+/* -------------------------------------------------------------------- */
+ nVertStart = psObject->panPartStart[iOpRing];
+
+ if( iOpRing == psObject->nParts-1 )
+ nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
+ else
+ nVertCount = psObject->panPartStart[iOpRing+1]
+ - psObject->panPartStart[iOpRing];
+
+ dfSum = 0.0;
+ for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ )
+ {
+ dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1]
+ - psObject->padfY[iVert] * psObject->padfX[iVert+1];
+ }
+
+ dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart]
+ - psObject->padfY[iVert] * psObject->padfX[nVertStart];
+
+/* -------------------------------------------------------------------- */
+/* Reverse if necessary. */
+/* -------------------------------------------------------------------- */
+ if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )
+ {
+ int i;
+
+ bAltered++;
+ for( i = 0; i < nVertCount/2; i++ )
+ {
+ double dfSaved;
+
+ /* Swap X */
+ dfSaved = psObject->padfX[nVertStart+i];
+ psObject->padfX[nVertStart+i] =
+ psObject->padfX[nVertStart+nVertCount-i-1];
+ psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
+
+ /* Swap Y */
+ dfSaved = psObject->padfY[nVertStart+i];
+ psObject->padfY[nVertStart+i] =
+ psObject->padfY[nVertStart+nVertCount-i-1];
+ psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
+
+ /* Swap Z */
+ if( psObject->padfZ )
+ {
+ dfSaved = psObject->padfZ[nVertStart+i];
+ psObject->padfZ[nVertStart+i] =
+ psObject->padfZ[nVertStart+nVertCount-i-1];
+ psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
+ }
+
+ /* Swap M */
+ if( psObject->padfM )
+ {
+ dfSaved = psObject->padfM[nVertStart+i];
+ psObject->padfM[nVertStart+i] =
+ psObject->padfM[nVertStart+nVertCount-i-1];
+ psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
+ }
+ }
+ }
+ }
+
+ return bAltered;
+}