From 3bc1641fb313b53d9cd6aa35b07df91797204c23 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Tue, 24 Jan 2012 21:57:06 +0000 Subject: [PATCH] Update shplib to the latest release (1.3.0b3) and stitch in our special date and logical handling. (#393) git-svn-id: http://svn.osgeo.org/postgis/trunk@8919 b70326c6-7e19-0410-871a-916f4a2858ee --- loader/dbfopen.c | 608 ++++++++++++++++++++++++++++------------ loader/pgsql2shp-core.c | 12 +- loader/safileio.c | 12 - loader/shapefil.h | 39 ++- loader/shp2pgsql-core.c | 2 +- loader/shpopen.c | 95 ++++--- 6 files changed, 514 insertions(+), 254 deletions(-) diff --git a/loader/dbfopen.c b/loader/dbfopen.c index 6f6438d35..aa50879d6 100644 --- a/loader/dbfopen.c +++ b/loader/dbfopen.c @@ -34,6 +34,21 @@ ****************************************************************************** * * $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) * @@ -259,14 +274,10 @@ static int DBFFlushRecord( DBFHandle psDBF ) 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; } } @@ -293,28 +304,20 @@ static int DBFLoadRecord( DBFHandle psDBF, int iRecord ) 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; } @@ -491,8 +494,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks ) if( pfCPG ) { size_t n; - char *buffer = (char *) pabyBuf; - buffer[0] = '\0'; + memset( pabyBuf, 0, nBufSize); psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG ); n = strcspn( (char *) pabyBuf, "\n\r" ); if( n > 0 ) @@ -576,9 +578,6 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks ) void SHPAPI_CALL DBFClose(DBFHandle psDBF) { - static char eof = 0x1a; - char eof_test; - if( psDBF == NULL ) return; @@ -597,19 +596,6 @@ DBFClose(DBFHandle psDBF) 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. */ /* -------------------------------------------------------------------- */ @@ -787,7 +773,7 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName, chNativeType = 'L'; else if( eType == FTString ) chNativeType = 'C'; - else if ( eType == FTDate ) + else if( eType == FTDate ) chNativeType = 'D'; else chNativeType = 'N'; @@ -796,6 +782,26 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName, 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() */ /* */ @@ -815,6 +821,10 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, 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. */ /* -------------------------------------------------------------------- */ @@ -902,22 +912,7 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, /* alloc record */ pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength); - switch (chType) - { - case 'N': - case 'F': - chFieldFill = '*'; - break; - case 'D': - chFieldFill = '0'; - break; - case 'L': - chFieldFill = '?'; - break; - default: - chFieldFill = ' '; - break; - } + chFieldFill = DBFGetNullCharacter(chType); for (i = psDBF->nRecords-1; i >= 0; --i) { @@ -944,76 +939,10 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, 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 ); } /************************************************************************/ @@ -1169,34 +1098,28 @@ DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField ) 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; @@ -1209,7 +1132,7 @@ DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField ) 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) { @@ -1220,14 +1143,12 @@ DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField ) // 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 */ @@ -1235,6 +1156,28 @@ DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField ) } } +/************************************************************************/ +/* DBFIsAttributeNULL() */ +/* */ +/* Return TRUE if value for field is NULL. */ +/* */ +/* Contributed by Jim Matthews. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField ) + +{ + const char *pszValue; + + pszValue = DBFReadStringAttribute( psDBF, iRecord, iField ); + + if( pszValue == NULL ) + return TRUE; + + return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue ); +} + /************************************************************************/ /* DBFGetFieldCount() */ /* */ @@ -1295,8 +1238,7 @@ DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, return( FTLogical); else if ( psDBF->pachFieldType[iField] == 'D' ) - return ( FTDate ); - + return ( FTDate ); else if( psDBF->pachFieldType[iField] == 'N' || psDBF->pachFieldType[iField] == 'F' ) @@ -1370,33 +1312,9 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, /* -------------------------------------------------------------------- */ if( pValue == NULL ) { - switch(psDBF->pachFieldType[iField]) - { - case 'N': - case 'F': - /* NULL numeric fields have value "****************" */ - memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*', - psDBF->panFieldSize[iField] ); - break; - - case 'D': - /* NULL date fields have value "00000000" */ - memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0', - psDBF->panFieldSize[iField] ); - break; - - case 'L': - /* NULL boolean fields have value "?" */ - memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?', - psDBF->panFieldSize[iField] ); - break; - - default: - /* empty string fields are considered NULL */ - memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), ' ', - psDBF->panFieldSize[iField] ); - break; - } + memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), + DBFGetNullCharacter(psDBF->pachFieldType[iField]), + psDBF->panFieldSize[iField] ); return TRUE; } @@ -1483,7 +1401,7 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, - const void * pValue ) + void * pValue ) { int i, j; @@ -1935,7 +1853,7 @@ DBFDeleteField(DBFHandle psDBF, int iField) 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); @@ -1983,5 +1901,337 @@ DBFDeleteField(DBFHandle psDBF, int iField) /* 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; } diff --git a/loader/pgsql2shp-core.c b/loader/pgsql2shp-core.c index c3075e879..d2abacf55 100644 --- a/loader/pgsql2shp-core.c +++ b/loader/pgsql2shp-core.c @@ -64,7 +64,7 @@ static SHPObject *create_polygon(SHPDUMPERSTATE *state, LWPOLY *lwpolygon); static SHPObject *create_multipolygon(SHPDUMPERSTATE *state, LWMPOLY *lwmultipolygon); static SHPObject *create_linestring(SHPDUMPERSTATE *state, LWLINE *lwlinestring); static SHPObject *create_multilinestring(SHPDUMPERSTATE *state, LWMLINE *lwmultilinestring); -static const char *nullDBFValue(char fieldType); +static char *nullDBFValue(char fieldType); static int getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname); static int getTableInfo(SHPDUMPERSTATE *state); static int projFileCreate(SHPDUMPERSTATE *state); @@ -74,7 +74,7 @@ static int projFileCreate(SHPDUMPERSTATE *state); * Might return untouched input or pointer to static private * buffer: use return value right away. */ -static const char * goodDBFValue(const char *in, char fieldType); +static char * goodDBFValue(char *in, char fieldType); /** @brief Binary to hexewkb conversion function */ char *convert_bytes_to_hex(uint8_t *ewkb, size_t size); @@ -633,7 +633,7 @@ shapetypename(int num) /* This is taken and adapted from dbfopen.c of shapelib */ -static const char * +static char * nullDBFValue(char fieldType) { switch (fieldType) @@ -662,8 +662,8 @@ nullDBFValue(char fieldType) * Might return untouched input or pointer to static private * buffer: use return value right away. */ -static const char * -goodDBFValue(const char *in, char fieldType) +static char * +goodDBFValue(char *in, char fieldType) { /* * We only work on FTLogical and FTDate. @@ -2026,7 +2026,7 @@ int ShpLoaderGenerateShapeRow(SHPDUMPERSTATE *state) char *hexewkb = NULL; unsigned char *hexewkb_binary = NULL; size_t hexewkb_len; - const char *val; + char *val; SHPObject *obj = NULL; LWGEOM *lwgeom; diff --git a/loader/safileio.c b/loader/safileio.c index 43b1e3106..f3affe2ea 100644 --- a/loader/safileio.c +++ b/loader/safileio.c @@ -76,18 +76,6 @@ SHP_CVSID("$Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $"); # endif #endif -/* Local Prototypes */ -SAFile SADFOpen( const char *pszFilename, const char *pszAccess ); -SAOffset SADFRead( void *p, SAOffset size, SAOffset nmemb, SAFile file ); -SAOffset SADFWrite( void *p, SAOffset size, SAOffset nmemb, SAFile file ); -SAOffset SADFSeek( SAFile file, SAOffset offset, int whence ); -SAOffset SADFTell( SAFile file ); -int SADFFlush( SAFile file ); -int SADFClose( SAFile file ); -int SADRemove( const char *filename ); -void SADError( const char *message ); - - /************************************************************************/ /* SADFOpen() */ /************************************************************************/ diff --git a/loader/shapefil.h b/loader/shapefil.h index 535c880fa..b6ca718ed 100644 --- a/loader/shapefil.h +++ b/loader/shapefil.h @@ -37,6 +37,18 @@ ****************************************************************************** * * $Log: shapefil.h,v $ + * Revision 1.51 2011-07-24 05:59:25 fwarmerdam + * minimize use of CPLError in favor of SAHooks.Error() + * + * Revision 1.50 2011-05-13 17:35:17 fwarmerdam + * added DBFReorderFields() and DBFAlterFields() functions (from Even) + * + * Revision 1.49 2011-04-16 14:38:21 fwarmerdam + * avoid warnings with gcc on SHP_CVSID + * + * Revision 1.48 2010-08-27 23:42:52 fwarmerdam + * add SHPAPI_CALL attribute in code + * * Revision 1.47 2010-01-28 11:34:34 fwarmerdam * handle the shape file length limits more gracefully (#3236) * @@ -131,11 +143,6 @@ #include #endif -#ifdef USE_CPL -#include "cpl_error.h" -#include "cpl_vsi.h" -#endif - #ifdef __cplusplus extern "C" { #endif @@ -209,8 +216,12 @@ extern "C" { /* as unreferenced variables resulting in lots of warnings. */ /* -------------------------------------------------------------------- */ #ifndef DISABLE_CVSID -# define SHP_CVSID(string) static char cpl_cvsid[] = string; \ +# if defined(__GNUC__) && __GNUC__ >= 4 +# define SHP_CVSID(string) static char cpl_cvsid[] __attribute__((used)) = string; +# else +# define SHP_CVSID(string) static char cpl_cvsid[] = string; \ static char *cvsid_aw() { return( cvsid_aw() ? ((char *) NULL) : cpl_cvsid ); } +# endif #else # define SHP_CVSID(string) #endif @@ -444,8 +455,6 @@ void SHPAPI_CALL int SHPAPI_CALL SHPWriteTree( SHPTree *hTree, const char * pszFilename ); -SHPTree SHPAPI_CALL - SHPReadTree( const char * pszFilename ); int SHPAPI_CALL SHPTreeAddObject( SHPTree * hTree, SHPObject * psObject ); @@ -548,6 +557,13 @@ int SHPAPI_CALL int SHPAPI_CALL DBFDeleteField( DBFHandle hDBF, int iField ); +int SHPAPI_CALL + DBFReorderFields( DBFHandle psDBF, int* panMap ); + +int SHPAPI_CALL + DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName, + char chType, int nWidth, int nDecimals ); + DBFFieldType SHPAPI_CALL DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, int * pnWidth, int * pnDecimals ); @@ -566,11 +582,6 @@ const char SHPAPI_CALL1(*) int SHPAPI_CALL DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField ); -int SHPAPI_CALL - DBFReadSetup ( DBFHandle psDBF, int hEntity ); -int SHPAPI_CALL - DBFReadDeleted ( DBFHandle psDBF, int hEntity ); - int SHPAPI_CALL DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField, int nFieldValue ); @@ -588,7 +599,7 @@ int SHPAPI_CALL const char lFieldValue); int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, - const void * pValue ); + void * pValue ); const char SHPAPI_CALL1(*) DBFReadTuple(DBFHandle psDBF, int hEntity ); int SHPAPI_CALL diff --git a/loader/shp2pgsql-core.c b/loader/shp2pgsql-core.c index 31704c558..e66bcb699 100644 --- a/loader/shp2pgsql-core.c +++ b/loader/shp2pgsql-core.c @@ -1453,7 +1453,7 @@ ShpLoaderGenerateSQLRowStatement(SHPLOADERSTATE *state, int item, char **strreco stringbuffer_clear(sb); /* If we are reading the DBF only and the record has been marked deleted, return deleted record status */ - if (state->config->readshape == 0 && DBFReadDeleted(state->hDBFHandle, item)) + if (state->config->readshape == 0 && DBFIsRecordDeleted(state->hDBFHandle, item)) { *strrecord = NULL; return SHPLOADERRECDELETED; diff --git a/loader/shpopen.c b/loader/shpopen.c index 689a2ddc9..197071f31 100644 --- a/loader/shpopen.c +++ b/loader/shpopen.c @@ -34,6 +34,15 @@ ****************************************************************************** * * $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 * @@ -257,7 +266,7 @@ SHP_CVSID("$Id$") -typedef unsigned char uint8_t; +typedef unsigned char uchar; #if UINT_MAX == 65535 typedef unsigned long int32; @@ -295,13 +304,13 @@ static void SwapWord( int length, void * wordP ) { 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; } } @@ -328,10 +337,10 @@ static void * SfRealloc( void * pMem, int nNewSize ) /* 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; @@ -477,10 +486,9 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks ) 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 */ @@ -497,7 +505,7 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks ) /* Establish the byte order on this machine. */ /* -------------------------------------------------------------------- */ i = 1; - if( *((uint8_t *) &i) == 1 ) + if( *((uchar *) &i) == 1 ) bBigEndian = FALSE; else bBigEndian = TRUE; @@ -539,15 +547,11 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks ) 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 ); @@ -560,11 +564,12 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks ) 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 ); @@ -578,7 +583,7 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks ) /* -------------------------------------------------------------------- */ /* 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 @@ -673,7 +678,7 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks ) 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 || @@ -695,15 +700,14 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks ) 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. */ @@ -839,10 +843,10 @@ SHPHandle SHPAPI_CALL 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; @@ -850,7 +854,7 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks ) /* Establish the byte order on this system. */ /* -------------------------------------------------------------------- */ i = 1; - if( *((uint8_t *) &i) == 1 ) + if( *((uchar *) &i) == 1 ) bBigEndian = FALSE; else bBigEndian = TRUE; @@ -878,7 +882,7 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks ) if( fpSHP == NULL ) { psHooks->Error( "Failed to create file .shp file." ); - return( NULL ); + goto error; } sprintf( pszFullname, "%s.shx", pszBasename ); @@ -886,11 +890,11 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks ) 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. */ @@ -925,7 +929,7 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks ) if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 ) { psHooks->Error( "Failed to write .shp header." ); - return NULL; + goto error; } /* -------------------------------------------------------------------- */ @@ -938,7 +942,7 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks ) if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 ) { psHooks->Error( "Failed to write .shx header." ); - return NULL; + goto error; } /* -------------------------------------------------------------------- */ @@ -948,6 +952,13 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks ) psHooks->FClose( fpSHX ); return( SHPOpenLL( pszLayer, "r+b", psHooks ) ); + +error: + if (pszFullname) free(pszFullname); + if (pszBasename) free(pszBasename); + if (fpSHP) psHooks->FClose( fpSHP ); + if (fpSHX) psHooks->FClose( fpSHX ); + return NULL; } /************************************************************************/ @@ -957,7 +968,7 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks ) /* 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 ); @@ -1158,7 +1169,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject ) { unsigned int nRecordOffset, nRecordSize=0; int i; - uint8_t *pabyRec; + uchar *pabyRec; int32 i32; psSHP->bUpdated = TRUE; @@ -1197,7 +1208,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject ) /* -------------------------------------------------------------------- */ /* Initialize record. */ /* -------------------------------------------------------------------- */ - pabyRec = (uint8_t *) malloc(psObject->nVertices * 4 * sizeof(double) + pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double) + psObject->nParts * 8 + 128); /* -------------------------------------------------------------------- */ @@ -1565,7 +1576,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) 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]; -- 2.40.0