GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
dbfopen.c
Go to the documentation of this file.
1 /******************************************************************************
2  * $Id: dbfopen.c 32581 2008-08-06 19:30:45Z neteler $
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  *
11  * This software is available under the following "MIT Style" license,
12  * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
13  * option is discussed in more detail in shapelib.html.
14  *
15  * --
16  *
17  * Permission is hereby granted, free of charge, to any person obtaining a
18  * copy of this software and associated documentation files (the "Software"),
19  * to deal in the Software without restriction, including without limitation
20  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21  * and/or sell copies of the Software, and to permit persons to whom the
22  * Software is furnished to do so, subject to the following conditions:
23  *
24  * The above copyright notice and this permission notice shall be included
25  * in all copies or substantial portions of the Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33  * DEALINGS IN THE SOFTWARE.
34  ******************************************************************************
35  *
36  * $Log: dbfopen.c,v $
37  * Revision 1.74 2007/12/06 07:00:25 fwarmerdam
38  * dbfopen now using SAHooks for fileio
39  *
40  * Revision 1.73 2007/09/03 19:48:11 fwarmerdam
41  * move DBFReadAttribute() static dDoubleField into dbfinfo
42  *
43  * Revision 1.72 2007/09/03 19:34:06 fwarmerdam
44  * Avoid use of static tuple buffer in DBFReadTuple()
45  *
46  * Revision 1.71 2006/06/22 14:37:18 fwarmerdam
47  * avoid memory leak if dbfopen fread fails
48  *
49  * Revision 1.70 2006/06/17 17:47:05 fwarmerdam
50  * use calloc() for dbfinfo in DBFCreate
51  *
52  * Revision 1.69 2006/06/17 15:34:32 fwarmerdam
53  * disallow creating fields wider than 255
54  *
55  * Revision 1.68 2006/06/17 15:12:40 fwarmerdam
56  * Fixed C++ style comments.
57  *
58  * Revision 1.67 2006/06/17 00:24:53 fwarmerdam
59  * Don't treat non-zero decimals values as high order byte for length
60  * for strings. It causes serious corruption for some files.
61  * http://bugzilla.remotesensing.org/show_bug.cgi?id=1202
62  *
63  * Revision 1.66 2006/03/29 18:26:20 fwarmerdam
64  * fixed bug with size of pachfieldtype in dbfcloneempty
65  *
66  * Revision 1.65 2006/02/15 01:14:30 fwarmerdam
67  * added DBFAddNativeFieldType
68  *
69  * Revision 1.64 2006/02/09 00:29:04 fwarmerdam
70  * Changed to put spaces into string fields that are NULL as
71  * per http://bugzilla.maptools.org/show_bug.cgi?id=316.
72  *
73  * Revision 1.63 2006/01/25 15:35:43 fwarmerdam
74  * check success on DBFFlushRecord
75  *
76  * Revision 1.62 2006/01/10 16:28:03 fwarmerdam
77  * Fixed typo in CPLError.
78  *
79  * Revision 1.61 2006/01/10 16:26:29 fwarmerdam
80  * Push loading record buffer into DBFLoadRecord.
81  * Implement CPL error reporting if USE_CPL defined.
82  *
83  * Revision 1.60 2006/01/05 01:27:27 fwarmerdam
84  * added dbf deletion mark/fetch
85  *
86  * Revision 1.59 2005/03/14 15:20:28 fwarmerdam
87  * Fixed last change.
88  *
89  * Revision 1.58 2005/03/14 15:18:54 fwarmerdam
90  * Treat very wide fields with no decimals as double. This is
91  * more than 32bit integer fields.
92  *
93  * Revision 1.57 2005/02/10 20:16:54 fwarmerdam
94  * Make the pszStringField buffer for DBFReadAttribute() static char [256]
95  * as per bug 306.
96  *
97  * Revision 1.56 2005/02/10 20:07:56 fwarmerdam
98  * Fixed bug 305 in DBFCloneEmpty() - header length problem.
99  *
100  * Revision 1.55 2004/09/26 20:23:46 fwarmerdam
101  * avoid warnings with rcsid and signed/unsigned stuff
102  *
103  * Revision 1.54 2004/09/15 16:26:10 fwarmerdam
104  * Treat all blank numeric fields as null too.
105  */
106 
107 #include <grass/shapefil.h>
108 
109 #include <math.h>
110 #include <stdlib.h>
111 #include <ctype.h>
112 #include <string.h>
113 
114 SHP_CVSID("$Id: dbfopen.c 32581 2008-08-06 19:30:45Z neteler $")
115 
116 #ifndef FALSE
117 # define FALSE 0
118 # define TRUE 1
119 #endif
120 
121 /************************************************************************/
122 /* SfRealloc() */
123 /* */
124 /* A realloc cover function that will access a NULL pointer as */
125 /* a valid input. */
126 /************************************************************************/
127 
128 static void * SfRealloc( void * pMem, int nNewSize )
129 
130 {
131  if( pMem == NULL )
132  return( (void *) malloc(nNewSize) );
133  else
134  return( (void *) realloc(pMem,nNewSize) );
135 }
136 
137 /************************************************************************/
138 /* DBFWriteHeader() */
139 /* */
140 /* This is called to write out the file header, and field */
141 /* descriptions before writing any actual data records. This */
142 /* also computes all the DBFDataSet field offset/size/decimals */
143 /* and so forth values. */
144 /************************************************************************/
145 
146 static void DBFWriteHeader(DBFHandle psDBF)
147 
148 {
149  unsigned char abyHeader[XBASE_FLDHDR_SZ];
150  int i;
151 
152  if( !psDBF->bNoHeader )
153  return;
154 
155  psDBF->bNoHeader = FALSE;
156 
157 /* -------------------------------------------------------------------- */
158 /* Initialize the file header information. */
159 /* -------------------------------------------------------------------- */
160  for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
161  abyHeader[i] = 0;
162 
163  abyHeader[0] = 0x03; /* memo field? - just copying */
164 
165  /* write out a dummy date */
166  abyHeader[1] = 95; /* YY */
167  abyHeader[2] = 7; /* MM */
168  abyHeader[3] = 26; /* DD */
169 
170  /* record count preset at zero */
171 
172  abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
173  abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
174 
175  abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
176  abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
177 
178 /* -------------------------------------------------------------------- */
179 /* Write the initial 32 byte file header, and all the field */
180 /* descriptions. */
181 /* -------------------------------------------------------------------- */
182  psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
183  psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
184  psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
185  psDBF->fp );
186 
187 /* -------------------------------------------------------------------- */
188 /* Write out the newline character if there is room for it. */
189 /* -------------------------------------------------------------------- */
190  if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
191  {
192  char cNewline;
193 
194  cNewline = 0x0d;
195  psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
196  }
197 }
198 
199 /************************************************************************/
200 /* DBFFlushRecord() */
201 /* */
202 /* Write out the current record if there is one. */
203 /************************************************************************/
204 
205 static int DBFFlushRecord( DBFHandle psDBF )
206 
207 {
208  SAOffset nRecordOffset;
209 
210  if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
211  {
212  psDBF->bCurrentRecordModified = FALSE;
213 
214  nRecordOffset =
215  psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord
216  + psDBF->nHeaderLength;
217 
218  if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0
219  || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord,
220  psDBF->nRecordLength,
221  1, psDBF->fp ) != 1 )
222  {
223 #ifdef USE_CPL
224  CPLError( CE_Failure, CPLE_FileIO,
225  "Failure writing DBF record %d.",
226  psDBF->nCurrentRecord );
227 #else
228  fprintf( stderr, "Failure writing DBF record %d.",
229  psDBF->nCurrentRecord );
230 #endif
231  return FALSE;
232  }
233  }
234 
235  return TRUE;
236 }
237 
238 /************************************************************************/
239 /* DBFLoadRecord() */
240 /************************************************************************/
241 
242 static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
243 
244 {
245  if( psDBF->nCurrentRecord != iRecord )
246  {
247  SAOffset nRecordOffset;
248 
249  if( !DBFFlushRecord( psDBF ) )
250  return FALSE;
251 
252  nRecordOffset =
253  psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
254 
255  if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
256  {
257 #ifdef USE_CPL
258  CPLError( CE_Failure, CPLE_FileIO,
259  "fseek(%ld) failed on DBF file.\n",
260  (long) nRecordOffset );
261 #else
262  fprintf( stderr, "fseek(%ld) failed on DBF file.\n",
263  (long) nRecordOffset );
264 #endif
265  return FALSE;
266  }
267 
268  if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
269  psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
270  {
271 #ifdef USE_CPL
272  CPLError( CE_Failure, CPLE_FileIO,
273  "fread(%d) failed on DBF file.\n",
274  psDBF->nRecordLength );
275 #else
276  fprintf( stderr, "fread(%d) failed on DBF file.\n",
277  psDBF->nRecordLength );
278 #endif
279  return FALSE;
280  }
281 
282  psDBF->nCurrentRecord = iRecord;
283  }
284 
285  return TRUE;
286 }
287 
288 /************************************************************************/
289 /* DBFUpdateHeader() */
290 /************************************************************************/
291 
292 void SHPAPI_CALL
293 DBFUpdateHeader( DBFHandle psDBF )
294 
295 {
296  unsigned char abyFileHeader[32];
297 
298  if( psDBF->bNoHeader )
299  DBFWriteHeader( psDBF );
300 
301  DBFFlushRecord( psDBF );
302 
303  psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
304  psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
305 
306  abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
307  abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
308  abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
309  abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
310 
311  psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
312  psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
313 
314  psDBF->sHooks.FFlush( psDBF->fp );
315 }
316 
317 /************************************************************************/
318 /* DBFOpen() */
319 /* */
320 /* Open a .dbf file. */
321 /************************************************************************/
322 
323 DBFHandle SHPAPI_CALL
324 DBFOpen( const char * pszFilename, const char * pszAccess )
325 
326 {
327  SAHooks sHooks;
328 
329  SASetupDefaultHooks( &sHooks );
330 
331  return DBFOpenLL( pszFilename, pszAccess, &sHooks );
332 }
333 
334 /************************************************************************/
335 /* DBFOpen() */
336 /* */
337 /* Open a .dbf file. */
338 /************************************************************************/
339 
340 DBFHandle SHPAPI_CALL
341 DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
342 
343 {
344  DBFHandle psDBF;
345  unsigned char *pabyBuf;
346  int nFields, nHeadLen, iField, i;
347  char *pszBasename, *pszFullname;
348 
349 /* -------------------------------------------------------------------- */
350 /* We only allow the access strings "rb" and "r+". */
351 /* -------------------------------------------------------------------- */
352  if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
353  && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
354  && strcmp(pszAccess,"r+b") != 0 )
355  return( NULL );
356 
357  if( strcmp(pszAccess,"r") == 0 )
358  pszAccess = "rb";
359 
360  if( strcmp(pszAccess,"r+") == 0 )
361  pszAccess = "rb+";
362 
363 /* -------------------------------------------------------------------- */
364 /* Compute the base (layer) name. If there is any extension */
365 /* on the passed in filename we will strip it off. */
366 /* -------------------------------------------------------------------- */
367  pszBasename = (char *) malloc(strlen(pszFilename)+5);
368  strcpy( pszBasename, pszFilename );
369  for( i = strlen(pszBasename)-1;
370  i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
371  && pszBasename[i] != '\\';
372  i-- ) {}
373 
374  if( pszBasename[i] == '.' )
375  pszBasename[i] = '\0';
376 
377  pszFullname = (char *) malloc(strlen(pszBasename) + 5);
378  sprintf( pszFullname, "%s.dbf", pszBasename );
379 
380  psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
381  psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
382  memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
383 
384  if( psDBF->fp == NULL )
385  {
386  sprintf( pszFullname, "%s.DBF", pszBasename );
387  psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
388  }
389 
390  free( pszBasename );
391  free( pszFullname );
392 
393  if( psDBF->fp == NULL )
394  {
395  free( psDBF );
396  return( NULL );
397  }
398 
399  psDBF->bNoHeader = FALSE;
400  psDBF->nCurrentRecord = -1;
401  psDBF->bCurrentRecordModified = FALSE;
402 
403 /* -------------------------------------------------------------------- */
404 /* Read Table Header info */
405 /* -------------------------------------------------------------------- */
406  pabyBuf = (unsigned char *) malloc(500);
407  if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
408  {
409  psDBF->sHooks.FClose( psDBF->fp );
410  free( pabyBuf );
411  free( psDBF );
412  return NULL;
413  }
414 
415  psDBF->nRecords =
416  pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
417 
418  psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
419  psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
420 
421  psDBF->nFields = nFields = (nHeadLen - 32) / 32;
422 
423  psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
424 
425 /* -------------------------------------------------------------------- */
426 /* Read in Field Definitions */
427 /* -------------------------------------------------------------------- */
428 
429  pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
430  psDBF->pszHeader = (char *) pabyBuf;
431 
432  psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
433  if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
434  {
435  psDBF->sHooks.FClose( psDBF->fp );
436  free( pabyBuf );
437  free( psDBF->pszCurrentRecord );
438  free( psDBF );
439  return NULL;
440  }
441 
442  psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
443  psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
444  psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
445  psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
446 
447  for( iField = 0; iField < nFields; iField++ )
448  {
449  unsigned char *pabyFInfo;
450 
451  pabyFInfo = pabyBuf+iField*32;
452 
453  if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
454  {
455  psDBF->panFieldSize[iField] = pabyFInfo[16];
456  psDBF->panFieldDecimals[iField] = pabyFInfo[17];
457  }
458  else
459  {
460  psDBF->panFieldSize[iField] = pabyFInfo[16];
461  psDBF->panFieldDecimals[iField] = 0;
462 
463 /*
464 ** The following seemed to be used sometimes to handle files with long
465 ** string fields, but in other cases (such as bug 1202) the decimals field
466 ** just seems to indicate some sort of preferred formatting, not very
467 ** wide fields. So I have disabled this code. FrankW.
468  psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
469  psDBF->panFieldDecimals[iField] = 0;
470 */
471  }
472 
473  psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
474  if( iField == 0 )
475  psDBF->panFieldOffset[iField] = 1;
476  else
477  psDBF->panFieldOffset[iField] =
478  psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
479  }
480 
481  return( psDBF );
482 }
483 
484 /************************************************************************/
485 /* DBFClose() */
486 /************************************************************************/
487 
488 void SHPAPI_CALL
489 DBFClose(DBFHandle psDBF)
490 {
491 /* -------------------------------------------------------------------- */
492 /* Write out header if not already written. */
493 /* -------------------------------------------------------------------- */
494  if( psDBF->bNoHeader )
495  DBFWriteHeader( psDBF );
496 
497  DBFFlushRecord( psDBF );
498 
499 /* -------------------------------------------------------------------- */
500 /* Update last access date, and number of records if we have */
501 /* write access. */
502 /* -------------------------------------------------------------------- */
503  if( psDBF->bUpdated )
504  DBFUpdateHeader( psDBF );
505 
506 /* -------------------------------------------------------------------- */
507 /* Close, and free resources. */
508 /* -------------------------------------------------------------------- */
509  psDBF->sHooks.FClose( psDBF->fp );
510 
511  if( psDBF->panFieldOffset != NULL )
512  {
513  free( psDBF->panFieldOffset );
514  free( psDBF->panFieldSize );
515  free( psDBF->panFieldDecimals );
516  free( psDBF->pachFieldType );
517  }
518 
519  if( psDBF->pszWorkField != NULL )
520  free( psDBF->pszWorkField );
521 
522  free( psDBF->pszHeader );
523  free( psDBF->pszCurrentRecord );
524 
525  free( psDBF );
526 }
527 
528 /************************************************************************/
529 /* DBFCreate() */
530 /* */
531 /* Create a new .dbf file. */
532 /************************************************************************/
533 
534 DBFHandle SHPAPI_CALL
535 DBFCreate( const char * pszFilename )
536 
537 {
538  SAHooks sHooks;
539 
540  SASetupDefaultHooks( &sHooks );
541 
542  return DBFCreateLL( pszFilename, &sHooks );
543 }
544 
545 /************************************************************************/
546 /* DBFCreate() */
547 /* */
548 /* Create a new .dbf file. */
549 /************************************************************************/
550 
551 DBFHandle SHPAPI_CALL
552 DBFCreateLL( const char * pszFilename, SAHooks *psHooks )
553 
554 {
555  DBFHandle psDBF;
556  SAFile fp;
557  char *pszFullname, *pszBasename;
558  int i;
559  char chZero = '\0';
560 
561 /* -------------------------------------------------------------------- */
562 /* Compute the base (layer) name. If there is any extension */
563 /* on the passed in filename we will strip it off. */
564 /* -------------------------------------------------------------------- */
565  pszBasename = (char *) malloc(strlen(pszFilename)+5);
566  strcpy( pszBasename, pszFilename );
567  for( i = strlen(pszBasename)-1;
568  i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
569  && pszBasename[i] != '\\';
570  i-- ) {}
571 
572  if( pszBasename[i] == '.' )
573  pszBasename[i] = '\0';
574 
575  pszFullname = (char *) malloc(strlen(pszBasename) + 5);
576  sprintf( pszFullname, "%s.dbf", pszBasename );
577  free( pszBasename );
578 
579 /* -------------------------------------------------------------------- */
580 /* Create the file. */
581 /* -------------------------------------------------------------------- */
582  fp = psHooks->FOpen( pszFullname, "wb" );
583  if( fp == NULL )
584  return( NULL );
585 
586  psHooks->FWrite( &chZero, 1, 1, fp );
587  psHooks->FClose( fp );
588 
589  fp = psHooks->FOpen( pszFullname, "rb+" );
590  if( fp == NULL )
591  return( NULL );
592 
593  free( pszFullname );
594 
595 /* -------------------------------------------------------------------- */
596 /* Create the info structure. */
597 /* -------------------------------------------------------------------- */
598  psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo));
599 
600  memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
601  psDBF->fp = fp;
602  psDBF->nRecords = 0;
603  psDBF->nFields = 0;
604  psDBF->nRecordLength = 1;
605  psDBF->nHeaderLength = 33;
606 
607  psDBF->panFieldOffset = NULL;
608  psDBF->panFieldSize = NULL;
609  psDBF->panFieldDecimals = NULL;
610  psDBF->pachFieldType = NULL;
611  psDBF->pszHeader = NULL;
612 
613  psDBF->nCurrentRecord = -1;
614  psDBF->bCurrentRecordModified = FALSE;
615  psDBF->pszCurrentRecord = NULL;
616 
617  psDBF->bNoHeader = TRUE;
618 
619  return( psDBF );
620 }
621 
622 /************************************************************************/
623 /* DBFAddField() */
624 /* */
625 /* Add a field to a newly created .dbf file before any records */
626 /* are written. */
627 /************************************************************************/
628 
629 int SHPAPI_CALL
630 DBFAddField(DBFHandle psDBF, const char * pszFieldName,
631  DBFFieldType eType, int nWidth, int nDecimals )
632 
633 {
634  char chNativeType = 'C';
635 
636  if( eType == FTLogical )
637  chNativeType = 'L';
638  else if( eType == FTString )
639  chNativeType = 'C';
640  else
641  chNativeType = 'N';
642 
643  return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
644  nWidth, nDecimals );
645 }
646 
647 /************************************************************************/
648 /* DBFAddField() */
649 /* */
650 /* Add a field to a newly created .dbf file before any records */
651 /* are written. */
652 /************************************************************************/
653 
654 int SHPAPI_CALL
655 DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
656  char chType, int nWidth, int nDecimals )
657 
658 {
659  char *pszFInfo;
660  int i;
661 
662 /* -------------------------------------------------------------------- */
663 /* Do some checking to ensure we can add records to this file. */
664 /* -------------------------------------------------------------------- */
665  if( psDBF->nRecords > 0 )
666  return( -1 );
667 
668  if( !psDBF->bNoHeader )
669  return( -1 );
670 
671  if( nWidth < 1 )
672  return -1;
673 
674  if( nWidth > 255 )
675  nWidth = 255;
676 
677 /* -------------------------------------------------------------------- */
678 /* SfRealloc all the arrays larger to hold the additional field */
679 /* information. */
680 /* -------------------------------------------------------------------- */
681  psDBF->nFields++;
682 
683  psDBF->panFieldOffset = (int *)
684  SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
685 
686  psDBF->panFieldSize = (int *)
687  SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
688 
689  psDBF->panFieldDecimals = (int *)
690  SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
691 
692  psDBF->pachFieldType = (char *)
693  SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
694 
695 /* -------------------------------------------------------------------- */
696 /* Assign the new field information fields. */
697 /* -------------------------------------------------------------------- */
698  psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
699  psDBF->nRecordLength += nWidth;
700  psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
701  psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
702  psDBF->pachFieldType[psDBF->nFields-1] = chType;
703 
704 /* -------------------------------------------------------------------- */
705 /* Extend the required header information. */
706 /* -------------------------------------------------------------------- */
707  psDBF->nHeaderLength += 32;
708  psDBF->bUpdated = FALSE;
709 
710  psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
711 
712  pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
713 
714  for( i = 0; i < 32; i++ )
715  pszFInfo[i] = '\0';
716 
717  if( (int) strlen(pszFieldName) < 10 )
718  strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
719  else
720  strncpy( pszFInfo, pszFieldName, 10);
721 
722  pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
723 
724  if( chType == 'C' )
725  {
726  pszFInfo[16] = (unsigned char) (nWidth % 256);
727  pszFInfo[17] = (unsigned char) (nWidth / 256);
728  }
729  else
730  {
731  pszFInfo[16] = (unsigned char) nWidth;
732  pszFInfo[17] = (unsigned char) nDecimals;
733  }
734 
735 /* -------------------------------------------------------------------- */
736 /* Make the current record buffer appropriately larger. */
737 /* -------------------------------------------------------------------- */
738  psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
739  psDBF->nRecordLength);
740 
741  return( psDBF->nFields-1 );
742 }
743 
744 /************************************************************************/
745 /* DBFReadAttribute() */
746 /* */
747 /* Read one of the attribute fields of a record. */
748 /************************************************************************/
749 
750 static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
751  char chReqType )
752 
753 {
754  unsigned char *pabyRec;
755  void *pReturnField = NULL;
756 
757 /* -------------------------------------------------------------------- */
758 /* Verify selection. */
759 /* -------------------------------------------------------------------- */
760  if( hEntity < 0 || hEntity >= psDBF->nRecords )
761  return( NULL );
762 
763  if( iField < 0 || iField >= psDBF->nFields )
764  return( NULL );
765 
766 /* -------------------------------------------------------------------- */
767 /* Have we read the record? */
768 /* -------------------------------------------------------------------- */
769  if( !DBFLoadRecord( psDBF, hEntity ) )
770  return NULL;
771 
772  pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
773 
774 /* -------------------------------------------------------------------- */
775 /* Ensure we have room to extract the target field. */
776 /* -------------------------------------------------------------------- */
777  if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
778  {
779  psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
780  if( psDBF->pszWorkField == NULL )
781  psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength);
782  else
783  psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField,
784  psDBF->nWorkFieldLength);
785  }
786 
787 /* -------------------------------------------------------------------- */
788 /* Extract the requested field. */
789 /* -------------------------------------------------------------------- */
790  strncpy( psDBF->pszWorkField,
791  ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
792  psDBF->panFieldSize[iField] );
793  psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
794 
795  pReturnField = psDBF->pszWorkField;
796 
797 /* -------------------------------------------------------------------- */
798 /* Decode the field. */
799 /* -------------------------------------------------------------------- */
800  if( chReqType == 'N' )
801  {
802  psDBF->dfDoubleField = atof(psDBF->pszWorkField);
803 
804  pReturnField = &(psDBF->dfDoubleField);
805  }
806 
807 /* -------------------------------------------------------------------- */
808 /* Should we trim white space off the string attribute value? */
809 /* -------------------------------------------------------------------- */
810 #ifdef TRIM_DBF_WHITESPACE
811  else
812  {
813  char *pchSrc, *pchDst;
814 
815  pchDst = pchSrc = psDBF->pszWorkField;
816  while( *pchSrc == ' ' )
817  pchSrc++;
818 
819  while( *pchSrc != '\0' )
820  *(pchDst++) = *(pchSrc++);
821  *pchDst = '\0';
822 
823  while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
824  *pchDst = '\0';
825  }
826 #endif
827 
828  return( pReturnField );
829 }
830 
831 /************************************************************************/
832 /* DBFReadIntAttribute() */
833 /* */
834 /* Read an integer attribute. */
835 /************************************************************************/
836 
837 int SHPAPI_CALL
838 DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
839 
840 {
841  double *pdValue;
842 
843  pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
844 
845  if( pdValue == NULL )
846  return 0;
847  else
848  return( (int) *pdValue );
849 }
850 
851 /************************************************************************/
852 /* DBFReadDoubleAttribute() */
853 /* */
854 /* Read a double attribute. */
855 /************************************************************************/
856 
857 double SHPAPI_CALL
858 DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
859 
860 {
861  double *pdValue;
862 
863  pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
864 
865  if( pdValue == NULL )
866  return 0.0;
867  else
868  return( *pdValue );
869 }
870 
871 /************************************************************************/
872 /* DBFReadStringAttribute() */
873 /* */
874 /* Read a string attribute. */
875 /************************************************************************/
876 
877 const char SHPAPI_CALL1(*)
878 DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
879 
880 {
881  return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
882 }
883 
884 /************************************************************************/
885 /* DBFReadLogicalAttribute() */
886 /* */
887 /* Read a logical attribute. */
888 /************************************************************************/
889 
890 const char SHPAPI_CALL1(*)
891 DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
892 
893 {
894  return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
895 }
896 
897 /************************************************************************/
898 /* DBFIsAttributeNULL() */
899 /* */
900 /* Return TRUE if value for field is NULL. */
901 /* */
902 /* Contributed by Jim Matthews. */
903 /************************************************************************/
904 
905 int SHPAPI_CALL
906 DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
907 
908 {
909  const char *pszValue;
910  int i;
911 
912  pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
913 
914  if( pszValue == NULL )
915  return TRUE;
916 
917  switch(psDBF->pachFieldType[iField])
918  {
919  case 'N':
920  case 'F':
921  /*
922  ** We accept all asterisks or all blanks as NULL
923  ** though according to the spec I think it should be all
924  ** asterisks.
925  */
926  if( pszValue[0] == '*' )
927  return TRUE;
928 
929  for( i = 0; pszValue[i] != '\0'; i++ )
930  {
931  if( pszValue[i] != ' ' )
932  return FALSE;
933  }
934  return TRUE;
935 
936  case 'D':
937  /* NULL date fields have value "00000000" */
938  return strncmp(pszValue,"00000000",8) == 0;
939 
940  case 'L':
941  /* NULL boolean fields have value "?" */
942  return pszValue[0] == '?';
943 
944  default:
945  /* empty string fields are considered NULL */
946  return strlen(pszValue) == 0;
947  }
948 }
949 
950 /************************************************************************/
951 /* DBFGetFieldCount() */
952 /* */
953 /* Return the number of fields in this table. */
954 /************************************************************************/
955 
956 int SHPAPI_CALL
957 DBFGetFieldCount( DBFHandle psDBF )
958 
959 {
960  return( psDBF->nFields );
961 }
962 
963 /************************************************************************/
964 /* DBFGetRecordCount() */
965 /* */
966 /* Return the number of records in this table. */
967 /************************************************************************/
968 
969 int SHPAPI_CALL
970 DBFGetRecordCount( DBFHandle psDBF )
971 
972 {
973  return( psDBF->nRecords );
974 }
975 
976 /************************************************************************/
977 /* DBFGetFieldInfo() */
978 /* */
979 /* Return any requested information about the field. */
980 /************************************************************************/
981 
982 DBFFieldType SHPAPI_CALL
983 DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
984  int * pnWidth, int * pnDecimals )
985 
986 {
987  if( iField < 0 || iField >= psDBF->nFields )
988  return( FTInvalid );
989 
990  if( pnWidth != NULL )
991  *pnWidth = psDBF->panFieldSize[iField];
992 
993  if( pnDecimals != NULL )
994  *pnDecimals = psDBF->panFieldDecimals[iField];
995 
996  if( pszFieldName != NULL )
997  {
998  int i;
999 
1000  strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
1001  pszFieldName[11] = '\0';
1002  for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
1003  pszFieldName[i] = '\0';
1004  }
1005 
1006  if ( psDBF->pachFieldType[iField] == 'L' )
1007  return( FTLogical);
1008 
1009  else if( psDBF->pachFieldType[iField] == 'N'
1010  || psDBF->pachFieldType[iField] == 'F' )
1011  {
1012  if( psDBF->panFieldDecimals[iField] > 0 )
1013 /* || psDBF->panFieldSize[iField] > 10 ) */ /* GDAL bug #809 */
1014  return( FTDouble );
1015  else
1016  return( FTInteger );
1017  }
1018  else
1019  {
1020  return( FTString );
1021  }
1022 }
1023 
1024 /************************************************************************/
1025 /* DBFWriteAttribute() */
1026 /* */
1027 /* Write an attribute record to the file. */
1028 /************************************************************************/
1029 
1030 static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
1031  void * pValue )
1032 
1033 {
1034  int i, j, nRetResult = TRUE;
1035  unsigned char *pabyRec;
1036  char szSField[400], szFormat[20];
1037 
1038 /* -------------------------------------------------------------------- */
1039 /* Is this a valid record? */
1040 /* -------------------------------------------------------------------- */
1041  if( hEntity < 0 || hEntity > psDBF->nRecords )
1042  return( FALSE );
1043 
1044  if( psDBF->bNoHeader )
1045  DBFWriteHeader(psDBF);
1046 
1047 /* -------------------------------------------------------------------- */
1048 /* Is this a brand new record? */
1049 /* -------------------------------------------------------------------- */
1050  if( hEntity == psDBF->nRecords )
1051  {
1052  if( !DBFFlushRecord( psDBF ) )
1053  return FALSE;
1054 
1055  psDBF->nRecords++;
1056  for( i = 0; i < psDBF->nRecordLength; i++ )
1057  psDBF->pszCurrentRecord[i] = ' ';
1058 
1059  psDBF->nCurrentRecord = hEntity;
1060  }
1061 
1062 /* -------------------------------------------------------------------- */
1063 /* Is this an existing record, but different than the last one */
1064 /* we accessed? */
1065 /* -------------------------------------------------------------------- */
1066  if( !DBFLoadRecord( psDBF, hEntity ) )
1067  return FALSE;
1068 
1069  pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1070 
1071  psDBF->bCurrentRecordModified = TRUE;
1072  psDBF->bUpdated = TRUE;
1073 
1074 /* -------------------------------------------------------------------- */
1075 /* Translate NULL value to valid DBF file representation. */
1076 /* */
1077 /* Contributed by Jim Matthews. */
1078 /* -------------------------------------------------------------------- */
1079  if( pValue == NULL )
1080  {
1081  switch(psDBF->pachFieldType[iField])
1082  {
1083  case 'N':
1084  case 'F':
1085  /* NULL numeric fields have value "****************" */
1086  memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
1087  psDBF->panFieldSize[iField] );
1088  break;
1089 
1090  case 'D':
1091  /* NULL date fields have value "00000000" */
1092  memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
1093  psDBF->panFieldSize[iField] );
1094  break;
1095 
1096  case 'L':
1097  /* NULL boolean fields have value "?" */
1098  memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
1099  psDBF->panFieldSize[iField] );
1100  break;
1101 
1102  default:
1103  /* empty string fields are considered NULL */
1104  memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), ' ',
1105  psDBF->panFieldSize[iField] );
1106  break;
1107  }
1108  return TRUE;
1109  }
1110 
1111 /* -------------------------------------------------------------------- */
1112 /* Assign all the record fields. */
1113 /* -------------------------------------------------------------------- */
1114  switch( psDBF->pachFieldType[iField] )
1115  {
1116  case 'D':
1117  case 'N':
1118  case 'F':
1119  if( psDBF->panFieldDecimals[iField] == 0 )
1120  {
1121  int nWidth = psDBF->panFieldSize[iField];
1122 
1123  if( (int) sizeof(szSField)-2 < nWidth )
1124  nWidth = sizeof(szSField)-2;
1125 
1126  sprintf( szFormat, "%%%dd", nWidth );
1127  sprintf(szSField, szFormat, (int) *((double *) pValue) );
1128  if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
1129  {
1130  szSField[psDBF->panFieldSize[iField]] = '\0';
1131  nRetResult = FALSE;
1132  }
1133 
1134  strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1135  szSField, strlen(szSField) );
1136  }
1137  else
1138  {
1139  int nWidth = psDBF->panFieldSize[iField];
1140 
1141  if( (int) sizeof(szSField)-2 < nWidth )
1142  nWidth = sizeof(szSField)-2;
1143 
1144  sprintf( szFormat, "%%%d.%df",
1145  nWidth, psDBF->panFieldDecimals[iField] );
1146  sprintf(szSField, szFormat, *((double *) pValue) );
1147  if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
1148  {
1149  szSField[psDBF->panFieldSize[iField]] = '\0';
1150  nRetResult = FALSE;
1151  }
1152  strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1153  szSField, strlen(szSField) );
1154  }
1155  break;
1156 
1157  case 'L':
1158  if (psDBF->panFieldSize[iField] >= 1 &&
1159  (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
1160  *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
1161  break;
1162 
1163  default:
1164  if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1165  {
1166  j = psDBF->panFieldSize[iField];
1167  nRetResult = FALSE;
1168  }
1169  else
1170  {
1171  memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1172  psDBF->panFieldSize[iField] );
1173  j = strlen((char *) pValue);
1174  }
1175 
1176  strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1177  (char *) pValue, j );
1178  break;
1179  }
1180 
1181  return( nRetResult );
1182 }
1183 
1184 /************************************************************************/
1185 /* DBFWriteAttributeDirectly() */
1186 /* */
1187 /* Write an attribute record to the file, but without any */
1188 /* reformatting based on type. The provided buffer is written */
1189 /* as is to the field position in the record. */
1190 /************************************************************************/
1191 
1192 int SHPAPI_CALL
1193 DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1194  void * pValue )
1195 
1196 {
1197  int i, j;
1198  unsigned char *pabyRec;
1199 
1200 /* -------------------------------------------------------------------- */
1201 /* Is this a valid record? */
1202 /* -------------------------------------------------------------------- */
1203  if( hEntity < 0 || hEntity > psDBF->nRecords )
1204  return( FALSE );
1205 
1206  if( psDBF->bNoHeader )
1207  DBFWriteHeader(psDBF);
1208 
1209 /* -------------------------------------------------------------------- */
1210 /* Is this a brand new record? */
1211 /* -------------------------------------------------------------------- */
1212  if( hEntity == psDBF->nRecords )
1213  {
1214  if( !DBFFlushRecord( psDBF ) )
1215  return FALSE;
1216 
1217  psDBF->nRecords++;
1218  for( i = 0; i < psDBF->nRecordLength; i++ )
1219  psDBF->pszCurrentRecord[i] = ' ';
1220 
1221  psDBF->nCurrentRecord = hEntity;
1222  }
1223 
1224 /* -------------------------------------------------------------------- */
1225 /* Is this an existing record, but different than the last one */
1226 /* we accessed? */
1227 /* -------------------------------------------------------------------- */
1228  if( !DBFLoadRecord( psDBF, hEntity ) )
1229  return FALSE;
1230 
1231  pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1232 
1233 /* -------------------------------------------------------------------- */
1234 /* Assign all the record fields. */
1235 /* -------------------------------------------------------------------- */
1236  if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1237  j = psDBF->panFieldSize[iField];
1238  else
1239  {
1240  memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1241  psDBF->panFieldSize[iField] );
1242  j = strlen((char *) pValue);
1243  }
1244 
1245  strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1246  (char *) pValue, j );
1247 
1248  psDBF->bCurrentRecordModified = TRUE;
1249  psDBF->bUpdated = TRUE;
1250 
1251  return( TRUE );
1252 }
1253 
1254 /************************************************************************/
1255 /* DBFWriteDoubleAttribute() */
1256 /* */
1257 /* Write a double attribute. */
1258 /************************************************************************/
1259 
1260 int SHPAPI_CALL
1261 DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
1262  double dValue )
1263 
1264 {
1265  return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1266 }
1267 
1268 /************************************************************************/
1269 /* DBFWriteIntegerAttribute() */
1270 /* */
1271 /* Write a integer attribute. */
1272 /************************************************************************/
1273 
1274 int SHPAPI_CALL
1275 DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
1276  int nValue )
1277 
1278 {
1279  double dValue = nValue;
1280 
1281  return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1282 }
1283 
1284 /************************************************************************/
1285 /* DBFWriteStringAttribute() */
1286 /* */
1287 /* Write a string attribute. */
1288 /************************************************************************/
1289 
1290 int SHPAPI_CALL
1291 DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
1292  const char * pszValue )
1293 
1294 {
1295  return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
1296 }
1297 
1298 /************************************************************************/
1299 /* DBFWriteNULLAttribute() */
1300 /* */
1301 /* Write a string attribute. */
1302 /************************************************************************/
1303 
1304 int SHPAPI_CALL
1305 DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
1306 
1307 {
1308  return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
1309 }
1310 
1311 /************************************************************************/
1312 /* DBFWriteLogicalAttribute() */
1313 /* */
1314 /* Write a logical attribute. */
1315 /************************************************************************/
1316 
1317 int SHPAPI_CALL
1318 DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
1319  const char lValue)
1320 
1321 {
1322  return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
1323 }
1324 
1325 /************************************************************************/
1326 /* DBFWriteTuple() */
1327 /* */
1328 /* Write an attribute record to the file. */
1329 /************************************************************************/
1330 
1331 int SHPAPI_CALL
1332 DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
1333 
1334 {
1335  int i;
1336  unsigned char *pabyRec;
1337 
1338 /* -------------------------------------------------------------------- */
1339 /* Is this a valid record? */
1340 /* -------------------------------------------------------------------- */
1341  if( hEntity < 0 || hEntity > psDBF->nRecords )
1342  return( FALSE );
1343 
1344  if( psDBF->bNoHeader )
1345  DBFWriteHeader(psDBF);
1346 
1347 /* -------------------------------------------------------------------- */
1348 /* Is this a brand new record? */
1349 /* -------------------------------------------------------------------- */
1350  if( hEntity == psDBF->nRecords )
1351  {
1352  if( !DBFFlushRecord( psDBF ) )
1353  return FALSE;
1354 
1355  psDBF->nRecords++;
1356  for( i = 0; i < psDBF->nRecordLength; i++ )
1357  psDBF->pszCurrentRecord[i] = ' ';
1358 
1359  psDBF->nCurrentRecord = hEntity;
1360  }
1361 
1362 /* -------------------------------------------------------------------- */
1363 /* Is this an existing record, but different than the last one */
1364 /* we accessed? */
1365 /* -------------------------------------------------------------------- */
1366  if( !DBFLoadRecord( psDBF, hEntity ) )
1367  return FALSE;
1368 
1369  pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1370 
1371  memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
1372 
1373  psDBF->bCurrentRecordModified = TRUE;
1374  psDBF->bUpdated = TRUE;
1375 
1376  return( TRUE );
1377 }
1378 
1379 /************************************************************************/
1380 /* DBFReadTuple() */
1381 /* */
1382 /* Read a complete record. Note that the result is only valid */
1383 /* till the next record read for any reason. */
1384 /************************************************************************/
1385 
1386 const char SHPAPI_CALL1(*)
1387 DBFReadTuple(DBFHandle psDBF, int hEntity )
1388 
1389 {
1390  if( hEntity < 0 || hEntity >= psDBF->nRecords )
1391  return( NULL );
1392 
1393  if( !DBFLoadRecord( psDBF, hEntity ) )
1394  return NULL;
1395 
1396  return (const char *) psDBF->pszCurrentRecord;
1397 }
1398 
1399 /************************************************************************/
1400 /* DBFCloneEmpty() */
1401 /* */
1402 /* Read one of the attribute fields of a record. */
1403 /************************************************************************/
1404 
1405 DBFHandle SHPAPI_CALL
1406 DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
1407 {
1408  DBFHandle newDBF;
1409 
1410  newDBF = DBFCreate ( pszFilename );
1411  if ( newDBF == NULL ) return ( NULL );
1412 
1413  newDBF->nFields = psDBF->nFields;
1414  newDBF->nRecordLength = psDBF->nRecordLength;
1415  newDBF->nHeaderLength = psDBF->nHeaderLength;
1416 
1417  newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength );
1418  memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength );
1419 
1420  newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
1421  memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1422  newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
1423  memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1424  newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
1425  memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1426  newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields );
1427  memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
1428 
1429  newDBF->bNoHeader = TRUE;
1430  newDBF->bUpdated = TRUE;
1431 
1432  DBFWriteHeader ( newDBF );
1433  DBFClose ( newDBF );
1434 
1435  newDBF = DBFOpen ( pszFilename, "rb+" );
1436 
1437  return ( newDBF );
1438 }
1439 
1440 /************************************************************************/
1441 /* DBFGetNativeFieldType() */
1442 /* */
1443 /* Return the DBase field type for the specified field. */
1444 /* */
1445 /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
1446 /* 'N' (Numeric, with or without decimal), */
1447 /* 'L' (Logical), */
1448 /* 'M' (Memo: 10 digits .DBT block ptr) */
1449 /************************************************************************/
1450 
1451 char SHPAPI_CALL
1452 DBFGetNativeFieldType( DBFHandle psDBF, int iField )
1453 
1454 {
1455  if( iField >=0 && iField < psDBF->nFields )
1456  return psDBF->pachFieldType[iField];
1457 
1458  return ' ';
1459 }
1460 
1461 /************************************************************************/
1462 /* str_to_upper() */
1463 /************************************************************************/
1464 
1465 static void str_to_upper (char *string)
1466 {
1467  int len;
1468  short i = -1;
1469 
1470  len = strlen (string);
1471 
1472  while (++i < len)
1473  if (isalpha(string[i]) && islower(string[i]))
1474  string[i] = (char) toupper ((int)string[i]);
1475 }
1476 
1477 /************************************************************************/
1478 /* DBFGetFieldIndex() */
1479 /* */
1480 /* Get the index number for a field in a .dbf file. */
1481 /* */
1482 /* Contributed by Jim Matthews. */
1483 /************************************************************************/
1484 
1485 int SHPAPI_CALL
1486 DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
1487 
1488 {
1489  char name[12], name1[12], name2[12];
1490  int i;
1491 
1492  strncpy(name1, pszFieldName,11);
1493  name1[11] = '\0';
1494  str_to_upper(name1);
1495 
1496  for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
1497  {
1498  DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
1499  strncpy(name2,name,11);
1500  str_to_upper(name2);
1501 
1502  if(!strncmp(name1,name2,10))
1503  return(i);
1504  }
1505  return(-1);
1506 }
1507 
1508 /************************************************************************/
1509 /* DBFIsRecordDeleted() */
1510 /* */
1511 /* Returns TRUE if the indicated record is deleted, otherwise */
1512 /* it returns FALSE. */
1513 /************************************************************************/
1514 
1515 int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
1516 
1517 {
1518 /* -------------------------------------------------------------------- */
1519 /* Verify selection. */
1520 /* -------------------------------------------------------------------- */
1521  if( iShape < 0 || iShape >= psDBF->nRecords )
1522  return TRUE;
1523 
1524 /* -------------------------------------------------------------------- */
1525 /* Have we read the record? */
1526 /* -------------------------------------------------------------------- */
1527  if( !DBFLoadRecord( psDBF, iShape ) )
1528  return FALSE;
1529 
1530 /* -------------------------------------------------------------------- */
1531 /* '*' means deleted. */
1532 /* -------------------------------------------------------------------- */
1533  return psDBF->pszCurrentRecord[0] == '*';
1534 }
1535 
1536 /************************************************************************/
1537 /* DBFMarkRecordDeleted() */
1538 /************************************************************************/
1539 
1540 int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
1541  int bIsDeleted )
1542 
1543 {
1544  char chNewFlag;
1545 
1546 /* -------------------------------------------------------------------- */
1547 /* Verify selection. */
1548 /* -------------------------------------------------------------------- */
1549  if( iShape < 0 || iShape >= psDBF->nRecords )
1550  return FALSE;
1551 
1552 /* -------------------------------------------------------------------- */
1553 /* Is this an existing record, but different than the last one */
1554 /* we accessed? */
1555 /* -------------------------------------------------------------------- */
1556  if( !DBFLoadRecord( psDBF, iShape ) )
1557  return FALSE;
1558 
1559 /* -------------------------------------------------------------------- */
1560 /* Assign value, marking record as dirty if it changes. */
1561 /* -------------------------------------------------------------------- */
1562  if( bIsDeleted )
1563  chNewFlag = '*';
1564  else
1565  chNewFlag = ' ';
1566 
1567  if( psDBF->pszCurrentRecord[0] != chNewFlag )
1568  {
1569  psDBF->bCurrentRecordModified = TRUE;
1570  psDBF->bUpdated = TRUE;
1571  psDBF->pszCurrentRecord[0] = chNewFlag;
1572  }
1573 
1574  return TRUE;
1575 }
#define SHPAPI_CALL
Definition: shapefil.h:170
int SHPAPI_CALL DBFAddNativeFieldType(DBFHandle psDBF, const char *pszFieldName, char chType, int nWidth, int nDecimals)
Definition: dbfopen.c:655
int SHPAPI_CALL DBFWriteIntegerAttribute(DBFHandle psDBF, int iRecord, int iField, int nValue)
Definition: dbfopen.c:1275
double SHPAPI_CALL DBFReadDoubleAttribute(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:858
sprintf(buf2,"%s", G3D_CATS_ELEMENT)
const char SHPAPI_CALL1 * DBFReadLogicalAttribute(DBFHandle psDBF, int iRecord, int iField){return((const char *) DBFReadAttribute(psDBF, iRecord, iField, 'L')
void SHPAPI_CALL DBFClose(DBFHandle psDBF)
Definition: dbfopen.c:489
int SHPAPI_CALL DBFMarkRecordDeleted(DBFHandle psDBF, int iShape, int bIsDeleted)
Definition: dbfopen.c:1540
#define FALSE
Definition: dbfopen.c:117
void SHPAPI_CALL DBFUpdateHeader(DBFHandle psDBF)
Definition: dbfopen.c:293
string name
Definition: render.py:1314
DBFHandle SHPAPI_CALL DBFCreateLL(const char *pszFilename, SAHooks *psHooks)
Definition: dbfopen.c:552
int SHPAPI_CALL DBFGetFieldCount(DBFHandle psDBF)
Definition: dbfopen.c:957
SAFile(* FOpen)(const char *filename, const char *path)
Definition: shapefil.h:199
DBFHandle SHPAPI_CALL DBFCloneEmpty(DBFHandle psDBF, const char *pszFilename)
char SHPAPI_CALL DBFGetNativeFieldType(DBFHandle psDBF, int iField)
Definition: dbfopen.c:1452
unsigned long SAOffset
Definition: shapefil.h:195
const char SHPAPI_CALL1 * DBFReadStringAttribute(DBFHandle psDBF, int iRecord, int iField){return((const char *) DBFReadAttribute(psDBF, iRecord, iField, 'C')
int SHPAPI_CALL DBFAddField(DBFHandle psDBF, const char *pszFieldName, DBFFieldType eType, int nWidth, int nDecimals)
Definition: dbfopen.c:630
int * SAFile
Definition: shapefil.h:192
int(* FClose)(SAFile file)
Definition: shapefil.h:205
int SHPAPI_CALL DBFWriteLogicalAttribute(DBFHandle psDBF, int iRecord, int iField, const char lValue)
Definition: dbfopen.c:1318
int SHPAPI_CALL DBFGetRecordCount(DBFHandle psDBF)
Definition: dbfopen.c:970
#define SHPAPI_CALL1(x)
Definition: shapefil.h:175
DBFFieldType SHPAPI_CALL DBFGetFieldInfo(DBFHandle psDBF, int iField, char *pszFieldName, int *pnWidth, int *pnDecimals)
Definition: dbfopen.c:983
int SHPAPI_CALL DBFWriteDoubleAttribute(DBFHandle psDBF, int iRecord, int iField, double dValue)
Definition: dbfopen.c:1261
int SHPAPI_CALL DBFWriteStringAttribute(DBFHandle psDBF, int iRecord, int iField, const char *pszValue)
Definition: dbfopen.c:1291
int SHPAPI_CALL DBFIsAttributeNULL(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:906
DBFHandle SHPAPI_CALL DBFOpen(const char *pszFilename, const char *pszAccess)
Definition: dbfopen.c:324
SAOffset(* FWrite)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
Definition: shapefil.h:201
int SHPAPI_CALL DBFIsRecordDeleted(DBFHandle psDBF, int iShape)
Definition: dbfopen.c:1515
int SHPAPI_CALL DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
Definition: dbfopen.c:1486
SHP_CVSID("$Id: safileio.c,v 1.4 2008/01/16 20:05:14 bram Exp $")
void SASetupDefaultHooks(SAHooks *psHooks)
Definition: safileio.c:175
void * malloc(YYSIZE_T)
#define TRUE
Definition: dbfopen.c:118
DBFHandle SHPAPI_CALL DBFCreate(const char *pszFilename)
Definition: dbfopen.c:535
DBFHandle SHPAPI_CALL DBFOpenLL(const char *pszFilename, const char *pszAccess, SAHooks *psHooks)
Definition: dbfopen.c:341
int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, void *pRawTuple)
Definition: dbfopen.c:1332
const char SHPAPI_CALL1 * DBFReadTuple(DBFHandle psDBF, int hEntity){return(NULL
return NULL
Definition: dbfopen.c:1394
#define XBASE_FLDHDR_SZ
void free(void *)
int SHPAPI_CALL DBFReadIntegerAttribute(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:838
int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, void *pValue)
Definition: dbfopen.c:1193
int SHPAPI_CALL DBFWriteNULLAttribute(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:1305