24 #include "cpl_string.h"
28 #define STRCASECMP(a, b) (_stricmp(a, b))
30 #define STRCASECMP(a, b) (stricmp(a, b))
33 #define STRCASECMP(a, b) (strcasecmp(a, b))
38 #define snprintf _snprintf
42 #define snprintf _snprintf
46 #define CPLsprintf sprintf
47 #define CPLsnprintf snprintf
56 #define XBASE_FILEHDR_SZ 32
58 #define HEADER_RECORD_TERMINATOR 0x0D
61 #define END_OF_FILE_CHARACTER 0x1A
68 #define CPL_IGNORE_RET_VAL_INT(x) x
80 static void DBFWriteHeader(
DBFHandle psDBF)
143 static bool DBFFlushRecord(
DBFHandle psDBF)
164 szMessage,
sizeof(szMessage),
165 "Failure seeking to position before writing DBF record %d.",
173 1, psDBF->
fp) != 1) {
175 snprintf(szMessage,
sizeof(szMessage),
203 static bool DBFLoadRecord(
DBFHandle psDBF,
int iRecord)
206 if (!DBFFlushRecord(psDBF))
213 if (psDBF->
sHooks.
FSeek(psDBF->
fp, nRecordOffset, SEEK_SET) != 0) {
215 snprintf(szMessage,
sizeof(szMessage),
216 "fseek(%ld) failed on DBF file.",
223 1, psDBF->
fp) != 1) {
225 snprintf(szMessage,
sizeof(szMessage),
251 DBFWriteHeader(psDBF);
253 if (!DBFFlushRecord(psDBF))
259 psDBF->
sHooks.
FRead(abyFileHeader, 1,
sizeof(abyFileHeader), psDBF->
fp);
273 psDBF->
sHooks.
FWrite(abyFileHeader,
sizeof(abyFileHeader), 1, psDBF->
fp);
302 return DBFOpenLL(pszFilename, pszAccess, &sHooks);
309 static int DBFGetLenWithoutExtension(
const char *pszBasename)
311 const int nLen =
STATIC_CAST(
int, strlen(pszBasename));
312 for (
int i = nLen - 1;
313 i > 0 && pszBasename[i] !=
'/' && pszBasename[i] !=
'\\'; i--) {
314 if (pszBasename[i] ==
'.') {
333 if (strcmp(pszAccess,
"r") != 0 && strcmp(pszAccess,
"r+") != 0 &&
334 strcmp(pszAccess,
"rb") != 0 && strcmp(pszAccess,
"rb+") != 0 &&
335 strcmp(pszAccess,
"r+b") != 0)
338 if (strcmp(pszAccess,
"r") == 0)
341 if (strcmp(pszAccess,
"r+") == 0)
348 const int nLenWithoutExtension = DBFGetLenWithoutExtension(pszFilename);
350 memcpy(pszFullname, pszFilename, nLenWithoutExtension);
351 memcpy(pszFullname + nLenWithoutExtension,
".dbf", 5);
358 memcpy(pszFullname + nLenWithoutExtension,
".DBF", 5);
363 memcpy(pszFullname + nLenWithoutExtension,
".cpg", 5);
366 memcpy(pszFullname + nLenWithoutExtension,
".CPG", 5);
386 const int nBufSize = 500;
399 psDBF->
nRecords = pabyBuf[4] | (pabyBuf[5] << 8) | (pabyBuf[6] << 16) |
400 ((pabyBuf[7] & 0x7f) << 24);
402 const int nHeadLen = pabyBuf[8] | (pabyBuf[9] << 8);
427 memset(pabyBuf, 0, nBufSize);
428 psDBF->
sHooks.
FRead(pabyBuf, 1, nBufSize - 1, pfCPG);
448 pabyBuf =
STATIC_CAST(
unsigned char *, realloc(pabyBuf, nHeadLen));
467 for (
int iField = 0; iField < nFields; iField++) {
474 if (pabyFInfo[11] ==
'N' || pabyFInfo[11] ==
'F') {
531 DBFWriteHeader(psDBF);
582 const char *pszCodePage)
588 return DBFCreateLL(pszFilename, pszCodePage, &sHooks);
598 const char *pszCodePage,
605 const int nLenWithoutExtension = DBFGetLenWithoutExtension(pszFilename);
607 memcpy(pszFullname, pszFilename, nLenWithoutExtension);
608 memcpy(pszFullname + nLenWithoutExtension,
".dbf", 5);
619 memcpy(pszFullname + nLenWithoutExtension,
".cpg", 5);
622 if (strncmp(pszCodePage,
"LDID/", 5) == 0) {
623 ldid = atoi(pszCodePage + 5);
633 strlen(pszCodePage), 1, fpCPG);
712 static char DBFGetNullCharacter(
char chType)
735 char chType,
int nWidth,
int nDecimals)
738 if (!DBFFlushRecord(psDBF))
743 snprintf(szMessage,
sizeof(szMessage),
744 "Cannot add field %s. Header length limit reached "
745 "(max 65535 bytes, 2046 fields).",
762 snprintf(szMessage,
sizeof(szMessage),
763 "Cannot add field %s. Record length limit reached "
764 "(max 65535 bytes).",
819 pszFInfo[16] =
STATIC_CAST(
unsigned char, nWidth % 256);
820 pszFInfo[17] =
STATIC_CAST(
unsigned char, nWidth / 256);
824 pszFInfo[17] =
STATIC_CAST(
unsigned char, nDecimals);
845 const char chFieldFill = DBFGetNullCharacter(chType);
848 for (
int i = psDBF->
nRecords - 1; i >= 0; --i) {
854 if (psDBF->
sHooks.
FRead(pszRecord, nOldRecordLength, 1, psDBF->
fp) !=
861 memset(pszRecord + nOldRecordLength, chFieldFill, nWidth);
902 static void *DBFReadAttribute(
DBFHandle psDBF,
int hEntity,
int iField,
908 if (hEntity < 0 || hEntity >= psDBF->
nRecords)
911 if (iField < 0 || iField >= psDBF->
nFields)
917 if (!DBFLoadRecord(psDBF, hEntity))
920 const unsigned char *pabyRec =
950 if (chReqType ==
'I') {
955 else if (chReqType ==
'N') {
965 #ifdef TRIM_DBF_WHITESPACE
968 char *pchDst = pchSrc;
970 while (*pchSrc ==
' ')
973 while (*pchSrc !=
'\0')
974 *(pchDst++) = *(pchSrc++);
977 while (pchDst != psDBF->
pszWorkField && *(--pchDst) ==
' ')
995 STATIC_CAST(
int *, DBFReadAttribute(psDBF, iRecord, iField,
'I'));
1013 STATIC_CAST(
double *, DBFReadAttribute(psDBF, iRecord, iField,
'N'));
1031 DBFReadAttribute(psDBF, iRecord, iField,
'C'));
1044 DBFReadAttribute(psDBF, iRecord, iField,
'L'));
1057 const char *, DBFReadAttribute(psDBF, iRecord, iField,
'D'));
1066 else if (3 != sscanf(pdateValue,
"%4d%2d%2d", &date.
year, &date.
month,
1082 static bool DBFIsValueNULL(
char chType,
const char *pszValue)
1095 if (pszValue[0] ==
'*')
1098 for (
int i = 0; pszValue[i] !=
'\0'; i++) {
1099 if (pszValue[i] !=
' ')
1114 return pszValue[0] == 0 || strncmp(pszValue,
"00000000", 8) == 0 ||
1115 strcmp(pszValue,
" ") == 0 || strcmp(pszValue,
"0") == 0;
1119 return pszValue[0] ==
'?';
1123 return strlen(pszValue) == 0;
1143 return DBFIsValueNULL(psDBF->
pachFieldType[iField], pszValue);
1177 char *pszFieldName,
int *pnWidth,
1180 if (iField < 0 || iField >= psDBF->
nFields)
1190 strncpy(pszFieldName,
1196 i > 0 && pszFieldName[i] ==
' '; i--)
1197 pszFieldName[i] =
'\0';
1225 static bool DBFWriteAttribute(
DBFHandle psDBF,
int hEntity,
int iField,
1231 if (hEntity < 0 || hEntity > psDBF->
nRecords)
1235 DBFWriteHeader(psDBF);
1241 if (!DBFFlushRecord(psDBF))
1255 if (!DBFLoadRecord(psDBF, hEntity))
1258 unsigned char *pabyRec =
1279 bool nRetResult =
true;
1288 if (
STATIC_CAST(
int,
sizeof(szSField)) - 2 < nWidth)
1289 nWidth =
sizeof(szSField) - 2;
1292 snprintf(szFormat,
sizeof(szFormat),
"%%%d.%df", nWidth,
1296 szSField[
sizeof(szSField) - 1] =
'\0';
1303 szSField, strlen(szSField));
1351 int iField,
const void *pValue)
1356 if (hEntity < 0 || hEntity > psDBF->
nRecords)
1360 DBFWriteHeader(psDBF);
1366 if (!DBFFlushRecord(psDBF))
1380 if (!DBFLoadRecord(psDBF, hEntity))
1384 unsigned char *pabyRec =
1420 int iField,
double dValue)
1422 return (DBFWriteAttribute(psDBF, iRecord, iField,
1433 int iField,
int nValue)
1435 double dValue = nValue;
1437 return (DBFWriteAttribute(psDBF, iRecord, iField,
1448 int iField,
const char *pszValue)
1451 DBFWriteAttribute(psDBF, iRecord, iField,
1463 return (DBFWriteAttribute(psDBF, iRecord, iField,
SHPLIB_NULLPTR));
1473 int iField,
const char lValue)
1476 DBFWriteAttribute(psDBF, iRecord, iField,
1492 if (lValue->
year < 0 || lValue->
year > 9999)
1496 if (lValue->
day < 0 || lValue->
day > 99)
1499 snprintf(dateValue,
sizeof(dateValue),
"%04d%02d%02d", lValue->
year,
1511 const void *pRawTuple)
1516 if (hEntity < 0 || hEntity > psDBF->
nRecords)
1520 DBFWriteHeader(psDBF);
1526 if (!DBFFlushRecord(psDBF))
1540 if (!DBFLoadRecord(psDBF, hEntity))
1543 unsigned char *pabyRec =
1563 if (hEntity < 0 || hEntity >= psDBF->nRecords)
1566 if (!DBFLoadRecord(psDBF, hEntity))
1569 return STATIC_CAST(
const char *, psDBF->pszCurrentRecord);
1580 const char *pszFilename)
1601 sizeof(
int) * psDBF->
nFields);
1605 sizeof(
int) * psDBF->
nFields);
1609 sizeof(
int) * psDBF->
nFields);
1613 sizeof(
char) * psDBF->
nFields);
1619 DBFWriteHeader(newDBF);
1622 newDBF =
DBFOpen(pszFilename,
"rb+");
1641 if (iField >= 0 && iField < psDBF->nFields)
1656 const char *pszFieldName)
1680 if (iShape < 0 || iShape >= psDBF->
nRecords)
1686 if (!DBFLoadRecord(psDBF, iShape))
1705 if (iShape < 0 || iShape >= psDBF->
nRecords)
1712 if (!DBFLoadRecord(psDBF, iShape))
1741 return psDBF->pszCodePage;
1752 if (iField < 0 || iField >= psDBF->
nFields)
1756 if (!DBFFlushRecord(psDBF))
1766 for (
int i = iField + 1; i < psDBF->
nFields; i++) {
1818 for (
int iRecord = 0; iRecord < psDBF->
nRecords; iRecord++) {
1825 if (psDBF->
sHooks.
FRead(pszRecord, nOldRecordLength, 1, psDBF->
fp) !=
1836 psDBF->
sHooks.
FWrite(pszRecord, nDeletedFieldOffset, 1, psDBF->
fp);
1838 pszRecord + nDeletedFieldOffset + nDeletedFieldSize,
1839 nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize, 1,
1881 if (!DBFFlushRecord(psDBF))
1886 int *panFieldOffsetNew =
1888 int *panFieldSizeNew =
1890 int *panFieldDecimalsNew =
1892 char *pachFieldTypeNew =
1898 for (
int i = 0; i < psDBF->
nFields; i++) {
1905 panFieldOffsetNew[0] = 1;
1906 for (
int i = 1; i < psDBF->
nFields; i++) {
1907 panFieldOffsetNew[i] =
1908 panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
1914 bool errorAbort =
false;
1925 char *pszRecordNew =
1929 for (
int iRecord = 0; iRecord < psDBF->
nRecords; iRecord++) {
1942 pszRecordNew[0] = pszRecord[0];
1944 for (
int i = 0; i < psDBF->
nFields; i++) {
1945 memcpy(pszRecordNew + panFieldOffsetNew[i],
1962 free(panFieldOffsetNew);
1963 free(panFieldSizeNew);
1964 free(panFieldDecimalsNew);
1965 free(pachFieldTypeNew);
1996 const char *pszFieldName,
char chType,
1997 int nWidth,
int nDecimals)
1999 if (iField < 0 || iField >= psDBF->
nFields)
2003 if (!DBFFlushRecord(psDBF))
2006 const char chFieldFill = DBFGetNullCharacter(chType);
2041 if (chType ==
'C') {
2042 pszFInfo[16] =
STATIC_CAST(
unsigned char, nWidth % 256);
2043 pszFInfo[17] =
STATIC_CAST(
unsigned char, nWidth / 256);
2046 pszFInfo[16] =
STATIC_CAST(
unsigned char, nWidth);
2047 pszFInfo[17] =
STATIC_CAST(
unsigned char, nDecimals);
2053 if (nWidth != nOldWidth) {
2054 for (
int i = iField + 1; i < psDBF->
nFields; i++)
2070 bool errorAbort =
false;
2072 if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType)) {
2078 pszOldField[nOldWidth] = 0;
2081 for (
int iRecord = 0; iRecord < psDBF->
nRecords; iRecord++) {
2088 if (psDBF->
sHooks.
FRead(pszRecord, nOldRecordLength, 1,
2094 memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
2095 const bool bIsNULL = DBFIsValueNULL(chOldType, pszOldField);
2097 if (nWidth != nOldWidth) {
2098 if ((chOldType ==
'N' || chOldType ==
'F' ||
2099 chOldType ==
'D') &&
2100 pszOldField[0] ==
' ') {
2102 memmove(pszRecord + nOffset,
2103 pszRecord + nOffset + nOldWidth - nWidth, nWidth);
2105 if (nOffset + nOldWidth < nOldRecordLength) {
2106 memmove(pszRecord + nOffset + nWidth,
2107 pszRecord + nOffset + nOldWidth,
2108 nOldRecordLength - (nOffset + nOldWidth));
2114 memset(pszRecord + nOffset, chFieldFill, nWidth);
2141 else if (nWidth > nOldWidth) {
2147 pszOldField[nOldWidth] = 0;
2150 for (
int iRecord = psDBF->
nRecords - 1; iRecord >= 0; iRecord--) {
2157 if (psDBF->
sHooks.
FRead(pszRecord, nOldRecordLength, 1,
2163 memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
2164 const bool bIsNULL = DBFIsValueNULL(chOldType, pszOldField);
2166 if (nOffset + nOldWidth < nOldRecordLength) {
2167 memmove(pszRecord + nOffset + nWidth,
2168 pszRecord + nOffset + nOldWidth,
2169 nOldRecordLength - (nOffset + nOldWidth));
2174 memset(pszRecord + nOffset, chFieldFill, nWidth);
2177 if ((chOldType ==
'N' || chOldType ==
'F')) {
2179 memmove(pszRecord + nOffset + nWidth - nOldWidth,
2180 pszRecord + nOffset, nOldWidth);
2181 memset(pszRecord + nOffset,
' ', nWidth - nOldWidth);
2185 memset(pszRecord + nOffset + nOldWidth,
' ',
2186 nWidth - nOldWidth);
char SHPAPI_CALL DBFGetNativeFieldType(const DBFHandle psDBF, int iField)
int SHPAPI_CALL DBFGetFieldIndex(const DBFHandle psDBF, const char *pszFieldName)
int SHPAPI_CALL DBFGetRecordCount(const DBFHandle psDBF)
int SHPAPI_CALL DBFMarkRecordDeleted(DBFHandle psDBF, int iShape, int bIsDeleted)
int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, const void *pRawTuple)
int SHPAPI_CALL DBFWriteDoubleAttribute(DBFHandle psDBF, int iRecord, int iField, double dValue)
int SHPAPI_CALL DBFReadIntegerAttribute(DBFHandle psDBF, int iRecord, int iField)
int SHPAPI_CALL DBFAlterFieldDefn(DBFHandle psDBF, int iField, const char *pszFieldName, char chType, int nWidth, int nDecimals)
const char SHPAPI_CALL1 * DBFReadTuple(DBFHandle psDBF, int hEntity){ if(hEntity< 0||hEntity >=psDBF->nRecords) return SHPLIB_NULLPTR;if(!DBFLoadRecord(psDBF, hEntity)) return SHPLIB_NULLPTR;return STATIC_CAST(const char *, psDBF->pszCurrentRecord
DBFHandle SHPAPI_CALL DBFOpen(const char *pszFilename, const char *pszAccess)
DBFHandle SHPAPI_CALL DBFOpenLL(const char *pszFilename, const char *pszAccess, const SAHooks *psHooks)
double SHPAPI_CALL DBFReadDoubleAttribute(DBFHandle psDBF, int iRecord, int iField)
int SHPAPI_CALL DBFAddField(DBFHandle psDBF, const char *pszFieldName, DBFFieldType eType, int nWidth, int nDecimals)
const char SHPAPI_CALL1 * DBFReadLogicalAttribute(DBFHandle psDBF, int iRecord, int iField){ return STATIC_CAST(const char *, DBFReadAttribute(psDBF, iRecord, iField, 'L')
int SHPAPI_CALL DBFWriteDateAttribute(DBFHandle psDBF, int iRecord, int iField, const SHPDate *lValue)
int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, const void *pValue)
const char SHPAPI_CALL1 * DBFGetCodePage(const DBFHandle psDBF){ if(psDBF==SHPLIB_NULLPTR) return SHPLIB_NULLPTR;return psDBF->pszCodePage;}int SHPAPI_CALL DBFDeleteField(DBFHandle psDBF, int iField
DBFFieldType SHPAPI_CALL DBFGetFieldInfo(const DBFHandle psDBF, int iField, char *pszFieldName, int *pnWidth, int *pnDecimals)
int SHPAPI_CALL DBFGetFieldCount(const DBFHandle psDBF)
DBFHandle SHPAPI_CALL DBFCloneEmpty(const DBFHandle psDBF, const char *pszFilename)
int SHPAPI_CALL DBFIsRecordDeleted(const DBFHandle psDBF, int iShape)
int SHPAPI_CALL DBFReorderFields(DBFHandle psDBF, const int *panMap)
int SHPAPI_CALL DBFWriteIntegerAttribute(DBFHandle psDBF, int iRecord, int iField, int nValue)
int SHPAPI_CALL DBFWriteStringAttribute(DBFHandle psDBF, int iRecord, int iField, const char *pszValue)
DBFHandle SHPAPI_CALL DBFCreateEx(const char *pszFilename, const char *pszCodePage)
#define HEADER_RECORD_TERMINATOR
int SHPAPI_CALL DBFIsAttributeNULL(const DBFHandle psDBF, int iRecord, int iField)
SHPDate SHPAPI_CALL DBFReadDateAttribute(DBFHandle psDBF, int iRecord, int iField)
void SHPAPI_CALL DBFClose(DBFHandle psDBF)
int SHPAPI_CALL DBFAddNativeFieldType(DBFHandle psDBF, const char *pszFieldName, char chType, int nWidth, int nDecimals)
DBFHandle SHPAPI_CALL DBFCreateLL(const char *pszFilename, const char *pszCodePage, const SAHooks *psHooks)
DBFHandle SHPAPI_CALL DBFCreate(const char *pszFilename)
#define END_OF_FILE_CHARACTER
void SHPAPI_CALL DBFSetLastModifiedDate(DBFHandle psDBF, int nYYSince1900, int nMM, int nDD)
void SHPAPI_CALL DBFSetWriteEndOfFileChar(DBFHandle psDBF, int bWriteFlag)
int SHPAPI_CALL DBFWriteNULLAttribute(DBFHandle psDBF, int iRecord, int iField)
int SHPAPI_CALL DBFWriteLogicalAttribute(DBFHandle psDBF, int iRecord, int iField, const char lValue)
const char SHPAPI_CALL1 * DBFReadStringAttribute(DBFHandle psDBF, int iRecord, int iField){ return STATIC_CAST(const char *, DBFReadAttribute(psDBF, iRecord, iField, 'C')
#define CPL_IGNORE_RET_VAL_INT(x)
void SHPAPI_CALL DBFUpdateHeader(DBFHandle psDBF)
void SASetupDefaultHooks(SAHooks *psHooks)
int SHPAPI_CALL DBFDeleteField(DBFHandle hDBF, int iField)
#define XBASE_FLDNAME_LEN_WRITE
#define XBASE_FLDNAME_LEN_READ
#define XBASE_FLD_MAX_WIDTH
#define STATIC_CAST(type, x)
#define REINTERPRET_CAST(type, x)
#define CONST_CAST(type, x)
union DBFInfo::@16 fieldValue
int bCurrentRecordModified
int bRequireNextWriteSeek
void(* Error)(const char *message)
SAOffset(* FTell)(SAFile file)
int(* FFlush)(SAFile file)
SAFile(* FOpen)(const char *filename, const char *access, void *pvUserData)
double(* Atof)(const char *str)
SAOffset(* FWrite)(const void *p, SAOffset size, SAOffset nmemb, SAFile file)
int(* FClose)(SAFile file)
int(* Remove)(const char *filename, void *pvUserData)
SAOffset(* FRead)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
SAOffset(* FSeek)(SAFile file, SAOffset offset, int whence)