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);
 
DBFHandle DBFCloneEmpty(const DBFHandle psDBF, const char *pszFilename)
const char * DBFReadStringAttribute(DBFHandle psDBF, int iRecord, int iField)
const char * DBFGetCodePage(const DBFHandle psDBF)
int DBFWriteIntegerAttribute(DBFHandle psDBF, int iRecord, int iField, int nValue)
DBFHandle DBFCreate(const char *pszFilename)
int DBFWriteStringAttribute(DBFHandle psDBF, int iRecord, int iField, const char *pszValue)
int DBFGetFieldCount(const DBFHandle psDBF)
int DBFMarkRecordDeleted(DBFHandle psDBF, int iShape, int bIsDeleted)
int DBFWriteLogicalAttribute(DBFHandle psDBF, int iRecord, int iField, const char lValue)
DBFHandle DBFOpenLL(const char *pszFilename, const char *pszAccess, const SAHooks *psHooks)
int DBFDeleteField(DBFHandle psDBF, int iField)
void DBFClose(DBFHandle psDBF)
int DBFAddField(DBFHandle psDBF, const char *pszFieldName, DBFFieldType eType, int nWidth, int nDecimals)
int DBFAlterFieldDefn(DBFHandle psDBF, int iField, const char *pszFieldName, char chType, int nWidth, int nDecimals)
int DBFWriteNULLAttribute(DBFHandle psDBF, int iRecord, int iField)
SHPDate DBFReadDateAttribute(DBFHandle psDBF, int iRecord, int iField)
int DBFIsRecordDeleted(const DBFHandle psDBF, int iShape)
void DBFSetWriteEndOfFileChar(DBFHandle psDBF, int bWriteFlag)
int DBFReadIntegerAttribute(DBFHandle psDBF, int iRecord, int iField)
DBFHandle DBFCreateEx(const char *pszFilename, const char *pszCodePage)
int DBFIsAttributeNULL(const DBFHandle psDBF, int iRecord, int iField)
DBFFieldType DBFGetFieldInfo(const DBFHandle psDBF, int iField, char *pszFieldName, int *pnWidth, int *pnDecimals)
int DBFReorderFields(DBFHandle psDBF, const int *panMap)
const char * DBFReadTuple(DBFHandle psDBF, int hEntity)
int DBFWriteDoubleAttribute(DBFHandle psDBF, int iRecord, int iField, double dValue)
double DBFReadDoubleAttribute(DBFHandle psDBF, int iRecord, int iField)
#define HEADER_RECORD_TERMINATOR
void DBFSetLastModifiedDate(DBFHandle psDBF, int nYYSince1900, int nMM, int nDD)
void DBFUpdateHeader(DBFHandle psDBF)
char DBFGetNativeFieldType(const DBFHandle psDBF, int iField)
DBFHandle DBFCreateLL(const char *pszFilename, const char *pszCodePage, const SAHooks *psHooks)
int DBFAddNativeFieldType(DBFHandle psDBF, const char *pszFieldName, char chType, int nWidth, int nDecimals)
#define END_OF_FILE_CHARACTER
int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, const void *pValue)
int DBFGetRecordCount(const DBFHandle psDBF)
int DBFWriteDateAttribute(DBFHandle psDBF, int iRecord, int iField, const SHPDate *lValue)
int DBFWriteTuple(DBFHandle psDBF, int hEntity, const void *pRawTuple)
DBFHandle DBFOpen(const char *pszFilename, const char *pszAccess)
int DBFGetFieldIndex(const DBFHandle psDBF, const char *pszFieldName)
const char * DBFReadLogicalAttribute(DBFHandle psDBF, int iRecord, int iField)
#define CPL_IGNORE_RET_VAL_INT(x)
void SASetupDefaultHooks(SAHooks *psHooks)
#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)