******************************************************************************
*
* $Log: dbfopen.c,v $
+ * Revision 1.89 2011-07-24 05:59:25 fwarmerdam
+ * minimize use of CPLError in favor of SAHooks.Error()
+ *
+ * Revision 1.88 2011-05-13 17:35:17 fwarmerdam
+ * added DBFReorderFields() and DBFAlterFields() functions (from Even)
+ *
+ * Revision 1.87 2011-05-07 22:41:02 fwarmerdam
+ * ensure pending record is flushed when adding a native field (GDAL #4073)
+ *
+ * Revision 1.86 2011-04-17 15:15:29 fwarmerdam
+ * Removed unused variable.
+ *
+ * Revision 1.85 2010-12-06 16:09:34 fwarmerdam
+ * fix buffer read overrun fetching code page (bug 2276)
+ *
* Revision 1.84 2009-10-29 19:59:48 fwarmerdam
* avoid crash on truncated header (gdal #3093)
*
psDBF->nRecordLength,
1, psDBF->fp ) != 1 )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_FileIO,
- "Failure writing DBF record %d.",
- psDBF->nCurrentRecord );
-#else
- fprintf( stderr, "Failure writing DBF record %d.",
+ char szMessage[128];
+ sprintf( szMessage, "Failure writing DBF record %d.",
psDBF->nCurrentRecord );
-#endif
+ psDBF->sHooks.Error( szMessage );
return FALSE;
}
}
if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_FileIO,
- "fseek(%ld) failed on DBF file.\n",
- (long) nRecordOffset );
-#else
- fprintf( stderr, "fseek(%ld) failed on DBF file.\n",
+ char szMessage[128];
+ sprintf( szMessage, "fseek(%ld) failed on DBF file.\n",
(long) nRecordOffset );
-#endif
+ psDBF->sHooks.Error( szMessage );
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",
+ char szMessage[128];
+ sprintf( szMessage, "fread(%d) failed on DBF file.\n",
psDBF->nRecordLength );
-#endif
+ psDBF->sHooks.Error( szMessage );
return FALSE;
}
if( pfCPG )
{
size_t n;
- char *buffer = (char *) pabyBuf;
- buffer[0] = '\0';
+ memset( pabyBuf, 0, nBufSize);
psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
n = strcspn( (char *) pabyBuf, "\n\r" );
if( n > 0 )
void SHPAPI_CALL
DBFClose(DBFHandle psDBF)
{
- static char eof = 0x1a;
- char eof_test;
-
if( psDBF == NULL )
return;
if( psDBF->bUpdated )
DBFUpdateHeader( psDBF );
-
-/* -------------------------------------------------------------------- */
-/* Add the DBF end-of-file marker after the last record. */
-/* -------------------------------------------------------------------- */
-
- psDBF->sHooks.FSeek(psDBF->fp, -1, SEEK_END);
- psDBF->sHooks.FRead(&eof_test, 1, 1, psDBF->fp);
- if( eof_test != 0x1a ) /* no EOF exists, so write one */
- {
- psDBF->sHooks.FSeek(psDBF->fp, 0, SEEK_END);
- psDBF->sHooks.FWrite(&eof, 1, 1, psDBF->fp);
- }
-
/* -------------------------------------------------------------------- */
/* Close, and free resources. */
/* -------------------------------------------------------------------- */
chNativeType = 'L';
else if( eType == FTString )
chNativeType = 'C';
- else if ( eType == FTDate )
+ else if( eType == FTDate )
chNativeType = 'D';
else
chNativeType = 'N';
nWidth, nDecimals );
}
+/************************************************************************/
+/* DBFGetNullCharacter() */
+/************************************************************************/
+
+static char DBFGetNullCharacter(char chType)
+{
+ switch (chType)
+ {
+ case 'N':
+ case 'F':
+ return '*';
+ case 'D':
+ return '0';
+ case 'L':
+ return '?';
+ default:
+ return ' ';
+ }
+}
+
/************************************************************************/
/* DBFAddField() */
/* */
char chFieldFill;
SAOffset nRecordOffset;
+ /* make sure that everything is written in .dbf */
+ if( !DBFFlushRecord( psDBF ) )
+ return -1;
+
/* -------------------------------------------------------------------- */
/* Do some checking to ensure we can add records to this file. */
/* -------------------------------------------------------------------- */
/* alloc record */
pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
- switch (chType)
- {
- case 'N':
- case 'F':
- chFieldFill = '*';
- break;
- case 'D':
- chFieldFill = '0';
- break;
- case 'L':
- chFieldFill = '?';
- break;
- default:
- chFieldFill = ' ';
- break;
- }
+ chFieldFill = DBFGetNullCharacter(chType);
for (i = psDBF->nRecords-1; i >= 0; --i)
{
psDBF->bNoHeader = TRUE;
DBFUpdateHeader( psDBF );
- return( psDBF->nFields-1 );
-}
-
-/************************************************************************/
-/* DBFReadSetup() */
-/* */
-/* Prep a record for reading. */
-/************************************************************************/
-
-int DBFReadSetup(DBFHandle psDBF, int hEntity)
-{
- int nRecordOffset;
-
- /* -------------------------------------------------------------------- */
- /* Verify selection. */
- /* -------------------------------------------------------------------- */
- if ( hEntity < 0 || hEntity >= psDBF->nRecords )
- return( 0 );
-
- /* -------------------------------------------------------------------- */
- /* Have we read the record? */
- /* -------------------------------------------------------------------- */
- if ( psDBF->nCurrentRecord != hEntity )
- {
- DBFFlushRecord( psDBF );
-
- nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
-
- if ( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0 )
- {
- fprintf( stderr, "fseek(%d) failed on DBF file.\n",
- nRecordOffset );
- return 0;
- }
-
- if ( psDBF->sHooks.FRead( psDBF->pszCurrentRecord, psDBF->nRecordLength,
- 1, psDBF->fp ) != 1 )
- {
- fprintf( stderr, "fread(%d) failed on DBF file.\n",
- psDBF->nRecordLength );
- return 0;
- }
-
- psDBF->nCurrentRecord = hEntity;
- }
-
- return 1;
-
-}
-
-
-/************************************************************************/
-/* DBFReadDeleted() */
-/* */
-/* Read whether a record is deleted. */
-/************************************************************************/
-
-int DBFReadDeleted(DBFHandle psDBF, int hEntity)
-{
- unsigned char *pabyRec;
-
- if ( ! DBFReadSetup( psDBF, hEntity) )
- return 0;
-
- /* get reference to current record */
- pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
-
- /* 0x20 => not deleted, 0x24 => deleted */
- return *pabyRec == 0x20 ? 0 : 1;
+ psDBF->nCurrentRecord = -1;
+ psDBF->bCurrentRecordModified = FALSE;
+ return( psDBF->nFields-1 );
}
/************************************************************************/
return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
}
+
/************************************************************************/
-/* DBFIsAttributeNULL() */
+/* DBFIsValueNULL() */
/* */
-/* Return TRUE if value for field is NULL. */
-/* */
-/* Contributed by Jim Matthews. */
+/* Return TRUE if the passed string is NULL. */
/************************************************************************/
-int SHPAPI_CALL
-DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
-
+static int DBFIsValueNULL( char chType, const char* pszValue )
{
- const char *pszValue;
int i;
- pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
-
if( pszValue == NULL )
return TRUE;
- switch(psDBF->pachFieldType[iField])
+ switch(chType)
{
case 'N':
case 'F':
/*
- ** We accept all asterisks or all blanks as NULL
- ** though according to the spec I think it should be all
- ** asterisks.
+ ** We accept all asterisks or all blanks as NULL
+ ** though according to the spec I think it should be all
+ ** asterisks.
*/
if( pszValue[0] == '*' )
return TRUE;
return TRUE;
case 'D':
- /* NULL date fields have value "00000000" */
+ /* NULL date fields have value "00000000" or blank or empty */
if (pszValue[0] == '\0' || // emtpy string
strncmp(pszValue,"00000000",8) == 0 ||
strncmp(pszValue," ",8) == 0) {
// return strncmp(pszValue,"00000000",8) == 0;
case 'L':
- // printf("Is [%s] NULL?", pszValue);
- /* NULL boolean fields have value "?" */
- if (pszValue[0] == '\0' || pszValue[0] == '?') {
- return 1;
- } else {
- return 0;
- }
- // return pszValue[0] == '?';
+ /* NULL boolean fields have value "?" or empty */
+ if (pszValue[0] == '\0' || pszValue[0] == '?') {
+ return 1;
+ } else {
+ return 0;
+ }
default:
/* empty string fields are considered NULL */
}
}
+/************************************************************************/
+/* DBFIsAttributeNULL() */
+/* */
+/* Return TRUE if value for field is NULL. */
+/* */
+/* Contributed by Jim Matthews. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
+
+{
+ const char *pszValue;
+
+ pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
+
+ if( pszValue == NULL )
+ return TRUE;
+
+ return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue );
+}
+
/************************************************************************/
/* DBFGetFieldCount() */
/* */
return( FTLogical);
else if ( psDBF->pachFieldType[iField] == 'D' )
- return ( FTDate );
-
+ return ( FTDate );
else if( psDBF->pachFieldType[iField] == 'N'
|| psDBF->pachFieldType[iField] == 'F' )
/* -------------------------------------------------------------------- */
if( pValue == NULL )
{
- switch(psDBF->pachFieldType[iField])
- {
- case 'N':
- case 'F':
- /* NULL numeric fields have value "****************" */
- memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
- psDBF->panFieldSize[iField] );
- break;
-
- case 'D':
- /* NULL date fields have value "00000000" */
- memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
- psDBF->panFieldSize[iField] );
- break;
-
- case 'L':
- /* NULL boolean fields have value "?" */
- memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
- psDBF->panFieldSize[iField] );
- break;
-
- default:
- /* empty string fields are considered NULL */
- memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), ' ',
- psDBF->panFieldSize[iField] );
- break;
- }
+ memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]),
+ DBFGetNullCharacter(psDBF->pachFieldType[iField]),
+ psDBF->panFieldSize[iField] );
return TRUE;
}
int SHPAPI_CALL
DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
- const void * pValue )
+ void * pValue )
{
int i, j;
psDBF->nRecordLength -= nDeletedFieldSize;
/* overwrite field information in header */
- memcpy(psDBF->pszHeader + iField*32,
+ memmove(psDBF->pszHeader + iField*32,
psDBF->pszHeader + (iField+1)*32,
sizeof(char) * (psDBF->nFields - iField)*32);
/* free record */
free(pszRecord);
+ psDBF->nCurrentRecord = -1;
+ psDBF->bCurrentRecordModified = FALSE;
+
+ return TRUE;
+}
+
+/************************************************************************/
+/* DBFReorderFields() */
+/* */
+/* Reorder the fields of a .dbf file */
+/* */
+/* panMap must be exactly psDBF->nFields long and be a permutation */
+/* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/
+/* code of DBFReorderFields. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFReorderFields( DBFHandle psDBF, int* panMap )
+{
+ SAOffset nRecordOffset;
+ int i, iRecord;
+ int *panFieldOffsetNew;
+ int *panFieldSizeNew;
+ int *panFieldDecimalsNew;
+ char *pachFieldTypeNew;
+ char *pszHeaderNew;
+ char *pszRecord;
+ char *pszRecordNew;
+
+ if ( psDBF->nFields == 0 )
+ return TRUE;
+
+ /* make sure that everything is written in .dbf */
+ if( !DBFFlushRecord( psDBF ) )
+ return FALSE;
+
+ panFieldOffsetNew = (int *) malloc(sizeof(int) * psDBF->nFields);
+ panFieldSizeNew = (int *) malloc(sizeof(int) * psDBF->nFields);
+ panFieldDecimalsNew = (int *) malloc(sizeof(int) * psDBF->nFields);
+ pachFieldTypeNew = (char *) malloc(sizeof(char) * psDBF->nFields);
+ pszHeaderNew = (char*) malloc(sizeof(char) * 32 * psDBF->nFields);
+
+ /* shuffle fields definitions */
+ for(i=0; i < psDBF->nFields; i++)
+ {
+ panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
+ panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
+ pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
+ memcpy(pszHeaderNew + i * 32,
+ psDBF->pszHeader + panMap[i] * 32, 32);
+ }
+ panFieldOffsetNew[0] = 1;
+ for(i=1; i < psDBF->nFields; i++)
+ {
+ panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
+ }
+
+ free(psDBF->pszHeader);
+ psDBF->pszHeader = pszHeaderNew;
+
+ /* we're done if we're dealing with not yet created .dbf */
+ if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) )
+ {
+ /* force update of header with new header and record length */
+ psDBF->bNoHeader = TRUE;
+ DBFUpdateHeader( psDBF );
+
+ /* alloc record */
+ pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
+ pszRecordNew = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
+
+ /* shuffle fields in records */
+ for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
+ {
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+ /* load record */
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
+
+ pszRecordNew[0] = pszRecord[0];
+
+ for(i=0; i < psDBF->nFields; i++)
+ {
+ memcpy(pszRecordNew + panFieldOffsetNew[i],
+ pszRecord + psDBF->panFieldOffset[panMap[i]],
+ psDBF->panFieldSize[panMap[i]]);
+ }
+
+ /* write record */
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp );
+ }
+
+ /* free record */
+ free(pszRecord);
+ free(pszRecordNew);
+ }
+
+ free(psDBF->panFieldOffset);
+ free(psDBF->panFieldSize);
+ free(psDBF->panFieldDecimals);
+ free(psDBF->pachFieldType);
+
+ psDBF->panFieldOffset = panFieldOffsetNew;
+ psDBF->panFieldSize = panFieldSizeNew;
+ psDBF->panFieldDecimals =panFieldDecimalsNew;
+ psDBF->pachFieldType = pachFieldTypeNew;
+
+ psDBF->nCurrentRecord = -1;
+ psDBF->bCurrentRecordModified = FALSE;
+
+ return TRUE;
+}
+
+
+/************************************************************************/
+/* DBFAlterFieldDefn() */
+/* */
+/* Alter a field definition in a .dbf file */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
+ char chType, int nWidth, int nDecimals )
+{
+ int i;
+ int iRecord;
+ int nOffset;
+ int nOldWidth;
+ int nOldRecordLength;
+ int nRecordOffset;
+ char* pszFInfo;
+ char chOldType;
+ int bIsNULL;
+ char chFieldFill;
+
+ if (iField < 0 || iField >= psDBF->nFields)
+ return FALSE;
+
+ /* make sure that everything is written in .dbf */
+ if( !DBFFlushRecord( psDBF ) )
+ return FALSE;
+
+ chFieldFill = DBFGetNullCharacter(chType);
+
+ chOldType = psDBF->pachFieldType[iField];
+ nOffset = psDBF->panFieldOffset[iField];
+ nOldWidth = psDBF->panFieldSize[iField];
+ nOldRecordLength = psDBF->nRecordLength;
+
+/* -------------------------------------------------------------------- */
+/* Do some checking to ensure we can add records to this file. */
+/* -------------------------------------------------------------------- */
+ if( nWidth < 1 )
+ return -1;
+
+ if( nWidth > 255 )
+ nWidth = 255;
+
+/* -------------------------------------------------------------------- */
+/* Assign the new field information fields. */
+/* -------------------------------------------------------------------- */
+ psDBF->panFieldSize[iField] = nWidth;
+ psDBF->panFieldDecimals[iField] = nDecimals;
+ psDBF->pachFieldType[iField] = chType;
+
+/* -------------------------------------------------------------------- */
+/* Update the header information. */
+/* -------------------------------------------------------------------- */
+ pszFInfo = psDBF->pszHeader + 32 * iField;
+
+ for( i = 0; i < 32; i++ )
+ pszFInfo[i] = '\0';
+
+ if( (int) strlen(pszFieldName) < 10 )
+ strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
+ else
+ strncpy( pszFInfo, pszFieldName, 10);
+
+ pszFInfo[11] = psDBF->pachFieldType[iField];
+
+ if( chType == 'C' )
+ {
+ pszFInfo[16] = (unsigned char) (nWidth % 256);
+ pszFInfo[17] = (unsigned char) (nWidth / 256);
+ }
+ else
+ {
+ pszFInfo[16] = (unsigned char) nWidth;
+ pszFInfo[17] = (unsigned char) nDecimals;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Update offsets */
+/* -------------------------------------------------------------------- */
+ if (nWidth != nOldWidth)
+ {
+ for (i = iField + 1; i < psDBF->nFields; i++)
+ psDBF->panFieldOffset[i] += nWidth - nOldWidth;
+ psDBF->nRecordLength += nWidth - nOldWidth;
+
+ psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
+ psDBF->nRecordLength);
+ }
+
+ /* we're done if we're dealing with not yet created .dbf */
+ if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
+ return TRUE;
+
+ /* force update of header with new header and record length */
+ psDBF->bNoHeader = TRUE;
+ DBFUpdateHeader( psDBF );
+
+ if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType))
+ {
+ char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
+ char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
+
+ pszOldField[nOldWidth] = 0;
+
+ /* move records to their new positions */
+ for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
+ {
+ nRecordOffset =
+ nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+ /* load record */
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
+
+ memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
+ bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
+
+ if (nWidth != nOldWidth)
+ {
+ if ((chOldType == 'N' || chOldType == 'F') && pszOldField[0] == ' ')
+ {
+ /* Strip leading spaces when truncating a numeric field */
+ memmove( pszRecord + nOffset,
+ pszRecord + nOffset + nOldWidth - nWidth,
+ nWidth );
+ }
+ if (nOffset + nOldWidth < nOldRecordLength)
+ {
+ memmove( pszRecord + nOffset + nWidth,
+ pszRecord + nOffset + nOldWidth,
+ nOldRecordLength - (nOffset + nOldWidth));
+ }
+ }
+
+ /* Convert null value to the appropriate value of the new type */
+ if (bIsNULL)
+ {
+ memset( pszRecord + nOffset, chFieldFill, nWidth);
+ }
+
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+ /* write record */
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
+ }
+
+ free(pszRecord);
+ free(pszOldField);
+ }
+ else if (nWidth > nOldWidth)
+ {
+ char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
+ char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
+
+ pszOldField[nOldWidth] = 0;
+
+ /* move records to their new positions */
+ for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
+ {
+ nRecordOffset =
+ nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+ /* load record */
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
+
+ memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
+ bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
+
+ if (nOffset + nOldWidth < nOldRecordLength)
+ {
+ memmove( pszRecord + nOffset + nWidth,
+ pszRecord + nOffset + nOldWidth,
+ nOldRecordLength - (nOffset + nOldWidth));
+ }
+
+ /* Convert null value to the appropriate value of the new type */
+ if (bIsNULL)
+ {
+ memset( pszRecord + nOffset, chFieldFill, nWidth);
+ }
+ else
+ {
+ if ((chOldType == 'N' || chOldType == 'F'))
+ {
+ /* Add leading spaces when expanding a numeric field */
+ memmove( pszRecord + nOffset + nWidth - nOldWidth,
+ pszRecord + nOffset, nOldWidth );
+ memset( pszRecord + nOffset, ' ', nWidth - nOldWidth );
+ }
+ else
+ {
+ /* Add trailing spaces */
+ memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth);
+ }
+ }
+
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
+
+ /* write record */
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
+ }
+
+ free(pszRecord);
+ free(pszOldField);
+ }
+
+ psDBF->nCurrentRecord = -1;
+ psDBF->bCurrentRecordModified = FALSE;
+
return TRUE;
}
******************************************************************************
*
* $Log: shpopen.c,v $
+ * Revision 1.70 2011-07-24 05:59:25 fwarmerdam
+ * minimize use of CPLError in favor of SAHooks.Error()
+ *
+ * Revision 1.69 2011-07-24 03:24:22 fwarmerdam
+ * fix memory leaks in error cases creating shapefiles (#2061)
+ *
+ * Revision 1.68 2010-08-27 23:42:52 fwarmerdam
+ * add SHPAPI_CALL attribute in code
+ *
* Revision 1.67 2010-07-01 08:15:48 fwarmerdam
* do not error out on an object with zero vertices
*
SHP_CVSID("$Id$")
-typedef unsigned char uint8_t;
+typedef unsigned char uchar;
#if UINT_MAX == 65535
typedef unsigned long int32;
{
int i;
- uint8_t temp;
+ uchar temp;
for( i=0; i < length/2; i++ )
{
- temp = ((uint8_t *) wordP)[i];
- ((uint8_t *)wordP)[i] = ((uint8_t *) wordP)[length-i-1];
- ((uint8_t *) wordP)[length-i-1] = temp;
+ temp = ((uchar *) wordP)[i];
+ ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];
+ ((uchar *) wordP)[length-i-1] = temp;
}
}
/* contents of the index (.shx) file. */
/************************************************************************/
-void SHPWriteHeader( SHPHandle psSHP )
+void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
{
- uint8_t abyHeader[100];
+ uchar abyHeader[100];
int i;
int32 i32;
double dValue;
char *pszFullname, *pszBasename;
SHPHandle psSHP;
- uint8_t *pabyBuf;
+ uchar *pabyBuf;
int i;
double dValue;
- int recordsInSHP;
/* -------------------------------------------------------------------- */
/* Ensure the access string is one of the legal ones. We */
/* Establish the byte order on this machine. */
/* -------------------------------------------------------------------- */
i = 1;
- if( *((uint8_t *) &i) == 1 )
+ if( *((uchar *) &i) == 1 )
bBigEndian = FALSE;
else
bBigEndian = TRUE;
if( psSHP->fpSHP == NULL )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_OpenFailed,
- "Unable to open %s.shp or %s.SHP.",
+ char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
+ sprintf( pszMessage, "Unable to open %s.shp or %s.SHP.",
pszBasename, pszBasename );
-#endif
- free( psSHP );
- free( pszBasename );
- free( pszFullname );
- return( NULL );
+ psHooks->Error( pszMessage );
+ free( pszMessage );
}
sprintf( pszFullname, "%s.shx", pszBasename );
if( psSHP->fpSHX == NULL )
{
-#ifdef USE_CPL
- CPLError( CE_Failure, CPLE_OpenFailed,
- "Unable to open %s.shx or %s.SHX.",
+ char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
+ sprintf( pszMessage, "Unable to open %s.shx or %s.SHX.",
pszBasename, pszBasename );
-#endif
+ psHooks->Error( pszMessage );
+ free( pszMessage );
+
psSHP->sHooks.FClose( psSHP->fpSHP );
free( psSHP );
free( pszBasename );
/* -------------------------------------------------------------------- */
/* Read the file size from the SHP file. */
/* -------------------------------------------------------------------- */
- pabyBuf = (uint8_t *) malloc(100);
+ pabyBuf = (uchar *) malloc(100);
psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP );
psSHP->nFileSize = ((unsigned int)pabyBuf[24] * 256 * 256 * 256
malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
psSHP->panRecSize = (unsigned int *)
malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
- pabyBuf = (uint8_t *) malloc(8 * MAX(1,psSHP->nRecords) );
+ pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
if (psSHP->panRecOffset == NULL ||
psSHP->panRecSize == NULL ||
return( NULL );
}
- recordsInSHP = (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX );
- if( recordsInSHP
+ 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, %d expected.",
- psSHP->nRecords, recordsInSHP );
+ "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. */
SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
{
- char *pszBasename, *pszFullname;
+ char *pszBasename = NULL, *pszFullname = NULL;
int i;
- SAFile fpSHP, fpSHX;
- uint8_t abyHeader[100];
+ SAFile fpSHP = NULL, fpSHX = NULL;
+ uchar abyHeader[100];
int32 i32;
double dValue;
/* Establish the byte order on this system. */
/* -------------------------------------------------------------------- */
i = 1;
- if( *((uint8_t *) &i) == 1 )
+ if( *((uchar *) &i) == 1 )
bBigEndian = FALSE;
else
bBigEndian = TRUE;
if( fpSHP == NULL )
{
psHooks->Error( "Failed to create file .shp file." );
- return( NULL );
+ goto error;
}
sprintf( pszFullname, "%s.shx", pszBasename );
if( fpSHX == NULL )
{
psHooks->Error( "Failed to create file .shx file." );
- return( NULL );
+ goto error;
}
- free( pszFullname );
- free( pszBasename );
+ free( pszFullname ); pszFullname = NULL;
+ free( pszBasename ); pszBasename = NULL;
/* -------------------------------------------------------------------- */
/* Prepare header block for .shp file. */
if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
{
psHooks->Error( "Failed to write .shp header." );
- return NULL;
+ goto error;
}
/* -------------------------------------------------------------------- */
if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 )
{
psHooks->Error( "Failed to write .shx header." );
- return NULL;
+ goto error;
}
/* -------------------------------------------------------------------- */
psHooks->FClose( fpSHX );
return( SHPOpenLL( pszLayer, "r+b", psHooks ) );
+
+error:
+ if (pszFullname) free(pszFullname);
+ if (pszBasename) free(pszBasename);
+ if (fpSHP) psHooks->FClose( fpSHP );
+ if (fpSHX) psHooks->FClose( fpSHX );
+ return NULL;
}
/************************************************************************/
/* indicated location in the record. */
/************************************************************************/
-static void _SHPSetBounds( uint8_t * pabyRec, SHPObject * psShape )
+static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape )
{
ByteCopy( &(psShape->dfXMin), pabyRec + 0, 8 );
{
unsigned int nRecordOffset, nRecordSize=0;
int i;
- uint8_t *pabyRec;
+ uchar *pabyRec;
int32 i32;
psSHP->bUpdated = TRUE;
/* -------------------------------------------------------------------- */
/* Initialize record. */
/* -------------------------------------------------------------------- */
- pabyRec = (uint8_t *) malloc(psObject->nVertices * 4 * sizeof(double)
+ pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
+ psObject->nParts * 8 + 128);
/* -------------------------------------------------------------------- */
nEntitySize = psSHP->panRecSize[hEntity]+8;
if( nEntitySize > psSHP->nBufSize )
{
- psSHP->pabyRec = (uint8_t *) SfRealloc(psSHP->pabyRec,nEntitySize);
+ psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize);
if (psSHP->pabyRec == NULL)
{
char szError[200];