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