/[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 2212 - (show annotations)
Mon May 17 15:47:57 2004 UTC (20 years, 9 months ago) by bh
Original Path: trunk/thuban/libraries/shapelib/dbfopen.c
File MIME type: text/plain
File size: 54855 byte(s)
Update to newest shapelib and get rid of Thuban specific extensions,
i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge

* libraries/shapelib/shpopen.c: Update to version from current
shapelib CVS.

* libraries/shapelib/shapefil.h: Update to version from current
shapelib CVS.

* libraries/shapelib/dbfopen.c: Update to version from current
shapelib CVS.
(DBFCommit): Effectively removed since shapelib itself has
DBFUpdateHeader now which is better for what DBFCommit wanted to
achieve.
We're now using an unmodified version of dbfopen.

* libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
Update from dbflib.i

* libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
the commit method.  This new indirection is necessary because we use the
DBFUpdateHeader function now which is not available in shapelib <=
1.2.10
(DBFFile::commit): Use DBFInfo_commit as implementation
(pragma __class__): New. Kludge to remove the commit method when
the DBFUpdateHeader function isn't available
(_have_commit): New. Helper for the pragma kludge.

* libraries/pyshapelib/setup.py (dbf_macros): New. Return the
preprocessor macros needed to compile the dbflib wrapper.  Determine
whether DBFUpdateHeader is available and define the right value of
HAVE_UPDATE_HEADER
(extensions): Use dbf_macros for the dbflibc extension

* setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
value '1' to the Lib.dbflibc extension.  This simply reflects the
shapelib and pyshapelib updates

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 /* SfRealloc() */
259 /* */
260 /* A realloc cover function that will access a NULL pointer as */
261 /* a valid input. */
262 /************************************************************************/
263
264 static void * SfRealloc( void * pMem, int nNewSize )
265
266 {
267 if( pMem == NULL )
268 return( (void *) malloc(nNewSize) );
269 else
270 return( (void *) realloc(pMem,nNewSize) );
271 }
272
273 /************************************************************************/
274 /* DBFWriteHeader() */
275 /* */
276 /* This is called to write out the file header, and field */
277 /* descriptions before writing any actual data records. This */
278 /* also computes all the DBFDataSet field offset/size/decimals */
279 /* and so forth values. */
280 /************************************************************************/
281
282 static void DBFWriteHeader(DBFHandle psDBF)
283
284 {
285 unsigned char abyHeader[XBASE_FLDHDR_SZ];
286 int i;
287
288 if( !psDBF->bNoHeader )
289 return;
290
291 psDBF->bNoHeader = FALSE;
292
293 /* -------------------------------------------------------------------- */
294 /* Initialize the file header information. */
295 /* -------------------------------------------------------------------- */
296 for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
297 abyHeader[i] = 0;
298
299 abyHeader[0] = 0x03; /* memo field? - just copying */
300
301 /* write out a dummy date */
302 abyHeader[1] = 95; /* YY */
303 abyHeader[2] = 7; /* MM */
304 abyHeader[3] = 26; /* DD */
305
306 /* record count preset at zero */
307
308 abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
309 abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
310
311 abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
312 abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
313
314 /* -------------------------------------------------------------------- */
315 /* Write the initial 32 byte file header, and all the field */
316 /* descriptions. */
317 /* -------------------------------------------------------------------- */
318 fseek( psDBF->fp, 0, 0 );
319 fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
320 fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );
321
322 /* -------------------------------------------------------------------- */
323 /* Write out the newline character if there is room for it. */
324 /* -------------------------------------------------------------------- */
325 if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
326 {
327 char cNewline;
328
329 cNewline = 0x0d;
330 fwrite( &cNewline, 1, 1, psDBF->fp );
331 }
332 }
333
334 /************************************************************************/
335 /* DBFFlushRecord() */
336 /* */
337 /* Write out the current record if there is one. */
338 /************************************************************************/
339
340 static void DBFFlushRecord( DBFHandle psDBF )
341
342 {
343 int nRecordOffset;
344
345 if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
346 {
347 psDBF->bCurrentRecordModified = FALSE;
348
349 nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord
350 + psDBF->nHeaderLength;
351
352 fseek( psDBF->fp, nRecordOffset, 0 );
353 fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
354 }
355 }
356
357 /************************************************************************/
358 /* DBFUpdateHeader() */
359 /************************************************************************/
360
361 void SHPAPI_CALL
362 DBFUpdateHeader( DBFHandle psDBF )
363
364 {
365 unsigned char abyFileHeader[32];
366
367 if( psDBF->bNoHeader )
368 DBFWriteHeader( psDBF );
369
370 DBFFlushRecord( psDBF );
371
372 fseek( psDBF->fp, 0, 0 );
373 fread( abyFileHeader, 32, 1, psDBF->fp );
374
375 abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
376 abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
377 abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
378 abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
379
380 fseek( psDBF->fp, 0, 0 );
381 fwrite( abyFileHeader, 32, 1, psDBF->fp );
382
383 fflush( psDBF->fp );
384 }
385
386 /************************************************************************/
387 /* DBFOpen() */
388 /* */
389 /* Open a .dbf file. */
390 /************************************************************************/
391
392 DBFHandle SHPAPI_CALL
393 DBFOpen( const char * pszFilename, const char * pszAccess )
394
395 {
396 DBFHandle psDBF;
397 unsigned char *pabyBuf;
398 int nFields, nHeadLen, nRecLen, iField, i;
399 char *pszBasename, *pszFullname;
400
401 /* -------------------------------------------------------------------- */
402 /* We only allow the access strings "rb" and "r+". */
403 /* -------------------------------------------------------------------- */
404 if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
405 && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
406 && strcmp(pszAccess,"r+b") != 0 )
407 return( NULL );
408
409 if( strcmp(pszAccess,"r") == 0 )
410 pszAccess = "rb";
411
412 if( strcmp(pszAccess,"r+") == 0 )
413 pszAccess = "rb+";
414
415 /* -------------------------------------------------------------------- */
416 /* Compute the base (layer) name. If there is any extension */
417 /* on the passed in filename we will strip it off. */
418 /* -------------------------------------------------------------------- */
419 pszBasename = (char *) malloc(strlen(pszFilename)+5);
420 strcpy( pszBasename, pszFilename );
421 for( i = strlen(pszBasename)-1;
422 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
423 && pszBasename[i] != '\\';
424 i-- ) {}
425
426 if( pszBasename[i] == '.' )
427 pszBasename[i] = '\0';
428
429 pszFullname = (char *) malloc(strlen(pszBasename) + 5);
430 sprintf( pszFullname, "%s.dbf", pszBasename );
431
432 psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
433 psDBF->fp = fopen( pszFullname, pszAccess );
434
435 if( psDBF->fp == NULL )
436 {
437 sprintf( pszFullname, "%s.DBF", pszBasename );
438 psDBF->fp = fopen(pszFullname, pszAccess );
439 }
440
441 free( pszBasename );
442 free( pszFullname );
443
444 if( psDBF->fp == NULL )
445 {
446 free( psDBF );
447 return( NULL );
448 }
449
450 psDBF->bNoHeader = FALSE;
451 psDBF->nCurrentRecord = -1;
452 psDBF->bCurrentRecordModified = FALSE;
453
454 /* -------------------------------------------------------------------- */
455 /* Read Table Header info */
456 /* -------------------------------------------------------------------- */
457 pabyBuf = (unsigned char *) malloc(500);
458 if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
459 {
460 fclose( psDBF->fp );
461 free( pabyBuf );
462 free( psDBF );
463 return NULL;
464 }
465
466 psDBF->nRecords =
467 pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
468
469 psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
470 psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;
471
472 psDBF->nFields = nFields = (nHeadLen - 32) / 32;
473
474 psDBF->pszCurrentRecord = (char *) malloc(nRecLen);
475
476 /* -------------------------------------------------------------------- */
477 /* Read in Field Definitions */
478 /* -------------------------------------------------------------------- */
479
480 pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
481 psDBF->pszHeader = (char *) pabyBuf;
482
483 fseek( psDBF->fp, 32, 0 );
484 if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
485 {
486 fclose( psDBF->fp );
487 free( pabyBuf );
488 free( psDBF );
489 return NULL;
490 }
491
492 psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
493 psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
494 psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
495 psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
496
497 for( iField = 0; iField < nFields; iField++ )
498 {
499 unsigned char *pabyFInfo;
500
501 pabyFInfo = pabyBuf+iField*32;
502
503 if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
504 {
505 psDBF->panFieldSize[iField] = pabyFInfo[16];
506 psDBF->panFieldDecimals[iField] = pabyFInfo[17];
507 }
508 else
509 {
510 psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
511 psDBF->panFieldDecimals[iField] = 0;
512 }
513
514 psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
515 if( iField == 0 )
516 psDBF->panFieldOffset[iField] = 1;
517 else
518 psDBF->panFieldOffset[iField] =
519 psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
520 }
521
522 return( psDBF );
523 }
524
525 /************************************************************************/
526 /* DBFClose() */
527 /************************************************************************/
528
529 void SHPAPI_CALL
530 DBFClose(DBFHandle psDBF)
531 {
532 /* -------------------------------------------------------------------- */
533 /* Write out header if not already written. */
534 /* -------------------------------------------------------------------- */
535 if( psDBF->bNoHeader )
536 DBFWriteHeader( psDBF );
537
538 DBFFlushRecord( psDBF );
539
540 /* -------------------------------------------------------------------- */
541 /* Update last access date, and number of records if we have */
542 /* write access. */
543 /* -------------------------------------------------------------------- */
544 if( psDBF->bUpdated )
545 DBFUpdateHeader( psDBF );
546
547 /* -------------------------------------------------------------------- */
548 /* Close, and free resources. */
549 /* -------------------------------------------------------------------- */
550 fclose( psDBF->fp );
551
552 if( psDBF->panFieldOffset != NULL )
553 {
554 free( psDBF->panFieldOffset );
555 free( psDBF->panFieldSize );
556 free( psDBF->panFieldDecimals );
557 free( psDBF->pachFieldType );
558 }
559
560 free( psDBF->pszHeader );
561 free( psDBF->pszCurrentRecord );
562
563 free( psDBF );
564
565 if( pszStringField != NULL )
566 {
567 free( pszStringField );
568 pszStringField = NULL;
569 nStringFieldLen = 0;
570 }
571 }
572
573 /************************************************************************/
574 /* DBFCreate() */
575 /* */
576 /* Create a new .dbf file. */
577 /************************************************************************/
578
579 DBFHandle SHPAPI_CALL
580 DBFCreate( const char * pszFilename )
581
582 {
583 DBFHandle psDBF;
584 FILE *fp;
585 char *pszFullname, *pszBasename;
586 int i;
587
588 /* -------------------------------------------------------------------- */
589 /* Compute the base (layer) name. If there is any extension */
590 /* on the passed in filename we will strip it off. */
591 /* -------------------------------------------------------------------- */
592 pszBasename = (char *) malloc(strlen(pszFilename)+5);
593 strcpy( pszBasename, pszFilename );
594 for( i = strlen(pszBasename)-1;
595 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
596 && pszBasename[i] != '\\';
597 i-- ) {}
598
599 if( pszBasename[i] == '.' )
600 pszBasename[i] = '\0';
601
602 pszFullname = (char *) malloc(strlen(pszBasename) + 5);
603 sprintf( pszFullname, "%s.dbf", pszBasename );
604 free( pszBasename );
605
606 /* -------------------------------------------------------------------- */
607 /* Create the file. */
608 /* -------------------------------------------------------------------- */
609 fp = fopen( pszFullname, "wb" );
610 if( fp == NULL )
611 return( NULL );
612
613 fputc( 0, fp );
614 fclose( fp );
615
616 fp = fopen( pszFullname, "rb+" );
617 if( fp == NULL )
618 return( NULL );
619
620 free( pszFullname );
621
622 /* -------------------------------------------------------------------- */
623 /* Create the info structure. */
624 /* -------------------------------------------------------------------- */
625 psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
626
627 psDBF->fp = fp;
628 psDBF->nRecords = 0;
629 psDBF->nFields = 0;
630 psDBF->nRecordLength = 1;
631 psDBF->nHeaderLength = 33;
632
633 psDBF->panFieldOffset = NULL;
634 psDBF->panFieldSize = NULL;
635 psDBF->panFieldDecimals = NULL;
636 psDBF->pachFieldType = NULL;
637 psDBF->pszHeader = NULL;
638
639 psDBF->nCurrentRecord = -1;
640 psDBF->bCurrentRecordModified = FALSE;
641 psDBF->pszCurrentRecord = NULL;
642
643 psDBF->bNoHeader = TRUE;
644
645 return( psDBF );
646 }
647
648 /************************************************************************/
649 /* DBFAddField() */
650 /* */
651 /* Add a field to a newly created .dbf file before any records */
652 /* are written. */
653 /************************************************************************/
654
655 int SHPAPI_CALL
656 DBFAddField(DBFHandle psDBF, const char * pszFieldName,
657 DBFFieldType eType, int nWidth, int nDecimals )
658
659 {
660 char *pszFInfo;
661 int i;
662
663 /* -------------------------------------------------------------------- */
664 /* Do some checking to ensure we can add records to this file. */
665 /* -------------------------------------------------------------------- */
666 if( psDBF->nRecords > 0 )
667 return( -1 );
668
669 if( !psDBF->bNoHeader )
670 return( -1 );
671
672 if( eType != FTDouble && nDecimals != 0 )
673 return( -1 );
674
675 if( nWidth < 1 )
676 return -1;
677
678 /* -------------------------------------------------------------------- */
679 /* SfRealloc all the arrays larger to hold the additional field */
680 /* information. */
681 /* -------------------------------------------------------------------- */
682 psDBF->nFields++;
683
684 psDBF->panFieldOffset = (int *)
685 SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
686
687 psDBF->panFieldSize = (int *)
688 SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
689
690 psDBF->panFieldDecimals = (int *)
691 SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
692
693 psDBF->pachFieldType = (char *)
694 SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
695
696 /* -------------------------------------------------------------------- */
697 /* Assign the new field information fields. */
698 /* -------------------------------------------------------------------- */
699 psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
700 psDBF->nRecordLength += nWidth;
701 psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
702 psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
703
704 if( eType == FTLogical )
705 psDBF->pachFieldType[psDBF->nFields-1] = 'L';
706 else if( eType == FTString )
707 psDBF->pachFieldType[psDBF->nFields-1] = 'C';
708 else
709 psDBF->pachFieldType[psDBF->nFields-1] = 'N';
710
711 /* -------------------------------------------------------------------- */
712 /* Extend the required header information. */
713 /* -------------------------------------------------------------------- */
714 psDBF->nHeaderLength += 32;
715 psDBF->bUpdated = FALSE;
716
717 psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
718
719 pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
720
721 for( i = 0; i < 32; i++ )
722 pszFInfo[i] = '\0';
723
724 if( (int) strlen(pszFieldName) < 10 )
725 strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
726 else
727 strncpy( pszFInfo, pszFieldName, 10);
728
729 pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
730
731 if( eType == FTString )
732 {
733 pszFInfo[16] = (unsigned char) (nWidth % 256);
734 pszFInfo[17] = (unsigned char) (nWidth / 256);
735 }
736 else
737 {
738 pszFInfo[16] = (unsigned char) nWidth;
739 pszFInfo[17] = (unsigned char) nDecimals;
740 }
741
742 /* -------------------------------------------------------------------- */
743 /* Make the current record buffer appropriately larger. */
744 /* -------------------------------------------------------------------- */
745 psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
746 psDBF->nRecordLength);
747
748 return( psDBF->nFields-1 );
749 }
750
751 /************************************************************************/
752 /* DBFReadAttribute() */
753 /* */
754 /* Read one of the attribute fields of a record. */
755 /************************************************************************/
756
757 static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
758 char chReqType )
759
760 {
761 int nRecordOffset;
762 unsigned char *pabyRec;
763 void *pReturnField = NULL;
764
765 static double dDoubleField;
766
767 /* -------------------------------------------------------------------- */
768 /* Verify selection. */
769 /* -------------------------------------------------------------------- */
770 if( hEntity < 0 || hEntity >= psDBF->nRecords )
771 return( NULL );
772
773 if( iField < 0 || iField >= psDBF->nFields )
774 return( NULL );
775
776 /* -------------------------------------------------------------------- */
777 /* Have we read the record? */
778 /* -------------------------------------------------------------------- */
779 if( psDBF->nCurrentRecord != hEntity )
780 {
781 DBFFlushRecord( psDBF );
782
783 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
784
785 if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
786 {
787 fprintf( stderr, "fseek(%d) failed on DBF file.\n",
788 nRecordOffset );
789 return NULL;
790 }
791
792 if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength,
793 1, psDBF->fp ) != 1 )
794 {
795 fprintf( stderr, "fread(%d) failed on DBF file.\n",
796 psDBF->nRecordLength );
797 return NULL;
798 }
799
800 psDBF->nCurrentRecord = hEntity;
801 }
802
803 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
804
805 /* -------------------------------------------------------------------- */
806 /* Ensure our field buffer is large enough to hold this buffer. */
807 /* -------------------------------------------------------------------- */
808 if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
809 {
810 nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
811 pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
812 }
813
814 /* -------------------------------------------------------------------- */
815 /* Extract the requested field. */
816 /* -------------------------------------------------------------------- */
817 strncpy( pszStringField,
818 ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
819 psDBF->panFieldSize[iField] );
820 pszStringField[psDBF->panFieldSize[iField]] = '\0';
821
822 pReturnField = pszStringField;
823
824 /* -------------------------------------------------------------------- */
825 /* Decode the field. */
826 /* -------------------------------------------------------------------- */
827 if( chReqType == 'N' )
828 {
829 dDoubleField = atof(pszStringField);
830
831 pReturnField = &dDoubleField;
832 }
833
834 /* -------------------------------------------------------------------- */
835 /* Should we trim white space off the string attribute value? */
836 /* -------------------------------------------------------------------- */
837 #ifdef TRIM_DBF_WHITESPACE
838 else
839 {
840 char *pchSrc, *pchDst;
841
842 pchDst = pchSrc = pszStringField;
843 while( *pchSrc == ' ' )
844 pchSrc++;
845
846 while( *pchSrc != '\0' )
847 *(pchDst++) = *(pchSrc++);
848 *pchDst = '\0';
849
850 while( pchDst != pszStringField && *(--pchDst) == ' ' )
851 *pchDst = '\0';
852 }
853 #endif
854
855 return( pReturnField );
856 }
857
858 /************************************************************************/
859 /* DBFReadIntAttribute() */
860 /* */
861 /* Read an integer attribute. */
862 /************************************************************************/
863
864 int SHPAPI_CALL
865 DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
866
867 {
868 double *pdValue;
869
870 pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
871
872 if( pdValue == NULL )
873 return 0;
874 else
875 return( (int) *pdValue );
876 }
877
878 /************************************************************************/
879 /* DBFReadDoubleAttribute() */
880 /* */
881 /* Read a double attribute. */
882 /************************************************************************/
883
884 double SHPAPI_CALL
885 DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
886
887 {
888 double *pdValue;
889
890 pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
891
892 if( pdValue == NULL )
893 return 0.0;
894 else
895 return( *pdValue );
896 }
897
898 /************************************************************************/
899 /* DBFReadStringAttribute() */
900 /* */
901 /* Read a string attribute. */
902 /************************************************************************/
903
904 const char SHPAPI_CALL1(*)
905 DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
906
907 {
908 return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
909 }
910
911 /************************************************************************/
912 /* DBFReadLogicalAttribute() */
913 /* */
914 /* Read a logical attribute. */
915 /************************************************************************/
916
917 const char SHPAPI_CALL1(*)
918 DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
919
920 {
921 return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
922 }
923
924 /************************************************************************/
925 /* DBFIsAttributeNULL() */
926 /* */
927 /* Return TRUE if value for field is NULL. */
928 /* */
929 /* Contributed by Jim Matthews. */
930 /************************************************************************/
931
932 int SHPAPI_CALL
933 DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
934
935 {
936 const char *pszValue;
937
938 pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
939
940 if( pszValue == NULL )
941 return TRUE;
942
943 switch(psDBF->pachFieldType[iField])
944 {
945 case 'N':
946 case 'F':
947 /* NULL numeric fields have value "****************" */
948 return pszValue[0] == '*';
949
950 case 'D':
951 /* NULL date fields have value "00000000" */
952 return strncmp(pszValue,"00000000",8) == 0;
953
954 case 'L':
955 /* NULL boolean fields have value "?" */
956 return pszValue[0] == '?';
957
958 default:
959 /* empty string fields are considered NULL */
960 return strlen(pszValue) == 0;
961 }
962 }
963
964 /************************************************************************/
965 /* DBFGetFieldCount() */
966 /* */
967 /* Return the number of fields in this table. */
968 /************************************************************************/
969
970 int SHPAPI_CALL
971 DBFGetFieldCount( DBFHandle psDBF )
972
973 {
974 return( psDBF->nFields );
975 }
976
977 /************************************************************************/
978 /* DBFGetRecordCount() */
979 /* */
980 /* Return the number of records in this table. */
981 /************************************************************************/
982
983 int SHPAPI_CALL
984 DBFGetRecordCount( DBFHandle psDBF )
985
986 {
987 return( psDBF->nRecords );
988 }
989
990 /************************************************************************/
991 /* DBFGetFieldInfo() */
992 /* */
993 /* Return any requested information about the field. */
994 /************************************************************************/
995
996 DBFFieldType SHPAPI_CALL
997 DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
998 int * pnWidth, int * pnDecimals )
999
1000 {
1001 if( iField < 0 || iField >= psDBF->nFields )
1002 return( FTInvalid );
1003
1004 if( pnWidth != NULL )
1005 *pnWidth = psDBF->panFieldSize[iField];
1006
1007 if( pnDecimals != NULL )
1008 *pnDecimals = psDBF->panFieldDecimals[iField];
1009
1010 if( pszFieldName != NULL )
1011 {
1012 int i;
1013
1014 strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
1015 pszFieldName[11] = '\0';
1016 for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
1017 pszFieldName[i] = '\0';
1018 }
1019
1020 if ( psDBF->pachFieldType[iField] == 'L' )
1021 return( FTLogical);
1022
1023 else if( psDBF->pachFieldType[iField] == 'N'
1024 || psDBF->pachFieldType[iField] == 'F'
1025 || psDBF->pachFieldType[iField] == 'D' )
1026 {
1027 if( psDBF->panFieldDecimals[iField] > 0 )
1028 return( FTDouble );
1029 else
1030 return( FTInteger );
1031 }
1032 else
1033 {
1034 return( FTString );
1035 }
1036 }
1037
1038 /************************************************************************/
1039 /* DBFWriteAttribute() */
1040 /* */
1041 /* Write an attribute record to the file. */
1042 /************************************************************************/
1043
1044 static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
1045 void * pValue )
1046
1047 {
1048 int nRecordOffset, i, j, nRetResult = TRUE;
1049 unsigned char *pabyRec;
1050 char szSField[400], szFormat[20];
1051
1052 /* -------------------------------------------------------------------- */
1053 /* Is this a valid record? */
1054 /* -------------------------------------------------------------------- */
1055 if( hEntity < 0 || hEntity > psDBF->nRecords )
1056 return( FALSE );
1057
1058 if( psDBF->bNoHeader )
1059 DBFWriteHeader(psDBF);
1060
1061 /* -------------------------------------------------------------------- */
1062 /* Is this a brand new record? */
1063 /* -------------------------------------------------------------------- */
1064 if( hEntity == psDBF->nRecords )
1065 {
1066 DBFFlushRecord( psDBF );
1067
1068 psDBF->nRecords++;
1069 for( i = 0; i < psDBF->nRecordLength; i++ )
1070 psDBF->pszCurrentRecord[i] = ' ';
1071
1072 psDBF->nCurrentRecord = hEntity;
1073 }
1074
1075 /* -------------------------------------------------------------------- */
1076 /* Is this an existing record, but different than the last one */
1077 /* we accessed? */
1078 /* -------------------------------------------------------------------- */
1079 if( psDBF->nCurrentRecord != hEntity )
1080 {
1081 DBFFlushRecord( psDBF );
1082
1083 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1084
1085 fseek( psDBF->fp, nRecordOffset, 0 );
1086 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1087
1088 psDBF->nCurrentRecord = hEntity;
1089 }
1090
1091 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1092
1093 psDBF->bCurrentRecordModified = TRUE;
1094 psDBF->bUpdated = TRUE;
1095
1096 /* -------------------------------------------------------------------- */
1097 /* Translate NULL value to valid DBF file representation. */
1098 /* */
1099 /* Contributed by Jim Matthews. */
1100 /* -------------------------------------------------------------------- */
1101 if( pValue == NULL )
1102 {
1103 switch(psDBF->pachFieldType[iField])
1104 {
1105 case 'N':
1106 case 'F':
1107 /* NULL numeric fields have value "****************" */
1108 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
1109 psDBF->panFieldSize[iField] );
1110 break;
1111
1112 case 'D':
1113 /* NULL date fields have value "00000000" */
1114 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
1115 psDBF->panFieldSize[iField] );
1116 break;
1117
1118 case 'L':
1119 /* NULL boolean fields have value "?" */
1120 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
1121 psDBF->panFieldSize[iField] );
1122 break;
1123
1124 default:
1125 /* empty string fields are considered NULL */
1126 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0',
1127 psDBF->panFieldSize[iField] );
1128 break;
1129 }
1130 return TRUE;
1131 }
1132
1133 /* -------------------------------------------------------------------- */
1134 /* Assign all the record fields. */
1135 /* -------------------------------------------------------------------- */
1136 switch( psDBF->pachFieldType[iField] )
1137 {
1138 case 'D':
1139 case 'N':
1140 case 'F':
1141 if( psDBF->panFieldDecimals[iField] == 0 )
1142 {
1143 int nWidth = psDBF->panFieldSize[iField];
1144
1145 if( sizeof(szSField)-2 < nWidth )
1146 nWidth = sizeof(szSField)-2;
1147
1148 sprintf( szFormat, "%%%dd", nWidth );
1149 sprintf(szSField, szFormat, (int) *((double *) pValue) );
1150 if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
1151 {
1152 szSField[psDBF->panFieldSize[iField]] = '\0';
1153 nRetResult = FALSE;
1154 }
1155
1156 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1157 szSField, strlen(szSField) );
1158 }
1159 else
1160 {
1161 int nWidth = psDBF->panFieldSize[iField];
1162
1163 if( sizeof(szSField)-2 < nWidth )
1164 nWidth = sizeof(szSField)-2;
1165
1166 sprintf( szFormat, "%%%d.%df",
1167 nWidth, psDBF->panFieldDecimals[iField] );
1168 sprintf(szSField, szFormat, *((double *) pValue) );
1169 if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
1170 {
1171 szSField[psDBF->panFieldSize[iField]] = '\0';
1172 nRetResult = FALSE;
1173 }
1174 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1175 szSField, strlen(szSField) );
1176 }
1177 break;
1178
1179 case 'L':
1180 if (psDBF->panFieldSize[iField] >= 1 &&
1181 (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
1182 *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
1183 break;
1184
1185 default:
1186 if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1187 {
1188 j = psDBF->panFieldSize[iField];
1189 nRetResult = FALSE;
1190 }
1191 else
1192 {
1193 memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1194 psDBF->panFieldSize[iField] );
1195 j = strlen((char *) pValue);
1196 }
1197
1198 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1199 (char *) pValue, j );
1200 break;
1201 }
1202
1203 return( nRetResult );
1204 }
1205
1206 /************************************************************************/
1207 /* DBFWriteAttributeDirectly() */
1208 /* */
1209 /* Write an attribute record to the file, but without any */
1210 /* reformatting based on type. The provided buffer is written */
1211 /* as is to the field position in the record. */
1212 /************************************************************************/
1213
1214 int SHPAPI_CALL
1215 DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1216 void * pValue )
1217
1218 {
1219 int nRecordOffset, i, j;
1220 unsigned char *pabyRec;
1221
1222 /* -------------------------------------------------------------------- */
1223 /* Is this a valid record? */
1224 /* -------------------------------------------------------------------- */
1225 if( hEntity < 0 || hEntity > psDBF->nRecords )
1226 return( FALSE );
1227
1228 if( psDBF->bNoHeader )
1229 DBFWriteHeader(psDBF);
1230
1231 /* -------------------------------------------------------------------- */
1232 /* Is this a brand new record? */
1233 /* -------------------------------------------------------------------- */
1234 if( hEntity == psDBF->nRecords )
1235 {
1236 DBFFlushRecord( psDBF );
1237
1238 psDBF->nRecords++;
1239 for( i = 0; i < psDBF->nRecordLength; i++ )
1240 psDBF->pszCurrentRecord[i] = ' ';
1241
1242 psDBF->nCurrentRecord = hEntity;
1243 }
1244
1245 /* -------------------------------------------------------------------- */
1246 /* Is this an existing record, but different than the last one */
1247 /* we accessed? */
1248 /* -------------------------------------------------------------------- */
1249 if( psDBF->nCurrentRecord != hEntity )
1250 {
1251 DBFFlushRecord( psDBF );
1252
1253 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1254
1255 fseek( psDBF->fp, nRecordOffset, 0 );
1256 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1257
1258 psDBF->nCurrentRecord = hEntity;
1259 }
1260
1261 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1262
1263 /* -------------------------------------------------------------------- */
1264 /* Assign all the record fields. */
1265 /* -------------------------------------------------------------------- */
1266 if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1267 j = psDBF->panFieldSize[iField];
1268 else
1269 {
1270 memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1271 psDBF->panFieldSize[iField] );
1272 j = strlen((char *) pValue);
1273 }
1274
1275 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1276 (char *) pValue, j );
1277
1278 psDBF->bCurrentRecordModified = TRUE;
1279 psDBF->bUpdated = TRUE;
1280
1281 return( TRUE );
1282 }
1283
1284 /************************************************************************/
1285 /* DBFWriteDoubleAttribute() */
1286 /* */
1287 /* Write a double attribute. */
1288 /************************************************************************/
1289
1290 int SHPAPI_CALL
1291 DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
1292 double dValue )
1293
1294 {
1295 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1296 }
1297
1298 /************************************************************************/
1299 /* DBFWriteIntegerAttribute() */
1300 /* */
1301 /* Write a integer attribute. */
1302 /************************************************************************/
1303
1304 int SHPAPI_CALL
1305 DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
1306 int nValue )
1307
1308 {
1309 double dValue = nValue;
1310
1311 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1312 }
1313
1314 /************************************************************************/
1315 /* DBFWriteStringAttribute() */
1316 /* */
1317 /* Write a string attribute. */
1318 /************************************************************************/
1319
1320 int SHPAPI_CALL
1321 DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
1322 const char * pszValue )
1323
1324 {
1325 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
1326 }
1327
1328 /************************************************************************/
1329 /* DBFWriteNULLAttribute() */
1330 /* */
1331 /* Write a string attribute. */
1332 /************************************************************************/
1333
1334 int SHPAPI_CALL
1335 DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
1336
1337 {
1338 return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
1339 }
1340
1341 /************************************************************************/
1342 /* DBFWriteLogicalAttribute() */
1343 /* */
1344 /* Write a logical attribute. */
1345 /************************************************************************/
1346
1347 int SHPAPI_CALL
1348 DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
1349 const char lValue)
1350
1351 {
1352 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
1353 }
1354
1355 /************************************************************************/
1356 /* DBFWriteTuple() */
1357 /* */
1358 /* Write an attribute record to the file. */
1359 /************************************************************************/
1360
1361 int SHPAPI_CALL
1362 DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
1363
1364 {
1365 int nRecordOffset, i;
1366 unsigned char *pabyRec;
1367
1368 /* -------------------------------------------------------------------- */
1369 /* Is this a valid record? */
1370 /* -------------------------------------------------------------------- */
1371 if( hEntity < 0 || hEntity > psDBF->nRecords )
1372 return( FALSE );
1373
1374 if( psDBF->bNoHeader )
1375 DBFWriteHeader(psDBF);
1376
1377 /* -------------------------------------------------------------------- */
1378 /* Is this a brand new record? */
1379 /* -------------------------------------------------------------------- */
1380 if( hEntity == psDBF->nRecords )
1381 {
1382 DBFFlushRecord( psDBF );
1383
1384 psDBF->nRecords++;
1385 for( i = 0; i < psDBF->nRecordLength; i++ )
1386 psDBF->pszCurrentRecord[i] = ' ';
1387
1388 psDBF->nCurrentRecord = hEntity;
1389 }
1390
1391 /* -------------------------------------------------------------------- */
1392 /* Is this an existing record, but different than the last one */
1393 /* we accessed? */
1394 /* -------------------------------------------------------------------- */
1395 if( psDBF->nCurrentRecord != hEntity )
1396 {
1397 DBFFlushRecord( psDBF );
1398
1399 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1400
1401 fseek( psDBF->fp, nRecordOffset, 0 );
1402 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1403
1404 psDBF->nCurrentRecord = hEntity;
1405 }
1406
1407 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1408
1409 memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
1410
1411 psDBF->bCurrentRecordModified = TRUE;
1412 psDBF->bUpdated = TRUE;
1413
1414 return( TRUE );
1415 }
1416
1417 /************************************************************************/
1418 /* DBFReadTuple() */
1419 /* */
1420 /* Read one of the attribute fields of a record. */
1421 /************************************************************************/
1422
1423 const char SHPAPI_CALL1(*)
1424 DBFReadTuple(DBFHandle psDBF, int hEntity )
1425
1426 {
1427 int nRecordOffset;
1428 unsigned char *pabyRec;
1429 static char *pReturnTuple = NULL;
1430
1431 static int nTupleLen = 0;
1432
1433 /* -------------------------------------------------------------------- */
1434 /* Have we read the record? */
1435 /* -------------------------------------------------------------------- */
1436 if( hEntity < 0 || hEntity >= psDBF->nRecords )
1437 return( NULL );
1438
1439 if( psDBF->nCurrentRecord != hEntity )
1440 {
1441 DBFFlushRecord( psDBF );
1442
1443 nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1444
1445 fseek( psDBF->fp, nRecordOffset, 0 );
1446 fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1447
1448 psDBF->nCurrentRecord = hEntity;
1449 }
1450
1451 pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1452
1453 if ( nTupleLen < psDBF->nRecordLength) {
1454 nTupleLen = psDBF->nRecordLength;
1455 pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
1456 }
1457
1458 memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
1459
1460 return( pReturnTuple );
1461 }
1462
1463 /************************************************************************/
1464 /* DBFCloneEmpty() */
1465 /* */
1466 /* Read one of the attribute fields of a record. */
1467 /************************************************************************/
1468
1469 DBFHandle SHPAPI_CALL
1470 DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
1471 {
1472 DBFHandle newDBF;
1473
1474 newDBF = DBFCreate ( pszFilename );
1475 if ( newDBF == NULL ) return ( NULL );
1476
1477 newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
1478 memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
1479
1480 newDBF->nFields = psDBF->nFields;
1481 newDBF->nRecordLength = psDBF->nRecordLength;
1482 newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
1483
1484 newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
1485 memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1486 newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
1487 memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1488 newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
1489 memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1490 newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
1491 memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
1492
1493 newDBF->bNoHeader = TRUE;
1494 newDBF->bUpdated = TRUE;
1495
1496 DBFWriteHeader ( newDBF );
1497 DBFClose ( newDBF );
1498
1499 newDBF = DBFOpen ( pszFilename, "rb+" );
1500
1501 return ( newDBF );
1502 }
1503
1504 /************************************************************************/
1505 /* DBFGetNativeFieldType() */
1506 /* */
1507 /* Return the DBase field type for the specified field. */
1508 /* */
1509 /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
1510 /* 'N' (Numeric, with or without decimal), */
1511 /* 'L' (Logical), */
1512 /* 'M' (Memo: 10 digits .DBT block ptr) */
1513 /************************************************************************/
1514
1515 char SHPAPI_CALL
1516 DBFGetNativeFieldType( DBFHandle psDBF, int iField )
1517
1518 {
1519 if( iField >=0 && iField < psDBF->nFields )
1520 return psDBF->pachFieldType[iField];
1521
1522 return ' ';
1523 }
1524
1525 /************************************************************************/
1526 /* str_to_upper() */
1527 /************************************************************************/
1528
1529 static void str_to_upper (char *string)
1530 {
1531 int len;
1532 short i = -1;
1533
1534 len = strlen (string);
1535
1536 while (++i < len)
1537 if (isalpha(string[i]) && islower(string[i]))
1538 string[i] = (char) toupper ((int)string[i]);
1539 }
1540
1541 /************************************************************************/
1542 /* DBFGetFieldIndex() */
1543 /* */
1544 /* Get the index number for a field in a .dbf file. */
1545 /* */
1546 /* Contributed by Jim Matthews. */
1547 /************************************************************************/
1548
1549 int SHPAPI_CALL
1550 DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
1551
1552 {
1553 char name[12], name1[12], name2[12];
1554 int i;
1555
1556 strncpy(name1, pszFieldName,11);
1557 name1[11] = '\0';
1558 str_to_upper(name1);
1559
1560 for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
1561 {
1562 DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
1563 strncpy(name2,name,11);
1564 str_to_upper(name2);
1565
1566 if(!strncmp(name1,name2,10))
1567 return(i);
1568 }
1569 return(-1);
1570 }

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26