PostGIS  3.7.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  if( pszFullname == SHPLIB_NULLPTR )
420  return SHPLIB_NULLPTR;
421  memcpy(pszFullname, pszFilename, nLenWithoutExtension);
422  memcpy(pszFullname + nLenWithoutExtension, ".dbf", 5);
423 
424  psDBF = STATIC_CAST(DBFHandle, calloc( 1, sizeof(DBFInfo) ));
425  if( psDBF == SHPLIB_NULLPTR )
426  {
427  free( pszFullname );
428  return SHPLIB_NULLPTR;
429  }
430  psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
431  memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
432 
433  if( psDBF->fp == SHPLIB_NULLPTR )
434  {
435  memcpy(pszFullname + nLenWithoutExtension, ".DBF", 5);
436  psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
437  }
438 
439  memcpy(pszFullname + nLenWithoutExtension, ".cpg", 5);
440  pfCPG = psHooks->FOpen( pszFullname, "r" );
441  if( pfCPG == SHPLIB_NULLPTR )
442  {
443  memcpy(pszFullname + nLenWithoutExtension, ".CPG", 5);
444  pfCPG = psHooks->FOpen( pszFullname, "r" );
445  }
446 
447  free( pszFullname );
448 
449  if( psDBF->fp == SHPLIB_NULLPTR )
450  {
451  free( psDBF );
452  if( pfCPG ) psHooks->FClose( pfCPG );
453  return SHPLIB_NULLPTR;
454  }
455 
456  psDBF->bNoHeader = FALSE;
457  psDBF->nCurrentRecord = -1;
458  psDBF->bCurrentRecordModified = FALSE;
459 
460 /* -------------------------------------------------------------------- */
461 /* Read Table Header info */
462 /* -------------------------------------------------------------------- */
463  pabyBuf = STATIC_CAST(unsigned char *, malloc(nBufSize));
464  if( psDBF->sHooks.FRead( pabyBuf, XBASE_FILEHDR_SZ, 1, psDBF->fp ) != 1 )
465  {
466  psDBF->sHooks.FClose( psDBF->fp );
467  if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
468  free( pabyBuf );
469  free( psDBF );
470  return SHPLIB_NULLPTR;
471  }
472 
473  DBFSetLastModifiedDate(psDBF, pabyBuf[1], pabyBuf[2], pabyBuf[3]);
474 
475  psDBF->nRecords =
476  pabyBuf[4]|(pabyBuf[5]<<8)|(pabyBuf[6]<<16)|((pabyBuf[7]&0x7f)<<24);
477 
478  psDBF->nHeaderLength = nHeadLen = pabyBuf[8]|(pabyBuf[9]<<8);
479  psDBF->nRecordLength = pabyBuf[10]|(pabyBuf[11]<<8);
480  psDBF->iLanguageDriver = pabyBuf[29];
481 
482  if (psDBF->nRecordLength == 0 || nHeadLen < XBASE_FILEHDR_SZ)
483  {
484  psDBF->sHooks.FClose( psDBF->fp );
485  if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
486  free( pabyBuf );
487  free( psDBF );
488  return SHPLIB_NULLPTR;
489  }
490 
491  psDBF->nFields = nFields = (nHeadLen - XBASE_FILEHDR_SZ) / XBASE_FLDHDR_SZ;
492 
493  /* coverity[tainted_data] */
494  psDBF->pszCurrentRecord = STATIC_CAST(char *, malloc(psDBF->nRecordLength));
495 
496 /* -------------------------------------------------------------------- */
497 /* Figure out the code page from the LDID and CPG */
498 /* -------------------------------------------------------------------- */
499 
500  psDBF->pszCodePage = SHPLIB_NULLPTR;
501  if( pfCPG )
502  {
503  size_t n;
504  memset( pabyBuf, 0, nBufSize);
505  psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
506  n = strcspn( REINTERPRET_CAST(char *, pabyBuf), "\n\r" );
507  if( n > 0 )
508  {
509  pabyBuf[n] = '\0';
510  psDBF->pszCodePage = STATIC_CAST(char *, malloc(n + 1));
511  memcpy( psDBF->pszCodePage, pabyBuf, n + 1 );
512  }
513  psDBF->sHooks.FClose( pfCPG );
514  }
515  if( psDBF->pszCodePage == SHPLIB_NULLPTR && pabyBuf[29] != 0 )
516  {
517  snprintf( REINTERPRET_CAST(char *, pabyBuf), nBufSize, "LDID/%d", psDBF->iLanguageDriver );
518  psDBF->pszCodePage = STATIC_CAST(char *, malloc(strlen(REINTERPRET_CAST(char*, pabyBuf)) + 1));
519  strcpy( psDBF->pszCodePage, REINTERPRET_CAST(char *, pabyBuf) );
520  }
521 
522 /* -------------------------------------------------------------------- */
523 /* Read in Field Definitions */
524 /* -------------------------------------------------------------------- */
525 
526  pabyBuf = STATIC_CAST(unsigned char *, SfRealloc(pabyBuf,nHeadLen));
527  psDBF->pszHeader = REINTERPRET_CAST(char *, pabyBuf);
528 
529  psDBF->sHooks.FSeek( psDBF->fp, XBASE_FILEHDR_SZ, 0 );
530  if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-XBASE_FILEHDR_SZ, 1,
531  psDBF->fp ) != 1 )
532  {
533  psDBF->sHooks.FClose( psDBF->fp );
534  free( pabyBuf );
535  free( psDBF->pszCurrentRecord );
536  free( psDBF->pszCodePage );
537  free( psDBF );
538  return SHPLIB_NULLPTR;
539  }
540 
541  psDBF->panFieldOffset = STATIC_CAST(int *, malloc(sizeof(int) * nFields));
542  psDBF->panFieldSize = STATIC_CAST(int *, malloc(sizeof(int) * nFields));
543  psDBF->panFieldDecimals = STATIC_CAST(int *, malloc(sizeof(int) * nFields));
544  psDBF->pachFieldType = STATIC_CAST(char *, malloc(sizeof(char) * nFields));
545 
546  for( iField = 0; iField < nFields; iField++ )
547  {
548  unsigned char *pabyFInfo;
549 
550  pabyFInfo = pabyBuf+iField*XBASE_FLDHDR_SZ;
551  if( pabyFInfo[0] == HEADER_RECORD_TERMINATOR )
552  {
553  psDBF->nFields = iField;
554  break;
555  }
556 
557  if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
558  {
559  psDBF->panFieldSize[iField] = pabyFInfo[16];
560  psDBF->panFieldDecimals[iField] = pabyFInfo[17];
561  }
562  else
563  {
564  psDBF->panFieldSize[iField] = pabyFInfo[16];
565  psDBF->panFieldDecimals[iField] = 0;
566 
567 /*
568 ** The following seemed to be used sometimes to handle files with long
569 ** string fields, but in other cases (such as bug 1202) the decimals field
570 ** just seems to indicate some sort of preferred formatting, not very
571 ** wide fields. So I have disabled this code. FrankW.
572  psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
573  psDBF->panFieldDecimals[iField] = 0;
574 */
575  }
576 
577  psDBF->pachFieldType[iField] = STATIC_CAST(char, pabyFInfo[11]);
578  if( iField == 0 )
579  psDBF->panFieldOffset[iField] = 1;
580  else
581  psDBF->panFieldOffset[iField] =
582  psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
583  }
584 
585  /* Check that the total width of fields does not exceed the record width */
586  if( psDBF->nFields > 0 &&
587  psDBF->panFieldOffset[psDBF->nFields-1] +
588  psDBF->panFieldSize[psDBF->nFields-1] > psDBF->nRecordLength )
589  {
590  DBFClose( psDBF );
591  return SHPLIB_NULLPTR;
592  }
593 
594  DBFSetWriteEndOfFileChar( psDBF, TRUE );
595 
596  psDBF->bRequireNextWriteSeek = TRUE;
597 
598  return( psDBF );
599 }
600 
601 /************************************************************************/
602 /* DBFClose() */
603 /************************************************************************/
604 
605 void SHPAPI_CALL
607 {
608  if( psDBF == SHPLIB_NULLPTR )
609  return;
610 
611 /* -------------------------------------------------------------------- */
612 /* Write out header if not already written. */
613 /* -------------------------------------------------------------------- */
614  if( psDBF->bNoHeader )
615  DBFWriteHeader( psDBF );
616 
618 
619 /* -------------------------------------------------------------------- */
620 /* Update last access date, and number of records if we have */
621 /* write access. */
622 /* -------------------------------------------------------------------- */
623  if( psDBF->bUpdated )
624  DBFUpdateHeader( psDBF );
625 
626 /* -------------------------------------------------------------------- */
627 /* Close, and free resources. */
628 /* -------------------------------------------------------------------- */
629  psDBF->sHooks.FClose( psDBF->fp );
630 
631  if( psDBF->panFieldOffset != SHPLIB_NULLPTR )
632  {
633  free( psDBF->panFieldOffset );
634  free( psDBF->panFieldSize );
635  free( psDBF->panFieldDecimals );
636  free( psDBF->pachFieldType );
637  }
638 
639  if( psDBF->pszWorkField != SHPLIB_NULLPTR )
640  free( psDBF->pszWorkField );
641 
642  free( psDBF->pszHeader );
643  free( psDBF->pszCurrentRecord );
644  free( psDBF->pszCodePage );
645 
646  free( psDBF );
647 }
648 
649 /************************************************************************/
650 /* DBFCreate() */
651 /* */
652 /* Create a new .dbf file with default code page LDID/87 (0x57) */
653 /************************************************************************/
654 
656 DBFCreate( const char * pszFilename )
657 
658 {
659  return DBFCreateEx( pszFilename, "LDID/87" ); // 0x57
660 }
661 
662 /************************************************************************/
663 /* DBFCreateEx() */
664 /* */
665 /* Create a new .dbf file. */
666 /************************************************************************/
667 
669 DBFCreateEx( const char * pszFilename, const char* pszCodePage )
670 
671 {
672  SAHooks sHooks;
673 
674  SASetupDefaultHooks( &sHooks );
675 
676  return DBFCreateLL( pszFilename, pszCodePage , &sHooks );
677 }
678 
679 /************************************************************************/
680 /* DBFCreate() */
681 /* */
682 /* Create a new .dbf file. */
683 /************************************************************************/
684 
686 DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks )
687 
688 {
689  DBFHandle psDBF;
690  SAFile fp;
691  char *pszFullname;
692  int ldid = -1;
693  char chZero = '\0';
694  int nLenWithoutExtension;
695 
696 /* -------------------------------------------------------------------- */
697 /* Compute the base (layer) name. If there is any extension */
698 /* on the passed in filename we will strip it off. */
699 /* -------------------------------------------------------------------- */
700  nLenWithoutExtension = DBFGetLenWithoutExtension(pszFilename);
701  pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
702  if( pszFullname == SHPLIB_NULLPTR )
703  return SHPLIB_NULLPTR;
704  memcpy(pszFullname, pszFilename, nLenWithoutExtension);
705  memcpy(pszFullname + nLenWithoutExtension, ".dbf", 5);
706 
707 /* -------------------------------------------------------------------- */
708 /* Create the file. */
709 /* -------------------------------------------------------------------- */
710  fp = psHooks->FOpen( pszFullname, "wb" );
711  if( fp == SHPLIB_NULLPTR )
712  {
713  free( pszFullname );
714  return SHPLIB_NULLPTR;
715  }
716 
717  psHooks->FWrite( &chZero, 1, 1, fp );
718  psHooks->FClose( fp );
719 
720  fp = psHooks->FOpen( pszFullname, "rb+" );
721  if( fp == SHPLIB_NULLPTR )
722  {
723  free( pszFullname );
724  return SHPLIB_NULLPTR;
725  }
726 
727  memcpy(pszFullname + nLenWithoutExtension, ".cpg", 5);
728  if( pszCodePage != SHPLIB_NULLPTR )
729  {
730  if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
731  {
732  ldid = atoi( pszCodePage + 5 );
733  if( ldid > 255 )
734  ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one
735  }
736  if( ldid < 0 )
737  {
738  SAFile fpCPG = psHooks->FOpen( pszFullname, "w" );
739  psHooks->FWrite( CONST_CAST(void*, STATIC_CAST(const void*, pszCodePage)), strlen(pszCodePage), 1, fpCPG );
740  psHooks->FClose( fpCPG );
741  }
742  }
743  if( pszCodePage == SHPLIB_NULLPTR || ldid >= 0 )
744  {
745  psHooks->Remove( pszFullname );
746  }
747 
748  free( pszFullname );
749 
750 /* -------------------------------------------------------------------- */
751 /* Create the info structure. */
752 /* -------------------------------------------------------------------- */
753  psDBF = STATIC_CAST(DBFHandle, calloc(1,sizeof(DBFInfo)));
754 
755  memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
756  psDBF->fp = fp;
757  psDBF->nRecords = 0;
758  psDBF->nFields = 0;
759  psDBF->nRecordLength = 1;
760  psDBF->nHeaderLength = XBASE_FILEHDR_SZ + 1; /* + 1 for HEADER_RECORD_TERMINATOR */
761 
763  psDBF->panFieldSize = SHPLIB_NULLPTR;
765  psDBF->pachFieldType = SHPLIB_NULLPTR;
766  psDBF->pszHeader = SHPLIB_NULLPTR;
767 
768  psDBF->nCurrentRecord = -1;
769  psDBF->bCurrentRecordModified = FALSE;
771 
772  psDBF->bNoHeader = TRUE;
773 
774  psDBF->iLanguageDriver = ldid > 0 ? ldid : 0;
775  psDBF->pszCodePage = SHPLIB_NULLPTR;
776  if( pszCodePage )
777  {
778  psDBF->pszCodePage = STATIC_CAST(char *, malloc( strlen(pszCodePage) + 1 ));
779  strcpy( psDBF->pszCodePage, pszCodePage );
780  }
781  DBFSetLastModifiedDate(psDBF, 95, 7, 26); /* dummy date */
782 
784 
785  psDBF->bRequireNextWriteSeek = TRUE;
786 
787  return( psDBF );
788 }
789 
790 /************************************************************************/
791 /* DBFAddField() */
792 /* */
793 /* Add a field to a newly created .dbf or to an existing one */
794 /************************************************************************/
795 
796 int SHPAPI_CALL
797 DBFAddField(DBFHandle psDBF, const char * pszFieldName,
798  DBFFieldType eType, int nWidth, int nDecimals )
799 
800 {
801  char chNativeType = 'C';
802 
803  if( eType == FTLogical )
804  chNativeType = 'L';
805  else if( eType == FTDate )
806  chNativeType = 'D';
807  else if( eType == FTString )
808  chNativeType = 'C';
809  else
810  chNativeType = 'N';
811 
812  return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
813  nWidth, nDecimals );
814 }
815 
816 /************************************************************************/
817 /* DBFGetNullCharacter() */
818 /************************************************************************/
819 
820 static char DBFGetNullCharacter(char chType)
821 {
822  switch (chType)
823  {
824  case 'N':
825  case 'F':
826  return '*';
827  case 'D':
828  return '0';
829  case 'L':
830  return '?';
831  default:
832  return ' ';
833  }
834 }
835 
836 /************************************************************************/
837 /* DBFAddField() */
838 /* */
839 /* Add a field to a newly created .dbf file before any records */
840 /* are written. */
841 /************************************************************************/
842 
843 int SHPAPI_CALL
844 DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
845  char chType, int nWidth, int nDecimals )
846 
847 {
848  char *pszFInfo;
849  int i;
850  int nOldRecordLength, nOldHeaderLength;
851  char *pszRecord;
852  char chFieldFill;
853  SAOffset nRecordOffset;
854 
855  /* make sure that everything is written in .dbf */
856  if( !DBFFlushRecord( psDBF ) )
857  return -1;
858 
859  if( psDBF->nHeaderLength + XBASE_FLDHDR_SZ > 65535 )
860  {
861  char szMessage[128];
862  snprintf( szMessage, sizeof(szMessage),
863  "Cannot add field %s. Header length limit reached "
864  "(max 65535 bytes, 2046 fields).",
865  pszFieldName );
866  psDBF->sHooks.Error( szMessage );
867  return -1;
868  }
869 
870 /* -------------------------------------------------------------------- */
871 /* Do some checking to ensure we can add records to this file. */
872 /* -------------------------------------------------------------------- */
873  if( nWidth < 1 )
874  return -1;
875 
876  if( nWidth > XBASE_FLD_MAX_WIDTH )
877  nWidth = XBASE_FLD_MAX_WIDTH;
878 
879  if( psDBF->nRecordLength + nWidth > 65535 )
880  {
881  char szMessage[128];
882  snprintf( szMessage, sizeof(szMessage),
883  "Cannot add field %s. Record length limit reached "
884  "(max 65535 bytes).",
885  pszFieldName );
886  psDBF->sHooks.Error( szMessage );
887  return -1;
888  }
889 
890  nOldRecordLength = psDBF->nRecordLength;
891  nOldHeaderLength = psDBF->nHeaderLength;
892 
893 /* -------------------------------------------------------------------- */
894 /* SfRealloc all the arrays larger to hold the additional field */
895 /* information. */
896 /* -------------------------------------------------------------------- */
897  psDBF->nFields++;
898 
899  psDBF->panFieldOffset = STATIC_CAST(int *,
900  SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ));
901 
902  psDBF->panFieldSize = STATIC_CAST(int *,
903  SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ));
904 
905  psDBF->panFieldDecimals = STATIC_CAST(int *,
906  SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ));
907 
908  psDBF->pachFieldType = STATIC_CAST(char *,
909  SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ));
910 
911 /* -------------------------------------------------------------------- */
912 /* Assign the new field information fields. */
913 /* -------------------------------------------------------------------- */
914  psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
915  psDBF->nRecordLength += nWidth;
916  psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
917  psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
918  psDBF->pachFieldType[psDBF->nFields-1] = chType;
919 
920 /* -------------------------------------------------------------------- */
921 /* Extend the required header information. */
922 /* -------------------------------------------------------------------- */
923  psDBF->nHeaderLength += XBASE_FLDHDR_SZ;
924  psDBF->bUpdated = FALSE;
925 
926  psDBF->pszHeader = STATIC_CAST(char *, SfRealloc(psDBF->pszHeader,
927  psDBF->nFields*XBASE_FLDHDR_SZ));
928 
929  pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * (psDBF->nFields-1);
930 
931  for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
932  pszFInfo[i] = '\0';
933 
934  strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
935 
936  pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
937 
938  if( chType == 'C' )
939  {
940  pszFInfo[16] = STATIC_CAST(unsigned char, nWidth % 256);
941  pszFInfo[17] = STATIC_CAST(unsigned char, nWidth / 256);
942  }
943  else
944  {
945  pszFInfo[16] = STATIC_CAST(unsigned char, nWidth);
946  pszFInfo[17] = STATIC_CAST(unsigned char, nDecimals);
947  }
948 
949 /* -------------------------------------------------------------------- */
950 /* Make the current record buffer appropriately larger. */
951 /* -------------------------------------------------------------------- */
952  psDBF->pszCurrentRecord = STATIC_CAST(char *, SfRealloc(psDBF->pszCurrentRecord,
953  psDBF->nRecordLength));
954 
955  /* we're done if dealing with new .dbf */
956  if( psDBF->bNoHeader )
957  return( psDBF->nFields - 1 );
958 
959 /* -------------------------------------------------------------------- */
960 /* For existing .dbf file, shift records */
961 /* -------------------------------------------------------------------- */
962 
963  /* alloc record */
964  pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
965 
966  chFieldFill = DBFGetNullCharacter(chType);
967 
968  for (i = psDBF->nRecords-1; i >= 0; --i)
969  {
970  nRecordOffset = nOldRecordLength * STATIC_CAST(SAOffset, i) + nOldHeaderLength;
971 
972  /* load record */
973  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
974  psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
975 
976  /* set new field's value to NULL */
977  memset(pszRecord + nOldRecordLength, chFieldFill, nWidth);
978 
979  nRecordOffset = psDBF->nRecordLength * STATIC_CAST(SAOffset, i) + psDBF->nHeaderLength;
980 
981  /* move record to the new place*/
982  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
983  psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
984  }
985 
986  if( psDBF->bWriteEndOfFileChar )
987  {
988  char ch = END_OF_FILE_CHARACTER;
989 
990  nRecordOffset =
991  psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
992 
993  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
994  psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
995  }
996 
997  /* free record */
998  free(pszRecord);
999 
1000  /* force update of header with new header, record length and new field */
1001  psDBF->bNoHeader = TRUE;
1002  DBFUpdateHeader( psDBF );
1003 
1004  psDBF->nCurrentRecord = -1;
1005  psDBF->bCurrentRecordModified = FALSE;
1006  psDBF->bUpdated = TRUE;
1007 
1008  return( psDBF->nFields-1 );
1009 }
1010 
1011 /************************************************************************/
1012 /* DBFReadAttribute() */
1013 /* */
1014 /* Read one of the attribute fields of a record. */
1015 /************************************************************************/
1016 
1017 static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
1018  char chReqType )
1019 
1020 {
1021  unsigned char *pabyRec;
1022  void *pReturnField = SHPLIB_NULLPTR;
1023 
1024 /* -------------------------------------------------------------------- */
1025 /* Verify selection. */
1026 /* -------------------------------------------------------------------- */
1027  if( hEntity < 0 || hEntity >= psDBF->nRecords )
1028  return SHPLIB_NULLPTR;
1029 
1030  if( iField < 0 || iField >= psDBF->nFields )
1031  return SHPLIB_NULLPTR;
1032 
1033 /* -------------------------------------------------------------------- */
1034 /* Have we read the record? */
1035 /* -------------------------------------------------------------------- */
1036  if( !DBFLoadRecord( psDBF, hEntity ) )
1037  return SHPLIB_NULLPTR;
1038 
1039  pabyRec = REINTERPRET_CAST(unsigned char *, psDBF->pszCurrentRecord);
1040 
1041 /* -------------------------------------------------------------------- */
1042 /* Ensure we have room to extract the target field. */
1043 /* -------------------------------------------------------------------- */
1044  if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
1045  {
1046  psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
1047  if( psDBF->pszWorkField == SHPLIB_NULLPTR )
1048  psDBF->pszWorkField = STATIC_CAST(char *, malloc(psDBF->nWorkFieldLength));
1049  else
1050  psDBF->pszWorkField = STATIC_CAST(char *, realloc(psDBF->pszWorkField,
1051  psDBF->nWorkFieldLength));
1052  }
1053 
1054 /* -------------------------------------------------------------------- */
1055 /* Extract the requested field. */
1056 /* -------------------------------------------------------------------- */
1057  memcpy( psDBF->pszWorkField,
1058  REINTERPRET_CAST(const char *, pabyRec) + psDBF->panFieldOffset[iField],
1059  psDBF->panFieldSize[iField] );
1060  psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
1061 
1062  pReturnField = psDBF->pszWorkField;
1063 
1064 /* -------------------------------------------------------------------- */
1065 /* Decode the field. */
1066 /* -------------------------------------------------------------------- */
1067  if( chReqType == 'I' )
1068  {
1069  psDBF->fieldValue.nIntField = atoi(psDBF->pszWorkField);
1070 
1071  pReturnField = &(psDBF->fieldValue.nIntField);
1072  }
1073  else if( chReqType == 'N' )
1074  {
1075  psDBF->fieldValue.dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
1076 
1077  pReturnField = &(psDBF->fieldValue.dfDoubleField);
1078  }
1079 
1080 /* -------------------------------------------------------------------- */
1081 /* Should we trim white space off the string attribute value? */
1082 /* -------------------------------------------------------------------- */
1083 #ifdef TRIM_DBF_WHITESPACE
1084  else
1085  {
1086  char *pchSrc, *pchDst;
1087 
1088  pchDst = pchSrc = psDBF->pszWorkField;
1089  while( *pchSrc == ' ' )
1090  pchSrc++;
1091 
1092  while( *pchSrc != '\0' )
1093  *(pchDst++) = *(pchSrc++);
1094  *pchDst = '\0';
1095 
1096  while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
1097  *pchDst = '\0';
1098  }
1099 #endif
1100 
1101  return pReturnField;
1102 }
1103 
1104 /************************************************************************/
1105 /* DBFReadIntAttribute() */
1106 /* */
1107 /* Read an integer attribute. */
1108 /************************************************************************/
1109 
1110 int SHPAPI_CALL
1111 DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
1112 
1113 {
1114  int *pnValue;
1115 
1116  pnValue = STATIC_CAST(int *, DBFReadAttribute( psDBF, iRecord, iField, 'I' ));
1117 
1118  if( pnValue == SHPLIB_NULLPTR )
1119  return 0;
1120  else
1121  return *pnValue;
1122 }
1123 
1124 /************************************************************************/
1125 /* DBFReadDoubleAttribute() */
1126 /* */
1127 /* Read a double attribute. */
1128 /************************************************************************/
1129 
1130 double SHPAPI_CALL
1131 DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
1132 
1133 {
1134  double *pdValue;
1135 
1136  pdValue = STATIC_CAST(double *, DBFReadAttribute( psDBF, iRecord, iField, 'N' ));
1137 
1138  if( pdValue == SHPLIB_NULLPTR )
1139  return 0.0;
1140  else
1141  return *pdValue ;
1142 }
1143 
1144 /************************************************************************/
1145 /* DBFReadStringAttribute() */
1146 /* */
1147 /* Read a string attribute. */
1148 /************************************************************************/
1149 
1150 const char SHPAPI_CALL1(*)
1151 DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
1152 
1153 {
1154  return STATIC_CAST(const char *, DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
1155 }
1156 
1157 /************************************************************************/
1158 /* DBFReadLogicalAttribute() */
1159 /* */
1160 /* Read a logical attribute. */
1161 /************************************************************************/
1162 
1163 const char SHPAPI_CALL1(*)
1164 DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
1165 
1166 {
1167  return STATIC_CAST(const char *, DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
1168 }
1169 
1170 
1171 /************************************************************************/
1172 /* DBFIsValueNULL() */
1173 /* */
1174 /* Return TRUE if the passed string is NULL. */
1175 /************************************************************************/
1176 
1177 static int DBFIsValueNULL( char chType, const char* pszValue )
1178 {
1179  int i;
1180 
1181  if( pszValue == SHPLIB_NULLPTR )
1182  return TRUE;
1183 
1184  switch(chType)
1185  {
1186  case 'N':
1187  case 'F':
1188  /*
1189  ** We accept all asterisks or all blanks as NULL
1190  ** though according to the spec I think it should be all
1191  ** asterisks.
1192  */
1193  if( pszValue[0] == '*' )
1194  return TRUE;
1195 
1196  for( i = 0; pszValue[i] != '\0'; i++ )
1197  {
1198  if( pszValue[i] != ' ' )
1199  return FALSE;
1200  }
1201  return TRUE;
1202 
1203  case 'D':
1204  /* NULL date fields have value "00000000" */
1205  return strncmp(pszValue,"00000000",8) == 0;
1206 
1207  case 'L':
1208  /* NULL boolean fields have value "?" */
1209  return pszValue[0] == '?';
1210 
1211  default:
1212  /* empty string fields are considered NULL */
1213  return strlen(pszValue) == 0;
1214  }
1215 }
1216 
1217 /************************************************************************/
1218 /* DBFIsAttributeNULL() */
1219 /* */
1220 /* Return TRUE if value for field is NULL. */
1221 /* */
1222 /* Contributed by Jim Matthews. */
1223 /************************************************************************/
1224 
1225 int SHPAPI_CALL
1226 DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
1227 
1228 {
1229  const char *pszValue;
1230 
1231  pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
1232 
1233  if( pszValue == SHPLIB_NULLPTR )
1234  return TRUE;
1235 
1236  return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue );
1237 }
1238 
1239 /************************************************************************/
1240 /* DBFGetFieldCount() */
1241 /* */
1242 /* Return the number of fields in this table. */
1243 /************************************************************************/
1244 
1245 int SHPAPI_CALL
1247 
1248 {
1249  return( psDBF->nFields );
1250 }
1251 
1252 /************************************************************************/
1253 /* DBFGetRecordCount() */
1254 /* */
1255 /* Return the number of records in this table. */
1256 /************************************************************************/
1257 
1258 int SHPAPI_CALL
1260 
1261 {
1262  return( psDBF->nRecords );
1263 }
1264 
1265 /************************************************************************/
1266 /* DBFGetFieldInfo() */
1267 /* */
1268 /* Return any requested information about the field. */
1269 /* pszFieldName must be at least XBASE_FLDNAME_LEN_READ+1 (=12) */
1270 /* bytes long. */
1271 /************************************************************************/
1272 
1274 DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
1275  int * pnWidth, int * pnDecimals )
1276 
1277 {
1278  if( iField < 0 || iField >= psDBF->nFields )
1279  return( FTInvalid );
1280 
1281  if( pnWidth != SHPLIB_NULLPTR )
1282  *pnWidth = psDBF->panFieldSize[iField];
1283 
1284  if( pnDecimals != SHPLIB_NULLPTR )
1285  *pnDecimals = psDBF->panFieldDecimals[iField];
1286 
1287  if( pszFieldName != SHPLIB_NULLPTR )
1288  {
1289  int i;
1290 
1291  strncpy( pszFieldName, STATIC_CAST(char *,psDBF->pszHeader)+iField*XBASE_FLDHDR_SZ,
1293  pszFieldName[XBASE_FLDNAME_LEN_READ] = '\0';
1294  for( i = XBASE_FLDNAME_LEN_READ - 1; i > 0 && pszFieldName[i] == ' '; i-- )
1295  pszFieldName[i] = '\0';
1296  }
1297 
1298  if ( psDBF->pachFieldType[iField] == 'L' )
1299  return( FTLogical );
1300 
1301  else if( psDBF->pachFieldType[iField] == 'D' )
1302  return( FTDate );
1303 
1304  else if( psDBF->pachFieldType[iField] == 'N'
1305  || psDBF->pachFieldType[iField] == 'F' )
1306  {
1307  if( psDBF->panFieldDecimals[iField] > 0
1308  || psDBF->panFieldSize[iField] >= 10 )
1309  return( FTDouble );
1310  else
1311  return( FTInteger );
1312  }
1313  else
1314  {
1315  return( FTString );
1316  }
1317 }
1318 
1319 /************************************************************************/
1320 /* DBFWriteAttribute() */
1321 /* */
1322 /* Write an attribute record to the file. */
1323 /************************************************************************/
1324 
1325 static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
1326  void * pValue )
1327 
1328 {
1329  int i, j, nRetResult = TRUE;
1330  unsigned char *pabyRec;
1331  char szSField[XBASE_FLD_MAX_WIDTH+1], szFormat[20];
1332 
1333 /* -------------------------------------------------------------------- */
1334 /* Is this a valid record? */
1335 /* -------------------------------------------------------------------- */
1336  if( hEntity < 0 || hEntity > psDBF->nRecords )
1337  return( FALSE );
1338 
1339  if( psDBF->bNoHeader )
1340  DBFWriteHeader(psDBF);
1341 
1342 /* -------------------------------------------------------------------- */
1343 /* Is this a brand new record? */
1344 /* -------------------------------------------------------------------- */
1345  if( hEntity == psDBF->nRecords )
1346  {
1347  if( !DBFFlushRecord( psDBF ) )
1348  return FALSE;
1349 
1350  psDBF->nRecords++;
1351  for( i = 0; i < psDBF->nRecordLength; i++ )
1352  psDBF->pszCurrentRecord[i] = ' ';
1353 
1354  psDBF->nCurrentRecord = hEntity;
1355  }
1356 
1357 /* -------------------------------------------------------------------- */
1358 /* Is this an existing record, but different than the last one */
1359 /* we accessed? */
1360 /* -------------------------------------------------------------------- */
1361  if( !DBFLoadRecord( psDBF, hEntity ) )
1362  return FALSE;
1363 
1364  pabyRec = REINTERPRET_CAST(unsigned char *,psDBF->pszCurrentRecord);
1365 
1366  psDBF->bCurrentRecordModified = TRUE;
1367  psDBF->bUpdated = TRUE;
1368 
1369 /* -------------------------------------------------------------------- */
1370 /* Translate NULL value to valid DBF file representation. */
1371 /* */
1372 /* Contributed by Jim Matthews. */
1373 /* -------------------------------------------------------------------- */
1374  if( pValue == SHPLIB_NULLPTR )
1375  {
1376  memset( pabyRec+psDBF->panFieldOffset[iField],
1377  DBFGetNullCharacter(psDBF->pachFieldType[iField]),
1378  psDBF->panFieldSize[iField] );
1379  return TRUE;
1380  }
1381 
1382 /* -------------------------------------------------------------------- */
1383 /* Assign all the record fields. */
1384 /* -------------------------------------------------------------------- */
1385  switch( psDBF->pachFieldType[iField] )
1386  {
1387  case 'D':
1388  case 'N':
1389  case 'F':
1390  {
1391  int nWidth = psDBF->panFieldSize[iField];
1392 
1393  if( STATIC_CAST(int,sizeof(szSField))-2 < nWidth )
1394  nWidth = sizeof(szSField)-2;
1395 
1396  snprintf( szFormat, sizeof(szFormat), "%%%d.%df",
1397  nWidth, psDBF->panFieldDecimals[iField] );
1398  CPLsnprintf(szSField, sizeof(szSField), szFormat, *STATIC_CAST(double *, pValue) );
1399  szSField[sizeof(szSField)-1] = '\0';
1400  if( STATIC_CAST(int,strlen(szSField)) > psDBF->panFieldSize[iField] )
1401  {
1402  szSField[psDBF->panFieldSize[iField]] = '\0';
1403  nRetResult = FALSE;
1404  }
1405  memcpy(REINTERPRET_CAST(char *, pabyRec+psDBF->panFieldOffset[iField]),
1406  szSField, strlen(szSField) );
1407  break;
1408  }
1409 
1410  case 'L':
1411  if (psDBF->panFieldSize[iField] >= 1 &&
1412  (*STATIC_CAST(char*,pValue) == 'F' || *STATIC_CAST(char*,pValue) == 'T'))
1413  *(pabyRec+psDBF->panFieldOffset[iField]) = *STATIC_CAST(char*,pValue);
1414  break;
1415 
1416  default:
1417  if( STATIC_CAST(int, strlen(STATIC_CAST(char *,pValue))) > psDBF->panFieldSize[iField] )
1418  {
1419  j = psDBF->panFieldSize[iField];
1420  nRetResult = FALSE;
1421  }
1422  else
1423  {
1424  memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1425  psDBF->panFieldSize[iField] );
1426  j = STATIC_CAST(int, strlen(STATIC_CAST(char *,pValue)));
1427  }
1428 
1429  strncpy(REINTERPRET_CAST(char *, pabyRec+psDBF->panFieldOffset[iField]),
1430  STATIC_CAST(const char *, pValue), j );
1431  break;
1432  }
1433 
1434  return( nRetResult );
1435 }
1436 
1437 /************************************************************************/
1438 /* DBFWriteAttributeDirectly() */
1439 /* */
1440 /* Write an attribute record to the file, but without any */
1441 /* reformatting based on type. The provided buffer is written */
1442 /* as is to the field position in the record. */
1443 /************************************************************************/
1444 
1445 int SHPAPI_CALL
1446 DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1447  void * pValue )
1448 
1449 {
1450  int i, j;
1451  unsigned char *pabyRec;
1452 
1453 /* -------------------------------------------------------------------- */
1454 /* Is this a valid record? */
1455 /* -------------------------------------------------------------------- */
1456  if( hEntity < 0 || hEntity > psDBF->nRecords )
1457  return( FALSE );
1458 
1459  if( psDBF->bNoHeader )
1460  DBFWriteHeader(psDBF);
1461 
1462 /* -------------------------------------------------------------------- */
1463 /* Is this a brand new record? */
1464 /* -------------------------------------------------------------------- */
1465  if( hEntity == psDBF->nRecords )
1466  {
1467  if( !DBFFlushRecord( psDBF ) )
1468  return FALSE;
1469 
1470  psDBF->nRecords++;
1471  for( i = 0; i < psDBF->nRecordLength; i++ )
1472  psDBF->pszCurrentRecord[i] = ' ';
1473 
1474  psDBF->nCurrentRecord = hEntity;
1475  }
1476 
1477 /* -------------------------------------------------------------------- */
1478 /* Is this an existing record, but different than the last one */
1479 /* we accessed? */
1480 /* -------------------------------------------------------------------- */
1481  if( !DBFLoadRecord( psDBF, hEntity ) )
1482  return FALSE;
1483 
1484  pabyRec = REINTERPRET_CAST(unsigned char *, psDBF->pszCurrentRecord);
1485 
1486 /* -------------------------------------------------------------------- */
1487 /* Assign all the record fields. */
1488 /* -------------------------------------------------------------------- */
1489  if( STATIC_CAST(int, strlen(STATIC_CAST(char *, pValue))) > psDBF->panFieldSize[iField] )
1490  j = psDBF->panFieldSize[iField];
1491  else
1492  {
1493  memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1494  psDBF->panFieldSize[iField] );
1495  j = STATIC_CAST(int, strlen(STATIC_CAST(char *, pValue)));
1496  }
1497 
1498  strncpy(REINTERPRET_CAST(char *, pabyRec+psDBF->panFieldOffset[iField]),
1499  STATIC_CAST(const char *, pValue), j );
1500 
1501  psDBF->bCurrentRecordModified = TRUE;
1502  psDBF->bUpdated = TRUE;
1503 
1504  return( TRUE );
1505 }
1506 
1507 /************************************************************************/
1508 /* DBFWriteDoubleAttribute() */
1509 /* */
1510 /* Write a double attribute. */
1511 /************************************************************************/
1512 
1513 int SHPAPI_CALL
1514 DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
1515  double dValue )
1516 
1517 {
1518  return( DBFWriteAttribute( psDBF, iRecord, iField, STATIC_CAST(void *, &dValue) ) );
1519 }
1520 
1521 /************************************************************************/
1522 /* DBFWriteIntegerAttribute() */
1523 /* */
1524 /* Write a integer attribute. */
1525 /************************************************************************/
1526 
1527 int SHPAPI_CALL
1528 DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
1529  int nValue )
1530 
1531 {
1532  double dValue = nValue;
1533 
1534  return( DBFWriteAttribute( psDBF, iRecord, iField, STATIC_CAST(void *, &dValue) ) );
1535 }
1536 
1537 /************************************************************************/
1538 /* DBFWriteStringAttribute() */
1539 /* */
1540 /* Write a string attribute. */
1541 /************************************************************************/
1542 
1543 int SHPAPI_CALL
1544 DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
1545  const char * pszValue )
1546 
1547 {
1548  return( DBFWriteAttribute( psDBF, iRecord, iField, STATIC_CAST(void *, CONST_CAST(char*, pszValue))) );
1549 }
1550 
1551 /************************************************************************/
1552 /* DBFWriteNULLAttribute() */
1553 /* */
1554 /* Write a string attribute. */
1555 /************************************************************************/
1556 
1557 int SHPAPI_CALL
1558 DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
1559 
1560 {
1561  return( DBFWriteAttribute( psDBF, iRecord, iField, SHPLIB_NULLPTR ) );
1562 }
1563 
1564 /************************************************************************/
1565 /* DBFWriteLogicalAttribute() */
1566 /* */
1567 /* Write a logical attribute. */
1568 /************************************************************************/
1569 
1570 int SHPAPI_CALL
1571 DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
1572  const char lValue)
1573 
1574 {
1575  return( DBFWriteAttribute( psDBF, iRecord, iField, STATIC_CAST(void *, CONST_CAST(char*, &lValue)) ) );
1576 }
1577 
1578 /************************************************************************/
1579 /* DBFWriteTuple() */
1580 /* */
1581 /* Write an attribute record to the file. */
1582 /************************************************************************/
1583 
1584 int SHPAPI_CALL
1585 DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
1586 
1587 {
1588  int i;
1589  unsigned char *pabyRec;
1590 
1591 /* -------------------------------------------------------------------- */
1592 /* Is this a valid record? */
1593 /* -------------------------------------------------------------------- */
1594  if( hEntity < 0 || hEntity > psDBF->nRecords )
1595  return( FALSE );
1596 
1597  if( psDBF->bNoHeader )
1598  DBFWriteHeader(psDBF);
1599 
1600 /* -------------------------------------------------------------------- */
1601 /* Is this a brand new record? */
1602 /* -------------------------------------------------------------------- */
1603  if( hEntity == psDBF->nRecords )
1604  {
1605  if( !DBFFlushRecord( psDBF ) )
1606  return FALSE;
1607 
1608  psDBF->nRecords++;
1609  for( i = 0; i < psDBF->nRecordLength; i++ )
1610  psDBF->pszCurrentRecord[i] = ' ';
1611 
1612  psDBF->nCurrentRecord = hEntity;
1613  }
1614 
1615 /* -------------------------------------------------------------------- */
1616 /* Is this an existing record, but different than the last one */
1617 /* we accessed? */
1618 /* -------------------------------------------------------------------- */
1619  if( !DBFLoadRecord( psDBF, hEntity ) )
1620  return FALSE;
1621 
1622  pabyRec = REINTERPRET_CAST(unsigned char *, psDBF->pszCurrentRecord);
1623 
1624  memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
1625 
1626  psDBF->bCurrentRecordModified = TRUE;
1627  psDBF->bUpdated = TRUE;
1628 
1629  return( TRUE );
1630 }
1631 
1632 /************************************************************************/
1633 /* DBFReadTuple() */
1634 /* */
1635 /* Read a complete record. Note that the result is only valid */
1636 /* till the next record read for any reason. */
1637 /************************************************************************/
1638 
1639 const char SHPAPI_CALL1(*)
1640 DBFReadTuple(DBFHandle psDBF, int hEntity )
1641 
1642 {
1643  if( hEntity < 0 || hEntity >= psDBF->nRecords )
1644  return SHPLIB_NULLPTR;
1645 
1646  if( !DBFLoadRecord( psDBF, hEntity ) )
1647  return SHPLIB_NULLPTR;
1648 
1649  return STATIC_CAST(const char *, psDBF->pszCurrentRecord);
1650 }
1651 
1652 /************************************************************************/
1653 /* DBFCloneEmpty() */
1654 /* */
1655 /* Read one of the attribute fields of a record. */
1656 /************************************************************************/
1657 
1659 DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
1660 {
1661  DBFHandle newDBF;
1662 
1663  newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
1664  if ( newDBF == SHPLIB_NULLPTR ) return SHPLIB_NULLPTR;
1665 
1666  newDBF->nFields = psDBF->nFields;
1667  newDBF->nRecordLength = psDBF->nRecordLength;
1668  newDBF->nHeaderLength = psDBF->nHeaderLength;
1669 
1670  if( psDBF->pszHeader )
1671  {
1672  newDBF->pszHeader = STATIC_CAST(char *, malloc ( XBASE_FLDHDR_SZ * psDBF->nFields ));
1673  memcpy ( newDBF->pszHeader, psDBF->pszHeader, XBASE_FLDHDR_SZ * psDBF->nFields );
1674  }
1675 
1676  newDBF->panFieldOffset = STATIC_CAST(int *, malloc ( sizeof(int) * psDBF->nFields ));
1677  memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1678  newDBF->panFieldSize = STATIC_CAST(int *, malloc ( sizeof(int) * psDBF->nFields ));
1679  memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1680  newDBF->panFieldDecimals = STATIC_CAST(int *, malloc ( sizeof(int) * psDBF->nFields ));
1681  memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1682  newDBF->pachFieldType = STATIC_CAST(char *, malloc ( sizeof(char) * psDBF->nFields ));
1683  memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
1684 
1685  newDBF->bNoHeader = TRUE;
1686  newDBF->bUpdated = TRUE;
1687  newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
1688 
1689  DBFWriteHeader ( newDBF );
1690  DBFClose ( newDBF );
1691 
1692  newDBF = DBFOpen ( pszFilename, "rb+" );
1693  newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
1694 
1695  return ( newDBF );
1696 }
1697 
1698 /************************************************************************/
1699 /* DBFGetNativeFieldType() */
1700 /* */
1701 /* Return the DBase field type for the specified field. */
1702 /* */
1703 /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
1704 /* 'N' (Numeric, with or without decimal), */
1705 /* 'L' (Logical), */
1706 /* 'M' (Memo: 10 digits .DBT block ptr) */
1707 /************************************************************************/
1708 
1709 char SHPAPI_CALL
1710 DBFGetNativeFieldType( DBFHandle psDBF, int iField )
1711 
1712 {
1713  if( iField >=0 && iField < psDBF->nFields )
1714  return psDBF->pachFieldType[iField];
1715 
1716  return ' ';
1717 }
1718 
1719 /************************************************************************/
1720 /* DBFGetFieldIndex() */
1721 /* */
1722 /* Get the index number for a field in a .dbf file. */
1723 /* */
1724 /* Contributed by Jim Matthews. */
1725 /************************************************************************/
1726 
1727 int SHPAPI_CALL
1728 DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
1729 
1730 {
1731  char name[XBASE_FLDNAME_LEN_READ+1];
1732  int i;
1733 
1734  for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
1735  {
1736  DBFGetFieldInfo( psDBF, i, name, SHPLIB_NULLPTR, SHPLIB_NULLPTR );
1737  if(!STRCASECMP(pszFieldName,name))
1738  return(i);
1739  }
1740  return(-1);
1741 }
1742 
1743 /************************************************************************/
1744 /* DBFIsRecordDeleted() */
1745 /* */
1746 /* Returns TRUE if the indicated record is deleted, otherwise */
1747 /* it returns FALSE. */
1748 /************************************************************************/
1749 
1750 int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
1751 
1752 {
1753 /* -------------------------------------------------------------------- */
1754 /* Verify selection. */
1755 /* -------------------------------------------------------------------- */
1756  if( iShape < 0 || (psDBF->nRecords > 0 && iShape >= psDBF->nRecords) )
1757  return TRUE;
1758 
1759 /* -------------------------------------------------------------------- */
1760 /* Have we read the record? */
1761 /* -------------------------------------------------------------------- */
1762  if( !DBFLoadRecord( psDBF, iShape ) )
1763  return FALSE;
1764 
1765 /* -------------------------------------------------------------------- */
1766 /* '*' means deleted. */
1767 /* -------------------------------------------------------------------- */
1768  return psDBF->pszCurrentRecord[0] == '*';
1769 }
1770 
1771 /************************************************************************/
1772 /* DBFMarkRecordDeleted() */
1773 /************************************************************************/
1774 
1776  int bIsDeleted )
1777 
1778 {
1779  char chNewFlag;
1780 
1781 /* -------------------------------------------------------------------- */
1782 /* Verify selection. */
1783 /* -------------------------------------------------------------------- */
1784  if( iShape < 0 || iShape >= psDBF->nRecords )
1785  return FALSE;
1786 
1787 /* -------------------------------------------------------------------- */
1788 /* Is this an existing record, but different than the last one */
1789 /* we accessed? */
1790 /* -------------------------------------------------------------------- */
1791  if( !DBFLoadRecord( psDBF, iShape ) )
1792  return FALSE;
1793 
1794 /* -------------------------------------------------------------------- */
1795 /* Assign value, marking record as dirty if it changes. */
1796 /* -------------------------------------------------------------------- */
1797  if( bIsDeleted )
1798  chNewFlag = '*';
1799  else
1800  chNewFlag = ' ';
1801 
1802  if( psDBF->pszCurrentRecord[0] != chNewFlag )
1803  {
1804  psDBF->bCurrentRecordModified = TRUE;
1805  psDBF->bUpdated = TRUE;
1806  psDBF->pszCurrentRecord[0] = chNewFlag;
1807  }
1808 
1809  return TRUE;
1810 }
1811 
1812 /************************************************************************/
1813 /* DBFGetCodePage */
1814 /************************************************************************/
1815 
1816 const char SHPAPI_CALL1(*)
1817 DBFGetCodePage(DBFHandle psDBF )
1818 {
1819  if( psDBF == SHPLIB_NULLPTR )
1820  return SHPLIB_NULLPTR;
1821  return psDBF->pszCodePage;
1822 }
1823 
1824 /************************************************************************/
1825 /* DBFDeleteField() */
1826 /* */
1827 /* Remove a field from a .dbf file */
1828 /************************************************************************/
1829 
1830 int SHPAPI_CALL
1831 DBFDeleteField(DBFHandle psDBF, int iField)
1832 {
1833  int nOldRecordLength, nOldHeaderLength;
1834  int nDeletedFieldOffset, nDeletedFieldSize;
1835  SAOffset nRecordOffset;
1836  char* pszRecord;
1837  int i, iRecord;
1838 
1839  if (iField < 0 || iField >= psDBF->nFields)
1840  return FALSE;
1841 
1842  /* make sure that everything is written in .dbf */
1843  if( !DBFFlushRecord( psDBF ) )
1844  return FALSE;
1845 
1846  /* get information about field to be deleted */
1847  nOldRecordLength = psDBF->nRecordLength;
1848  nOldHeaderLength = psDBF->nHeaderLength;
1849  nDeletedFieldOffset = psDBF->panFieldOffset[iField];
1850  nDeletedFieldSize = psDBF->panFieldSize[iField];
1851 
1852  /* update fields info */
1853  for (i = iField + 1; i < psDBF->nFields; i++)
1854  {
1855  psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize;
1856  psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i];
1857  psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i];
1858  psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i];
1859  }
1860 
1861  /* resize fields arrays */
1862  psDBF->nFields--;
1863 
1864  psDBF->panFieldOffset = STATIC_CAST(int *,
1865  SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ));
1866 
1867  psDBF->panFieldSize = STATIC_CAST(int *,
1868  SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ));
1869 
1870  psDBF->panFieldDecimals = STATIC_CAST(int *,
1871  SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ));
1872 
1873  psDBF->pachFieldType = STATIC_CAST(char *,
1874  SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ));
1875 
1876  /* update header information */
1877  psDBF->nHeaderLength -= XBASE_FLDHDR_SZ;
1878  psDBF->nRecordLength -= nDeletedFieldSize;
1879 
1880  /* overwrite field information in header */
1881  memmove(psDBF->pszHeader + iField*XBASE_FLDHDR_SZ,
1882  psDBF->pszHeader + (iField+1)*XBASE_FLDHDR_SZ,
1883  sizeof(char) * (psDBF->nFields - iField)*XBASE_FLDHDR_SZ);
1884 
1885  psDBF->pszHeader = STATIC_CAST(char *, SfRealloc(psDBF->pszHeader,
1886  psDBF->nFields*XBASE_FLDHDR_SZ));
1887 
1888  /* update size of current record appropriately */
1889  psDBF->pszCurrentRecord = STATIC_CAST(char *, SfRealloc(psDBF->pszCurrentRecord,
1890  psDBF->nRecordLength));
1891 
1892  /* we're done if we're dealing with not yet created .dbf */
1893  if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
1894  return TRUE;
1895 
1896  /* force update of header with new header and record length */
1897  psDBF->bNoHeader = TRUE;
1898  DBFUpdateHeader( psDBF );
1899 
1900  /* alloc record */
1901  pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * nOldRecordLength));
1902 
1903  /* shift records to their new positions */
1904  for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
1905  {
1906  nRecordOffset =
1907  nOldRecordLength * STATIC_CAST(SAOffset,iRecord) + nOldHeaderLength;
1908 
1909  /* load record */
1910  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
1911  psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
1912 
1913  nRecordOffset =
1914  psDBF->nRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
1915 
1916  /* move record in two steps */
1917  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
1918  psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp );
1919  psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize,
1920  nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize,
1921  1, psDBF->fp );
1922 
1923  }
1924 
1925  if( psDBF->bWriteEndOfFileChar )
1926  {
1927  char ch = END_OF_FILE_CHARACTER;
1928  SAOffset nEOFOffset =
1929  psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
1930 
1931  psDBF->sHooks.FSeek( psDBF->fp, nEOFOffset, 0 );
1932  psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
1933  }
1934 
1935  /* TODO: truncate file */
1936 
1937  /* free record */
1938  free(pszRecord);
1939 
1940  psDBF->nCurrentRecord = -1;
1941  psDBF->bCurrentRecordModified = FALSE;
1942  psDBF->bUpdated = TRUE;
1943 
1944  return TRUE;
1945 }
1946 
1947 /************************************************************************/
1948 /* DBFReorderFields() */
1949 /* */
1950 /* Reorder the fields of a .dbf file */
1951 /* */
1952 /* panMap must be exactly psDBF->nFields long and be a permutation */
1953 /* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/
1954 /* code of DBFReorderFields. */
1955 /************************************************************************/
1956 
1957 int SHPAPI_CALL
1958 DBFReorderFields( DBFHandle psDBF, int* panMap )
1959 {
1960  SAOffset nRecordOffset;
1961  int i, iRecord;
1962  int *panFieldOffsetNew;
1963  int *panFieldSizeNew;
1964  int *panFieldDecimalsNew;
1965  char *pachFieldTypeNew;
1966  char *pszHeaderNew;
1967  char *pszRecord;
1968  char *pszRecordNew;
1969 
1970  if ( psDBF->nFields == 0 )
1971  return TRUE;
1972 
1973  /* make sure that everything is written in .dbf */
1974  if( !DBFFlushRecord( psDBF ) )
1975  return FALSE;
1976 
1977  /* a simple malloc() would be enough, but calloc() helps clang static analyzer */
1978  panFieldOffsetNew = STATIC_CAST(int *, calloc(psDBF->nFields, sizeof(int)));
1979  panFieldSizeNew = STATIC_CAST(int *, calloc(psDBF->nFields, sizeof(int)));
1980  panFieldDecimalsNew = STATIC_CAST(int *, calloc(psDBF->nFields, sizeof(int)));
1981  pachFieldTypeNew = STATIC_CAST(char *, calloc(psDBF->nFields, sizeof(char)));
1982  pszHeaderNew = STATIC_CAST(char*, malloc(sizeof(char) * XBASE_FLDHDR_SZ * psDBF->nFields));
1983 
1984  if( panFieldOffsetNew == SHPLIB_NULLPTR || panFieldSizeNew == SHPLIB_NULLPTR ||
1985  panFieldDecimalsNew == SHPLIB_NULLPTR || pachFieldTypeNew == SHPLIB_NULLPTR ||
1986  pszHeaderNew == SHPLIB_NULLPTR )
1987  {
1988  free( panFieldOffsetNew );
1989  free( panFieldSizeNew );
1990  free( panFieldDecimalsNew );
1991  free( pachFieldTypeNew );
1992  free( pszHeaderNew );
1993  return FALSE;
1994  }
1995 
1996  /* shuffle fields definitions */
1997  for(i=0; i < psDBF->nFields; i++)
1998  {
1999  panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
2000  panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
2001  pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
2002  memcpy(pszHeaderNew + i * XBASE_FLDHDR_SZ,
2003  psDBF->pszHeader + panMap[i] * XBASE_FLDHDR_SZ, XBASE_FLDHDR_SZ);
2004  }
2005  panFieldOffsetNew[0] = 1;
2006  for(i=1; i < psDBF->nFields; i++)
2007  {
2008  panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
2009  }
2010 
2011  free(psDBF->pszHeader);
2012  psDBF->pszHeader = pszHeaderNew;
2013 
2014  /* we're done if we're dealing with not yet created .dbf */
2015  if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) )
2016  {
2017  /* force update of header with new header and record length */
2018  psDBF->bNoHeader = TRUE;
2019  DBFUpdateHeader( psDBF );
2020 
2021  /* alloc record */
2022  pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
2023  pszRecordNew = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
2024 
2025  /* shuffle fields in records */
2026  for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
2027  {
2028  nRecordOffset =
2029  psDBF->nRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
2030 
2031  /* load record */
2032  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2033  psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
2034 
2035  pszRecordNew[0] = pszRecord[0];
2036 
2037  for(i=0; i < psDBF->nFields; i++)
2038  {
2039  memcpy(pszRecordNew + panFieldOffsetNew[i],
2040  pszRecord + psDBF->panFieldOffset[panMap[i]],
2041  psDBF->panFieldSize[panMap[i]]);
2042  }
2043 
2044  /* write record */
2045  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2046  psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp );
2047  }
2048 
2049  /* free record */
2050  free(pszRecord);
2051  free(pszRecordNew);
2052  }
2053 
2054  free(psDBF->panFieldOffset);
2055  free(psDBF->panFieldSize);
2056  free(psDBF->panFieldDecimals);
2057  free(psDBF->pachFieldType);
2058 
2059  psDBF->panFieldOffset = panFieldOffsetNew;
2060  psDBF->panFieldSize = panFieldSizeNew;
2061  psDBF->panFieldDecimals =panFieldDecimalsNew;
2062  psDBF->pachFieldType = pachFieldTypeNew;
2063 
2064  psDBF->nCurrentRecord = -1;
2065  psDBF->bCurrentRecordModified = FALSE;
2066  psDBF->bUpdated = TRUE;
2067 
2068  return TRUE;
2069 }
2070 
2071 
2072 /************************************************************************/
2073 /* DBFAlterFieldDefn() */
2074 /* */
2075 /* Alter a field definition in a .dbf file */
2076 /************************************************************************/
2077 
2078 int SHPAPI_CALL
2079 DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
2080  char chType, int nWidth, int nDecimals )
2081 {
2082  int i;
2083  int iRecord;
2084  int nOffset;
2085  int nOldWidth;
2086  int nOldRecordLength;
2087  SAOffset nRecordOffset;
2088  char* pszFInfo;
2089  char chOldType;
2090  int bIsNULL;
2091  char chFieldFill;
2092 
2093  if (iField < 0 || iField >= psDBF->nFields)
2094  return FALSE;
2095 
2096  /* make sure that everything is written in .dbf */
2097  if( !DBFFlushRecord( psDBF ) )
2098  return FALSE;
2099 
2100  chFieldFill = DBFGetNullCharacter(chType);
2101 
2102  chOldType = psDBF->pachFieldType[iField];
2103  nOffset = psDBF->panFieldOffset[iField];
2104  nOldWidth = psDBF->panFieldSize[iField];
2105  nOldRecordLength = psDBF->nRecordLength;
2106 
2107 /* -------------------------------------------------------------------- */
2108 /* Do some checking to ensure we can add records to this file. */
2109 /* -------------------------------------------------------------------- */
2110  if( nWidth < 1 )
2111  return -1;
2112 
2113  if( nWidth > XBASE_FLD_MAX_WIDTH )
2114  nWidth = XBASE_FLD_MAX_WIDTH;
2115 
2116 /* -------------------------------------------------------------------- */
2117 /* Assign the new field information fields. */
2118 /* -------------------------------------------------------------------- */
2119  psDBF->panFieldSize[iField] = nWidth;
2120  psDBF->panFieldDecimals[iField] = nDecimals;
2121  psDBF->pachFieldType[iField] = chType;
2122 
2123 /* -------------------------------------------------------------------- */
2124 /* Update the header information. */
2125 /* -------------------------------------------------------------------- */
2126  pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * iField;
2127 
2128  for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
2129  pszFInfo[i] = '\0';
2130 
2131  strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
2132 
2133  pszFInfo[11] = psDBF->pachFieldType[iField];
2134 
2135  if( chType == 'C' )
2136  {
2137  pszFInfo[16] = STATIC_CAST(unsigned char, nWidth % 256);
2138  pszFInfo[17] = STATIC_CAST(unsigned char, nWidth / 256);
2139  }
2140  else
2141  {
2142  pszFInfo[16] = STATIC_CAST(unsigned char, nWidth);
2143  pszFInfo[17] = STATIC_CAST(unsigned char, nDecimals);
2144  }
2145 
2146 /* -------------------------------------------------------------------- */
2147 /* Update offsets */
2148 /* -------------------------------------------------------------------- */
2149  if (nWidth != nOldWidth)
2150  {
2151  for (i = iField + 1; i < psDBF->nFields; i++)
2152  psDBF->panFieldOffset[i] += nWidth - nOldWidth;
2153  psDBF->nRecordLength += nWidth - nOldWidth;
2154 
2155  psDBF->pszCurrentRecord = STATIC_CAST(char *, SfRealloc(psDBF->pszCurrentRecord,
2156  psDBF->nRecordLength));
2157  }
2158 
2159  /* we're done if we're dealing with not yet created .dbf */
2160  if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
2161  return TRUE;
2162 
2163  /* force update of header with new header and record length */
2164  psDBF->bNoHeader = TRUE;
2165  DBFUpdateHeader( psDBF );
2166 
2167  if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType))
2168  {
2169  char* pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * nOldRecordLength));
2170  char* pszOldField = STATIC_CAST(char *, malloc(sizeof(char) * (nOldWidth + 1)));
2171 
2172  /* cppcheck-suppress uninitdata */
2173  pszOldField[nOldWidth] = 0;
2174 
2175  /* move records to their new positions */
2176  for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
2177  {
2178  nRecordOffset =
2179  nOldRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
2180 
2181  /* load record */
2182  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2183  psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
2184 
2185  memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
2186  bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
2187 
2188  if (nWidth != nOldWidth)
2189  {
2190  if ((chOldType == 'N' || chOldType == 'F' || chOldType == 'D') && pszOldField[0] == ' ')
2191  {
2192  /* Strip leading spaces when truncating a numeric field */
2193  memmove( pszRecord + nOffset,
2194  pszRecord + nOffset + nOldWidth - nWidth,
2195  nWidth );
2196  }
2197  if (nOffset + nOldWidth < nOldRecordLength)
2198  {
2199  memmove( pszRecord + nOffset + nWidth,
2200  pszRecord + nOffset + nOldWidth,
2201  nOldRecordLength - (nOffset + nOldWidth));
2202  }
2203  }
2204 
2205  /* Convert null value to the appropriate value of the new type */
2206  if (bIsNULL)
2207  {
2208  memset( pszRecord + nOffset, chFieldFill, nWidth);
2209  }
2210 
2211  nRecordOffset =
2212  psDBF->nRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
2213 
2214  /* write record */
2215  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2216  psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
2217  }
2218 
2219  if( psDBF->bWriteEndOfFileChar )
2220  {
2221  char ch = END_OF_FILE_CHARACTER;
2222 
2223  nRecordOffset =
2224  psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
2225 
2226  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2227  psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
2228  }
2229  /* TODO: truncate file */
2230 
2231  free(pszRecord);
2232  free(pszOldField);
2233  }
2234  else if (nWidth > nOldWidth)
2235  {
2236  char* pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
2237  char* pszOldField = STATIC_CAST(char *, malloc(sizeof(char) * (nOldWidth + 1)));
2238 
2239  /* cppcheck-suppress uninitdata */
2240  pszOldField[nOldWidth] = 0;
2241 
2242  /* move records to their new positions */
2243  for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
2244  {
2245  nRecordOffset =
2246  nOldRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
2247 
2248  /* load record */
2249  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2250  psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
2251 
2252  memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
2253  bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
2254 
2255  if (nOffset + nOldWidth < nOldRecordLength)
2256  {
2257  memmove( pszRecord + nOffset + nWidth,
2258  pszRecord + nOffset + nOldWidth,
2259  nOldRecordLength - (nOffset + nOldWidth));
2260  }
2261 
2262  /* Convert null value to the appropriate value of the new type */
2263  if (bIsNULL)
2264  {
2265  memset( pszRecord + nOffset, chFieldFill, nWidth);
2266  }
2267  else
2268  {
2269  if ((chOldType == 'N' || chOldType == 'F'))
2270  {
2271  /* Add leading spaces when expanding a numeric field */
2272  memmove( pszRecord + nOffset + nWidth - nOldWidth,
2273  pszRecord + nOffset, nOldWidth );
2274  memset( pszRecord + nOffset, ' ', nWidth - nOldWidth );
2275  }
2276  else
2277  {
2278  /* Add trailing spaces */
2279  memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth);
2280  }
2281  }
2282 
2283  nRecordOffset =
2284  psDBF->nRecordLength * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
2285 
2286  /* write record */
2287  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2288  psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
2289  }
2290 
2291  if( psDBF->bWriteEndOfFileChar )
2292  {
2293  char ch = END_OF_FILE_CHARACTER;
2294 
2295  nRecordOffset =
2296  psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
2297 
2298  psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
2299  psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
2300  }
2301 
2302  free(pszRecord);
2303  free(pszOldField);
2304  }
2305 
2306  psDBF->nCurrentRecord = -1;
2307  psDBF->bCurrentRecordModified = FALSE;
2308  psDBF->bUpdated = TRUE;
2309 
2310  return TRUE;
2311 }
2312 
2313 /************************************************************************/
2314 /* DBFSetWriteEndOfFileChar() */
2315 /************************************************************************/
2316 
2317 void SHPAPI_CALL DBFSetWriteEndOfFileChar( DBFHandle psDBF, int bWriteFlag )
2318 {
2319  psDBF->bWriteEndOfFileChar = bWriteFlag;
2320 }
static int DBFIsValueNULL(char chType, const char *pszValue)
Definition: dbfopen.c:1177
int SHPAPI_CALL DBFMarkRecordDeleted(DBFHandle psDBF, int iShape, int bIsDeleted)
Definition: dbfopen.c:1775
int SHPAPI_CALL DBFWriteDoubleAttribute(DBFHandle psDBF, int iRecord, int iField, double dValue)
Definition: dbfopen.c:1514
int SHPAPI_CALL DBFGetFieldCount(DBFHandle psDBF)
Definition: dbfopen.c:1246
int SHPAPI_CALL DBFReadIntegerAttribute(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:1111
int SHPAPI_CALL DBFAlterFieldDefn(DBFHandle psDBF, int iField, const char *pszFieldName, char chType, int nWidth, int nDecimals)
Definition: dbfopen.c:2079
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:1817
#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:1131
int SHPAPI_CALL DBFAddField(DBFHandle psDBF, const char *pszFieldName, DBFFieldType eType, int nWidth, int nDecimals)
Definition: dbfopen.c:797
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:1659
DBFHandle SHPAPI_CALL DBFCreateLL(const char *pszFilename, const char *pszCodePage, SAHooks *psHooks)
Definition: dbfopen.c:686
static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, void *pValue)
Definition: dbfopen.c:1325
int SHPAPI_CALL DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
Definition: dbfopen.c:1728
int SHPAPI_CALL DBFGetRecordCount(DBFHandle psDBF)
Definition: dbfopen.c:1259
int SHPAPI_CALL DBFWriteIntegerAttribute(DBFHandle psDBF, int iRecord, int iField, int nValue)
Definition: dbfopen.c:1528
#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:1544
DBFHandle SHPAPI_CALL DBFCreateEx(const char *pszFilename, const char *pszCodePage)
Definition: dbfopen.c:669
#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:606
#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:844
DBFHandle SHPAPI_CALL DBFCreate(const char *pszFilename)
Definition: dbfopen.c:656
#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:2317
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:1558
static char DBFGetNullCharacter(char chType)
Definition: dbfopen.c:820
int SHPAPI_CALL DBFIsAttributeNULL(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:1226
#define SHPLIB_NULLPTR
Definition: dbfopen.c:99
int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, void *pRawTuple)
Definition: dbfopen.c:1585
int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, void *pValue)
Definition: dbfopen.c:1446
static int DBFFlushRecord(DBFHandle psDBF)
Definition: dbfopen.c:195
int SHPAPI_CALL DBFReorderFields(DBFHandle psDBF, int *panMap)
Definition: dbfopen.c:1958
#define CONST_CAST(type, x)
Definition: dbfopen.c:98
int SHPAPI_CALL DBFIsRecordDeleted(DBFHandle psDBF, int iShape)
Definition: dbfopen.c:1750
int SHPAPI_CALL DBFWriteLogicalAttribute(DBFHandle psDBF, int iRecord, int iField, const char lValue)
Definition: dbfopen.c:1571
char SHPAPI_CALL DBFGetNativeFieldType(DBFHandle psDBF, int iField)
Definition: dbfopen.c:1710
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:1017
#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:1274
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
union DBFInfo::@5 fieldValue
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
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