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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26