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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26