3 |
* |
* |
4 |
* Project: Shapelib |
* Project: Shapelib |
5 |
* Purpose: Implementation of .dbf access API documented in dbf_api.html. |
* Purpose: Implementation of .dbf access API documented in dbf_api.html. |
6 |
* Author: Frank Warmerdam, [email protected] |
* Author: Frank Warmerdam, [email protected] |
7 |
* |
* |
8 |
****************************************************************************** |
****************************************************************************** |
9 |
* Copyright (c) 1999, Frank Warmerdam |
* Copyright (c) 1999, Frank Warmerdam |
34 |
****************************************************************************** |
****************************************************************************** |
35 |
* |
* |
36 |
* $Log$ |
* $Log$ |
37 |
* Revision 1.1 2003/08/19 21:29:25 jan |
* Revision 1.2 2003/10/02 15:15:16 bh |
38 |
* These files have been moved here from thuban/extensions/shapelib/ |
* Update to shapelib 1.2.10 |
39 |
* See there in the Attic for the older history. |
* |
40 |
* |
* Revision 1.48 2003/03/10 14:51:27 warmerda |
41 |
* Revision 1.4 2002/08/22 16:00:01 bh |
* DBFWrite* calls now return FALSE if they have to truncate |
42 |
* * extensions/shapelib/shapefil.h (DBFCommit), |
* |
43 |
* extensions/shapelib/dbfopen.c (DBFCommit): New API function to |
* Revision 1.47 2002/11/20 03:32:22 warmerda |
44 |
* commit any changes made to the DBF file. |
* Ensure field name in DBFGetFieldIndex() is properly terminated. |
45 |
* |
* |
46 |
* Revision 1.3 2002/05/07 14:09:45 bh |
* Revision 1.46 2002/10/09 13:10:21 warmerda |
47 |
* * extensions/shapelib/shpopen.c, extensions/shapelib/shapefil.h, |
* Added check that width is positive. |
48 |
* extensions/shapelib/dbfopen.c: Really update to the versions of |
* |
49 |
* shapelib 1.2.9. For some reason it wasn't really done on |
* Revision 1.45 2002/09/29 00:00:08 warmerda |
50 |
* 2002-04-11. |
* added FTLogical and logical attribute read/write calls |
51 |
|
* |
52 |
|
* Revision 1.44 2002/05/07 13:46:11 warmerda |
53 |
|
* Added DBFWriteAttributeDirectly(). |
54 |
|
* |
55 |
|
* Revision 1.43 2002/02/13 19:39:21 warmerda |
56 |
|
* Fix casting issues in DBFCloneEmpty(). |
57 |
|
* |
58 |
|
* Revision 1.42 2002/01/15 14:36:07 warmerda |
59 |
|
* updated email address |
60 |
|
* |
61 |
|
* Revision 1.41 2002/01/15 14:31:49 warmerda |
62 |
|
* compute rather than copying nHeaderLength in DBFCloneEmpty() |
63 |
|
* |
64 |
|
* Revision 1.40 2002/01/09 04:32:35 warmerda |
65 |
|
* fixed to read correct amount of header |
66 |
|
* |
67 |
|
* Revision 1.39 2001/12/11 22:41:03 warmerda |
68 |
|
* improve io related error checking when reading header |
69 |
|
* |
70 |
|
* Revision 1.38 2001/11/28 16:07:31 warmerda |
71 |
|
* Cleanup to avoid compiler warnings as suggested by Richard Hash. |
72 |
* |
* |
73 |
* Revision 1.37 2001/07/04 05:18:09 warmerda |
* Revision 1.37 2001/07/04 05:18:09 warmerda |
74 |
* do last fix properly |
* do last fix properly |
310 |
{ |
{ |
311 |
DBFHandle psDBF; |
DBFHandle psDBF; |
312 |
unsigned char *pabyBuf; |
unsigned char *pabyBuf; |
313 |
int nFields, nRecords, nHeadLen, nRecLen, iField, i; |
int nFields, nHeadLen, nRecLen, iField, i; |
314 |
char *pszBasename, *pszFullname; |
char *pszBasename, *pszFullname; |
315 |
|
|
316 |
/* -------------------------------------------------------------------- */ |
/* -------------------------------------------------------------------- */ |
370 |
/* Read Table Header info */ |
/* Read Table Header info */ |
371 |
/* -------------------------------------------------------------------- */ |
/* -------------------------------------------------------------------- */ |
372 |
pabyBuf = (unsigned char *) malloc(500); |
pabyBuf = (unsigned char *) malloc(500); |
373 |
fread( pabyBuf, 32, 1, psDBF->fp ); |
if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 ) |
374 |
|
{ |
375 |
|
fclose( psDBF->fp ); |
376 |
|
free( pabyBuf ); |
377 |
|
free( psDBF ); |
378 |
|
return NULL; |
379 |
|
} |
380 |
|
|
381 |
psDBF->nRecords = nRecords = |
psDBF->nRecords = |
382 |
pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256; |
pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256; |
383 |
|
|
384 |
psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256; |
psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256; |
396 |
psDBF->pszHeader = (char *) pabyBuf; |
psDBF->pszHeader = (char *) pabyBuf; |
397 |
|
|
398 |
fseek( psDBF->fp, 32, 0 ); |
fseek( psDBF->fp, 32, 0 ); |
399 |
fread( pabyBuf, nHeadLen, 1, psDBF->fp ); |
if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 ) |
400 |
|
{ |
401 |
|
fclose( psDBF->fp ); |
402 |
|
free( pabyBuf ); |
403 |
|
free( psDBF ); |
404 |
|
return NULL; |
405 |
|
} |
406 |
|
|
407 |
psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields); |
psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields); |
408 |
psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields); |
psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields); |
604 |
if( eType != FTDouble && nDecimals != 0 ) |
if( eType != FTDouble && nDecimals != 0 ) |
605 |
return( -1 ); |
return( -1 ); |
606 |
|
|
607 |
|
if( nWidth < 1 ) |
608 |
|
return -1; |
609 |
|
|
610 |
/* -------------------------------------------------------------------- */ |
/* -------------------------------------------------------------------- */ |
611 |
/* SfRealloc all the arrays larger to hold the additional field */ |
/* SfRealloc all the arrays larger to hold the additional field */ |
612 |
/* information. */ |
/* information. */ |
633 |
psDBF->panFieldSize[psDBF->nFields-1] = nWidth; |
psDBF->panFieldSize[psDBF->nFields-1] = nWidth; |
634 |
psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals; |
psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals; |
635 |
|
|
636 |
if( eType == FTString ) |
if( eType == FTLogical ) |
637 |
|
psDBF->pachFieldType[psDBF->nFields-1] = 'L'; |
638 |
|
else if( eType == FTString ) |
639 |
psDBF->pachFieldType[psDBF->nFields-1] = 'C'; |
psDBF->pachFieldType[psDBF->nFields-1] = 'C'; |
640 |
else |
else |
641 |
psDBF->pachFieldType[psDBF->nFields-1] = 'N'; |
psDBF->pachFieldType[psDBF->nFields-1] = 'N'; |
841 |
} |
} |
842 |
|
|
843 |
/************************************************************************/ |
/************************************************************************/ |
844 |
|
/* DBFReadLogicalAttribute() */ |
845 |
|
/* */ |
846 |
|
/* Read a logical attribute. */ |
847 |
|
/************************************************************************/ |
848 |
|
|
849 |
|
const char SHPAPI_CALL1(*) |
850 |
|
DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField ) |
851 |
|
|
852 |
|
{ |
853 |
|
return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) ); |
854 |
|
} |
855 |
|
|
856 |
|
/************************************************************************/ |
857 |
/* DBFIsAttributeNULL() */ |
/* DBFIsAttributeNULL() */ |
858 |
/* */ |
/* */ |
859 |
/* Return TRUE if value for field is NULL. */ |
/* Return TRUE if value for field is NULL. */ |
888 |
/* empty string fields are considered NULL */ |
/* empty string fields are considered NULL */ |
889 |
return strlen(pszValue) == 0; |
return strlen(pszValue) == 0; |
890 |
} |
} |
|
return FALSE; |
|
891 |
} |
} |
892 |
|
|
893 |
/************************************************************************/ |
/************************************************************************/ |
946 |
pszFieldName[i] = '\0'; |
pszFieldName[i] = '\0'; |
947 |
} |
} |
948 |
|
|
949 |
if( psDBF->pachFieldType[iField] == 'N' |
if ( psDBF->pachFieldType[iField] == 'L' ) |
950 |
|| psDBF->pachFieldType[iField] == 'F' |
return( FTLogical); |
951 |
|| psDBF->pachFieldType[iField] == 'D' ) |
|
952 |
|
else if( psDBF->pachFieldType[iField] == 'N' |
953 |
|
|| psDBF->pachFieldType[iField] == 'F' |
954 |
|
|| psDBF->pachFieldType[iField] == 'D' ) |
955 |
{ |
{ |
956 |
if( psDBF->panFieldDecimals[iField] > 0 ) |
if( psDBF->panFieldDecimals[iField] > 0 ) |
957 |
return( FTDouble ); |
return( FTDouble ); |
974 |
void * pValue ) |
void * pValue ) |
975 |
|
|
976 |
{ |
{ |
977 |
int nRecordOffset, i, j; |
int nRecordOffset, i, j, nRetResult = TRUE; |
978 |
unsigned char *pabyRec; |
unsigned char *pabyRec; |
979 |
char szSField[400], szFormat[20]; |
char szSField[400], szFormat[20]; |
980 |
|
|
1077 |
sprintf( szFormat, "%%%dd", nWidth ); |
sprintf( szFormat, "%%%dd", nWidth ); |
1078 |
sprintf(szSField, szFormat, (int) *((double *) pValue) ); |
sprintf(szSField, szFormat, (int) *((double *) pValue) ); |
1079 |
if( (int)strlen(szSField) > psDBF->panFieldSize[iField] ) |
if( (int)strlen(szSField) > psDBF->panFieldSize[iField] ) |
1080 |
|
{ |
1081 |
szSField[psDBF->panFieldSize[iField]] = '\0'; |
szSField[psDBF->panFieldSize[iField]] = '\0'; |
1082 |
|
nRetResult = FALSE; |
1083 |
|
} |
1084 |
|
|
1085 |
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), |
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), |
1086 |
szSField, strlen(szSField) ); |
szSField, strlen(szSField) ); |
1096 |
nWidth, psDBF->panFieldDecimals[iField] ); |
nWidth, psDBF->panFieldDecimals[iField] ); |
1097 |
sprintf(szSField, szFormat, *((double *) pValue) ); |
sprintf(szSField, szFormat, *((double *) pValue) ); |
1098 |
if( (int) strlen(szSField) > psDBF->panFieldSize[iField] ) |
if( (int) strlen(szSField) > psDBF->panFieldSize[iField] ) |
1099 |
|
{ |
1100 |
szSField[psDBF->panFieldSize[iField]] = '\0'; |
szSField[psDBF->panFieldSize[iField]] = '\0'; |
1101 |
|
nRetResult = FALSE; |
1102 |
|
} |
1103 |
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), |
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), |
1104 |
szSField, strlen(szSField) ); |
szSField, strlen(szSField) ); |
1105 |
} |
} |
1106 |
break; |
break; |
1107 |
|
|
1108 |
|
case 'L': |
1109 |
|
if (psDBF->panFieldSize[iField] >= 1 && |
1110 |
|
(*(char*)pValue == 'F' || *(char*)pValue == 'T')) |
1111 |
|
*(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue; |
1112 |
|
break; |
1113 |
|
|
1114 |
default: |
default: |
1115 |
if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] ) |
if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] ) |
1116 |
|
{ |
1117 |
j = psDBF->panFieldSize[iField]; |
j = psDBF->panFieldSize[iField]; |
1118 |
|
nRetResult = FALSE; |
1119 |
|
} |
1120 |
else |
else |
1121 |
{ |
{ |
1122 |
memset( pabyRec+psDBF->panFieldOffset[iField], ' ', |
memset( pabyRec+psDBF->panFieldOffset[iField], ' ', |
1129 |
break; |
break; |
1130 |
} |
} |
1131 |
|
|
1132 |
|
return( nRetResult ); |
1133 |
|
} |
1134 |
|
|
1135 |
|
/************************************************************************/ |
1136 |
|
/* DBFWriteAttributeDirectly() */ |
1137 |
|
/* */ |
1138 |
|
/* Write an attribute record to the file, but without any */ |
1139 |
|
/* reformatting based on type. The provided buffer is written */ |
1140 |
|
/* as is to the field position in the record. */ |
1141 |
|
/************************************************************************/ |
1142 |
|
|
1143 |
|
int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, |
1144 |
|
void * pValue ) |
1145 |
|
|
1146 |
|
{ |
1147 |
|
int nRecordOffset, i, j; |
1148 |
|
unsigned char *pabyRec; |
1149 |
|
|
1150 |
|
/* -------------------------------------------------------------------- */ |
1151 |
|
/* Is this a valid record? */ |
1152 |
|
/* -------------------------------------------------------------------- */ |
1153 |
|
if( hEntity < 0 || hEntity > psDBF->nRecords ) |
1154 |
|
return( FALSE ); |
1155 |
|
|
1156 |
|
if( psDBF->bNoHeader ) |
1157 |
|
DBFWriteHeader(psDBF); |
1158 |
|
|
1159 |
|
/* -------------------------------------------------------------------- */ |
1160 |
|
/* Is this a brand new record? */ |
1161 |
|
/* -------------------------------------------------------------------- */ |
1162 |
|
if( hEntity == psDBF->nRecords ) |
1163 |
|
{ |
1164 |
|
DBFFlushRecord( psDBF ); |
1165 |
|
|
1166 |
|
psDBF->nRecords++; |
1167 |
|
for( i = 0; i < psDBF->nRecordLength; i++ ) |
1168 |
|
psDBF->pszCurrentRecord[i] = ' '; |
1169 |
|
|
1170 |
|
psDBF->nCurrentRecord = hEntity; |
1171 |
|
} |
1172 |
|
|
1173 |
|
/* -------------------------------------------------------------------- */ |
1174 |
|
/* Is this an existing record, but different than the last one */ |
1175 |
|
/* we accessed? */ |
1176 |
|
/* -------------------------------------------------------------------- */ |
1177 |
|
if( psDBF->nCurrentRecord != hEntity ) |
1178 |
|
{ |
1179 |
|
DBFFlushRecord( psDBF ); |
1180 |
|
|
1181 |
|
nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; |
1182 |
|
|
1183 |
|
fseek( psDBF->fp, nRecordOffset, 0 ); |
1184 |
|
fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); |
1185 |
|
|
1186 |
|
psDBF->nCurrentRecord = hEntity; |
1187 |
|
} |
1188 |
|
|
1189 |
|
pabyRec = (unsigned char *) psDBF->pszCurrentRecord; |
1190 |
|
|
1191 |
|
/* -------------------------------------------------------------------- */ |
1192 |
|
/* Assign all the record fields. */ |
1193 |
|
/* -------------------------------------------------------------------- */ |
1194 |
|
if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] ) |
1195 |
|
j = psDBF->panFieldSize[iField]; |
1196 |
|
else |
1197 |
|
{ |
1198 |
|
memset( pabyRec+psDBF->panFieldOffset[iField], ' ', |
1199 |
|
psDBF->panFieldSize[iField] ); |
1200 |
|
j = strlen((char *) pValue); |
1201 |
|
} |
1202 |
|
|
1203 |
|
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), |
1204 |
|
(char *) pValue, j ); |
1205 |
|
|
1206 |
|
psDBF->bCurrentRecordModified = TRUE; |
1207 |
|
psDBF->bUpdated = TRUE; |
1208 |
|
|
1209 |
return( TRUE ); |
return( TRUE ); |
1210 |
} |
} |
1211 |
|
|
1267 |
} |
} |
1268 |
|
|
1269 |
/************************************************************************/ |
/************************************************************************/ |
1270 |
|
/* DBFWriteLogicalAttribute() */ |
1271 |
|
/* */ |
1272 |
|
/* Write a logical attribute. */ |
1273 |
|
/************************************************************************/ |
1274 |
|
|
1275 |
|
int SHPAPI_CALL |
1276 |
|
DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField, |
1277 |
|
const char lValue) |
1278 |
|
|
1279 |
|
{ |
1280 |
|
return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) ); |
1281 |
|
} |
1282 |
|
|
1283 |
|
/************************************************************************/ |
1284 |
/* DBFWriteTuple() */ |
/* DBFWriteTuple() */ |
1285 |
/* */ |
/* */ |
1286 |
/* Write an attribute record to the file. */ |
/* Write an attribute record to the file. */ |
1402 |
newDBF = DBFCreate ( pszFilename ); |
newDBF = DBFCreate ( pszFilename ); |
1403 |
if ( newDBF == NULL ) return ( NULL ); |
if ( newDBF == NULL ) return ( NULL ); |
1404 |
|
|
1405 |
newDBF->pszHeader = (void *) malloc ( 32 * psDBF->nFields ); |
newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields ); |
1406 |
memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields ); |
memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields ); |
1407 |
|
|
1408 |
newDBF->nFields = psDBF->nFields; |
newDBF->nFields = psDBF->nFields; |
1409 |
newDBF->nRecordLength = psDBF->nRecordLength; |
newDBF->nRecordLength = psDBF->nRecordLength; |
1410 |
newDBF->nHeaderLength = psDBF->nHeaderLength; |
newDBF->nHeaderLength = 32 * (psDBF->nFields+1); |
1411 |
|
|
1412 |
newDBF->panFieldOffset = (void *) malloc ( sizeof(int) * psDBF->nFields ); |
newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); |
1413 |
memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); |
memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); |
1414 |
newDBF->panFieldSize = (void *) malloc ( sizeof(int) * psDBF->nFields ); |
newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields ); |
1415 |
memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); |
memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); |
1416 |
newDBF->panFieldDecimals = (void *) malloc ( sizeof(int) * psDBF->nFields ); |
newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields ); |
1417 |
memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); |
memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); |
1418 |
newDBF->pachFieldType = (void *) malloc ( sizeof(int) * psDBF->nFields ); |
newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields ); |
1419 |
memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields ); |
memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields ); |
1420 |
|
|
1421 |
newDBF->bNoHeader = TRUE; |
newDBF->bNoHeader = TRUE; |
1482 |
int i; |
int i; |
1483 |
|
|
1484 |
strncpy(name1, pszFieldName,11); |
strncpy(name1, pszFieldName,11); |
1485 |
|
name1[11] = '\0'; |
1486 |
str_to_upper(name1); |
str_to_upper(name1); |
1487 |
|
|
1488 |
for( i = 0; i < DBFGetFieldCount(psDBF); i++ ) |
for( i = 0; i < DBFGetFieldCount(psDBF); i++ ) |