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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26