/[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 2747 - (show annotations)
Tue Mar 20 23:12:45 2007 UTC (17 years, 11 months ago) by bramz
File MIME type: text/plain
File size: 56214 byte(s)
dbfopen.c: fixing bug in DBFClose, checks for NULL handle now.
shptreemodule.c: restoring something that shouldn't have been committed in the first place.
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 if( psSHP == NULL )
557 return;
558
559 /* -------------------------------------------------------------------- */
560 /* Write out header if not already written. */
561 /* -------------------------------------------------------------------- */
562 if( psDBF->bNoHeader )
563 DBFWriteHeader( psDBF );
564
565 DBFFlushRecord( psDBF );
566
567 /* -------------------------------------------------------------------- */
568 /* Update last access date, and number of records if we have */
569 /* write access. */
570 /* -------------------------------------------------------------------- */
571 if( psDBF->bUpdated )
572 DBFUpdateHeader( psDBF );
573
574 /* -------------------------------------------------------------------- */
575 /* Close, and free resources. */
576 /* -------------------------------------------------------------------- */
577 fclose( psDBF->fp );
578
579 if( psDBF->panFieldOffset != NULL )
580 {
581 free( psDBF->panFieldOffset );
582 free( psDBF->panFieldSize );
583 free( psDBF->panFieldDecimals );
584 free( psDBF->pachFieldType );
585 }
586
587 free( psDBF->pszHeader );
588 free( psDBF->pszCurrentRecord );
589
590 free( psDBF );
591
592 if( pszStringField != NULL )
593 {
594 free( pszStringField );
595 pszStringField = NULL;
596 nStringFieldLen = 0;
597 }
598 }
599
600 /************************************************************************/
601 /* DBFCreate() */
602 /* */
603 /* Create a new .dbf file. */
604 /************************************************************************/
605
606 DBFHandle SHPAPI_CALL
607 DBFCreate( const char * pszFilename )
608
609 {
610 DBFHandle psDBF;
611 FILE *fp;
612 char *pszFullname, *pszBasename;
613 int i;
614
615 /* -------------------------------------------------------------------- */
616 /* Compute the base (layer) name. If there is any extension */
617 /* on the passed in filename we will strip it off. */
618 /* -------------------------------------------------------------------- */
619 pszBasename = (char *) malloc(strlen(pszFilename)+5);
620 strcpy( pszBasename, pszFilename );
621 for( i = strlen(pszBasename)-1;
622 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
623 && pszBasename[i] != '\\';
624 i-- ) {}
625
626 if( pszBasename[i] == '.' )
627 pszBasename[i] = '\0';
628
629 pszFullname = (char *) malloc(strlen(pszBasename) + 5);
630 sprintf( pszFullname, "%s.dbf", pszBasename );
631 free( pszBasename );
632
633 /* -------------------------------------------------------------------- */
634 /* Create the file. */
635 /* -------------------------------------------------------------------- */
636 fp = fopen( pszFullname, "wb" );
637 if( fp == NULL )
638 return( NULL );
639
640 fputc( 0, fp );
641 fclose( fp );
642
643 fp = fopen( pszFullname, "rb+" );
644 if( fp == NULL )
645 return( NULL );
646
647 free( pszFullname );
648
649 /* -------------------------------------------------------------------- */
650 /* Create the info structure. */
651 /* -------------------------------------------------------------------- */
652 psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
653
654 psDBF->fp = fp;
655 psDBF->nRecords = 0;
656 psDBF->nFields = 0;
657 psDBF->nRecordLength = 1;
658 psDBF->nHeaderLength = 33;
659
660 psDBF->panFieldOffset = NULL;
661 psDBF->panFieldSize = NULL;
662 psDBF->panFieldDecimals = NULL;
663 psDBF->pachFieldType = NULL;
664 psDBF->pszHeader = NULL;
665
666 psDBF->nCurrentRecord = -1;
667 psDBF->bCurrentRecordModified = FALSE;
668 psDBF->pszCurrentRecord = NULL;
669
670 psDBF->bNoHeader = TRUE;
671
672 return( psDBF );
673 }
674
675 /************************************************************************/
676 /* DBFAddField() */
677 /* */
678 /* Add a field to a newly created .dbf file before any records */
679 /* are written. */
680 /************************************************************************/
681
682 int SHPAPI_CALL
683 DBFAddField(DBFHandle psDBF, const char * pszFieldName,
684 DBFFieldType eType, int nWidth, int nDecimals )
685
686 {
687 char *pszFInfo;
688 int i;
689
690 /* -------------------------------------------------------------------- */
691 /* Do some checking to ensure we can add records to this file. */
692 /* -------------------------------------------------------------------- */
693 if( psDBF->nRecords > 0 )
694 return( -1 );
695
696 if( !psDBF->bNoHeader )
697 return( -1 );
698
699 if( eType != FTDouble && nDecimals != 0 )
700 return( -1 );
701
702 if( nWidth < 1 )
703 return -1;
704
705 /* -------------------------------------------------------------------- */
706 /* SfRealloc all the arrays larger to hold the additional field */
707 /* information. */
708 /* -------------------------------------------------------------------- */
709 psDBF->nFields++;
710
711 psDBF->panFieldOffset = (int *)
712 SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
713
714 psDBF->panFieldSize = (int *)
715 SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
716
717 psDBF->panFieldDecimals = (int *)
718 SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
719
720 psDBF->pachFieldType = (char *)
721 SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
722
723 /* -------------------------------------------------------------------- */
724 /* Assign the new field information fields. */
725 /* -------------------------------------------------------------------- */
726 psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
727 psDBF->nRecordLength += nWidth;
728 psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
729 psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
730
731 if( eType == FTLogical )
732 psDBF->pachFieldType[psDBF->nFields-1] = 'L';
733 else if( eType == FTString )
734 psDBF->pachFieldType[psDBF->nFields-1] = 'C';
735 else
736 psDBF->pachFieldType[psDBF->nFields-1] = 'N';
737
738 /* -------------------------------------------------------------------- */
739 /* Extend the required header information. */
740 /* -------------------------------------------------------------------- */
741 psDBF->nHeaderLength += 32;
742 psDBF->bUpdated = FALSE;
743
744 psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
745
746 pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
747
748 for( i = 0; i < 32; i++ )
749 pszFInfo[i] = '\0';
750
751 if( (int) strlen(pszFieldName) < 10 )
752 strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
753 else
754 strncpy( pszFInfo, pszFieldName, 10);
755
756 pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
757
758 if( eType == FTString )
759 {
760 pszFInfo[16] = (unsigned char) (nWidth % 256);
761 pszFInfo[17] = (unsigned char) (nWidth / 256);
762 }
763 else
764 {
765 pszFInfo[16] = (unsigned char) nWidth;
766 pszFInfo[17] = (unsigned char) nDecimals;
767 }
768
769 /* -------------------------------------------------------------------- */
770 /* Make the current record buffer appropriately larger. */
771 /* -------------------------------------------------------------------- */
772 psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
773 psDBF->nRecordLength);
774
775 return( psDBF->nFields-1 );
776 }
777
778 /************************************************************************/
779 /* DBFReadAttribute() */
780 /* */
781 /* Read one of the attribute fields of a record. */
782 /************************************************************************/
783
784 static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
785 char chReqType )
786
787 {
788 int nRecordOffset;
789 unsigned char *pabyRec;
790 void *pReturnField = NULL;
791
792 static double dDoubleField;
793
794 /* -------------------------------------------------------------------- */
795 /* Verify selection. */
796 /* -------------------------------------------------------------------- */
797 if( hEntity < 0 || hEntity >= psDBF->nRecords )
798 return( NULL );
799
800 if( iField < 0 || iField >= psDBF->nFields )
801 return( NULL );
802
803 /* -------------------------------------------------------------------- */
804 /* Have we read the record? */
805 /* -------------------------------------------------------------------- */
806 if( psDBF->nCurrentRecord != hEntity )
807 {
808 DBFFlushRecord( psDBF );
809
810 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
811
812 if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
813 {
814 fprintf( stderr, "fseek(%d) failed on DBF file.\n",
815 nRecordOffset );
816 return NULL;
817 }
818
819 if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength,
820 1, psDBF->fp ) != 1 )
821 {
822 fprintf( stderr, "fread(%d) failed on DBF file.\n",
823 psDBF->nRecordLength );
824 return NULL;
825 }
826
827 psDBF->nCurrentRecord = hEntity;
828 }
829
830 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
831
832 /* -------------------------------------------------------------------- */
833 /* Ensure our field buffer is large enough to hold this buffer. */
834 /* -------------------------------------------------------------------- */
835 if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
836 {
837 nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
838 pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
839 }
840
841 /* -------------------------------------------------------------------- */
842 /* Extract the requested field. */
843 /* -------------------------------------------------------------------- */
844 strncpy( pszStringField,
845 ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
846 psDBF->panFieldSize[iField] );
847 pszStringField[psDBF->panFieldSize[iField]] = '\0';
848
849 pReturnField = pszStringField;
850
851 /* -------------------------------------------------------------------- */
852 /* Decode the field. */
853 /* -------------------------------------------------------------------- */
854 if( chReqType == 'N' )
855 {
856 dDoubleField = (*atof_function)(pszStringField);
857
858 pReturnField = &dDoubleField;
859 }
860
861 /* -------------------------------------------------------------------- */
862 /* Should we trim white space off the string attribute value? */
863 /* -------------------------------------------------------------------- */
864 #ifdef TRIM_DBF_WHITESPACE
865 else
866 {
867 char *pchSrc, *pchDst;
868
869 pchDst = pchSrc = pszStringField;
870 while( *pchSrc == ' ' )
871 pchSrc++;
872
873 while( *pchSrc != '\0' )
874 *(pchDst++) = *(pchSrc++);
875 *pchDst = '\0';
876
877 while( pchDst != pszStringField && *(--pchDst) == ' ' )
878 *pchDst = '\0';
879 }
880 #endif
881
882 return( pReturnField );
883 }
884
885 /************************************************************************/
886 /* DBFReadIntAttribute() */
887 /* */
888 /* Read an integer attribute. */
889 /************************************************************************/
890
891 int SHPAPI_CALL
892 DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
893
894 {
895 double *pdValue;
896
897 pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
898
899 if( pdValue == NULL )
900 return 0;
901 else
902 return( (int) *pdValue );
903 }
904
905 /************************************************************************/
906 /* DBFReadDoubleAttribute() */
907 /* */
908 /* Read a double attribute. */
909 /************************************************************************/
910
911 double SHPAPI_CALL
912 DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
913
914 {
915 double *pdValue;
916
917 pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
918
919 if( pdValue == NULL )
920 return 0.0;
921 else
922 return( *pdValue );
923 }
924
925 /************************************************************************/
926 /* DBFReadStringAttribute() */
927 /* */
928 /* Read a string attribute. */
929 /************************************************************************/
930
931 const char SHPAPI_CALL1(*)
932 DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
933
934 {
935 return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
936 }
937
938 /************************************************************************/
939 /* DBFReadLogicalAttribute() */
940 /* */
941 /* Read a logical attribute. */
942 /************************************************************************/
943
944 const char SHPAPI_CALL1(*)
945 DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
946
947 {
948 return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
949 }
950
951 /************************************************************************/
952 /* DBFIsAttributeNULL() */
953 /* */
954 /* Return TRUE if value for field is NULL. */
955 /* */
956 /* Contributed by Jim Matthews. */
957 /************************************************************************/
958
959 int SHPAPI_CALL
960 DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
961
962 {
963 const char *pszValue;
964
965 pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
966
967 if( pszValue == NULL )
968 return TRUE;
969
970 switch(psDBF->pachFieldType[iField])
971 {
972 case 'N':
973 case 'F':
974 /* NULL numeric fields have value "****************" */
975 return pszValue[0] == '*';
976
977 case 'D':
978 /* NULL date fields have value "00000000" */
979 return strncmp(pszValue,"00000000",8) == 0;
980
981 case 'L':
982 /* NULL boolean fields have value "?" */
983 return pszValue[0] == '?';
984
985 default:
986 /* empty string fields are considered NULL */
987 return strlen(pszValue) == 0;
988 }
989 }
990
991 /************************************************************************/
992 /* DBFGetFieldCount() */
993 /* */
994 /* Return the number of fields in this table. */
995 /************************************************************************/
996
997 int SHPAPI_CALL
998 DBFGetFieldCount( DBFHandle psDBF )
999
1000 {
1001 return( psDBF->nFields );
1002 }
1003
1004 /************************************************************************/
1005 /* DBFGetRecordCount() */
1006 /* */
1007 /* Return the number of records in this table. */
1008 /************************************************************************/
1009
1010 int SHPAPI_CALL
1011 DBFGetRecordCount( DBFHandle psDBF )
1012
1013 {
1014 return( psDBF->nRecords );
1015 }
1016
1017 /************************************************************************/
1018 /* DBFGetFieldInfo() */
1019 /* */
1020 /* Return any requested information about the field. */
1021 /************************************************************************/
1022
1023 DBFFieldType SHPAPI_CALL
1024 DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
1025 int * pnWidth, int * pnDecimals )
1026
1027 {
1028 if( iField < 0 || iField >= psDBF->nFields )
1029 return( FTInvalid );
1030
1031 if( pnWidth != NULL )
1032 *pnWidth = psDBF->panFieldSize[iField];
1033
1034 if( pnDecimals != NULL )
1035 *pnDecimals = psDBF->panFieldDecimals[iField];
1036
1037 if( pszFieldName != NULL )
1038 {
1039 int i;
1040
1041 strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
1042 pszFieldName[11] = '\0';
1043 for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
1044 pszFieldName[i] = '\0';
1045 }
1046
1047 if ( psDBF->pachFieldType[iField] == 'L' )
1048 return( FTLogical);
1049
1050 else if( psDBF->pachFieldType[iField] == 'N'
1051 || psDBF->pachFieldType[iField] == 'F'
1052 || psDBF->pachFieldType[iField] == 'D' )
1053 {
1054 if( psDBF->panFieldDecimals[iField] > 0 )
1055 return( FTDouble );
1056 else
1057 return( FTInteger );
1058 }
1059 else
1060 {
1061 return( FTString );
1062 }
1063 }
1064
1065 /************************************************************************/
1066 /* DBFWriteAttribute() */
1067 /* */
1068 /* Write an attribute record to the file. */
1069 /************************************************************************/
1070
1071 static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
1072 void * pValue )
1073
1074 {
1075 int nRecordOffset, i, j, nRetResult = TRUE;
1076 unsigned char *pabyRec;
1077 char szSField[400], szFormat[20];
1078
1079 /* -------------------------------------------------------------------- */
1080 /* Is this a valid record? */
1081 /* -------------------------------------------------------------------- */
1082 if( hEntity < 0 || hEntity > psDBF->nRecords )
1083 return( FALSE );
1084
1085 if( psDBF->bNoHeader )
1086 DBFWriteHeader(psDBF);
1087
1088 /* -------------------------------------------------------------------- */
1089 /* Is this a brand new record? */
1090 /* -------------------------------------------------------------------- */
1091 if( hEntity == psDBF->nRecords )
1092 {
1093 DBFFlushRecord( psDBF );
1094
1095 psDBF->nRecords++;
1096 for( i = 0; i < psDBF->nRecordLength; i++ )
1097 psDBF->pszCurrentRecord[i] = ' ';
1098
1099 psDBF->nCurrentRecord = hEntity;
1100 }
1101
1102 /* -------------------------------------------------------------------- */
1103 /* Is this an existing record, but different than the last one */
1104 /* we accessed? */
1105 /* -------------------------------------------------------------------- */
1106 if( psDBF->nCurrentRecord != hEntity )
1107 {
1108 DBFFlushRecord( psDBF );
1109
1110 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1111
1112 fseek( psDBF->fp, nRecordOffset, 0 );
1113 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1114
1115 psDBF->nCurrentRecord = hEntity;
1116 }
1117
1118 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1119
1120 psDBF->bCurrentRecordModified = TRUE;
1121 psDBF->bUpdated = TRUE;
1122
1123 /* -------------------------------------------------------------------- */
1124 /* Translate NULL value to valid DBF file representation. */
1125 /* */
1126 /* Contributed by Jim Matthews. */
1127 /* -------------------------------------------------------------------- */
1128 if( pValue == NULL )
1129 {
1130 switch(psDBF->pachFieldType[iField])
1131 {
1132 case 'N':
1133 case 'F':
1134 /* NULL numeric fields have value "****************" */
1135 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
1136 psDBF->panFieldSize[iField] );
1137 break;
1138
1139 case 'D':
1140 /* NULL date fields have value "00000000" */
1141 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
1142 psDBF->panFieldSize[iField] );
1143 break;
1144
1145 case 'L':
1146 /* NULL boolean fields have value "?" */
1147 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
1148 psDBF->panFieldSize[iField] );
1149 break;
1150
1151 default:
1152 /* empty string fields are considered NULL */
1153 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0',
1154 psDBF->panFieldSize[iField] );
1155 break;
1156 }
1157 return TRUE;
1158 }
1159
1160 /* -------------------------------------------------------------------- */
1161 /* Assign all the record fields. */
1162 /* -------------------------------------------------------------------- */
1163 switch( psDBF->pachFieldType[iField] )
1164 {
1165 case 'D':
1166 case 'N':
1167 case 'F':
1168 if( psDBF->panFieldDecimals[iField] == 0 )
1169 {
1170 int nWidth = psDBF->panFieldSize[iField];
1171
1172 if( sizeof(szSField)-2 < nWidth )
1173 nWidth = sizeof(szSField)-2;
1174
1175 sprintf( szFormat, "%%%dd", nWidth );
1176 sprintf(szSField, szFormat, (int) *((double *) pValue) );
1177 if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
1178 {
1179 szSField[psDBF->panFieldSize[iField]] = '\0';
1180 nRetResult = FALSE;
1181 }
1182
1183 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1184 szSField, strlen(szSField) );
1185 }
1186 else
1187 {
1188 int nWidth = psDBF->panFieldSize[iField];
1189
1190 if( sizeof(szSField)-2 < nWidth )
1191 nWidth = sizeof(szSField)-2;
1192
1193 sprintf( szFormat, "%%%d.%df",
1194 nWidth, psDBF->panFieldDecimals[iField] );
1195 sprintf(szSField, szFormat, *((double *) pValue) );
1196 if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
1197 {
1198 szSField[psDBF->panFieldSize[iField]] = '\0';
1199 nRetResult = FALSE;
1200 }
1201 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1202 szSField, strlen(szSField) );
1203 }
1204 break;
1205
1206 case 'L':
1207 if (psDBF->panFieldSize[iField] >= 1 &&
1208 (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
1209 *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
1210 break;
1211
1212 default:
1213 if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1214 {
1215 j = psDBF->panFieldSize[iField];
1216 nRetResult = FALSE;
1217 }
1218 else
1219 {
1220 memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1221 psDBF->panFieldSize[iField] );
1222 j = strlen((char *) pValue);
1223 }
1224
1225 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1226 (char *) pValue, j );
1227 break;
1228 }
1229
1230 return( nRetResult );
1231 }
1232
1233 /************************************************************************/
1234 /* DBFWriteAttributeDirectly() */
1235 /* */
1236 /* Write an attribute record to the file, but without any */
1237 /* reformatting based on type. The provided buffer is written */
1238 /* as is to the field position in the record. */
1239 /************************************************************************/
1240
1241 int SHPAPI_CALL
1242 DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1243 void * pValue )
1244
1245 {
1246 int nRecordOffset, i, j;
1247 unsigned char *pabyRec;
1248
1249 /* -------------------------------------------------------------------- */
1250 /* Is this a valid record? */
1251 /* -------------------------------------------------------------------- */
1252 if( hEntity < 0 || hEntity > psDBF->nRecords )
1253 return( FALSE );
1254
1255 if( psDBF->bNoHeader )
1256 DBFWriteHeader(psDBF);
1257
1258 /* -------------------------------------------------------------------- */
1259 /* Is this a brand new record? */
1260 /* -------------------------------------------------------------------- */
1261 if( hEntity == psDBF->nRecords )
1262 {
1263 DBFFlushRecord( psDBF );
1264
1265 psDBF->nRecords++;
1266 for( i = 0; i < psDBF->nRecordLength; i++ )
1267 psDBF->pszCurrentRecord[i] = ' ';
1268
1269 psDBF->nCurrentRecord = hEntity;
1270 }
1271
1272 /* -------------------------------------------------------------------- */
1273 /* Is this an existing record, but different than the last one */
1274 /* we accessed? */
1275 /* -------------------------------------------------------------------- */
1276 if( psDBF->nCurrentRecord != hEntity )
1277 {
1278 DBFFlushRecord( psDBF );
1279
1280 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1281
1282 fseek( psDBF->fp, nRecordOffset, 0 );
1283 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1284
1285 psDBF->nCurrentRecord = hEntity;
1286 }
1287
1288 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1289
1290 /* -------------------------------------------------------------------- */
1291 /* Assign all the record fields. */
1292 /* -------------------------------------------------------------------- */
1293 if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1294 j = psDBF->panFieldSize[iField];
1295 else
1296 {
1297 memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1298 psDBF->panFieldSize[iField] );
1299 j = strlen((char *) pValue);
1300 }
1301
1302 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1303 (char *) pValue, j );
1304
1305 psDBF->bCurrentRecordModified = TRUE;
1306 psDBF->bUpdated = TRUE;
1307
1308 return( TRUE );
1309 }
1310
1311 /************************************************************************/
1312 /* DBFWriteDoubleAttribute() */
1313 /* */
1314 /* Write a double attribute. */
1315 /************************************************************************/
1316
1317 int SHPAPI_CALL
1318 DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
1319 double dValue )
1320
1321 {
1322 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1323 }
1324
1325 /************************************************************************/
1326 /* DBFWriteIntegerAttribute() */
1327 /* */
1328 /* Write a integer attribute. */
1329 /************************************************************************/
1330
1331 int SHPAPI_CALL
1332 DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
1333 int nValue )
1334
1335 {
1336 double dValue = nValue;
1337
1338 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1339 }
1340
1341 /************************************************************************/
1342 /* DBFWriteStringAttribute() */
1343 /* */
1344 /* Write a string attribute. */
1345 /************************************************************************/
1346
1347 int SHPAPI_CALL
1348 DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
1349 const char * pszValue )
1350
1351 {
1352 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
1353 }
1354
1355 /************************************************************************/
1356 /* DBFWriteNULLAttribute() */
1357 /* */
1358 /* Write a string attribute. */
1359 /************************************************************************/
1360
1361 int SHPAPI_CALL
1362 DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
1363
1364 {
1365 return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
1366 }
1367
1368 /************************************************************************/
1369 /* DBFWriteLogicalAttribute() */
1370 /* */
1371 /* Write a logical attribute. */
1372 /************************************************************************/
1373
1374 int SHPAPI_CALL
1375 DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
1376 const char lValue)
1377
1378 {
1379 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
1380 }
1381
1382 /************************************************************************/
1383 /* DBFWriteTuple() */
1384 /* */
1385 /* Write an attribute record to the file. */
1386 /************************************************************************/
1387
1388 int SHPAPI_CALL
1389 DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
1390
1391 {
1392 int nRecordOffset, i;
1393 unsigned char *pabyRec;
1394
1395 /* -------------------------------------------------------------------- */
1396 /* Is this a valid record? */
1397 /* -------------------------------------------------------------------- */
1398 if( hEntity < 0 || hEntity > psDBF->nRecords )
1399 return( FALSE );
1400
1401 if( psDBF->bNoHeader )
1402 DBFWriteHeader(psDBF);
1403
1404 /* -------------------------------------------------------------------- */
1405 /* Is this a brand new record? */
1406 /* -------------------------------------------------------------------- */
1407 if( hEntity == psDBF->nRecords )
1408 {
1409 DBFFlushRecord( psDBF );
1410
1411 psDBF->nRecords++;
1412 for( i = 0; i < psDBF->nRecordLength; i++ )
1413 psDBF->pszCurrentRecord[i] = ' ';
1414
1415 psDBF->nCurrentRecord = hEntity;
1416 }
1417
1418 /* -------------------------------------------------------------------- */
1419 /* Is this an existing record, but different than the last one */
1420 /* we accessed? */
1421 /* -------------------------------------------------------------------- */
1422 if( psDBF->nCurrentRecord != hEntity )
1423 {
1424 DBFFlushRecord( psDBF );
1425
1426 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1427
1428 fseek( psDBF->fp, nRecordOffset, 0 );
1429 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1430
1431 psDBF->nCurrentRecord = hEntity;
1432 }
1433
1434 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1435
1436 memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
1437
1438 psDBF->bCurrentRecordModified = TRUE;
1439 psDBF->bUpdated = TRUE;
1440
1441 return( TRUE );
1442 }
1443
1444 /************************************************************************/
1445 /* DBFReadTuple() */
1446 /* */
1447 /* Read one of the attribute fields of a record. */
1448 /************************************************************************/
1449
1450 const char SHPAPI_CALL1(*)
1451 DBFReadTuple(DBFHandle psDBF, int hEntity )
1452
1453 {
1454 int nRecordOffset;
1455 unsigned char *pabyRec;
1456 static char *pReturnTuple = NULL;
1457
1458 static int nTupleLen = 0;
1459
1460 /* -------------------------------------------------------------------- */
1461 /* Have we read the record? */
1462 /* -------------------------------------------------------------------- */
1463 if( hEntity < 0 || hEntity >= psDBF->nRecords )
1464 return( NULL );
1465
1466 if( psDBF->nCurrentRecord != hEntity )
1467 {
1468 DBFFlushRecord( psDBF );
1469
1470 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1471
1472 fseek( psDBF->fp, nRecordOffset, 0 );
1473 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1474
1475 psDBF->nCurrentRecord = hEntity;
1476 }
1477
1478 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1479
1480 if ( nTupleLen < psDBF->nRecordLength) {
1481 nTupleLen = psDBF->nRecordLength;
1482 pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
1483 }
1484
1485 memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
1486
1487 return( pReturnTuple );
1488 }
1489
1490 /************************************************************************/
1491 /* DBFCloneEmpty() */
1492 /* */
1493 /* Read one of the attribute fields of a record. */
1494 /************************************************************************/
1495
1496 DBFHandle SHPAPI_CALL
1497 DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
1498 {
1499 DBFHandle newDBF;
1500
1501 newDBF = DBFCreate ( pszFilename );
1502 if ( newDBF == NULL ) return ( NULL );
1503
1504 newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
1505 memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
1506
1507 newDBF->nFields = psDBF->nFields;
1508 newDBF->nRecordLength = psDBF->nRecordLength;
1509 newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
1510
1511 newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
1512 memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1513 newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
1514 memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1515 newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
1516 memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1517 newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
1518 memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
1519
1520 newDBF->bNoHeader = TRUE;
1521 newDBF->bUpdated = TRUE;
1522
1523 DBFWriteHeader ( newDBF );
1524 DBFClose ( newDBF );
1525
1526 newDBF = DBFOpen ( pszFilename, "rb+" );
1527
1528 return ( newDBF );
1529 }
1530
1531 /************************************************************************/
1532 /* DBFGetNativeFieldType() */
1533 /* */
1534 /* Return the DBase field type for the specified field. */
1535 /* */
1536 /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
1537 /* 'N' (Numeric, with or without decimal), */
1538 /* 'L' (Logical), */
1539 /* 'M' (Memo: 10 digits .DBT block ptr) */
1540 /************************************************************************/
1541
1542 char SHPAPI_CALL
1543 DBFGetNativeFieldType( DBFHandle psDBF, int iField )
1544
1545 {
1546 if( iField >=0 && iField < psDBF->nFields )
1547 return psDBF->pachFieldType[iField];
1548
1549 return ' ';
1550 }
1551
1552 /************************************************************************/
1553 /* str_to_upper() */
1554 /************************************************************************/
1555
1556 static void str_to_upper (char *string)
1557 {
1558 int len;
1559 short i = -1;
1560
1561 len = strlen (string);
1562
1563 while (++i < len)
1564 if (isalpha(string[i]) && islower(string[i]))
1565 string[i] = (char) toupper ((int)string[i]);
1566 }
1567
1568 /************************************************************************/
1569 /* DBFGetFieldIndex() */
1570 /* */
1571 /* Get the index number for a field in a .dbf file. */
1572 /* */
1573 /* Contributed by Jim Matthews. */
1574 /************************************************************************/
1575
1576 int SHPAPI_CALL
1577 DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
1578
1579 {
1580 char name[12], name1[12], name2[12];
1581 int i;
1582
1583 strncpy(name1, pszFieldName,11);
1584 name1[11] = '\0';
1585 str_to_upper(name1);
1586
1587 for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
1588 {
1589 DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
1590 strncpy(name2,name,11);
1591 str_to_upper(name2);
1592
1593 if(!strncmp(name1,name2,10))
1594 return(i);
1595 }
1596 return(-1);
1597 }

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26