/[thuban]/branches/WIP-pyshapelib-bramz/libraries/shapelib/dbfopen.c
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/libraries/shapelib/dbfopen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2751 - (hide 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 jan 1612 /******************************************************************************
2     * $Id$
3     *
4     * Project: Shapelib
5     * Purpose: Implementation of .dbf access API documented in dbf_api.html.
6 bh 1769 * Author: Frank Warmerdam, [email protected]
7 jan 1612 *
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 bh 2212 * 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 jan 1612 *
41 bh 2212 * * 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 bh 1769 * Revision 1.48 2003/03/10 14:51:27 warmerda
92     * DBFWrite* calls now return FALSE if they have to truncate
93 jan 1612 *
94 bh 1769 * Revision 1.47 2002/11/20 03:32:22 warmerda
95     * Ensure field name in DBFGetFieldIndex() is properly terminated.
96 jan 1612 *
97 bh 1769 * 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 jan 1612 * 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 bramz 2751 #if defined(_WIN32) || defined(_WIN64)
255     # define MS_WINDOWS
256     #endif
257    
258 jan 1612 static int nStringFieldLen = 0;
259     static char * pszStringField = NULL;
260    
261     /************************************************************************/
262 bernhard 2703 /* 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 jan 1612 /* 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 bh 2212 /* write out a dummy date */
330     abyHeader[1] = 95; /* YY */
331     abyHeader[2] = 7; /* MM */
332     abyHeader[3] = 26; /* DD */
333 jan 1612
334 bh 2212 /* record count preset at zero */
335    
336     abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
337     abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
338 jan 1612
339 bh 2212 abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
340     abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
341 jan 1612
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 bh 2212 /* 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 jan 1612 /* DBFOpen() */
416     /* */
417     /* Open a .dbf file. */
418     /************************************************************************/
419    
420     DBFHandle SHPAPI_CALL
421     DBFOpen( const char * pszFilename, const char * pszAccess )
422    
423     {
424 bramz 2751 FILE* fp;
425     int i;
426 jan 1612 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 bramz 2751 fp = fopen( pszFullname, pszAccess );
460 jan 1612
461 bramz 2751 if( fp == NULL )
462 jan 1612 {
463     sprintf( pszFullname, "%s.DBF", pszBasename );
464 bramz 2751 fp = fopen(pszFullname, pszAccess );
465 jan 1612 }
466    
467     free( pszBasename );
468     free( pszFullname );
469 bramz 2751
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 jan 1612 {
526 bramz 2751 swprintf( pszFullname, L"%s.DBF", pszBasename );
527     fp = _wfopen(pszFullname, pszAccess );
528 jan 1612 }
529 bramz 2751
530     free( pszBasename );
531     free( pszFullname );
532 jan 1612
533 bramz 2751 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 jan 1612 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 bh 1769 if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
571     {
572     fclose( psDBF->fp );
573     free( pabyBuf );
574     free( psDBF );
575     return NULL;
576     }
577 jan 1612
578 bh 1769 psDBF->nRecords =
579 jan 1612 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 bh 1769 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 jan 1612
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 bramz 2748 if( psDBF == NULL )
645 bramz 2747 return;
646    
647 jan 1612 /* -------------------------------------------------------------------- */
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 bh 2212 DBFUpdateHeader( psDBF );
661 jan 1612
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 bramz 2751 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 jan 1612 /* -------------------------------------------------------------------- */
758 bramz 2751 /* 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 jan 1612 /* 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 bramz 2751
836    
837 jan 1612 /************************************************************************/
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 bh 1769 if( nWidth < 1 )
865     return -1;
866    
867 jan 1612 /* -------------------------------------------------------------------- */
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 bh 1769 if( eType == FTLogical )
894     psDBF->pachFieldType[psDBF->nFields-1] = 'L';
895     else if( eType == FTString )
896 jan 1612 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 bh 2212 pszFInfo[16] = (unsigned char) (nWidth % 256);
923     pszFInfo[17] = (unsigned char) (nWidth / 256);
924 jan 1612 }
925     else
926     {
927 bh 2212 pszFInfo[16] = (unsigned char) nWidth;
928     pszFInfo[17] = (unsigned char) nDecimals;
929 jan 1612 }
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 bernhard 2703 dDoubleField = (*atof_function)(pszStringField);
1019 jan 1612
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 bh 1769 /* 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 jan 1612 /* 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 bh 2212 if( pszValue == NULL )
1130     return TRUE;
1131    
1132 jan 1612 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 bh 1769 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 jan 1612 {
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 bh 1769 int nRecordOffset, i, j, nRetResult = TRUE;
1238 jan 1612 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 bh 1769 {
1341 jan 1612 szSField[psDBF->panFieldSize[iField]] = '\0';
1342 bh 1769 nRetResult = FALSE;
1343     }
1344 jan 1612
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 bh 1769 {
1360 jan 1612 szSField[psDBF->panFieldSize[iField]] = '\0';
1361 bh 1769 nRetResult = FALSE;
1362     }
1363 jan 1612 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1364     szSField, strlen(szSField) );
1365     }
1366     break;
1367    
1368 bh 1769 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 jan 1612 default:
1375     if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1376 bh 1769 {
1377 jan 1612 j = psDBF->panFieldSize[iField];
1378 bh 1769 nRetResult = FALSE;
1379     }
1380 jan 1612 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 bh 1769 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 bh 2212 int SHPAPI_CALL
1404     DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1405 bh 1769 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 jan 1612 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 bh 1769 /* 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 jan 1612 /* 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 bramz 2751 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 jan 1612 if ( newDBF == NULL ) return ( NULL );
1713    
1714 bh 1769 newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
1715 jan 1612 memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
1716    
1717     newDBF->nFields = psDBF->nFields;
1718     newDBF->nRecordLength = psDBF->nRecordLength;
1719 bh 1769 newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
1720 jan 1612
1721 bh 1769 newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
1722 jan 1612 memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1723 bh 1769 newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
1724 jan 1612 memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1725 bh 1769 newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
1726 jan 1612 memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1727 bh 1769 newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
1728 jan 1612 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 bh 2212 string[i] = (char) toupper ((int)string[i]);
1771 jan 1612 }
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 bh 1769 name1[11] = '\0';
1790 jan 1612 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