/[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 1612 - (show annotations)
Tue Aug 19 21:29:25 2003 UTC (21 years, 6 months ago) by jan
Original Path: trunk/thuban/libraries/shapelib/dbfopen.c
File MIME type: text/plain
File size: 47197 byte(s)
These files have been moved here from thuban/extensions/shapelib/
See there in the Attic for the older history.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26