PostGIS  3.4.0dev-r@@SVN_REVISION@@
dbfopen.c
Go to the documentation of this file.
1 /******************************************************************************
2  * $Id$
3  *
4  * Project: Shapelib
5  * Purpose: Implementation of .dbf access API documented in dbf_api.html.
6  * Author: Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 1999, Frank Warmerdam
10  * Copyright (c) 2012-2019, Even Rouault <even dot rouault at spatialys.com>
11  *
12  * This software is available under the following "MIT Style" license,
13  * or at the option of the licensee under the LGPL (see COPYING). This
14  * option is discussed in more detail in shapelib.html.
15  *
16  * --
17  *
18  * Permission is hereby granted, free of charge, to any person obtaining a
19  * copy of this software and associated documentation files (the "Software"),
20  * to deal in the Software without restriction, including without limitation
21  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
22  * and/or sell copies of the Software, and to permit persons to whom the
23  * Software is furnished to do so, subject to the following conditions:
24  *
25  * The above copyright notice and this permission notice shall be included
26  * in all copies or substantial portions of the Software.
27  *
28  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
31  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34  * DEALINGS IN THE SOFTWARE.
35  ******************************************************************************/
36 
37 #include "shapefil.h"
38 
39 #include <math.h>
40 #include <stdlib.h>
41 #include <ctype.h>
42 #include <string.h>
43 
44 #ifdef USE_CPL
45 #include "cpl_string.h"
46 #else
47 
48 #if defined(WIN32) || defined(_WIN32)
49 # define STRCASECMP(a,b) (stricmp(a,b))
50 # else
51 #include <strings.h>
52 # define STRCASECMP(a,b) (strcasecmp(a,b))
53 #endif
54 
55 #if defined(_MSC_VER)
56 # if _MSC_VER < 1900
57 # define snprintf _snprintf
58 # endif
59 #elif defined(WIN32) || defined(_WIN32)
60 # ifndef snprintf
61 # define snprintf _snprintf
62 # endif
63 #endif
64 
65 #define CPLsprintf sprintf
66 #define CPLsnprintf snprintf
67 #endif
68 
69 SHP_CVSID("$Id$")
70 
71 #ifndef FALSE
72 # define FALSE 0
73 # define TRUE 1
74 #endif
75 
76 /* File header size */
77 #define XBASE_FILEHDR_SZ 32
78 
79 #define HEADER_RECORD_TERMINATOR 0x0D
80 
81 /* See http://www.manmrk.net/tutorials/database/xbase/dbf.html */
82 #define END_OF_FILE_CHARACTER 0x1A
83 
84 #ifdef USE_CPL
85 CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused) {}
86 #else
87 #define CPL_IGNORE_RET_VAL_INT(x) x
88 #endif
89 
90 #ifdef __cplusplus
91 #define STATIC_CAST(type,x) static_cast<type>(x)
92 #define REINTERPRET_CAST(type,x) reinterpret_cast<type>(x)
93 #define CONST_CAST(type,x) const_cast<type>(x)
94 #define SHPLIB_NULLPTR nullptr
95 #else
96 #define STATIC_CAST(type,x) ((type)(x))
97 #define REINTERPRET_CAST(type,x) ((type)(x))
98 #define CONST_CAST(type,x) ((type)(x))
99 #define SHPLIB_NULLPTR NULL
100 #endif
101 
102 /************************************************************************/
103 /* SfRealloc() */
104 /* */
105 /* A realloc cover function that will access a NULL pointer as */
106 /* a valid input. */
107 /************************************************************************/
108 
109 static void * SfRealloc( void * pMem, int nNewSize )
110 
111 {
112  if( pMem == SHPLIB_NULLPTR )
113  return malloc(nNewSize);
114  else
115  return realloc(pMem,nNewSize);
116 }
117 
118 /************************************************************************/
119 /* DBFWriteHeader() */
120 /* */
121 /* This is called to write out the file header, and field */
122 /* descriptions before writing any actual data records. This */
123 /* also computes all the DBFDataSet field offset/size/decimals */
124 /* and so forth values. */
125 /************************************************************************/
126 
127 static void DBFWriteHeader(DBFHandle psDBF)
128 
129 {
130  unsigned char abyHeader[XBASE_FILEHDR_SZ] = { 0 };
131 
132  if( !psDBF->bNoHeader )
133  return;
134 
135  psDBF->bNoHeader = FALSE;
136 
137 /* -------------------------------------------------------------------- */
138 /* Initialize the file header information. */
139 /* -------------------------------------------------------------------- */
140  abyHeader[0] = 0x03; /* memo field? - just copying */
141 
142  /* write out update date */
143  abyHeader[1] = STATIC_CAST(unsigned char, psDBF->nUpdateYearSince1900);
144  abyHeader[2] = STATIC_CAST(unsigned char, psDBF->nUpdateMonth);
145  abyHeader[3] = STATIC_CAST(unsigned char, psDBF->nUpdateDay);
146 
147  /* record count preset at zero */
148 
149  abyHeader[8] = STATIC_CAST(unsigned char, psDBF->nHeaderLength % 256);
150  abyHeader[9] = STATIC_CAST(unsigned char, psDBF->nHeaderLength / 256);
151 
152  abyHeader[10] = STATIC_CAST(unsigned char, psDBF->nRecordLength % 256);
153  abyHeader[11] = STATIC_CAST(unsigned char, psDBF->nRecordLength / 256);
154 
155  abyHeader[29] = STATIC_CAST(unsigned char, psDBF->iLanguageDriver);
156 
157 /* -------------------------------------------------------------------- */
158 /* Write the initial 32 byte file header, and all the field */
159 /* descriptions. */
160 /* -------------------------------------------------------------------- */
161  psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
162  psDBF->sHooks.FWrite( abyHeader, XBASE_FILEHDR_SZ, 1, psDBF->fp );
163  psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
164  psDBF->fp );
165 
166 /* -------------------------------------------------------------------- */
167 /* Write out the newline character if there is room for it. */
168 /* -------------------------------------------------------------------- */
169  if( psDBF->nHeaderLength > XBASE_FLDHDR_SZ*psDBF->nFields +
171  {
172  char cNewline;
173 
174  cNewline = HEADER_RECORD_TERMINATOR;
175  psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
176  }
177 
178 /* -------------------------------------------------------------------- */
179 /* If the file is new, add a EOF character. */
180 /* -------------------------------------------------------------------- */
181  if( psDBF->nRecords == 0 && psDBF->bWriteEndOfFileChar )
182  {
183  char ch = END_OF_FILE_CHARACTER;
184 
185  psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
186  }
187 }
188 
189 /************************************************************************/
190 /* DBFFlushRecord() */
191 /* */
192 /* Write out the current record if there is one. */
193 /************************************************************************/
194 
195 static int DBFFlushRecord( DBFHandle psDBF )
196 
197 {
198  SAOffset nRecordOffset;
199 
200  if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
201  {
202  psDBF->bCurrentRecordModified = FALSE;
203 
204  nRecordOffset =
206  + psDBF->nHeaderLength;
207 
208 /* -------------------------------------------------------------------- */
209 /* Guard FSeek with check for whether we're already at position; */
210 /* no-op FSeeks defeat network filesystems' write buffering. */
211 /* -------------------------------------------------------------------- */
212  if ( psDBF->bRequireNextWriteSeek ||
213  psDBF->sHooks.FTell( psDBF->fp ) != nRecordOffset ) {
214  if ( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0 ) {
215  char szMessage[128];
216  snprintf( szMessage, sizeof(szMessage),
217  "Failure seeking to position before writing DBF record %d.",
218  psDBF->nCurrentRecord );
219  psDBF->sHooks.Error( szMessage );
220  return FALSE;
221  }
222  }
223 
224  if ( psDBF->sHooks.FWrite( psDBF->pszCurrentRecord,
225  psDBF->nRecordLength,
226  1, psDBF->fp ) != 1 )
227  {
228  char szMessage[128];
229  snprintf( szMessage, sizeof(szMessage), "Failure writing DBF record %d.",
230  psDBF->nCurrentRecord );
231  psDBF->sHooks.Error( szMessage );
232  return FALSE;
233  }
234 
235 /* -------------------------------------------------------------------- */
236 /* If next op is also a write, allow possible skipping of FSeek. */
237 /* -------------------------------------------------------------------- */
238  psDBF->bRequireNextWriteSeek = FALSE;
239 
240  if( psDBF->nCurrentRecord == psDBF->nRecords - 1 )
241  {
242  if( psDBF->bWriteEndOfFileChar )
243  {
244  char ch = END_OF_FILE_CHARACTER;
245  psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
246  }
247  }
248  }
249 
250  return TRUE;
251 }
252 
253 /************************************************************************/
254 /* DBFLoadRecord() */
255 /************************************************************************/
256 
257 static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
258 
259 {
260  if( psDBF->nCurrentRecord != iRecord )
261  {
262  SAOffset nRecordOffset;
263 
264  if( !DBFFlushRecord( psDBF ) )
265  return FALSE;
266 
267  nRecordOffset =
268  psDBF->nRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
269 
270  if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
271  {
272  char szMessage[128];
273  snprintf( szMessage, sizeof(szMessage), "fseek(%ld) failed on DBF file.",
274  STATIC_CAST(long, nRecordOffset) );
275  psDBF->sHooks.Error( szMessage );
276  return FALSE;
277  }
278 
279  if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
280  psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
281  {
282  char szMessage[128];
283  snprintf( szMessage, sizeof(szMessage), "fread(%d) failed on DBF file.",
284  psDBF->nRecordLength );
285  psDBF->sHooks.Error( szMessage );
286  return FALSE;
287  }
288 
289  psDBF->nCurrentRecord = iRecord;
290 /* -------------------------------------------------------------------- */
291 /* Require a seek for next write in case of mixed R/W operations. */
292 /* -------------------------------------------------------------------- */
293  psDBF->bRequireNextWriteSeek = TRUE;
294  }
295 
296  return TRUE;
297 }
298 
299 /************************************************************************/
300 /* DBFUpdateHeader() */
301 /************************************************************************/
302 
303 void SHPAPI_CALL
305 
306 {
307  unsigned char abyFileHeader[XBASE_FILEHDR_SZ];
308 
309  if( psDBF->bNoHeader )
310  DBFWriteHeader( psDBF );
311 
312  if( !DBFFlushRecord( psDBF ) )
313  return;
314 
315  psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
316  psDBF->sHooks.FRead( abyFileHeader, sizeof(abyFileHeader), 1, psDBF->fp );
317 
318  abyFileHeader[1] = STATIC_CAST(unsigned char, psDBF->nUpdateYearSince1900);
319  abyFileHeader[2] = STATIC_CAST(unsigned char, psDBF->nUpdateMonth);
320  abyFileHeader[3] = STATIC_CAST(unsigned char, psDBF->nUpdateDay);
321  abyFileHeader[4] = STATIC_CAST(unsigned char, psDBF->nRecords & 0xFF);
322  abyFileHeader[5] = STATIC_CAST(unsigned char, (psDBF->nRecords>>8) & 0xFF);
323  abyFileHeader[6] = STATIC_CAST(unsigned char, (psDBF->nRecords>>16) & 0xFF);
324  abyFileHeader[7] = STATIC_CAST(unsigned char, (psDBF->nRecords>>24) & 0xFF);
325 
326  psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
327  psDBF->sHooks.FWrite( abyFileHeader, sizeof(abyFileHeader), 1, psDBF->fp );
328 
329  psDBF->sHooks.FFlush( psDBF->fp );
330 }
331 
332 /************************************************************************/
333 /* DBFSetLastModifiedDate() */
334 /************************************************************************/
335 
336 void SHPAPI_CALL
337 DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD )
338 {
339  psDBF->nUpdateYearSince1900 = nYYSince1900;
340  psDBF->nUpdateMonth = nMM;
341  psDBF->nUpdateDay = nDD;
342 }
343 
344 /************************************************************************/
345 /* DBFOpen() */
346 /* */
347 /* Open a .dbf file. */
348 /************************************************************************/
349 
351 DBFOpen( const char * pszFilename, const char * pszAccess )
352 
353 {
354  SAHooks sHooks;
355 
356  SASetupDefaultHooks( &sHooks );
357 
358  return DBFOpenLL( pszFilename, pszAccess, &sHooks );
359 }
360 
361 /************************************************************************/
362 /* DBFGetLenWithoutExtension() */
363 /************************************************************************/
364 
365 static int DBFGetLenWithoutExtension(const char* pszBasename)
366 {
367  int i;
368  int nLen = STATIC_CAST(int, strlen(pszBasename));
369  for( i = nLen-1;
370  i > 0 && pszBasename[i] != '/' && pszBasename[i] != '\\';
371  i-- )
372  {
373  if( pszBasename[i] == '.' )
374  {
375  return i;
376  }
377  }
378  return nLen;
379 }
380 
381 /************************************************************************/
382 /* DBFOpen() */
383 /* */
384 /* Open a .dbf file. */
385 /************************************************************************/
386 
388 DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
389 
390 {
391  DBFHandle psDBF;
392  SAFile pfCPG;
393  unsigned char *pabyBuf;
394  int nFields, nHeadLen, iField;
395  char *pszFullname;
396  int nBufSize = 500;
397  int nLenWithoutExtension;
398 
399 /* -------------------------------------------------------------------- */
400 /* We only allow the access strings "rb" and "r+". */
401 /* -------------------------------------------------------------------- */
402  if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
403  && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
404  && strcmp(pszAccess,"r+b") != 0 )
405  return SHPLIB_NULLPTR;
406 
407  if( strcmp(pszAccess,"r") == 0 )
408  pszAccess = "rb";
409 
410  if( strcmp(pszAccess,"r+") == 0 )
411  pszAccess = "rb+";
412 
413 /* -------------------------------------------------------------------- */
414 /* Compute the base (layer) name. If there is any extension */
415 /* on the passed in filename we will strip it off. */
416 /* -------------------------------------------------------------------- */
417  nLenWithoutExtension = DBFGetLenWithoutExtension(pszFilename);
418  pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
419  memcpy(pszFullname, pszFilename, nLenWithoutExtension);
420  memcpy(pszFullname + nLenWithoutExtension, ".dbf", 5);
421 
422  psDBF = STATIC_CAST(DBFHandle, calloc( 1, sizeof(DBFInfo) ));
423  psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
424  memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
425 
426  if( psDBF->fp == SHPLIB_NULLPTR )
427  {
428  memcpy(pszFullname + nLenWithoutExtension, ".DBF", 5);
429  psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
430  }
431 
432  memcpy(pszFullname + nLenWithoutExtension, ".cpg", 5);
433  pfCPG = psHooks->FOpen( pszFullname, "r" );
434  if( pfCPG == SHPLIB_NULLPTR )
435  {
436  memcpy(pszFullname + nLenWithoutExtension, ".CPG", 5);
437  pfCPG = psHooks->FOpen( pszFullname, "r" );
438  }
439 
440  free( pszFullname );
441 
442  if( psDBF->fp == SHPLIB_NULLPTR )
443  {
444  free( psDBF );
445  if( pfCPG ) psHooks->FClose( pfCPG );
446  return SHPLIB_NULLPTR;
447  }
448 
449  psDBF->bNoHeader = FALSE;
450  psDBF->nCurrentRecord = -1;
451  psDBF->bCurrentRecordModified = FALSE;
452 
453 /* -------------------------------------------------------------------- */
454 /* Read Table Header info */
455 /* -------------------------------------------------------------------- */
456  pabyBuf = STATIC_CAST(unsigned char *, malloc(nBufSize));
457  if( psDBF->sHooks.FRead( pabyBuf, XBASE_FILEHDR_SZ, 1, psDBF->fp ) != 1 )
458  {
459  psDBF->sHooks.FClose( psDBF->fp );
460  if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
461  free( pabyBuf );
462  free( psDBF );
463  return SHPLIB_NULLPTR;
464  }
465 
466  DBFSetLastModifiedDate(psDBF, pabyBuf[1], pabyBuf[2], pabyBuf[3]);
467 
468  psDBF->nRecords =
469  pabyBuf[4]|(pabyBuf[5]<<8)|(pabyBuf[6]<<16)|((pabyBuf[7]&0x7f)<<24);
470 
471  psDBF->nHeaderLength = nHeadLen = pabyBuf[8]|(pabyBuf[9]<<8);
472  psDBF->nRecordLength = pabyBuf[10]|(pabyBuf[11]<<8);
473  psDBF->iLanguageDriver = pabyBuf[29];
474 
475  if (psDBF->nRecordLength == 0 || nHeadLen < XBASE_FILEHDR_SZ)
476  {
477  psDBF->sHooks.FClose( psDBF->fp );
478  if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
479  free( pabyBuf );
480  free( psDBF );
481  return SHPLIB_NULLPTR;
482  }
483 
484  psDBF->nFields = nFields = (nHeadLen - XBASE_FILEHDR_SZ) / XBASE_FLDHDR_SZ;
485 
486  /* coverity[tainted_data] */
487  psDBF->pszCurrentRecord = STATIC_CAST(char *, malloc(psDBF->nRecordLength));
488 
489 /* -------------------------------------------------------------------- */
490 /* Figure out the code page from the LDID and CPG */
491 /* -------------------------------------------------------------------- */
492 
493  psDBF->pszCodePage = SHPLIB_NULLPTR;
494  if( pfCPG )
495  {
496  size_t n;
497  memset( pabyBuf, 0, nBufSize);
498  psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
499  n = strcspn( REINTERPRET_CAST(char *, pabyBuf), "\n\r" );
500  if( n > 0 )
501  {
502  pabyBuf[n] = '\0';
503  psDBF->pszCodePage = STATIC_CAST(char *, malloc(n + 1));
504  memcpy( psDBF->pszCodePage, pabyBuf, n + 1 );
505  }
506  psDBF->sHooks.FClose( pfCPG );
507  }
508  if( psDBF->pszCodePage == SHPLIB_NULLPTR && pabyBuf[29] != 0 )
509  {
510  snprintf( REINTERPRET_CAST(char *, pabyBuf), nBufSize, "LDID/%d", psDBF->iLanguageDriver );
511  psDBF->pszCodePage = STATIC_CAST(char *, malloc(strlen(REINTERPRET_CAST(char*, pabyBuf)) + 1));
512  strcpy( psDBF->pszCodePage, REINTERPRET_CAST(char *, pabyBuf) );
513  }
514 
515 /* -------------------------------------------------------------------- */
516 /* Read in Field Definitions */
517 /* -------------------------------------------------------------------- */
518 
519  pabyBuf = STATIC_CAST(unsigned char *, SfRealloc(pabyBuf,nHeadLen));
520  psDBF->pszHeader = REINTERPRET_CAST(char *, pabyBuf);
521 
522  psDBF->sHooks.FSeek( psDBF->fp, XBASE_FILEHDR_SZ, 0 );
523  if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-XBASE_FILEHDR_SZ, 1,
524  psDBF->fp ) != 1 )
525  {
526  psDBF->sHooks.FClose( psDBF->fp );
527  free( pabyBuf );
528  free( psDBF->pszCurrentRecord );
529  free( psDBF->pszCodePage );
530  free( psDBF );
531  return SHPLIB_NULLPTR;
532  }
533 
534  psDBF->panFieldOffset = STATIC_CAST(int *, malloc(sizeof(int) * nFields));
535  psDBF->panFieldSize = STATIC_CAST(int *, malloc(sizeof(int) * nFields));
536  psDBF->panFieldDecimals = STATIC_CAST(int *, malloc(sizeof(int) * nFields));
537  psDBF->pachFieldType = STATIC_CAST(char *, malloc(sizeof(char) * nFields));
538 
539  for( iField = 0; iField < nFields; iField++ )
540  {
541  unsigned char *pabyFInfo;
542 
543  pabyFInfo = pabyBuf+iField*XBASE_FLDHDR_SZ;
544  if( pabyFInfo[0] == HEADER_RECORD_TERMINATOR )
545  {
546  psDBF->nFields = iField;
547  break;
548  }
549 
550  if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
551  {
552  psDBF->panFieldSize[iField] = pabyFInfo[16];
553  psDBF->panFieldDecimals[iField] = pabyFInfo[17];
554  }
555  else
556  {
557  psDBF->panFieldSize[iField] = pabyFInfo[16];
558  psDBF->panFieldDecimals[iField] = 0;
559 
560 /*
561 ** The following seemed to be used sometimes to handle files with long
562 ** string fields, but in other cases (such as bug 1202) the decimals field
563 ** just seems to indicate some sort of preferred formatting, not very
564 ** wide fields. So I have disabled this code. FrankW.
565  psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
566  psDBF->panFieldDecimals[iField] = 0;
567 */
568  }
569 
570  psDBF->pachFieldType[iField] = STATIC_CAST(char, pabyFInfo[11]);
571  if( iField == 0 )
572  psDBF->panFieldOffset[iField] = 1;
573  else
574  psDBF->panFieldOffset[iField] =
575  psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
576  }
577 
578  /* Check that the total width of fields does not exceed the record width */
579  if( psDBF->nFields > 0 &&
580  psDBF->panFieldOffset[psDBF->nFields-1] +
581  psDBF->panFieldSize[psDBF->nFields-1] > psDBF->nRecordLength )
582  {
583  DBFClose( psDBF );
584  return SHPLIB_NULLPTR;
585  }
586 
587  DBFSetWriteEndOfFileChar( psDBF, TRUE );
588 
589  psDBF->bRequireNextWriteSeek = TRUE;
590 
591  return( psDBF );
592 }
593 
594 /************************************************************************/
595 /* DBFClose() */
596 /************************************************************************/
597 
598 void SHPAPI_CALL
600 {
601  if( psDBF == SHPLIB_NULLPTR )
602  return;
603 
604 /* -------------------------------------------------------------------- */
605 /* Write out header if not already written. */
606 /* -------------------------------------------------------------------- */
607  if( psDBF->bNoHeader )
608  DBFWriteHeader( psDBF );
609 
611 
612 /* -------------------------------------------------------------------- */
613 /* Update last access date, and number of records if we have */
614 /* write access. */
615 /* -------------------------------------------------------------------- */
616  if( psDBF->bUpdated )
617  DBFUpdateHeader( psDBF );
618 
619 /* -------------------------------------------------------------------- */
620 /* Close, and free resources. */
621 /* -------------------------------------------------------------------- */
622  psDBF->sHooks.FClose( psDBF->fp );
623 
624  if( psDBF->panFieldOffset != SHPLIB_NULLPTR )
625  {
626  free( psDBF->panFieldOffset );
627  free( psDBF->panFieldSize );
628  free( psDBF->panFieldDecimals );
629  free( psDBF->pachFieldType );
630  }
631 
632  if( psDBF->pszWorkField != SHPLIB_NULLPTR )
633  free( psDBF->pszWorkField );
634 
635  free( psDBF->pszHeader );
636  free( psDBF->pszCurrentRecord );
637  free( psDBF->pszCodePage );
638 
639  free( psDBF );
640 }
641 
642 /************************************************************************/
643 /* DBFCreate() */
644 /* */
645 /* Create a new .dbf file with default code page LDID/87 (0x57) */
646 /************************************************************************/
647 
649 DBFCreate( const char * pszFilename )
650 
651 {
652  return DBFCreateEx( pszFilename, "LDID/87" ); // 0x57
653 }
654 
655 /************************************************************************/
656 /* DBFCreateEx() */
657 /* */
658 /* Create a new .dbf file. */
659 /************************************************************************/
660 
662 DBFCreateEx( const char * pszFilename, const char* pszCodePage )
663 
664 {
665  SAHooks sHooks;
666 
667  SASetupDefaultHooks( &sHooks );
668 
669  return DBFCreateLL( pszFilename, pszCodePage , &sHooks );
670 }
671 
672 /************************************************************************/
673 /* DBFCreate() */
674 /* */
675 /* Create a new .dbf file. */
676 /************************************************************************/
677 
679 DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks )
680 
681 {
682  DBFHandle psDBF;
683  SAFile fp;
684  char *pszFullname;
685  int ldid = -1;
686  char chZero = '\0';
687  int nLenWithoutExtension;
688 
689 /* -------------------------------------------------------------------- */
690 /* Compute the base (layer) name. If there is any extension */
691 /* on the passed in filename we will strip it off. */
692 /* -------------------------------------------------------------------- */
693  nLenWithoutExtension = DBFGetLenWithoutExtension(pszFilename);
694  pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
695  memcpy(pszFullname, pszFilename, nLenWithoutExtension);
696  memcpy(pszFullname + nLenWithoutExtension, ".dbf", 5);
697 
698 /* -------------------------------------------------------------------- */
699 /* Create the file. */
700 /* -------------------------------------------------------------------- */
701  fp = psHooks->FOpen( pszFullname, "wb" );
702  if( fp == SHPLIB_NULLPTR )
703  {
704  free( pszFullname );
705  return SHPLIB_NULLPTR;
706  }
707 
708  psHooks->FWrite( &chZero, 1, 1, fp );
709  psHooks->FClose( fp );
710 
711  fp = psHooks->FOpen( pszFullname, "rb+" );
712  if( fp == SHPLIB_NULLPTR )
713  {
714  free( pszFullname );
715  return SHPLIB_NULLPTR;
716  }
717 
718  memcpy(pszFullname + nLenWithoutExtension, ".cpg", 5);
719  if( pszCodePage != SHPLIB_NULLPTR )
720  {
721  if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
722  {
723  ldid = atoi( pszCodePage + 5 );
724  if( ldid > 255 )
725  ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one
726  }
727  if( ldid < 0 )
728  {
729  SAFile fpCPG = psHooks->FOpen( pszFullname, "w" );
730  psHooks->FWrite( CONST_CAST(void*, STATIC_CAST(const void*, pszCodePage)), strlen(pszCodePage), 1, fpCPG );
731  psHooks->FClose( fpCPG );
732  }
733  }
734  if( pszCodePage == SHPLIB_NULLPTR || ldid >= 0 )
735  {
736  psHooks->Remove( pszFullname );
737  }
738 
739  free( pszFullname );
740 
741 /* -------------------------------------------------------------------- */
742 /* Create the info structure. */
743 /* -------------------------------------------------------------------- */
744  psDBF = STATIC_CAST(DBFHandle, calloc(1,sizeof(DBFInfo)));
745 
746  memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
747  psDBF->fp = fp;
748  psDBF->nRecords = 0;
749  psDBF->nFields = 0;
750  psDBF->nRecordLength = 1;
751  psDBF->nHeaderLength = XBASE_FILEHDR_SZ + 1; /* + 1 for HEADER_RECORD_TERMINATOR */
752 
754  psDBF->panFieldSize = SHPLIB_NULLPTR;
756  psDBF->pachFieldType = SHPLIB_NULLPTR;
757  psDBF->pszHeader = SHPLIB_NULLPTR;
758 
759  psDBF->nCurrentRecord = -1;
760  psDBF->bCurrentRecordModified = FALSE;
762 
763  psDBF->bNoHeader = TRUE;
764 
765  psDBF->iLanguageDriver = ldid > 0 ? ldid : 0;
766  psDBF->pszCodePage = SHPLIB_NULLPTR;
767  if( pszCodePage )
768  {
769  psDBF->pszCodePage = STATIC_CAST(char *, malloc( strlen(pszCodePage) + 1 ));
770  strcpy( psDBF->pszCodePage, pszCodePage );
771  }
772  DBFSetLastModifiedDate(psDBF, 95, 7, 26); /* dummy date */
773 
775 
776  psDBF->bRequireNextWriteSeek = TRUE;
777 
778  return( psDBF );
779 }
780 
781 /************************************************************************/
782 /* DBFAddField() */
783 /* */
784 /* Add a field to a newly created .dbf or to an existing one */
785 /************************************************************************/
786 
787 int SHPAPI_CALL
788 DBFAddField(DBFHandle psDBF, const char * pszFieldName,
789  DBFFieldType eType, int nWidth, int nDecimals )
790 
791 {
792  char chNativeType = 'C';
793 
794  if( eType == FTLogical )
795  chNativeType = 'L';
796  else if( eType == FTDate )
797  chNativeType = 'D';
798  else if( eType == FTString )
799  chNativeType = 'C';
800  else
801  chNativeType = 'N';
802 
803  return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
804  nWidth, nDecimals );
805 }
806 
807 /************************************************************************/
808 /* DBFGetNullCharacter() */
809 /************************************************************************/
810 
811 static char DBFGetNullCharacter(char chType)
812 {
813  switch (chType)
814  {
815  case 'N':
816  case 'F':
817  return '*';
818  case 'D':
819  return '0';
820  case 'L':
821  return '?';
822  default:
823  return ' ';
824  }
825 }
826 
827 /************************************************************************/
828 /* DBFAddField() */
829 /* */
830 /* Add a field to a newly created .dbf file before any records */
831 /* are written. */
832 /************************************************************************/
833 
834 int SHPAPI_CALL
835 DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
836  char chType, int nWidth, int nDecimals )
837 
838 {
839  char *pszFInfo;
840  int i;
841  int nOldRecordLength, nOldHeaderLength;
842  char *pszRecord;
843  char chFieldFill;
844  SAOffset nRecordOffset;
845 
846  /* make sure that everything is written in .dbf */
847  if( !DBFFlushRecord( psDBF ) )
848  return -1;
849 
850  if( psDBF->nHeaderLength + XBASE_FLDHDR_SZ > 65535 )
851  {
852  char szMessage[128];
853  snprintf( szMessage, sizeof(szMessage),
854  "Cannot add field %s. Header length limit reached "
855  "(max 65535 bytes, 2046 fields).",
856  pszFieldName );
857  psDBF->sHooks.Error( szMessage );
858  return -1;
859  }
860 
861 /* -------------------------------------------------------------------- */
862 /* Do some checking to ensure we can add records to this file. */
863 /* -------------------------------------------------------------------- */
864  if( nWidth < 1 )
865  return -1;
866 
867  if( nWidth > XBASE_FLD_MAX_WIDTH )
868  nWidth = XBASE_FLD_MAX_WIDTH;
869 
870  if( psDBF->nRecordLength + nWidth > 65535 )
871  {
872  char szMessage[128];
873  snprintf( szMessage, sizeof(szMessage),
874  "Cannot add field %s. Record length limit reached "
875  "(max 65535 bytes).",
876  pszFieldName );
877  psDBF->sHooks.Error( szMessage );
878  return -1;
879  }
880 
881  nOldRecordLength = psDBF->nRecordLength;
882  nOldHeaderLength = psDBF->nHeaderLength;
883 
884 /* -------------------------------------------------------------------- */
885 /* SfRealloc all the arrays larger to hold the additional field */
886 /* information. */
887 /* -------------------------------------------------------------------- */
888  psDBF->nFields++;
889 
890  psDBF->panFieldOffset = STATIC_CAST(int *,
891  SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ));
892 
893  psDBF->panFieldSize = STATIC_CAST(int *,
894  SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ));
895 
896  psDBF->panFieldDecimals = STATIC_CAST(int *,
897  SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ));
898 
899  psDBF->pachFieldType = STATIC_CAST(char *,
900  SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ));
901 
902 /* -------------------------------------------------------------------- */
903 /* Assign the new field information fields. */
904 /* -------------------------------------------------------------------- */
905  psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
906  psDBF->nRecordLength += nWidth;
907  psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
908  psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
909  psDBF->pachFieldType[psDBF->nFields-1] = chType;
910 
911 /* -------------------------------------------------------------------- */
912 /* Extend the required header information. */
913 /* -------------------------------------------------------------------- */
914  psDBF->nHeaderLength += XBASE_FLDHDR_SZ;
915  psDBF->bUpdated = FALSE;
916 
917  psDBF->pszHeader = STATIC_CAST(char *, SfRealloc(psDBF->pszHeader,
918  psDBF->nFields*XBASE_FLDHDR_SZ));
919 
920  pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * (psDBF->nFields-1);
921 
922  for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
923  pszFInfo[i] = '\0';
924 
925  strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
926 
927  pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
928 
929  if( chType == 'C' )
930  {
931  pszFInfo[16] = STATIC_CAST(unsigned char, nWidth % 256);
932  pszFInfo[17] = STATIC_CAST(unsigned char, nWidth / 256);
933  }
934  else
935  {
936  pszFInfo[16] = STATIC_CAST(unsigned char, nWidth);
937  pszFInfo[17] = STATIC_CAST(unsigned char, nDecimals);
938  }
939 
940 /* -------------------------------------------------------------------- */
941 /* Make the current record buffer appropriately larger. */
942 /* -------------------------------------------------------------------- */
943  psDBF->pszCurrentRecord = STATIC_CAST(char *, SfRealloc(psDBF->pszCurrentRecord,
944  psDBF->nRecordLength));
945 
946  /* we're done if dealing with new .dbf */
947  if( psDBF->bNoHeader )
948  return( psDBF->nFields - 1 );
949 
950 /* -------------------------------------------------------------------- */
951 /* For existing .dbf file, shift records */
952 /* -------------------------------------------------------------------- */
953 
954  /* alloc record */
955  pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
956 
957  chFieldFill = DBFGetNullCharacter(chType);
958 
959  for (i = psDBF->nRecords-1; i >= 0; --i)
960  {
961  nRecordOffset = nOldRecordLength * STATIC_CAST(SAOffset, i) + nOldHeaderLength;
962 
963  /* load record */
964  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
965  psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
966 
967  /* set new field's value to NULL */
968  memset(pszRecord + nOldRecordLength, chFieldFill, nWidth);
969 
970  nRecordOffset = psDBF->nRecordLength * STATIC_CAST(SAOffset, i) + psDBF->nHeaderLength;
971 
972  /* move record to the new place*/
973  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
974  psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
975  }
976 
977  if( psDBF->bWriteEndOfFileChar )
978  {
979  char ch = END_OF_FILE_CHARACTER;
980 
981  nRecordOffset =
982  psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
983 
984  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
985  psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
986  }
987 
988  /* free record */
989  free(pszRecord);
990 
991  /* force update of header with new header, record length and new field */
992  psDBF->bNoHeader = TRUE;
993  DBFUpdateHeader( psDBF );
994 
995  psDBF->nCurrentRecord = -1;
996  psDBF->bCurrentRecordModified = FALSE;
997  psDBF->bUpdated = TRUE;
998 
999  return( psDBF->nFields-1 );
1000 }
1001 
1002 /************************************************************************/
1003 /* DBFReadAttribute() */
1004 /* */
1005 /* Read one of the attribute fields of a record. */
1006 /************************************************************************/
1007 
1008 static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
1009  char chReqType )
1010 
1011 {
1012  unsigned char *pabyRec;
1013  void *pReturnField = SHPLIB_NULLPTR;
1014 
1015 /* -------------------------------------------------------------------- */
1016 /* Verify selection. */
1017 /* -------------------------------------------------------------------- */
1018  if( hEntity < 0 || hEntity >= psDBF->nRecords )
1019  return SHPLIB_NULLPTR;
1020 
1021  if( iField < 0 || iField >= psDBF->nFields )
1022  return SHPLIB_NULLPTR;
1023 
1024 /* -------------------------------------------------------------------- */
1025 /* Have we read the record? */
1026 /* -------------------------------------------------------------------- */
1027  if( !DBFLoadRecord( psDBF, hEntity ) )
1028  return SHPLIB_NULLPTR;
1029 
1030  pabyRec = REINTERPRET_CAST(unsigned char *, psDBF->pszCurrentRecord);
1031 
1032 /* -------------------------------------------------------------------- */
1033 /* Ensure we have room to extract the target field. */
1034 /* -------------------------------------------------------------------- */
1035  if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
1036  {
1037  psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
1038  if( psDBF->pszWorkField == SHPLIB_NULLPTR )
1039  psDBF->pszWorkField = STATIC_CAST(char *, malloc(psDBF->nWorkFieldLength));
1040  else
1041  psDBF->pszWorkField = STATIC_CAST(char *, realloc(psDBF->pszWorkField,
1042  psDBF->nWorkFieldLength));
1043  }
1044 
1045 /* -------------------------------------------------------------------- */
1046 /* Extract the requested field. */
1047 /* -------------------------------------------------------------------- */
1048  memcpy( psDBF->pszWorkField,
1049  REINTERPRET_CAST(const char *, pabyRec) + psDBF->panFieldOffset[iField],
1050  psDBF->panFieldSize[iField] );
1051  psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
1052 
1053  pReturnField = psDBF->pszWorkField;
1054 
1055 /* -------------------------------------------------------------------- */
1056 /* Decode the field. */
1057 /* -------------------------------------------------------------------- */
1058  if( chReqType == 'I' )
1059  {
1060  psDBF->fieldValue.nIntField = atoi(psDBF->pszWorkField);
1061 
1062  pReturnField = &(psDBF->fieldValue.nIntField);
1063  }
1064  else if( chReqType == 'N' )
1065  {
1066  psDBF->fieldValue.dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
1067 
1068  pReturnField = &(psDBF->fieldValue.dfDoubleField);
1069  }
1070 
1071 /* -------------------------------------------------------------------- */
1072 /* Should we trim white space off the string attribute value? */
1073 /* -------------------------------------------------------------------- */
1074 #ifdef TRIM_DBF_WHITESPACE
1075  else
1076  {
1077  char *pchSrc, *pchDst;
1078 
1079  pchDst = pchSrc = psDBF->pszWorkField;
1080  while( *pchSrc == ' ' )
1081  pchSrc++;
1082 
1083  while( *pchSrc != '\0' )
1084  *(pchDst++) = *(pchSrc++);
1085  *pchDst = '\0';
1086 
1087  while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
1088  *pchDst = '\0';
1089  }
1090 #endif
1091 
1092  return pReturnField;
1093 }
1094 
1095 /************************************************************************/
1096 /* DBFReadIntAttribute() */
1097 /* */
1098 /* Read an integer attribute. */
1099 /************************************************************************/
1100 
1101 int SHPAPI_CALL
1102 DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
1103 
1104 {
1105  int *pnValue;
1106 
1107  pnValue = STATIC_CAST(int *, DBFReadAttribute( psDBF, iRecord, iField, 'I' ));
1108 
1109  if( pnValue == SHPLIB_NULLPTR )
1110  return 0;
1111  else
1112  return *pnValue;
1113 }
1114 
1115 /************************************************************************/
1116 /* DBFReadDoubleAttribute() */
1117 /* */
1118 /* Read a double attribute. */
1119 /************************************************************************/
1120 
1121 double SHPAPI_CALL
1122 DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
1123 
1124 {
1125  double *pdValue;
1126 
1127  pdValue = STATIC_CAST(double *, DBFReadAttribute( psDBF, iRecord, iField, 'N' ));
1128 
1129  if( pdValue == SHPLIB_NULLPTR )
1130  return 0.0;
1131  else
1132  return *pdValue ;
1133 }
1134 
1135 /************************************************************************/
1136 /* DBFReadStringAttribute() */
1137 /* */
1138 /* Read a string attribute. */
1139 /************************************************************************/
1140 
1141 const char SHPAPI_CALL1(*)
1142 DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
1143 
1144 {
1145  return STATIC_CAST(const char *, DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
1146 }
1147 
1148 /************************************************************************/
1149 /* DBFReadLogicalAttribute() */
1150 /* */
1151 /* Read a logical attribute. */
1152 /************************************************************************/
1153 
1154 const char SHPAPI_CALL1(*)
1155 DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
1156 
1157 {
1158  return STATIC_CAST(const char *, DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
1159 }
1160 
1161 
1162 /************************************************************************/
1163 /* DBFIsValueNULL() */
1164 /* */
1165 /* Return TRUE if the passed string is NULL. */
1166 /************************************************************************/
1167 
1168 static int DBFIsValueNULL( char chType, const char* pszValue )
1169 {
1170  int i;
1171 
1172  if( pszValue == SHPLIB_NULLPTR )
1173  return TRUE;
1174 
1175  switch(chType)
1176  {
1177  case 'N':
1178  case 'F':
1179  /*
1180  ** We accept all asterisks or all blanks as NULL
1181  ** though according to the spec I think it should be all
1182  ** asterisks.
1183  */
1184  if( pszValue[0] == '*' )
1185  return TRUE;
1186 
1187  for( i = 0; pszValue[i] != '\0'; i++ )
1188  {
1189  if( pszValue[i] != ' ' )
1190  return FALSE;
1191  }
1192  return TRUE;
1193 
1194  case 'D':
1195  /* NULL date fields have value "00000000" */
1196  return strncmp(pszValue,"00000000",8) == 0;
1197 
1198  case 'L':
1199  /* NULL boolean fields have value "?" */
1200  return pszValue[0] == '?';
1201 
1202  default:
1203  /* empty string fields are considered NULL */
1204  return strlen(pszValue) == 0;
1205  }
1206 }
1207 
1208 /************************************************************************/
1209 /* DBFIsAttributeNULL() */
1210 /* */
1211 /* Return TRUE if value for field is NULL. */
1212 /* */
1213 /* Contributed by Jim Matthews. */
1214 /************************************************************************/
1215 
1216 int SHPAPI_CALL
1217 DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
1218 
1219 {
1220  const char *pszValue;
1221 
1222  pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
1223 
1224  if( pszValue == SHPLIB_NULLPTR )
1225  return TRUE;
1226 
1227  return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue );
1228 }
1229 
1230 /************************************************************************/
1231 /* DBFGetFieldCount() */
1232 /* */
1233 /* Return the number of fields in this table. */
1234 /************************************************************************/
1235 
1236 int SHPAPI_CALL
1238 
1239 {
1240  return( psDBF->nFields );
1241 }
1242 
1243 /************************************************************************/
1244 /* DBFGetRecordCount() */
1245 /* */
1246 /* Return the number of records in this table. */
1247 /************************************************************************/
1248 
1249 int SHPAPI_CALL
1251 
1252 {
1253  return( psDBF->nRecords );
1254 }
1255 
1256 /************************************************************************/
1257 /* DBFGetFieldInfo() */
1258 /* */
1259 /* Return any requested information about the field. */
1260 /* pszFieldName must be at least XBASE_FLDNAME_LEN_READ+1 (=12) */
1261 /* bytes long. */
1262 /************************************************************************/
1263 
1265 DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
1266  int * pnWidth, int * pnDecimals )
1267 
1268 {
1269  if( iField < 0 || iField >= psDBF->nFields )
1270  return( FTInvalid );
1271 
1272  if( pnWidth != SHPLIB_NULLPTR )
1273  *pnWidth = psDBF->panFieldSize[iField];
1274 
1275  if( pnDecimals != SHPLIB_NULLPTR )
1276  *pnDecimals = psDBF->panFieldDecimals[iField];
1277 
1278  if( pszFieldName != SHPLIB_NULLPTR )
1279  {
1280  int i;
1281 
1282  strncpy( pszFieldName, STATIC_CAST(char *,psDBF->pszHeader)+iField*XBASE_FLDHDR_SZ,
1284  pszFieldName[XBASE_FLDNAME_LEN_READ] = '\0';
1285  for( i = XBASE_FLDNAME_LEN_READ - 1; i > 0 && pszFieldName[i] == ' '; i-- )
1286  pszFieldName[i] = '\0';
1287  }
1288 
1289  if ( psDBF->pachFieldType[iField] == 'L' )
1290  return( FTLogical );
1291 
1292  else if( psDBF->pachFieldType[iField] == 'D' )
1293  return( FTDate );
1294 
1295  else if( psDBF->pachFieldType[iField] == 'N'
1296  || psDBF->pachFieldType[iField] == 'F' )
1297  {
1298  if( psDBF->panFieldDecimals[iField] > 0
1299  || psDBF->panFieldSize[iField] >= 10 )
1300  return( FTDouble );
1301  else
1302  return( FTInteger );
1303  }
1304  else
1305  {
1306  return( FTString );
1307  }
1308 }
1309 
1310 /************************************************************************/
1311 /* DBFWriteAttribute() */
1312 /* */
1313 /* Write an attribute record to the file. */
1314 /************************************************************************/
1315 
1316 static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
1317  void * pValue )
1318 
1319 {
1320  int i, j, nRetResult = TRUE;
1321  unsigned char *pabyRec;
1322  char szSField[XBASE_FLD_MAX_WIDTH+1], szFormat[20];
1323 
1324 /* -------------------------------------------------------------------- */
1325 /* Is this a valid record? */
1326 /* -------------------------------------------------------------------- */
1327  if( hEntity < 0 || hEntity > psDBF->nRecords )
1328  return( FALSE );
1329 
1330  if( psDBF->bNoHeader )
1331  DBFWriteHeader(psDBF);
1332 
1333 /* -------------------------------------------------------------------- */
1334 /* Is this a brand new record? */
1335 /* -------------------------------------------------------------------- */
1336  if( hEntity == psDBF->nRecords )
1337  {
1338  if( !DBFFlushRecord( psDBF ) )
1339  return FALSE;
1340 
1341  psDBF->nRecords++;
1342  for( i = 0; i < psDBF->nRecordLength; i++ )
1343  psDBF->pszCurrentRecord[i] = ' ';
1344 
1345  psDBF->nCurrentRecord = hEntity;
1346  }
1347 
1348 /* -------------------------------------------------------------------- */
1349 /* Is this an existing record, but different than the last one */
1350 /* we accessed? */
1351 /* -------------------------------------------------------------------- */
1352  if( !DBFLoadRecord( psDBF, hEntity ) )
1353  return FALSE;
1354 
1355  pabyRec = REINTERPRET_CAST(unsigned char *,psDBF->pszCurrentRecord);
1356 
1357  psDBF->bCurrentRecordModified = TRUE;
1358  psDBF->bUpdated = TRUE;
1359 
1360 /* -------------------------------------------------------------------- */
1361 /* Translate NULL value to valid DBF file representation. */
1362 /* */
1363 /* Contributed by Jim Matthews. */
1364 /* -------------------------------------------------------------------- */
1365  if( pValue == SHPLIB_NULLPTR )
1366  {
1367  memset( pabyRec+psDBF->panFieldOffset[iField],
1368  DBFGetNullCharacter(psDBF->pachFieldType[iField]),
1369  psDBF->panFieldSize[iField] );
1370  return TRUE;
1371  }
1372 
1373 /* -------------------------------------------------------------------- */
1374 /* Assign all the record fields. */
1375 /* -------------------------------------------------------------------- */
1376  switch( psDBF->pachFieldType[iField] )
1377  {
1378  case 'D':
1379  case 'N':
1380  case 'F':
1381  {
1382  int nWidth = psDBF->panFieldSize[iField];
1383 
1384  if( STATIC_CAST(int,sizeof(szSField))-2 < nWidth )
1385  nWidth = sizeof(szSField)-2;
1386 
1387  snprintf( szFormat, sizeof(szFormat), "%%%d.%df",
1388  nWidth, psDBF->panFieldDecimals[iField] );
1389  CPLsnprintf(szSField, sizeof(szSField), szFormat, *STATIC_CAST(double *, pValue) );
1390  szSField[sizeof(szSField)-1] = '\0';
1391  if( STATIC_CAST(int,strlen(szSField)) > psDBF->panFieldSize[iField] )
1392  {
1393  szSField[psDBF->panFieldSize[iField]] = '\0';
1394  nRetResult = FALSE;
1395  }
1396  memcpy(REINTERPRET_CAST(char *, pabyRec+psDBF->panFieldOffset[iField]),
1397  szSField, strlen(szSField) );
1398  break;
1399  }
1400 
1401  case 'L':
1402  if (psDBF->panFieldSize[iField] >= 1 &&
1403  (*STATIC_CAST(char*,pValue) == 'F' || *STATIC_CAST(char*,pValue) == 'T'))
1404  *(pabyRec+psDBF->panFieldOffset[iField]) = *STATIC_CAST(char*,pValue);
1405  break;
1406 
1407  default:
1408  if( STATIC_CAST(int, strlen(STATIC_CAST(char *,pValue))) > psDBF->panFieldSize[iField] )
1409  {
1410  j = psDBF->panFieldSize[iField];
1411  nRetResult = FALSE;
1412  }
1413  else
1414  {
1415  memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1416  psDBF->panFieldSize[iField] );
1417  j = STATIC_CAST(int, strlen(STATIC_CAST(char *,pValue)));
1418  }
1419 
1420  strncpy(REINTERPRET_CAST(char *, pabyRec+psDBF->panFieldOffset[iField]),
1421  STATIC_CAST(const char *, pValue), j );
1422  break;
1423  }
1424 
1425  return( nRetResult );
1426 }
1427 
1428 /************************************************************************/
1429 /* DBFWriteAttributeDirectly() */
1430 /* */
1431 /* Write an attribute record to the file, but without any */
1432 /* reformatting based on type. The provided buffer is written */
1433 /* as is to the field position in the record. */
1434 /************************************************************************/
1435 
1436 int SHPAPI_CALL
1437 DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1438  void * pValue )
1439 
1440 {
1441  int i, j;
1442  unsigned char *pabyRec;
1443 
1444 /* -------------------------------------------------------------------- */
1445 /* Is this a valid record? */
1446 /* -------------------------------------------------------------------- */
1447  if( hEntity < 0 || hEntity > psDBF->nRecords )
1448  return( FALSE );
1449 
1450  if( psDBF->bNoHeader )
1451  DBFWriteHeader(psDBF);
1452 
1453 /* -------------------------------------------------------------------- */
1454 /* Is this a brand new record? */
1455 /* -------------------------------------------------------------------- */
1456  if( hEntity == psDBF->nRecords )
1457  {
1458  if( !DBFFlushRecord( psDBF ) )
1459  return FALSE;
1460 
1461  psDBF->nRecords++;
1462  for( i = 0; i < psDBF->nRecordLength; i++ )
1463  psDBF->pszCurrentRecord[i] = ' ';
1464 
1465  psDBF->nCurrentRecord = hEntity;
1466  }
1467 
1468 /* -------------------------------------------------------------------- */
1469 /* Is this an existing record, but different than the last one */
1470 /* we accessed? */
1471 /* -------------------------------------------------------------------- */
1472  if( !DBFLoadRecord( psDBF, hEntity ) )
1473  return FALSE;
1474 
1475  pabyRec = REINTERPRET_CAST(unsigned char *, psDBF->pszCurrentRecord);
1476 
1477 /* -------------------------------------------------------------------- */
1478 /* Assign all the record fields. */
1479 /* -------------------------------------------------------------------- */
1480  if( STATIC_CAST(int, strlen(STATIC_CAST(char *, pValue))) > psDBF->panFieldSize[iField] )
1481  j = psDBF->panFieldSize[iField];
1482  else
1483  {
1484  memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1485  psDBF->panFieldSize[iField] );
1486  j = STATIC_CAST(int, strlen(STATIC_CAST(char *, pValue)));
1487  }
1488 
1489  strncpy(REINTERPRET_CAST(char *, pabyRec+psDBF->panFieldOffset[iField]),
1490  STATIC_CAST(const char *, pValue), j );
1491 
1492  psDBF->bCurrentRecordModified = TRUE;
1493  psDBF->bUpdated = TRUE;
1494 
1495  return( TRUE );
1496 }
1497 
1498 /************************************************************************/
1499 /* DBFWriteDoubleAttribute() */
1500 /* */
1501 /* Write a double attribute. */
1502 /************************************************************************/
1503 
1504 int SHPAPI_CALL
1505 DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
1506  double dValue )
1507 
1508 {
1509  return( DBFWriteAttribute( psDBF, iRecord, iField, STATIC_CAST(void *, &dValue) ) );
1510 }
1511 
1512 /************************************************************************/
1513 /* DBFWriteIntegerAttribute() */
1514 /* */
1515 /* Write a integer attribute. */
1516 /************************************************************************/
1517 
1518 int SHPAPI_CALL
1519 DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
1520  int nValue )
1521 
1522 {
1523  double dValue = nValue;
1524 
1525  return( DBFWriteAttribute( psDBF, iRecord, iField, STATIC_CAST(void *, &dValue) ) );
1526 }
1527 
1528 /************************************************************************/
1529 /* DBFWriteStringAttribute() */
1530 /* */
1531 /* Write a string attribute. */
1532 /************************************************************************/
1533 
1534 int SHPAPI_CALL
1535 DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
1536  const char * pszValue )
1537 
1538 {
1539  return( DBFWriteAttribute( psDBF, iRecord, iField, STATIC_CAST(void *, CONST_CAST(char*, pszValue))) );
1540 }
1541 
1542 /************************************************************************/
1543 /* DBFWriteNULLAttribute() */
1544 /* */
1545 /* Write a string attribute. */
1546 /************************************************************************/
1547 
1548 int SHPAPI_CALL
1549 DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
1550 
1551 {
1552  return( DBFWriteAttribute( psDBF, iRecord, iField, SHPLIB_NULLPTR ) );
1553 }
1554 
1555 /************************************************************************/
1556 /* DBFWriteLogicalAttribute() */
1557 /* */
1558 /* Write a logical attribute. */
1559 /************************************************************************/
1560 
1561 int SHPAPI_CALL
1562 DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
1563  const char lValue)
1564 
1565 {
1566  return( DBFWriteAttribute( psDBF, iRecord, iField, STATIC_CAST(void *, CONST_CAST(char*, &lValue)) ) );
1567 }
1568 
1569 /************************************************************************/
1570 /* DBFWriteTuple() */
1571 /* */
1572 /* Write an attribute record to the file. */
1573 /************************************************************************/
1574 
1575 int SHPAPI_CALL
1576 DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
1577 
1578 {
1579  int i;
1580  unsigned char *pabyRec;
1581 
1582 /* -------------------------------------------------------------------- */
1583 /* Is this a valid record? */
1584 /* -------------------------------------------------------------------- */
1585  if( hEntity < 0 || hEntity > psDBF->nRecords )
1586  return( FALSE );
1587 
1588  if( psDBF->bNoHeader )
1589  DBFWriteHeader(psDBF);
1590 
1591 /* -------------------------------------------------------------------- */
1592 /* Is this a brand new record? */
1593 /* -------------------------------------------------------------------- */
1594  if( hEntity == psDBF->nRecords )
1595  {
1596  if( !DBFFlushRecord( psDBF ) )
1597  return FALSE;
1598 
1599  psDBF->nRecords++;
1600  for( i = 0; i < psDBF->nRecordLength; i++ )
1601  psDBF->pszCurrentRecord[i] = ' ';
1602 
1603  psDBF->nCurrentRecord = hEntity;
1604  }
1605 
1606 /* -------------------------------------------------------------------- */
1607 /* Is this an existing record, but different than the last one */
1608 /* we accessed? */
1609 /* -------------------------------------------------------------------- */
1610  if( !DBFLoadRecord( psDBF, hEntity ) )
1611  return FALSE;
1612 
1613  pabyRec = REINTERPRET_CAST(unsigned char *, psDBF->pszCurrentRecord);
1614 
1615  memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
1616 
1617  psDBF->bCurrentRecordModified = TRUE;
1618  psDBF->bUpdated = TRUE;
1619 
1620  return( TRUE );
1621 }
1622 
1623 /************************************************************************/
1624 /* DBFReadTuple() */
1625 /* */
1626 /* Read a complete record. Note that the result is only valid */
1627 /* till the next record read for any reason. */
1628 /************************************************************************/
1629 
1630 const char SHPAPI_CALL1(*)
1631 DBFReadTuple(DBFHandle psDBF, int hEntity )
1632 
1633 {
1634  if( hEntity < 0 || hEntity >= psDBF->nRecords )
1635  return SHPLIB_NULLPTR;
1636 
1637  if( !DBFLoadRecord( psDBF, hEntity ) )
1638  return SHPLIB_NULLPTR;
1639 
1640  return STATIC_CAST(const char *, psDBF->pszCurrentRecord);
1641 }
1642 
1643 /************************************************************************/
1644 /* DBFCloneEmpty() */
1645 /* */
1646 /* Read one of the attribute fields of a record. */
1647 /************************************************************************/
1648 
1650 DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
1651 {
1652  DBFHandle newDBF;
1653 
1654  newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
1655  if ( newDBF == SHPLIB_NULLPTR ) return SHPLIB_NULLPTR;
1656 
1657  newDBF->nFields = psDBF->nFields;
1658  newDBF->nRecordLength = psDBF->nRecordLength;
1659  newDBF->nHeaderLength = psDBF->nHeaderLength;
1660 
1661  if( psDBF->pszHeader )
1662  {
1663  newDBF->pszHeader = STATIC_CAST(char *, malloc ( XBASE_FLDHDR_SZ * psDBF->nFields ));
1664  memcpy ( newDBF->pszHeader, psDBF->pszHeader, XBASE_FLDHDR_SZ * psDBF->nFields );
1665  }
1666 
1667  newDBF->panFieldOffset = STATIC_CAST(int *, malloc ( sizeof(int) * psDBF->nFields ));
1668  memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1669  newDBF->panFieldSize = STATIC_CAST(int *, malloc ( sizeof(int) * psDBF->nFields ));
1670  memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1671  newDBF->panFieldDecimals = STATIC_CAST(int *, malloc ( sizeof(int) * psDBF->nFields ));
1672  memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1673  newDBF->pachFieldType = STATIC_CAST(char *, malloc ( sizeof(char) * psDBF->nFields ));
1674  memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
1675 
1676  newDBF->bNoHeader = TRUE;
1677  newDBF->bUpdated = TRUE;
1678  newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
1679 
1680  DBFWriteHeader ( newDBF );
1681  DBFClose ( newDBF );
1682 
1683  newDBF = DBFOpen ( pszFilename, "rb+" );
1684  newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
1685 
1686  return ( newDBF );
1687 }
1688 
1689 /************************************************************************/
1690 /* DBFGetNativeFieldType() */
1691 /* */
1692 /* Return the DBase field type for the specified field. */
1693 /* */
1694 /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
1695 /* 'N' (Numeric, with or without decimal), */
1696 /* 'L' (Logical), */
1697 /* 'M' (Memo: 10 digits .DBT block ptr) */
1698 /************************************************************************/
1699 
1700 char SHPAPI_CALL
1701 DBFGetNativeFieldType( DBFHandle psDBF, int iField )
1702 
1703 {
1704  if( iField >=0 && iField < psDBF->nFields )
1705  return psDBF->pachFieldType[iField];
1706 
1707  return ' ';
1708 }
1709 
1710 /************************************************************************/
1711 /* DBFGetFieldIndex() */
1712 /* */
1713 /* Get the index number for a field in a .dbf file. */
1714 /* */
1715 /* Contributed by Jim Matthews. */
1716 /************************************************************************/
1717 
1718 int SHPAPI_CALL
1719 DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
1720 
1721 {
1722  char name[XBASE_FLDNAME_LEN_READ+1];
1723  int i;
1724 
1725  for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
1726  {
1727  DBFGetFieldInfo( psDBF, i, name, SHPLIB_NULLPTR, SHPLIB_NULLPTR );
1728  if(!STRCASECMP(pszFieldName,name))
1729  return(i);
1730  }
1731  return(-1);
1732 }
1733 
1734 /************************************************************************/
1735 /* DBFIsRecordDeleted() */
1736 /* */
1737 /* Returns TRUE if the indicated record is deleted, otherwise */
1738 /* it returns FALSE. */
1739 /************************************************************************/
1740 
1741 int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
1742 
1743 {
1744 /* -------------------------------------------------------------------- */
1745 /* Verify selection. */
1746 /* -------------------------------------------------------------------- */
1747  if( iShape < 0 || (psDBF->nRecords > 0 && iShape >= psDBF->nRecords) )
1748  return TRUE;
1749 
1750 /* -------------------------------------------------------------------- */
1751 /* Have we read the record? */
1752 /* -------------------------------------------------------------------- */
1753  if( !DBFLoadRecord( psDBF, iShape ) )
1754  return FALSE;
1755 
1756 /* -------------------------------------------------------------------- */
1757 /* '*' means deleted. */
1758 /* -------------------------------------------------------------------- */
1759  return psDBF->pszCurrentRecord[0] == '*';
1760 }
1761 
1762 /************************************************************************/
1763 /* DBFMarkRecordDeleted() */
1764 /************************************************************************/
1765 
1767  int bIsDeleted )
1768 
1769 {
1770  char chNewFlag;
1771 
1772 /* -------------------------------------------------------------------- */
1773 /* Verify selection. */
1774 /* -------------------------------------------------------------------- */
1775  if( iShape < 0 || iShape >= psDBF->nRecords )
1776  return FALSE;
1777 
1778 /* -------------------------------------------------------------------- */
1779 /* Is this an existing record, but different than the last one */
1780 /* we accessed? */
1781 /* -------------------------------------------------------------------- */
1782  if( !DBFLoadRecord( psDBF, iShape ) )
1783  return FALSE;
1784 
1785 /* -------------------------------------------------------------------- */
1786 /* Assign value, marking record as dirty if it changes. */
1787 /* -------------------------------------------------------------------- */
1788  if( bIsDeleted )
1789  chNewFlag = '*';
1790  else
1791  chNewFlag = ' ';
1792 
1793  if( psDBF->pszCurrentRecord[0] != chNewFlag )
1794  {
1795  psDBF->bCurrentRecordModified = TRUE;
1796  psDBF->bUpdated = TRUE;
1797  psDBF->pszCurrentRecord[0] = chNewFlag;
1798  }
1799 
1800  return TRUE;
1801 }
1802 
1803 /************************************************************************/
1804 /* DBFGetCodePage */
1805 /************************************************************************/
1806 
1807 const char SHPAPI_CALL1(*)
1808 DBFGetCodePage(DBFHandle psDBF )
1809 {
1810  if( psDBF == SHPLIB_NULLPTR )
1811  return SHPLIB_NULLPTR;
1812  return psDBF->pszCodePage;
1813 }
1814 
1815 /************************************************************************/
1816 /* DBFDeleteField() */
1817 /* */
1818 /* Remove a field from a .dbf file */
1819 /************************************************************************/
1820 
1821 int SHPAPI_CALL
1822 DBFDeleteField(DBFHandle psDBF, int iField)
1823 {
1824  int nOldRecordLength, nOldHeaderLength;
1825  int nDeletedFieldOffset, nDeletedFieldSize;
1826  SAOffset nRecordOffset;
1827  char* pszRecord;
1828  int i, iRecord;
1829 
1830  if (iField < 0 || iField >= psDBF->nFields)
1831  return FALSE;
1832 
1833  /* make sure that everything is written in .dbf */
1834  if( !DBFFlushRecord( psDBF ) )
1835  return FALSE;
1836 
1837  /* get information about field to be deleted */
1838  nOldRecordLength = psDBF->nRecordLength;
1839  nOldHeaderLength = psDBF->nHeaderLength;
1840  nDeletedFieldOffset = psDBF->panFieldOffset[iField];
1841  nDeletedFieldSize = psDBF->panFieldSize[iField];
1842 
1843  /* update fields info */
1844  for (i = iField + 1; i < psDBF->nFields; i++)
1845  {
1846  psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize;
1847  psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i];
1848  psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i];
1849  psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i];
1850  }
1851 
1852  /* resize fields arrays */
1853  psDBF->nFields--;
1854 
1855  psDBF->panFieldOffset = STATIC_CAST(int *,
1856  SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ));
1857 
1858  psDBF->panFieldSize = STATIC_CAST(int *,
1859  SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ));
1860 
1861  psDBF->panFieldDecimals = STATIC_CAST(int *,
1862  SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ));
1863 
1864  psDBF->pachFieldType = STATIC_CAST(char *,
1865  SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ));
1866 
1867  /* update header information */
1868  psDBF->nHeaderLength -= XBASE_FLDHDR_SZ;
1869  psDBF->nRecordLength -= nDeletedFieldSize;
1870 
1871  /* overwrite field information in header */
1872  memmove(psDBF->pszHeader + iField*XBASE_FLDHDR_SZ,
1873  psDBF->pszHeader + (iField+1)*XBASE_FLDHDR_SZ,
1874  sizeof(char) * (psDBF->nFields - iField)*XBASE_FLDHDR_SZ);
1875 
1876  psDBF->pszHeader = STATIC_CAST(char *, SfRealloc(psDBF->pszHeader,
1877  psDBF->nFields*XBASE_FLDHDR_SZ));
1878 
1879  /* update size of current record appropriately */
1880  psDBF->pszCurrentRecord = STATIC_CAST(char *, SfRealloc(psDBF->pszCurrentRecord,
1881  psDBF->nRecordLength));
1882 
1883  /* we're done if we're dealing with not yet created .dbf */
1884  if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
1885  return TRUE;
1886 
1887  /* force update of header with new header and record length */
1888  psDBF->bNoHeader = TRUE;
1889  DBFUpdateHeader( psDBF );
1890 
1891  /* alloc record */
1892  pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * nOldRecordLength));
1893 
1894  /* shift records to their new positions */
1895  for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
1896  {
1897  nRecordOffset =
1898  nOldRecordLength * STATIC_CAST(SAOffset,iRecord) + nOldHeaderLength;
1899 
1900  /* load record */
1901  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
1902  psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
1903 
1904  nRecordOffset =
1905  psDBF->nRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
1906 
1907  /* move record in two steps */
1908  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
1909  psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp );
1910  psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize,
1911  nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize,
1912  1, psDBF->fp );
1913 
1914  }
1915 
1916  if( psDBF->bWriteEndOfFileChar )
1917  {
1918  char ch = END_OF_FILE_CHARACTER;
1919  SAOffset nEOFOffset =
1920  psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
1921 
1922  psDBF->sHooks.FSeek( psDBF->fp, nEOFOffset, 0 );
1923  psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
1924  }
1925 
1926  /* TODO: truncate file */
1927 
1928  /* free record */
1929  free(pszRecord);
1930 
1931  psDBF->nCurrentRecord = -1;
1932  psDBF->bCurrentRecordModified = FALSE;
1933  psDBF->bUpdated = TRUE;
1934 
1935  return TRUE;
1936 }
1937 
1938 /************************************************************************/
1939 /* DBFReorderFields() */
1940 /* */
1941 /* Reorder the fields of a .dbf file */
1942 /* */
1943 /* panMap must be exactly psDBF->nFields long and be a permutation */
1944 /* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/
1945 /* code of DBFReorderFields. */
1946 /************************************************************************/
1947 
1948 int SHPAPI_CALL
1949 DBFReorderFields( DBFHandle psDBF, int* panMap )
1950 {
1951  SAOffset nRecordOffset;
1952  int i, iRecord;
1953  int *panFieldOffsetNew;
1954  int *panFieldSizeNew;
1955  int *panFieldDecimalsNew;
1956  char *pachFieldTypeNew;
1957  char *pszHeaderNew;
1958  char *pszRecord;
1959  char *pszRecordNew;
1960 
1961  if ( psDBF->nFields == 0 )
1962  return TRUE;
1963 
1964  /* make sure that everything is written in .dbf */
1965  if( !DBFFlushRecord( psDBF ) )
1966  return FALSE;
1967 
1968  /* a simple malloc() would be enough, but calloc() helps clang static analyzer */
1969  panFieldOffsetNew = STATIC_CAST(int *, calloc(sizeof(int), psDBF->nFields));
1970  panFieldSizeNew = STATIC_CAST(int *, calloc(sizeof(int), psDBF->nFields));
1971  panFieldDecimalsNew = STATIC_CAST(int *, calloc(sizeof(int), psDBF->nFields));
1972  pachFieldTypeNew = STATIC_CAST(char *, calloc(sizeof(char), psDBF->nFields));
1973  pszHeaderNew = STATIC_CAST(char*, malloc(sizeof(char) * XBASE_FLDHDR_SZ *
1974  psDBF->nFields));
1975 
1976  /* shuffle fields definitions */
1977  for(i=0; i < psDBF->nFields; i++)
1978  {
1979  panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
1980  panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
1981  pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
1982  memcpy(pszHeaderNew + i * XBASE_FLDHDR_SZ,
1983  psDBF->pszHeader + panMap[i] * XBASE_FLDHDR_SZ, XBASE_FLDHDR_SZ);
1984  }
1985  panFieldOffsetNew[0] = 1;
1986  for(i=1; i < psDBF->nFields; i++)
1987  {
1988  panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
1989  }
1990 
1991  free(psDBF->pszHeader);
1992  psDBF->pszHeader = pszHeaderNew;
1993 
1994  /* we're done if we're dealing with not yet created .dbf */
1995  if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) )
1996  {
1997  /* force update of header with new header and record length */
1998  psDBF->bNoHeader = TRUE;
1999  DBFUpdateHeader( psDBF );
2000 
2001  /* alloc record */
2002  pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
2003  pszRecordNew = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
2004 
2005  /* shuffle fields in records */
2006  for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
2007  {
2008  nRecordOffset =
2009  psDBF->nRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
2010 
2011  /* load record */
2012  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2013  psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
2014 
2015  pszRecordNew[0] = pszRecord[0];
2016 
2017  for(i=0; i < psDBF->nFields; i++)
2018  {
2019  memcpy(pszRecordNew + panFieldOffsetNew[i],
2020  pszRecord + psDBF->panFieldOffset[panMap[i]],
2021  psDBF->panFieldSize[panMap[i]]);
2022  }
2023 
2024  /* write record */
2025  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2026  psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp );
2027  }
2028 
2029  /* free record */
2030  free(pszRecord);
2031  free(pszRecordNew);
2032  }
2033 
2034  free(psDBF->panFieldOffset);
2035  free(psDBF->panFieldSize);
2036  free(psDBF->panFieldDecimals);
2037  free(psDBF->pachFieldType);
2038 
2039  psDBF->panFieldOffset = panFieldOffsetNew;
2040  psDBF->panFieldSize = panFieldSizeNew;
2041  psDBF->panFieldDecimals =panFieldDecimalsNew;
2042  psDBF->pachFieldType = pachFieldTypeNew;
2043 
2044  psDBF->nCurrentRecord = -1;
2045  psDBF->bCurrentRecordModified = FALSE;
2046  psDBF->bUpdated = TRUE;
2047 
2048  return TRUE;
2049 }
2050 
2051 
2052 /************************************************************************/
2053 /* DBFAlterFieldDefn() */
2054 /* */
2055 /* Alter a field definition in a .dbf file */
2056 /************************************************************************/
2057 
2058 int SHPAPI_CALL
2059 DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
2060  char chType, int nWidth, int nDecimals )
2061 {
2062  int i;
2063  int iRecord;
2064  int nOffset;
2065  int nOldWidth;
2066  int nOldRecordLength;
2067  SAOffset nRecordOffset;
2068  char* pszFInfo;
2069  char chOldType;
2070  int bIsNULL;
2071  char chFieldFill;
2072 
2073  if (iField < 0 || iField >= psDBF->nFields)
2074  return FALSE;
2075 
2076  /* make sure that everything is written in .dbf */
2077  if( !DBFFlushRecord( psDBF ) )
2078  return FALSE;
2079 
2080  chFieldFill = DBFGetNullCharacter(chType);
2081 
2082  chOldType = psDBF->pachFieldType[iField];
2083  nOffset = psDBF->panFieldOffset[iField];
2084  nOldWidth = psDBF->panFieldSize[iField];
2085  nOldRecordLength = psDBF->nRecordLength;
2086 
2087 /* -------------------------------------------------------------------- */
2088 /* Do some checking to ensure we can add records to this file. */
2089 /* -------------------------------------------------------------------- */
2090  if( nWidth < 1 )
2091  return -1;
2092 
2093  if( nWidth > XBASE_FLD_MAX_WIDTH )
2094  nWidth = XBASE_FLD_MAX_WIDTH;
2095 
2096 /* -------------------------------------------------------------------- */
2097 /* Assign the new field information fields. */
2098 /* -------------------------------------------------------------------- */
2099  psDBF->panFieldSize[iField] = nWidth;
2100  psDBF->panFieldDecimals[iField] = nDecimals;
2101  psDBF->pachFieldType[iField] = chType;
2102 
2103 /* -------------------------------------------------------------------- */
2104 /* Update the header information. */
2105 /* -------------------------------------------------------------------- */
2106  pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * iField;
2107 
2108  for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
2109  pszFInfo[i] = '\0';
2110 
2111  strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
2112 
2113  pszFInfo[11] = psDBF->pachFieldType[iField];
2114 
2115  if( chType == 'C' )
2116  {
2117  pszFInfo[16] = STATIC_CAST(unsigned char, nWidth % 256);
2118  pszFInfo[17] = STATIC_CAST(unsigned char, nWidth / 256);
2119  }
2120  else
2121  {
2122  pszFInfo[16] = STATIC_CAST(unsigned char, nWidth);
2123  pszFInfo[17] = STATIC_CAST(unsigned char, nDecimals);
2124  }
2125 
2126 /* -------------------------------------------------------------------- */
2127 /* Update offsets */
2128 /* -------------------------------------------------------------------- */
2129  if (nWidth != nOldWidth)
2130  {
2131  for (i = iField + 1; i < psDBF->nFields; i++)
2132  psDBF->panFieldOffset[i] += nWidth - nOldWidth;
2133  psDBF->nRecordLength += nWidth - nOldWidth;
2134 
2135  psDBF->pszCurrentRecord = STATIC_CAST(char *, SfRealloc(psDBF->pszCurrentRecord,
2136  psDBF->nRecordLength));
2137  }
2138 
2139  /* we're done if we're dealing with not yet created .dbf */
2140  if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
2141  return TRUE;
2142 
2143  /* force update of header with new header and record length */
2144  psDBF->bNoHeader = TRUE;
2145  DBFUpdateHeader( psDBF );
2146 
2147  if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType))
2148  {
2149  char* pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * nOldRecordLength));
2150  char* pszOldField = STATIC_CAST(char *, malloc(sizeof(char) * (nOldWidth + 1)));
2151 
2152  /* cppcheck-suppress uninitdata */
2153  pszOldField[nOldWidth] = 0;
2154 
2155  /* move records to their new positions */
2156  for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
2157  {
2158  nRecordOffset =
2159  nOldRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
2160 
2161  /* load record */
2162  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2163  psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
2164 
2165  memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
2166  bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
2167 
2168  if (nWidth != nOldWidth)
2169  {
2170  if ((chOldType == 'N' || chOldType == 'F' || chOldType == 'D') && pszOldField[0] == ' ')
2171  {
2172  /* Strip leading spaces when truncating a numeric field */
2173  memmove( pszRecord + nOffset,
2174  pszRecord + nOffset + nOldWidth - nWidth,
2175  nWidth );
2176  }
2177  if (nOffset + nOldWidth < nOldRecordLength)
2178  {
2179  memmove( pszRecord + nOffset + nWidth,
2180  pszRecord + nOffset + nOldWidth,
2181  nOldRecordLength - (nOffset + nOldWidth));
2182  }
2183  }
2184 
2185  /* Convert null value to the appropriate value of the new type */
2186  if (bIsNULL)
2187  {
2188  memset( pszRecord + nOffset, chFieldFill, nWidth);
2189  }
2190 
2191  nRecordOffset =
2192  psDBF->nRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
2193 
2194  /* write record */
2195  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2196  psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
2197  }
2198 
2199  if( psDBF->bWriteEndOfFileChar )
2200  {
2201  char ch = END_OF_FILE_CHARACTER;
2202 
2203  nRecordOffset =
2204  psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
2205 
2206  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2207  psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
2208  }
2209  /* TODO: truncate file */
2210 
2211  free(pszRecord);
2212  free(pszOldField);
2213  }
2214  else if (nWidth > nOldWidth)
2215  {
2216  char* pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
2217  char* pszOldField = STATIC_CAST(char *, malloc(sizeof(char) * (nOldWidth + 1)));
2218 
2219  /* cppcheck-suppress uninitdata */
2220  pszOldField[nOldWidth] = 0;
2221 
2222  /* move records to their new positions */
2223  for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
2224  {
2225  nRecordOffset =
2226  nOldRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
2227 
2228  /* load record */
2229  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2230  psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
2231 
2232  memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
2233  bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
2234 
2235  if (nOffset + nOldWidth < nOldRecordLength)
2236  {
2237  memmove( pszRecord + nOffset + nWidth,
2238  pszRecord + nOffset + nOldWidth,
2239  nOldRecordLength - (nOffset + nOldWidth));
2240  }
2241 
2242  /* Convert null value to the appropriate value of the new type */
2243  if (bIsNULL)
2244  {
2245  memset( pszRecord + nOffset, chFieldFill, nWidth);
2246  }
2247  else
2248  {
2249  if ((chOldType == 'N' || chOldType == 'F'))
2250  {
2251  /* Add leading spaces when expanding a numeric field */
2252  memmove( pszRecord + nOffset + nWidth - nOldWidth,
2253  pszRecord + nOffset, nOldWidth );
2254  memset( pszRecord + nOffset, ' ', nWidth - nOldWidth );
2255  }
2256  else
2257  {
2258  /* Add trailing spaces */
2259  memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth);
2260  }
2261  }
2262 
2263  nRecordOffset =
2264  psDBF->nRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
2265 
2266  /* write record */
2267  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2268  psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
2269  }
2270 
2271  if( psDBF->bWriteEndOfFileChar )
2272  {
2273  char ch = END_OF_FILE_CHARACTER;
2274 
2275  nRecordOffset =
2276  psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
2277 
2278  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2279  psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
2280  }
2281 
2282  free(pszRecord);
2283  free(pszOldField);
2284  }
2285 
2286  psDBF->nCurrentRecord = -1;
2287  psDBF->bCurrentRecordModified = FALSE;
2288  psDBF->bUpdated = TRUE;
2289 
2290  return TRUE;
2291 }
2292 
2293 /************************************************************************/
2294 /* DBFSetWriteEndOfFileChar() */
2295 /************************************************************************/
2296 
2297 void SHPAPI_CALL DBFSetWriteEndOfFileChar( DBFHandle psDBF, int bWriteFlag )
2298 {
2299  psDBF->bWriteEndOfFileChar = bWriteFlag;
2300 }
static int DBFIsValueNULL(char chType, const char *pszValue)
Definition: dbfopen.c:1168
int SHPAPI_CALL DBFMarkRecordDeleted(DBFHandle psDBF, int iShape, int bIsDeleted)
Definition: dbfopen.c:1766
int SHPAPI_CALL DBFWriteDoubleAttribute(DBFHandle psDBF, int iRecord, int iField, double dValue)
Definition: dbfopen.c:1505
int SHPAPI_CALL DBFGetFieldCount(DBFHandle psDBF)
Definition: dbfopen.c:1237
int SHPAPI_CALL DBFReadIntegerAttribute(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:1102
int SHPAPI_CALL DBFAlterFieldDefn(DBFHandle psDBF, int iField, const char *pszFieldName, char chType, int nWidth, int nDecimals)
Definition: dbfopen.c:2059
static int DBFLoadRecord(DBFHandle psDBF, int iRecord)
Definition: dbfopen.c:257
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
const char SHPAPI_CALL1 * DBFGetCodePage(DBFHandle psDBF){ if(psDBF==SHPLIB_NULLPTR) return SHPLIB_NULLPTR;return psDBF->pszCodePage;}int SHPAPI_CALLDBFDeleteField(DBFHandle psDBF, int iField
Definition: dbfopen.c:1808
#define STRCASECMP(a, b)
Definition: dbfopen.c:52
DBFHandle SHPAPI_CALL DBFOpen(const char *pszFilename, const char *pszAccess)
Definition: dbfopen.c:351
double SHPAPI_CALL DBFReadDoubleAttribute(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:1122
int SHPAPI_CALL DBFAddField(DBFHandle psDBF, const char *pszFieldName, DBFFieldType eType, int nWidth, int nDecimals)
Definition: dbfopen.c:788
const char SHPAPI_CALL1 * DBFReadLogicalAttribute(DBFHandle psDBF, int iRecord, int iField){ return STATIC_CAST(const char *, DBFReadAttribute(psDBF, iRecord, iField, 'L')
static int DBFGetLenWithoutExtension(const char *pszBasename)
Definition: dbfopen.c:365
DBFHandle SHPAPI_CALL DBFCloneEmpty(DBFHandle psDBF, const char *pszFilename)
Definition: dbfopen.c:1650
DBFHandle SHPAPI_CALL DBFCreateLL(const char *pszFilename, const char *pszCodePage, SAHooks *psHooks)
Definition: dbfopen.c:679
static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, void *pValue)
Definition: dbfopen.c:1316
int SHPAPI_CALL DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
Definition: dbfopen.c:1719
int SHPAPI_CALL DBFGetRecordCount(DBFHandle psDBF)
Definition: dbfopen.c:1250
int SHPAPI_CALL DBFWriteIntegerAttribute(DBFHandle psDBF, int iRecord, int iField, int nValue)
Definition: dbfopen.c:1519
#define STATIC_CAST(type, x)
Definition: dbfopen.c:96
int SHPAPI_CALL DBFWriteStringAttribute(DBFHandle psDBF, int iRecord, int iField, const char *pszValue)
Definition: dbfopen.c:1535
DBFHandle SHPAPI_CALL DBFCreateEx(const char *pszFilename, const char *pszCodePage)
Definition: dbfopen.c:662
#define HEADER_RECORD_TERMINATOR
Definition: dbfopen.c:79
#define REINTERPRET_CAST(type, x)
Definition: dbfopen.c:97
void SHPAPI_CALL DBFClose(DBFHandle psDBF)
Definition: dbfopen.c:599
#define XBASE_FILEHDR_SZ
Definition: dbfopen.c:77
static void DBFWriteHeader(DBFHandle psDBF)
Definition: dbfopen.c:127
#define TRUE
Definition: dbfopen.c:73
#define FALSE
Definition: dbfopen.c:72
int SHPAPI_CALL DBFAddNativeFieldType(DBFHandle psDBF, const char *pszFieldName, char chType, int nWidth, int nDecimals)
Definition: dbfopen.c:835
DBFHandle SHPAPI_CALL DBFCreate(const char *pszFilename)
Definition: dbfopen.c:649
#define END_OF_FILE_CHARACTER
Definition: dbfopen.c:82
void SHPAPI_CALL DBFSetLastModifiedDate(DBFHandle psDBF, int nYYSince1900, int nMM, int nDD)
Definition: dbfopen.c:337
void SHPAPI_CALL DBFSetWriteEndOfFileChar(DBFHandle psDBF, int bWriteFlag)
Definition: dbfopen.c:2297
DBFHandle SHPAPI_CALL DBFOpenLL(const char *pszFilename, const char *pszAccess, SAHooks *psHooks)
Definition: dbfopen.c:388
static void * SfRealloc(void *pMem, int nNewSize)
Definition: dbfopen.c:109
int SHPAPI_CALL DBFWriteNULLAttribute(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:1549
static char DBFGetNullCharacter(char chType)
Definition: dbfopen.c:811
int SHPAPI_CALL DBFIsAttributeNULL(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:1217
#define SHPLIB_NULLPTR
Definition: dbfopen.c:99
int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, void *pRawTuple)
Definition: dbfopen.c:1576
int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, void *pValue)
Definition: dbfopen.c:1437
static int DBFFlushRecord(DBFHandle psDBF)
Definition: dbfopen.c:195
int SHPAPI_CALL DBFReorderFields(DBFHandle psDBF, int *panMap)
Definition: dbfopen.c:1949
#define CONST_CAST(type, x)
Definition: dbfopen.c:98
int SHPAPI_CALL DBFIsRecordDeleted(DBFHandle psDBF, int iShape)
Definition: dbfopen.c:1741
int SHPAPI_CALL DBFWriteLogicalAttribute(DBFHandle psDBF, int iRecord, int iField, const char lValue)
Definition: dbfopen.c:1562
char SHPAPI_CALL DBFGetNativeFieldType(DBFHandle psDBF, int iField)
Definition: dbfopen.c:1701
const char SHPAPI_CALL1 * DBFReadStringAttribute(DBFHandle psDBF, int iRecord, int iField){ return STATIC_CAST(const char *, DBFReadAttribute(psDBF, iRecord, iField, 'C')
static void * DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField, char chReqType)
Definition: dbfopen.c:1008
#define CPLsnprintf
Definition: dbfopen.c:66
#define CPL_IGNORE_RET_VAL_INT(x)
Definition: dbfopen.c:87
void SHPAPI_CALL DBFUpdateHeader(DBFHandle psDBF)
Definition: dbfopen.c:304
DBFFieldType SHPAPI_CALL DBFGetFieldInfo(DBFHandle psDBF, int iField, char *pszFieldName, int *pnWidth, int *pnDecimals)
Definition: dbfopen.c:1265
void * malloc(YYSIZE_T)
void free(void *)
SHP_CVSID("$Id$")
void SASetupDefaultHooks(SAHooks *psHooks)
Definition: safileio.c:194
DBFFieldType
Definition: shapefil.h:638
@ FTDouble
Definition: shapefil.h:641
@ FTString
Definition: shapefil.h:639
@ FTInvalid
Definition: shapefil.h:644
@ FTLogical
Definition: shapefil.h:642
@ FTDate
Definition: shapefil.h:643
@ FTInteger
Definition: shapefil.h:640
int SHPAPI_CALL DBFDeleteField(DBFHandle hDBF, int iField)
#define XBASE_FLDNAME_LEN_WRITE
Definition: shapefil.h:652
#define XBASE_FLDHDR_SZ
Definition: shapefil.h:648
int * SAFile
Definition: shapefil.h:283
#define SHPAPI_CALL
Definition: shapefil.h:248
#define XBASE_FLDNAME_LEN_READ
Definition: shapefil.h:650
#define SHPAPI_CALL1(x)
Definition: shapefil.h:253
#define XBASE_FLD_MAX_WIDTH
Definition: shapefil.h:654
unsigned long SAOffset
Definition: shapefil.h:286
#define CPL_UNUSED
Definition: shpopen.c:84
int nUpdateDay
Definition: shapefil.h:629
int bWriteEndOfFileChar
Definition: shapefil.h:631
int nRecordLength
Definition: shapefil.h:596
int * panFieldOffset
Definition: shapefil.h:601
int * panFieldDecimals
Definition: shapefil.h:603
char * pszCodePage
Definition: shapefil.h:625
int nUpdateMonth
Definition: shapefil.h:628
int nFields
Definition: shapefil.h:600
int bUpdated
Definition: shapefil.h:616
int nHeaderLength
Definition: shapefil.h:597
int * panFieldSize
Definition: shapefil.h:602
char * pszCurrentRecord
Definition: shapefil.h:610
int bCurrentRecordModified
Definition: shapefil.h:609
char * pszHeader
Definition: shapefil.h:606
int nUpdateYearSince1900
Definition: shapefil.h:627
SAFile fp
Definition: shapefil.h:592
char * pachFieldType
Definition: shapefil.h:604
int bRequireNextWriteSeek
Definition: shapefil.h:633
int nWorkFieldLength
Definition: shapefil.h:612
SAHooks sHooks
Definition: shapefil.h:590
int bNoHeader
Definition: shapefil.h:615
int iLanguageDriver
Definition: shapefil.h:624
int nRecords
Definition: shapefil.h:594
char * pszWorkField
Definition: shapefil.h:613
union DBFInfo::@4 fieldValue
double dfDoubleField
Definition: shapefil.h:620
int nIntField
Definition: shapefil.h:621
int nCurrentRecord
Definition: shapefil.h:608
void(* Error)(const char *message)
Definition: shapefil.h:299
SAFile(* FOpen)(const char *filename, const char *access)
Definition: shapefil.h:290
SAOffset(* FTell)(SAFile file)
Definition: shapefil.h:294
int(* FFlush)(SAFile file)
Definition: shapefil.h:295
SAOffset(* FWrite)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
Definition: shapefil.h:292
double(* Atof)(const char *str)
Definition: shapefil.h:300
int(* Remove)(const char *filename)
Definition: shapefil.h:297
int(* FClose)(SAFile file)
Definition: shapefil.h:296
SAOffset(* FRead)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
Definition: shapefil.h:291
SAOffset(* FSeek)(SAFile file, SAOffset offset, int whence)
Definition: shapefil.h:293