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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26