/[thuban]/branches/WIP-pyshapelib-bramz/libraries/shapelib/dbfopen.c
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/libraries/shapelib/dbfopen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2703 - (show annotations)
Sun Sep 24 18:51:39 2006 UTC (18 years, 5 months ago) by bernhard
Original Path: trunk/thuban/libraries/shapelib/dbfopen.c
File MIME type: text/plain
File size: 56180 byte(s)
Introduced a pointer atof_function which is called by DBFReadAttribute() now.
Default value is &atof, but DBFSetatof_function() can now be used
to change this during runtime.

1 /******************************************************************************
2 * $Id$
3 *
4 * Project: Shapelib
5 * Purpose: Implementation of .dbf access API documented in dbf_api.html.
6 * Author: Frank Warmerdam, [email protected]
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$
37 * Revision 1.3 2004/05/17 15:47:57 bh
38 * Update to newest shapelib and get rid of Thuban specific extensions,
39 * i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge
40 *
41 * * libraries/shapelib/shpopen.c: Update to version from current
42 * shapelib CVS.
43 *
44 * * libraries/shapelib/shapefil.h: Update to version from current
45 * shapelib CVS.
46 *
47 * * libraries/shapelib/dbfopen.c: Update to version from current
48 * shapelib CVS.
49 * (DBFCommit): Effectively removed since shapelib itself has
50 * DBFUpdateHeader now which is better for what DBFCommit wanted to
51 * achieve.
52 * We're now using an unmodified version of dbfopen.
53 *
54 * * libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
55 * Update from dbflib.i
56 *
57 * * libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
58 * the commit method. This new indirection is necessary because we use the
59 * DBFUpdateHeader function now which is not available in shapelib <=
60 * 1.2.10
61 * (DBFFile::commit): Use DBFInfo_commit as implementation
62 * (pragma __class__): New. Kludge to remove the commit method when
63 * the DBFUpdateHeader function isn't available
64 * (_have_commit): New. Helper for the pragma kludge.
65 *
66 * * libraries/pyshapelib/setup.py (dbf_macros): New. Return the
67 * preprocessor macros needed to compile the dbflib wrapper. Determine
68 * whether DBFUpdateHeader is available and define the right value of
69 * HAVE_UPDATE_HEADER
70 * (extensions): Use dbf_macros for the dbflibc extension
71 *
72 * * setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
73 * value '1' to the Lib.dbflibc extension. This simply reflects the
74 * shapelib and pyshapelib updates
75 *
76 * Revision 1.53 2003/12/29 00:00:30 fwarmerdam
77 * mark DBFWriteAttributeDirectly as SHPAPI_CALL
78 *
79 * Revision 1.52 2003/07/08 15:20:03 warmerda
80 * avoid warnings about downcasting to unsigned char
81 *
82 * Revision 1.51 2003/07/08 13:50:15 warmerda
83 * DBFIsAttributeNULL check for pszValue==NULL - bug 360
84 *
85 * Revision 1.50 2003/04/21 18:58:25 warmerda
86 * ensure current record is flushed at same time as header is updated
87 *
88 * Revision 1.49 2003/04/21 18:30:37 warmerda
89 * added header write/update public methods
90 *
91 * Revision 1.48 2003/03/10 14:51:27 warmerda
92 * DBFWrite* calls now return FALSE if they have to truncate
93 *
94 * Revision 1.47 2002/11/20 03:32:22 warmerda
95 * Ensure field name in DBFGetFieldIndex() is properly terminated.
96 *
97 * Revision 1.46 2002/10/09 13:10:21 warmerda
98 * Added check that width is positive.
99 *
100 * Revision 1.45 2002/09/29 00:00:08 warmerda
101 * added FTLogical and logical attribute read/write calls
102 *
103 * Revision 1.44 2002/05/07 13:46:11 warmerda
104 * Added DBFWriteAttributeDirectly().
105 *
106 * Revision 1.43 2002/02/13 19:39:21 warmerda
107 * Fix casting issues in DBFCloneEmpty().
108 *
109 * Revision 1.42 2002/01/15 14:36:07 warmerda
110 * updated email address
111 *
112 * Revision 1.41 2002/01/15 14:31:49 warmerda
113 * compute rather than copying nHeaderLength in DBFCloneEmpty()
114 *
115 * Revision 1.40 2002/01/09 04:32:35 warmerda
116 * fixed to read correct amount of header
117 *
118 * Revision 1.39 2001/12/11 22:41:03 warmerda
119 * improve io related error checking when reading header
120 *
121 * Revision 1.38 2001/11/28 16:07:31 warmerda
122 * Cleanup to avoid compiler warnings as suggested by Richard Hash.
123 *
124 * Revision 1.37 2001/07/04 05:18:09 warmerda
125 * do last fix properly
126 *
127 * Revision 1.36 2001/07/04 05:16:09 warmerda
128 * fixed fieldname comparison in DBFGetFieldIndex
129 *
130 * Revision 1.35 2001/06/22 02:10:06 warmerda
131 * fixed NULL shape support with help from Jim Matthews
132 *
133 * Revision 1.33 2001/05/31 19:20:13 warmerda
134 * added DBFGetFieldIndex()
135 *
136 * Revision 1.32 2001/05/31 18:15:40 warmerda
137 * Added support for NULL fields in DBF files
138 *
139 * Revision 1.31 2001/05/23 13:36:52 warmerda
140 * added use of SHPAPI_CALL
141 *
142 * Revision 1.30 2000/12/05 14:43:38 warmerda
143 * DBReadAttribute() white space trimming bug fix
144 *
145 * Revision 1.29 2000/10/05 14:36:44 warmerda
146 * fix bug with writing very wide numeric fields
147 *
148 * Revision 1.28 2000/09/25 14:18:07 warmerda
149 * Added some casts of strlen() return result to fix warnings on some
150 * systems, as submitted by Daniel.
151 *
152 * Revision 1.27 2000/09/25 14:15:51 warmerda
153 * added DBFGetNativeFieldType()
154 *
155 * Revision 1.26 2000/07/07 13:39:45 warmerda
156 * removed unused variables, and added system include files
157 *
158 * Revision 1.25 2000/05/29 18:19:13 warmerda
159 * avoid use of uchar, and adding casting fix
160 *
161 * Revision 1.24 2000/05/23 13:38:27 warmerda
162 * Added error checks on return results of fread() and fseek().
163 *
164 * Revision 1.23 2000/05/23 13:25:49 warmerda
165 * Avoid crashing if field or record are out of range in dbfread*attribute().
166 *
167 * Revision 1.22 1999/12/15 13:47:24 warmerda
168 * Added stdlib.h to ensure that atof() is prototyped.
169 *
170 * Revision 1.21 1999/12/13 17:25:46 warmerda
171 * Added support for upper case .DBF extention.
172 *
173 * Revision 1.20 1999/11/30 16:32:11 warmerda
174 * Use atof() instead of sscanf().
175 *
176 * Revision 1.19 1999/11/05 14:12:04 warmerda
177 * updated license terms
178 *
179 * Revision 1.18 1999/07/27 00:53:28 warmerda
180 * ensure that whole old field value clear on write of string
181 *
182 * Revision 1.1 1999/07/05 18:58:07 warmerda
183 * New
184 *
185 * Revision 1.17 1999/06/11 19:14:12 warmerda
186 * Fixed some memory leaks.
187 *
188 * Revision 1.16 1999/06/11 19:04:11 warmerda
189 * Remoted some unused variables.
190 *
191 * Revision 1.15 1999/05/11 03:19:28 warmerda
192 * added new Tuple api, and improved extension handling - add from candrsn
193 *
194 * Revision 1.14 1999/05/04 15:01:48 warmerda
195 * Added 'F' support.
196 *
197 * Revision 1.13 1999/03/23 17:38:59 warmerda
198 * DBFAddField() now actually does return the new field number, or -1 if
199 * it fails.
200 *
201 * Revision 1.12 1999/03/06 02:54:46 warmerda
202 * Added logic to convert shapefile name to dbf filename in DBFOpen()
203 * for convenience.
204 *
205 * Revision 1.11 1998/12/31 15:30:34 warmerda
206 * Improved the interchangability of numeric and string attributes. Add
207 * white space trimming option for attributes.
208 *
209 * Revision 1.10 1998/12/03 16:36:44 warmerda
210 * Use r+b instead of rb+ for binary access.
211 *
212 * Revision 1.9 1998/12/03 15:34:23 warmerda
213 * Updated copyright message.
214 *
215 * Revision 1.8 1997/12/04 15:40:15 warmerda
216 * Added newline character after field definitions.
217 *
218 * Revision 1.7 1997/03/06 14:02:10 warmerda
219 * Ensure bUpdated is initialized.
220 *
221 * Revision 1.6 1996/02/12 04:54:41 warmerda
222 * Ensure that DBFWriteAttribute() returns TRUE if it succeeds.
223 *
224 * Revision 1.5 1995/10/21 03:15:12 warmerda
225 * Changed to use binary file access, and ensure that the
226 * field name field is zero filled, and limited to 10 chars.
227 *
228 * Revision 1.4 1995/08/24 18:10:42 warmerda
229 * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such
230 * as on the Sun.
231 *
232 * Revision 1.3 1995/08/04 03:15:16 warmerda
233 * Fixed up header.
234 *
235 * Revision 1.2 1995/08/04 03:14:43 warmerda
236 * Added header.
237 */
238
239 static char rcsid[] =
240 "$Id$";
241
242 #include "shapefil.h"
243
244 #include <math.h>
245 #include <stdlib.h>
246 #include <ctype.h>
247 #include <string.h>
248
249 #ifndef FALSE
250 # define FALSE 0
251 # define TRUE 1
252 #endif
253
254 static int nStringFieldLen = 0;
255 static char * pszStringField = NULL;
256
257 /************************************************************************/
258 /* DBFSet_atof_function() */
259 /* */
260 /* This makes it possible to initialise a different atof() function */
261 /* which might be necessary because the standard atof() might be */
262 /* sensitive to locale settings. */
263 /* */
264 /* If the calling application uses a locale with different decimal_point*/
265 /* it should better also give us a locale agnostic atof() function. */
266 /* */
267 /* As far as I can see from Python PEP331 and GNU libc documentation */
268 /* there is no standard for such a function yet. */
269 /* */
270 /* [email protected] 20060924 */
271 /************************************************************************/
272
273 static double (* atof_function)(const char *nptr) = &atof;
274
275 void SHPAPI_CALL
276 DBFSetatof_function( double (* new_atof_function)(const char *nptr))
277 {
278 atof_function = new_atof_function;
279 }
280
281 /************************************************************************/
282 /* SfRealloc() */
283 /* */
284 /* A realloc cover function that will access a NULL pointer as */
285 /* a valid input. */
286 /************************************************************************/
287
288 static void * SfRealloc( void * pMem, int nNewSize )
289
290 {
291 if( pMem == NULL )
292 return( (void *) malloc(nNewSize) );
293 else
294 return( (void *) realloc(pMem,nNewSize) );
295 }
296
297 /************************************************************************/
298 /* DBFWriteHeader() */
299 /* */
300 /* This is called to write out the file header, and field */
301 /* descriptions before writing any actual data records. This */
302 /* also computes all the DBFDataSet field offset/size/decimals */
303 /* and so forth values. */
304 /************************************************************************/
305
306 static void DBFWriteHeader(DBFHandle psDBF)
307
308 {
309 unsigned char abyHeader[XBASE_FLDHDR_SZ];
310 int i;
311
312 if( !psDBF->bNoHeader )
313 return;
314
315 psDBF->bNoHeader = FALSE;
316
317 /* -------------------------------------------------------------------- */
318 /* Initialize the file header information. */
319 /* -------------------------------------------------------------------- */
320 for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
321 abyHeader[i] = 0;
322
323 abyHeader[0] = 0x03; /* memo field? - just copying */
324
325 /* write out a dummy date */
326 abyHeader[1] = 95; /* YY */
327 abyHeader[2] = 7; /* MM */
328 abyHeader[3] = 26; /* DD */
329
330 /* record count preset at zero */
331
332 abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
333 abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
334
335 abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
336 abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
337
338 /* -------------------------------------------------------------------- */
339 /* Write the initial 32 byte file header, and all the field */
340 /* descriptions. */
341 /* -------------------------------------------------------------------- */
342 fseek( psDBF->fp, 0, 0 );
343 fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
344 fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );
345
346 /* -------------------------------------------------------------------- */
347 /* Write out the newline character if there is room for it. */
348 /* -------------------------------------------------------------------- */
349 if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
350 {
351 char cNewline;
352
353 cNewline = 0x0d;
354 fwrite( &cNewline, 1, 1, psDBF->fp );
355 }
356 }
357
358 /************************************************************************/
359 /* DBFFlushRecord() */
360 /* */
361 /* Write out the current record if there is one. */
362 /************************************************************************/
363
364 static void DBFFlushRecord( DBFHandle psDBF )
365
366 {
367 int nRecordOffset;
368
369 if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
370 {
371 psDBF->bCurrentRecordModified = FALSE;
372
373 nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord
374 + psDBF->nHeaderLength;
375
376 fseek( psDBF->fp, nRecordOffset, 0 );
377 fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
378 }
379 }
380
381 /************************************************************************/
382 /* DBFUpdateHeader() */
383 /************************************************************************/
384
385 void SHPAPI_CALL
386 DBFUpdateHeader( DBFHandle psDBF )
387
388 {
389 unsigned char abyFileHeader[32];
390
391 if( psDBF->bNoHeader )
392 DBFWriteHeader( psDBF );
393
394 DBFFlushRecord( psDBF );
395
396 fseek( psDBF->fp, 0, 0 );
397 fread( abyFileHeader, 32, 1, psDBF->fp );
398
399 abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
400 abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
401 abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
402 abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
403
404 fseek( psDBF->fp, 0, 0 );
405 fwrite( abyFileHeader, 32, 1, psDBF->fp );
406
407 fflush( psDBF->fp );
408 }
409
410 /************************************************************************/
411 /* DBFOpen() */
412 /* */
413 /* Open a .dbf file. */
414 /************************************************************************/
415
416 DBFHandle SHPAPI_CALL
417 DBFOpen( const char * pszFilename, const char * pszAccess )
418
419 {
420 DBFHandle psDBF;
421 unsigned char *pabyBuf;
422 int nFields, nHeadLen, nRecLen, iField, i;
423 char *pszBasename, *pszFullname;
424
425 /* -------------------------------------------------------------------- */
426 /* We only allow the access strings "rb" and "r+". */
427 /* -------------------------------------------------------------------- */
428 if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
429 && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
430 && strcmp(pszAccess,"r+b") != 0 )
431 return( NULL );
432
433 if( strcmp(pszAccess,"r") == 0 )
434 pszAccess = "rb";
435
436 if( strcmp(pszAccess,"r+") == 0 )
437 pszAccess = "rb+";
438
439 /* -------------------------------------------------------------------- */
440 /* Compute the base (layer) name. If there is any extension */
441 /* on the passed in filename we will strip it off. */
442 /* -------------------------------------------------------------------- */
443 pszBasename = (char *) malloc(strlen(pszFilename)+5);
444 strcpy( pszBasename, pszFilename );
445 for( i = strlen(pszBasename)-1;
446 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
447 && pszBasename[i] != '\\';
448 i-- ) {}
449
450 if( pszBasename[i] == '.' )
451 pszBasename[i] = '\0';
452
453 pszFullname = (char *) malloc(strlen(pszBasename) + 5);
454 sprintf( pszFullname, "%s.dbf", pszBasename );
455
456 psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
457 psDBF->fp = fopen( pszFullname, pszAccess );
458
459 if( psDBF->fp == NULL )
460 {
461 sprintf( pszFullname, "%s.DBF", pszBasename );
462 psDBF->fp = fopen(pszFullname, pszAccess );
463 }
464
465 free( pszBasename );
466 free( pszFullname );
467
468 if( psDBF->fp == NULL )
469 {
470 free( psDBF );
471 return( NULL );
472 }
473
474 psDBF->bNoHeader = FALSE;
475 psDBF->nCurrentRecord = -1;
476 psDBF->bCurrentRecordModified = FALSE;
477
478 /* -------------------------------------------------------------------- */
479 /* Read Table Header info */
480 /* -------------------------------------------------------------------- */
481 pabyBuf = (unsigned char *) malloc(500);
482 if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
483 {
484 fclose( psDBF->fp );
485 free( pabyBuf );
486 free( psDBF );
487 return NULL;
488 }
489
490 psDBF->nRecords =
491 pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
492
493 psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
494 psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;
495
496 psDBF->nFields = nFields = (nHeadLen - 32) / 32;
497
498 psDBF->pszCurrentRecord = (char *) malloc(nRecLen);
499
500 /* -------------------------------------------------------------------- */
501 /* Read in Field Definitions */
502 /* -------------------------------------------------------------------- */
503
504 pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
505 psDBF->pszHeader = (char *) pabyBuf;
506
507 fseek( psDBF->fp, 32, 0 );
508 if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
509 {
510 fclose( psDBF->fp );
511 free( pabyBuf );
512 free( psDBF );
513 return NULL;
514 }
515
516 psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
517 psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
518 psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
519 psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
520
521 for( iField = 0; iField < nFields; iField++ )
522 {
523 unsigned char *pabyFInfo;
524
525 pabyFInfo = pabyBuf+iField*32;
526
527 if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
528 {
529 psDBF->panFieldSize[iField] = pabyFInfo[16];
530 psDBF->panFieldDecimals[iField] = pabyFInfo[17];
531 }
532 else
533 {
534 psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
535 psDBF->panFieldDecimals[iField] = 0;
536 }
537
538 psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
539 if( iField == 0 )
540 psDBF->panFieldOffset[iField] = 1;
541 else
542 psDBF->panFieldOffset[iField] =
543 psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
544 }
545
546 return( psDBF );
547 }
548
549 /************************************************************************/
550 /* DBFClose() */
551 /************************************************************************/
552
553 void SHPAPI_CALL
554 DBFClose(DBFHandle psDBF)
555 {
556 /* -------------------------------------------------------------------- */
557 /* Write out header if not already written. */
558 /* -------------------------------------------------------------------- */
559 if( psDBF->bNoHeader )
560 DBFWriteHeader( psDBF );
561
562 DBFFlushRecord( psDBF );
563
564 /* -------------------------------------------------------------------- */
565 /* Update last access date, and number of records if we have */
566 /* write access. */
567 /* -------------------------------------------------------------------- */
568 if( psDBF->bUpdated )
569 DBFUpdateHeader( psDBF );
570
571 /* -------------------------------------------------------------------- */
572 /* Close, and free resources. */
573 /* -------------------------------------------------------------------- */
574 fclose( psDBF->fp );
575
576 if( psDBF->panFieldOffset != NULL )
577 {
578 free( psDBF->panFieldOffset );
579 free( psDBF->panFieldSize );
580 free( psDBF->panFieldDecimals );
581 free( psDBF->pachFieldType );
582 }
583
584 free( psDBF->pszHeader );
585 free( psDBF->pszCurrentRecord );
586
587 free( psDBF );
588
589 if( pszStringField != NULL )
590 {
591 free( pszStringField );
592 pszStringField = NULL;
593 nStringFieldLen = 0;
594 }
595 }
596
597 /************************************************************************/
598 /* DBFCreate() */
599 /* */
600 /* Create a new .dbf file. */
601 /************************************************************************/
602
603 DBFHandle SHPAPI_CALL
604 DBFCreate( const char * pszFilename )
605
606 {
607 DBFHandle psDBF;
608 FILE *fp;
609 char *pszFullname, *pszBasename;
610 int i;
611
612 /* -------------------------------------------------------------------- */
613 /* Compute the base (layer) name. If there is any extension */
614 /* on the passed in filename we will strip it off. */
615 /* -------------------------------------------------------------------- */
616 pszBasename = (char *) malloc(strlen(pszFilename)+5);
617 strcpy( pszBasename, pszFilename );
618 for( i = strlen(pszBasename)-1;
619 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
620 && pszBasename[i] != '\\';
621 i-- ) {}
622
623 if( pszBasename[i] == '.' )
624 pszBasename[i] = '\0';
625
626 pszFullname = (char *) malloc(strlen(pszBasename) + 5);
627 sprintf( pszFullname, "%s.dbf", pszBasename );
628 free( pszBasename );
629
630 /* -------------------------------------------------------------------- */
631 /* Create the file. */
632 /* -------------------------------------------------------------------- */
633 fp = fopen( pszFullname, "wb" );
634 if( fp == NULL )
635 return( NULL );
636
637 fputc( 0, fp );
638 fclose( fp );
639
640 fp = fopen( pszFullname, "rb+" );
641 if( fp == NULL )
642 return( NULL );
643
644 free( pszFullname );
645
646 /* -------------------------------------------------------------------- */
647 /* Create the info structure. */
648 /* -------------------------------------------------------------------- */
649 psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
650
651 psDBF->fp = fp;
652 psDBF->nRecords = 0;
653 psDBF->nFields = 0;
654 psDBF->nRecordLength = 1;
655 psDBF->nHeaderLength = 33;
656
657 psDBF->panFieldOffset = NULL;
658 psDBF->panFieldSize = NULL;
659 psDBF->panFieldDecimals = NULL;
660 psDBF->pachFieldType = NULL;
661 psDBF->pszHeader = NULL;
662
663 psDBF->nCurrentRecord = -1;
664 psDBF->bCurrentRecordModified = FALSE;
665 psDBF->pszCurrentRecord = NULL;
666
667 psDBF->bNoHeader = TRUE;
668
669 return( psDBF );
670 }
671
672 /************************************************************************/
673 /* DBFAddField() */
674 /* */
675 /* Add a field to a newly created .dbf file before any records */
676 /* are written. */
677 /************************************************************************/
678
679 int SHPAPI_CALL
680 DBFAddField(DBFHandle psDBF, const char * pszFieldName,
681 DBFFieldType eType, int nWidth, int nDecimals )
682
683 {
684 char *pszFInfo;
685 int i;
686
687 /* -------------------------------------------------------------------- */
688 /* Do some checking to ensure we can add records to this file. */
689 /* -------------------------------------------------------------------- */
690 if( psDBF->nRecords > 0 )
691 return( -1 );
692
693 if( !psDBF->bNoHeader )
694 return( -1 );
695
696 if( eType != FTDouble && nDecimals != 0 )
697 return( -1 );
698
699 if( nWidth < 1 )
700 return -1;
701
702 /* -------------------------------------------------------------------- */
703 /* SfRealloc all the arrays larger to hold the additional field */
704 /* information. */
705 /* -------------------------------------------------------------------- */
706 psDBF->nFields++;
707
708 psDBF->panFieldOffset = (int *)
709 SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
710
711 psDBF->panFieldSize = (int *)
712 SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
713
714 psDBF->panFieldDecimals = (int *)
715 SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
716
717 psDBF->pachFieldType = (char *)
718 SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
719
720 /* -------------------------------------------------------------------- */
721 /* Assign the new field information fields. */
722 /* -------------------------------------------------------------------- */
723 psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
724 psDBF->nRecordLength += nWidth;
725 psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
726 psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
727
728 if( eType == FTLogical )
729 psDBF->pachFieldType[psDBF->nFields-1] = 'L';
730 else if( eType == FTString )
731 psDBF->pachFieldType[psDBF->nFields-1] = 'C';
732 else
733 psDBF->pachFieldType[psDBF->nFields-1] = 'N';
734
735 /* -------------------------------------------------------------------- */
736 /* Extend the required header information. */
737 /* -------------------------------------------------------------------- */
738 psDBF->nHeaderLength += 32;
739 psDBF->bUpdated = FALSE;
740
741 psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
742
743 pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
744
745 for( i = 0; i < 32; i++ )
746 pszFInfo[i] = '\0';
747
748 if( (int) strlen(pszFieldName) < 10 )
749 strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
750 else
751 strncpy( pszFInfo, pszFieldName, 10);
752
753 pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
754
755 if( eType == FTString )
756 {
757 pszFInfo[16] = (unsigned char) (nWidth % 256);
758 pszFInfo[17] = (unsigned char) (nWidth / 256);
759 }
760 else
761 {
762 pszFInfo[16] = (unsigned char) nWidth;
763 pszFInfo[17] = (unsigned char) nDecimals;
764 }
765
766 /* -------------------------------------------------------------------- */
767 /* Make the current record buffer appropriately larger. */
768 /* -------------------------------------------------------------------- */
769 psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
770 psDBF->nRecordLength);
771
772 return( psDBF->nFields-1 );
773 }
774
775 /************************************************************************/
776 /* DBFReadAttribute() */
777 /* */
778 /* Read one of the attribute fields of a record. */
779 /************************************************************************/
780
781 static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
782 char chReqType )
783
784 {
785 int nRecordOffset;
786 unsigned char *pabyRec;
787 void *pReturnField = NULL;
788
789 static double dDoubleField;
790
791 /* -------------------------------------------------------------------- */
792 /* Verify selection. */
793 /* -------------------------------------------------------------------- */
794 if( hEntity < 0 || hEntity >= psDBF->nRecords )
795 return( NULL );
796
797 if( iField < 0 || iField >= psDBF->nFields )
798 return( NULL );
799
800 /* -------------------------------------------------------------------- */
801 /* Have we read the record? */
802 /* -------------------------------------------------------------------- */
803 if( psDBF->nCurrentRecord != hEntity )
804 {
805 DBFFlushRecord( psDBF );
806
807 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
808
809 if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
810 {
811 fprintf( stderr, "fseek(%d) failed on DBF file.\n",
812 nRecordOffset );
813 return NULL;
814 }
815
816 if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength,
817 1, psDBF->fp ) != 1 )
818 {
819 fprintf( stderr, "fread(%d) failed on DBF file.\n",
820 psDBF->nRecordLength );
821 return NULL;
822 }
823
824 psDBF->nCurrentRecord = hEntity;
825 }
826
827 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
828
829 /* -------------------------------------------------------------------- */
830 /* Ensure our field buffer is large enough to hold this buffer. */
831 /* -------------------------------------------------------------------- */
832 if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
833 {
834 nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
835 pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
836 }
837
838 /* -------------------------------------------------------------------- */
839 /* Extract the requested field. */
840 /* -------------------------------------------------------------------- */
841 strncpy( pszStringField,
842 ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
843 psDBF->panFieldSize[iField] );
844 pszStringField[psDBF->panFieldSize[iField]] = '\0';
845
846 pReturnField = pszStringField;
847
848 /* -------------------------------------------------------------------- */
849 /* Decode the field. */
850 /* -------------------------------------------------------------------- */
851 if( chReqType == 'N' )
852 {
853 dDoubleField = (*atof_function)(pszStringField);
854
855 pReturnField = &dDoubleField;
856 }
857
858 /* -------------------------------------------------------------------- */
859 /* Should we trim white space off the string attribute value? */
860 /* -------------------------------------------------------------------- */
861 #ifdef TRIM_DBF_WHITESPACE
862 else
863 {
864 char *pchSrc, *pchDst;
865
866 pchDst = pchSrc = pszStringField;
867 while( *pchSrc == ' ' )
868 pchSrc++;
869
870 while( *pchSrc != '\0' )
871 *(pchDst++) = *(pchSrc++);
872 *pchDst = '\0';
873
874 while( pchDst != pszStringField && *(--pchDst) == ' ' )
875 *pchDst = '\0';
876 }
877 #endif
878
879 return( pReturnField );
880 }
881
882 /************************************************************************/
883 /* DBFReadIntAttribute() */
884 /* */
885 /* Read an integer attribute. */
886 /************************************************************************/
887
888 int SHPAPI_CALL
889 DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
890
891 {
892 double *pdValue;
893
894 pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
895
896 if( pdValue == NULL )
897 return 0;
898 else
899 return( (int) *pdValue );
900 }
901
902 /************************************************************************/
903 /* DBFReadDoubleAttribute() */
904 /* */
905 /* Read a double attribute. */
906 /************************************************************************/
907
908 double SHPAPI_CALL
909 DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
910
911 {
912 double *pdValue;
913
914 pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
915
916 if( pdValue == NULL )
917 return 0.0;
918 else
919 return( *pdValue );
920 }
921
922 /************************************************************************/
923 /* DBFReadStringAttribute() */
924 /* */
925 /* Read a string attribute. */
926 /************************************************************************/
927
928 const char SHPAPI_CALL1(*)
929 DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
930
931 {
932 return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
933 }
934
935 /************************************************************************/
936 /* DBFReadLogicalAttribute() */
937 /* */
938 /* Read a logical attribute. */
939 /************************************************************************/
940
941 const char SHPAPI_CALL1(*)
942 DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
943
944 {
945 return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
946 }
947
948 /************************************************************************/
949 /* DBFIsAttributeNULL() */
950 /* */
951 /* Return TRUE if value for field is NULL. */
952 /* */
953 /* Contributed by Jim Matthews. */
954 /************************************************************************/
955
956 int SHPAPI_CALL
957 DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
958
959 {
960 const char *pszValue;
961
962 pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
963
964 if( pszValue == NULL )
965 return TRUE;
966
967 switch(psDBF->pachFieldType[iField])
968 {
969 case 'N':
970 case 'F':
971 /* NULL numeric fields have value "****************" */
972 return pszValue[0] == '*';
973
974 case 'D':
975 /* NULL date fields have value "00000000" */
976 return strncmp(pszValue,"00000000",8) == 0;
977
978 case 'L':
979 /* NULL boolean fields have value "?" */
980 return pszValue[0] == '?';
981
982 default:
983 /* empty string fields are considered NULL */
984 return strlen(pszValue) == 0;
985 }
986 }
987
988 /************************************************************************/
989 /* DBFGetFieldCount() */
990 /* */
991 /* Return the number of fields in this table. */
992 /************************************************************************/
993
994 int SHPAPI_CALL
995 DBFGetFieldCount( DBFHandle psDBF )
996
997 {
998 return( psDBF->nFields );
999 }
1000
1001 /************************************************************************/
1002 /* DBFGetRecordCount() */
1003 /* */
1004 /* Return the number of records in this table. */
1005 /************************************************************************/
1006
1007 int SHPAPI_CALL
1008 DBFGetRecordCount( DBFHandle psDBF )
1009
1010 {
1011 return( psDBF->nRecords );
1012 }
1013
1014 /************************************************************************/
1015 /* DBFGetFieldInfo() */
1016 /* */
1017 /* Return any requested information about the field. */
1018 /************************************************************************/
1019
1020 DBFFieldType SHPAPI_CALL
1021 DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
1022 int * pnWidth, int * pnDecimals )
1023
1024 {
1025 if( iField < 0 || iField >= psDBF->nFields )
1026 return( FTInvalid );
1027
1028 if( pnWidth != NULL )
1029 *pnWidth = psDBF->panFieldSize[iField];
1030
1031 if( pnDecimals != NULL )
1032 *pnDecimals = psDBF->panFieldDecimals[iField];
1033
1034 if( pszFieldName != NULL )
1035 {
1036 int i;
1037
1038 strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
1039 pszFieldName[11] = '\0';
1040 for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
1041 pszFieldName[i] = '\0';
1042 }
1043
1044 if ( psDBF->pachFieldType[iField] == 'L' )
1045 return( FTLogical);
1046
1047 else if( psDBF->pachFieldType[iField] == 'N'
1048 || psDBF->pachFieldType[iField] == 'F'
1049 || psDBF->pachFieldType[iField] == 'D' )
1050 {
1051 if( psDBF->panFieldDecimals[iField] > 0 )
1052 return( FTDouble );
1053 else
1054 return( FTInteger );
1055 }
1056 else
1057 {
1058 return( FTString );
1059 }
1060 }
1061
1062 /************************************************************************/
1063 /* DBFWriteAttribute() */
1064 /* */
1065 /* Write an attribute record to the file. */
1066 /************************************************************************/
1067
1068 static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
1069 void * pValue )
1070
1071 {
1072 int nRecordOffset, i, j, nRetResult = TRUE;
1073 unsigned char *pabyRec;
1074 char szSField[400], szFormat[20];
1075
1076 /* -------------------------------------------------------------------- */
1077 /* Is this a valid record? */
1078 /* -------------------------------------------------------------------- */
1079 if( hEntity < 0 || hEntity > psDBF->nRecords )
1080 return( FALSE );
1081
1082 if( psDBF->bNoHeader )
1083 DBFWriteHeader(psDBF);
1084
1085 /* -------------------------------------------------------------------- */
1086 /* Is this a brand new record? */
1087 /* -------------------------------------------------------------------- */
1088 if( hEntity == psDBF->nRecords )
1089 {
1090 DBFFlushRecord( psDBF );
1091
1092 psDBF->nRecords++;
1093 for( i = 0; i < psDBF->nRecordLength; i++ )
1094 psDBF->pszCurrentRecord[i] = ' ';
1095
1096 psDBF->nCurrentRecord = hEntity;
1097 }
1098
1099 /* -------------------------------------------------------------------- */
1100 /* Is this an existing record, but different than the last one */
1101 /* we accessed? */
1102 /* -------------------------------------------------------------------- */
1103 if( psDBF->nCurrentRecord != hEntity )
1104 {
1105 DBFFlushRecord( psDBF );
1106
1107 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1108
1109 fseek( psDBF->fp, nRecordOffset, 0 );
1110 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1111
1112 psDBF->nCurrentRecord = hEntity;
1113 }
1114
1115 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1116
1117 psDBF->bCurrentRecordModified = TRUE;
1118 psDBF->bUpdated = TRUE;
1119
1120 /* -------------------------------------------------------------------- */
1121 /* Translate NULL value to valid DBF file representation. */
1122 /* */
1123 /* Contributed by Jim Matthews. */
1124 /* -------------------------------------------------------------------- */
1125 if( pValue == NULL )
1126 {
1127 switch(psDBF->pachFieldType[iField])
1128 {
1129 case 'N':
1130 case 'F':
1131 /* NULL numeric fields have value "****************" */
1132 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
1133 psDBF->panFieldSize[iField] );
1134 break;
1135
1136 case 'D':
1137 /* NULL date fields have value "00000000" */
1138 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
1139 psDBF->panFieldSize[iField] );
1140 break;
1141
1142 case 'L':
1143 /* NULL boolean fields have value "?" */
1144 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
1145 psDBF->panFieldSize[iField] );
1146 break;
1147
1148 default:
1149 /* empty string fields are considered NULL */
1150 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0',
1151 psDBF->panFieldSize[iField] );
1152 break;
1153 }
1154 return TRUE;
1155 }
1156
1157 /* -------------------------------------------------------------------- */
1158 /* Assign all the record fields. */
1159 /* -------------------------------------------------------------------- */
1160 switch( psDBF->pachFieldType[iField] )
1161 {
1162 case 'D':
1163 case 'N':
1164 case 'F':
1165 if( psDBF->panFieldDecimals[iField] == 0 )
1166 {
1167 int nWidth = psDBF->panFieldSize[iField];
1168
1169 if( sizeof(szSField)-2 < nWidth )
1170 nWidth = sizeof(szSField)-2;
1171
1172 sprintf( szFormat, "%%%dd", nWidth );
1173 sprintf(szSField, szFormat, (int) *((double *) pValue) );
1174 if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
1175 {
1176 szSField[psDBF->panFieldSize[iField]] = '\0';
1177 nRetResult = FALSE;
1178 }
1179
1180 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1181 szSField, strlen(szSField) );
1182 }
1183 else
1184 {
1185 int nWidth = psDBF->panFieldSize[iField];
1186
1187 if( sizeof(szSField)-2 < nWidth )
1188 nWidth = sizeof(szSField)-2;
1189
1190 sprintf( szFormat, "%%%d.%df",
1191 nWidth, psDBF->panFieldDecimals[iField] );
1192 sprintf(szSField, szFormat, *((double *) pValue) );
1193 if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
1194 {
1195 szSField[psDBF->panFieldSize[iField]] = '\0';
1196 nRetResult = FALSE;
1197 }
1198 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1199 szSField, strlen(szSField) );
1200 }
1201 break;
1202
1203 case 'L':
1204 if (psDBF->panFieldSize[iField] >= 1 &&
1205 (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
1206 *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
1207 break;
1208
1209 default:
1210 if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1211 {
1212 j = psDBF->panFieldSize[iField];
1213 nRetResult = FALSE;
1214 }
1215 else
1216 {
1217 memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1218 psDBF->panFieldSize[iField] );
1219 j = strlen((char *) pValue);
1220 }
1221
1222 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1223 (char *) pValue, j );
1224 break;
1225 }
1226
1227 return( nRetResult );
1228 }
1229
1230 /************************************************************************/
1231 /* DBFWriteAttributeDirectly() */
1232 /* */
1233 /* Write an attribute record to the file, but without any */
1234 /* reformatting based on type. The provided buffer is written */
1235 /* as is to the field position in the record. */
1236 /************************************************************************/
1237
1238 int SHPAPI_CALL
1239 DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1240 void * pValue )
1241
1242 {
1243 int nRecordOffset, i, j;
1244 unsigned char *pabyRec;
1245
1246 /* -------------------------------------------------------------------- */
1247 /* Is this a valid record? */
1248 /* -------------------------------------------------------------------- */
1249 if( hEntity < 0 || hEntity > psDBF->nRecords )
1250 return( FALSE );
1251
1252 if( psDBF->bNoHeader )
1253 DBFWriteHeader(psDBF);
1254
1255 /* -------------------------------------------------------------------- */
1256 /* Is this a brand new record? */
1257 /* -------------------------------------------------------------------- */
1258 if( hEntity == psDBF->nRecords )
1259 {
1260 DBFFlushRecord( psDBF );
1261
1262 psDBF->nRecords++;
1263 for( i = 0; i < psDBF->nRecordLength; i++ )
1264 psDBF->pszCurrentRecord[i] = ' ';
1265
1266 psDBF->nCurrentRecord = hEntity;
1267 }
1268
1269 /* -------------------------------------------------------------------- */
1270 /* Is this an existing record, but different than the last one */
1271 /* we accessed? */
1272 /* -------------------------------------------------------------------- */
1273 if( psDBF->nCurrentRecord != hEntity )
1274 {
1275 DBFFlushRecord( psDBF );
1276
1277 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1278
1279 fseek( psDBF->fp, nRecordOffset, 0 );
1280 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1281
1282 psDBF->nCurrentRecord = hEntity;
1283 }
1284
1285 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1286
1287 /* -------------------------------------------------------------------- */
1288 /* Assign all the record fields. */
1289 /* -------------------------------------------------------------------- */
1290 if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1291 j = psDBF->panFieldSize[iField];
1292 else
1293 {
1294 memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1295 psDBF->panFieldSize[iField] );
1296 j = strlen((char *) pValue);
1297 }
1298
1299 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1300 (char *) pValue, j );
1301
1302 psDBF->bCurrentRecordModified = TRUE;
1303 psDBF->bUpdated = TRUE;
1304
1305 return( TRUE );
1306 }
1307
1308 /************************************************************************/
1309 /* DBFWriteDoubleAttribute() */
1310 /* */
1311 /* Write a double attribute. */
1312 /************************************************************************/
1313
1314 int SHPAPI_CALL
1315 DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
1316 double dValue )
1317
1318 {
1319 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1320 }
1321
1322 /************************************************************************/
1323 /* DBFWriteIntegerAttribute() */
1324 /* */
1325 /* Write a integer attribute. */
1326 /************************************************************************/
1327
1328 int SHPAPI_CALL
1329 DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
1330 int nValue )
1331
1332 {
1333 double dValue = nValue;
1334
1335 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1336 }
1337
1338 /************************************************************************/
1339 /* DBFWriteStringAttribute() */
1340 /* */
1341 /* Write a string attribute. */
1342 /************************************************************************/
1343
1344 int SHPAPI_CALL
1345 DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
1346 const char * pszValue )
1347
1348 {
1349 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
1350 }
1351
1352 /************************************************************************/
1353 /* DBFWriteNULLAttribute() */
1354 /* */
1355 /* Write a string attribute. */
1356 /************************************************************************/
1357
1358 int SHPAPI_CALL
1359 DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
1360
1361 {
1362 return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
1363 }
1364
1365 /************************************************************************/
1366 /* DBFWriteLogicalAttribute() */
1367 /* */
1368 /* Write a logical attribute. */
1369 /************************************************************************/
1370
1371 int SHPAPI_CALL
1372 DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
1373 const char lValue)
1374
1375 {
1376 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
1377 }
1378
1379 /************************************************************************/
1380 /* DBFWriteTuple() */
1381 /* */
1382 /* Write an attribute record to the file. */
1383 /************************************************************************/
1384
1385 int SHPAPI_CALL
1386 DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
1387
1388 {
1389 int nRecordOffset, i;
1390 unsigned char *pabyRec;
1391
1392 /* -------------------------------------------------------------------- */
1393 /* Is this a valid record? */
1394 /* -------------------------------------------------------------------- */
1395 if( hEntity < 0 || hEntity > psDBF->nRecords )
1396 return( FALSE );
1397
1398 if( psDBF->bNoHeader )
1399 DBFWriteHeader(psDBF);
1400
1401 /* -------------------------------------------------------------------- */
1402 /* Is this a brand new record? */
1403 /* -------------------------------------------------------------------- */
1404 if( hEntity == psDBF->nRecords )
1405 {
1406 DBFFlushRecord( psDBF );
1407
1408 psDBF->nRecords++;
1409 for( i = 0; i < psDBF->nRecordLength; i++ )
1410 psDBF->pszCurrentRecord[i] = ' ';
1411
1412 psDBF->nCurrentRecord = hEntity;
1413 }
1414
1415 /* -------------------------------------------------------------------- */
1416 /* Is this an existing record, but different than the last one */
1417 /* we accessed? */
1418 /* -------------------------------------------------------------------- */
1419 if( psDBF->nCurrentRecord != hEntity )
1420 {
1421 DBFFlushRecord( psDBF );
1422
1423 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1424
1425 fseek( psDBF->fp, nRecordOffset, 0 );
1426 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1427
1428 psDBF->nCurrentRecord = hEntity;
1429 }
1430
1431 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1432
1433 memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
1434
1435 psDBF->bCurrentRecordModified = TRUE;
1436 psDBF->bUpdated = TRUE;
1437
1438 return( TRUE );
1439 }
1440
1441 /************************************************************************/
1442 /* DBFReadTuple() */
1443 /* */
1444 /* Read one of the attribute fields of a record. */
1445 /************************************************************************/
1446
1447 const char SHPAPI_CALL1(*)
1448 DBFReadTuple(DBFHandle psDBF, int hEntity )
1449
1450 {
1451 int nRecordOffset;
1452 unsigned char *pabyRec;
1453 static char *pReturnTuple = NULL;
1454
1455 static int nTupleLen = 0;
1456
1457 /* -------------------------------------------------------------------- */
1458 /* Have we read the record? */
1459 /* -------------------------------------------------------------------- */
1460 if( hEntity < 0 || hEntity >= psDBF->nRecords )
1461 return( NULL );
1462
1463 if( psDBF->nCurrentRecord != hEntity )
1464 {
1465 DBFFlushRecord( psDBF );
1466
1467 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1468
1469 fseek( psDBF->fp, nRecordOffset, 0 );
1470 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1471
1472 psDBF->nCurrentRecord = hEntity;
1473 }
1474
1475 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1476
1477 if ( nTupleLen < psDBF->nRecordLength) {
1478 nTupleLen = psDBF->nRecordLength;
1479 pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
1480 }
1481
1482 memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
1483
1484 return( pReturnTuple );
1485 }
1486
1487 /************************************************************************/
1488 /* DBFCloneEmpty() */
1489 /* */
1490 /* Read one of the attribute fields of a record. */
1491 /************************************************************************/
1492
1493 DBFHandle SHPAPI_CALL
1494 DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
1495 {
1496 DBFHandle newDBF;
1497
1498 newDBF = DBFCreate ( pszFilename );
1499 if ( newDBF == NULL ) return ( NULL );
1500
1501 newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
1502 memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
1503
1504 newDBF->nFields = psDBF->nFields;
1505 newDBF->nRecordLength = psDBF->nRecordLength;
1506 newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
1507
1508 newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
1509 memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1510 newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
1511 memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1512 newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
1513 memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1514 newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
1515 memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
1516
1517 newDBF->bNoHeader = TRUE;
1518 newDBF->bUpdated = TRUE;
1519
1520 DBFWriteHeader ( newDBF );
1521 DBFClose ( newDBF );
1522
1523 newDBF = DBFOpen ( pszFilename, "rb+" );
1524
1525 return ( newDBF );
1526 }
1527
1528 /************************************************************************/
1529 /* DBFGetNativeFieldType() */
1530 /* */
1531 /* Return the DBase field type for the specified field. */
1532 /* */
1533 /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
1534 /* 'N' (Numeric, with or without decimal), */
1535 /* 'L' (Logical), */
1536 /* 'M' (Memo: 10 digits .DBT block ptr) */
1537 /************************************************************************/
1538
1539 char SHPAPI_CALL
1540 DBFGetNativeFieldType( DBFHandle psDBF, int iField )
1541
1542 {
1543 if( iField >=0 && iField < psDBF->nFields )
1544 return psDBF->pachFieldType[iField];
1545
1546 return ' ';
1547 }
1548
1549 /************************************************************************/
1550 /* str_to_upper() */
1551 /************************************************************************/
1552
1553 static void str_to_upper (char *string)
1554 {
1555 int len;
1556 short i = -1;
1557
1558 len = strlen (string);
1559
1560 while (++i < len)
1561 if (isalpha(string[i]) && islower(string[i]))
1562 string[i] = (char) toupper ((int)string[i]);
1563 }
1564
1565 /************************************************************************/
1566 /* DBFGetFieldIndex() */
1567 /* */
1568 /* Get the index number for a field in a .dbf file. */
1569 /* */
1570 /* Contributed by Jim Matthews. */
1571 /************************************************************************/
1572
1573 int SHPAPI_CALL
1574 DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
1575
1576 {
1577 char name[12], name1[12], name2[12];
1578 int i;
1579
1580 strncpy(name1, pszFieldName,11);
1581 name1[11] = '\0';
1582 str_to_upper(name1);
1583
1584 for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
1585 {
1586 DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
1587 strncpy(name2,name,11);
1588 str_to_upper(name2);
1589
1590 if(!strncmp(name1,name2,10))
1591 return(i);
1592 }
1593 return(-1);
1594 }

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26