/[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 2734 - (hide annotations)
Thu Mar 1 12:42:59 2007 UTC (18 years ago) by bramz
File MIME type: text/plain
File size: 56180 byte(s)
made a copy
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     /* -------------------------------------------------------------------- */
557     /* Write out header if not already written. */
558     /* -------------------------------------------------------------------- */
559     if( psDBF->bNoHeader )
560     DBFWriteHeader( psDBF );
561    
562     DBFFlushRecord( psDBF );
563    
564     /* -------------------------------------------------------------------- */
565     /* Update last access date, and number of records if we have */
566     /* write access. */
567     /* -------------------------------------------------------------------- */
568     if( psDBF->bUpdated )
569 bh 2212 DBFUpdateHeader( psDBF );
570 jan 1612
571     /* -------------------------------------------------------------------- */
572     /* Close, and free resources. */
573     /* -------------------------------------------------------------------- */
574     fclose( psDBF->fp );
575    
576     if( psDBF->panFieldOffset != NULL )
577     {
578     free( psDBF->panFieldOffset );
579     free( psDBF->panFieldSize );
580     free( psDBF->panFieldDecimals );
581     free( psDBF->pachFieldType );
582     }
583    
584     free( psDBF->pszHeader );
585     free( psDBF->pszCurrentRecord );
586    
587     free( psDBF );
588    
589     if( pszStringField != NULL )
590     {
591     free( pszStringField );
592     pszStringField = NULL;
593     nStringFieldLen = 0;
594     }
595     }
596    
597     /************************************************************************/
598     /* DBFCreate() */
599     /* */
600     /* Create a new .dbf file. */
601     /************************************************************************/
602    
603     DBFHandle SHPAPI_CALL
604     DBFCreate( const char * pszFilename )
605    
606     {
607     DBFHandle psDBF;
608     FILE *fp;
609     char *pszFullname, *pszBasename;
610     int i;
611    
612     /* -------------------------------------------------------------------- */
613     /* Compute the base (layer) name. If there is any extension */
614     /* on the passed in filename we will strip it off. */
615     /* -------------------------------------------------------------------- */
616     pszBasename = (char *) malloc(strlen(pszFilename)+5);
617     strcpy( pszBasename, pszFilename );
618     for( i = strlen(pszBasename)-1;
619     i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
620     && pszBasename[i] != '\\';
621     i-- ) {}
622    
623     if( pszBasename[i] == '.' )
624     pszBasename[i] = '\0';
625    
626     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
627     sprintf( pszFullname, "%s.dbf", pszBasename );
628     free( pszBasename );
629    
630     /* -------------------------------------------------------------------- */
631     /* Create the file. */
632     /* -------------------------------------------------------------------- */
633     fp = fopen( pszFullname, "wb" );
634     if( fp == NULL )
635     return( NULL );
636    
637     fputc( 0, fp );
638     fclose( fp );
639    
640     fp = fopen( pszFullname, "rb+" );
641     if( fp == NULL )
642     return( NULL );
643    
644     free( pszFullname );
645    
646     /* -------------------------------------------------------------------- */
647     /* Create the info structure. */
648     /* -------------------------------------------------------------------- */
649     psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
650    
651     psDBF->fp = fp;
652     psDBF->nRecords = 0;
653     psDBF->nFields = 0;
654     psDBF->nRecordLength = 1;
655     psDBF->nHeaderLength = 33;
656    
657     psDBF->panFieldOffset = NULL;
658     psDBF->panFieldSize = NULL;
659     psDBF->panFieldDecimals = NULL;
660     psDBF->pachFieldType = NULL;
661     psDBF->pszHeader = NULL;
662    
663     psDBF->nCurrentRecord = -1;
664     psDBF->bCurrentRecordModified = FALSE;
665     psDBF->pszCurrentRecord = NULL;
666    
667     psDBF->bNoHeader = TRUE;
668    
669     return( psDBF );
670     }
671    
672     /************************************************************************/
673     /* DBFAddField() */
674     /* */
675     /* Add a field to a newly created .dbf file before any records */
676     /* are written. */
677     /************************************************************************/
678    
679     int SHPAPI_CALL
680     DBFAddField(DBFHandle psDBF, const char * pszFieldName,
681     DBFFieldType eType, int nWidth, int nDecimals )
682    
683     {
684     char *pszFInfo;
685     int i;
686    
687     /* -------------------------------------------------------------------- */
688     /* Do some checking to ensure we can add records to this file. */
689     /* -------------------------------------------------------------------- */
690     if( psDBF->nRecords > 0 )
691     return( -1 );
692    
693     if( !psDBF->bNoHeader )
694     return( -1 );
695    
696     if( eType != FTDouble && nDecimals != 0 )
697     return( -1 );
698    
699 bh 1769 if( nWidth < 1 )
700     return -1;
701    
702 jan 1612 /* -------------------------------------------------------------------- */
703     /* SfRealloc all the arrays larger to hold the additional field */
704     /* information. */
705     /* -------------------------------------------------------------------- */
706     psDBF->nFields++;
707    
708     psDBF->panFieldOffset = (int *)
709     SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
710    
711     psDBF->panFieldSize = (int *)
712     SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
713    
714     psDBF->panFieldDecimals = (int *)
715     SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
716    
717     psDBF->pachFieldType = (char *)
718     SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
719    
720     /* -------------------------------------------------------------------- */
721     /* Assign the new field information fields. */
722     /* -------------------------------------------------------------------- */
723     psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
724     psDBF->nRecordLength += nWidth;
725     psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
726     psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
727    
728 bh 1769 if( eType == FTLogical )
729     psDBF->pachFieldType[psDBF->nFields-1] = 'L';
730     else if( eType == FTString )
731 jan 1612 psDBF->pachFieldType[psDBF->nFields-1] = 'C';
732     else
733     psDBF->pachFieldType[psDBF->nFields-1] = 'N';
734    
735     /* -------------------------------------------------------------------- */
736     /* Extend the required header information. */
737     /* -------------------------------------------------------------------- */
738     psDBF->nHeaderLength += 32;
739     psDBF->bUpdated = FALSE;
740    
741     psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
742    
743     pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
744    
745     for( i = 0; i < 32; i++ )
746     pszFInfo[i] = '\0';
747    
748     if( (int) strlen(pszFieldName) < 10 )
749     strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
750     else
751     strncpy( pszFInfo, pszFieldName, 10);
752    
753     pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
754    
755     if( eType == FTString )
756     {
757 bh 2212 pszFInfo[16] = (unsigned char) (nWidth % 256);
758     pszFInfo[17] = (unsigned char) (nWidth / 256);
759 jan 1612 }
760     else
761     {
762 bh 2212 pszFInfo[16] = (unsigned char) nWidth;
763     pszFInfo[17] = (unsigned char) nDecimals;
764 jan 1612 }
765    
766     /* -------------------------------------------------------------------- */
767     /* Make the current record buffer appropriately larger. */
768     /* -------------------------------------------------------------------- */
769     psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
770     psDBF->nRecordLength);
771    
772     return( psDBF->nFields-1 );
773     }
774    
775     /************************************************************************/
776     /* DBFReadAttribute() */
777     /* */
778     /* Read one of the attribute fields of a record. */
779     /************************************************************************/
780    
781     static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
782     char chReqType )
783    
784     {
785     int nRecordOffset;
786     unsigned char *pabyRec;
787     void *pReturnField = NULL;
788    
789     static double dDoubleField;
790    
791     /* -------------------------------------------------------------------- */
792     /* Verify selection. */
793     /* -------------------------------------------------------------------- */
794     if( hEntity < 0 || hEntity >= psDBF->nRecords )
795     return( NULL );
796    
797     if( iField < 0 || iField >= psDBF->nFields )
798     return( NULL );
799    
800     /* -------------------------------------------------------------------- */
801     /* Have we read the record? */
802     /* -------------------------------------------------------------------- */
803     if( psDBF->nCurrentRecord != hEntity )
804     {
805     DBFFlushRecord( psDBF );
806    
807     nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
808    
809     if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
810     {
811     fprintf( stderr, "fseek(%d) failed on DBF file.\n",
812     nRecordOffset );
813     return NULL;
814     }
815    
816     if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength,
817     1, psDBF->fp ) != 1 )
818     {
819     fprintf( stderr, "fread(%d) failed on DBF file.\n",
820     psDBF->nRecordLength );
821     return NULL;
822     }
823    
824     psDBF->nCurrentRecord = hEntity;
825     }
826    
827     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
828    
829     /* -------------------------------------------------------------------- */
830     /* Ensure our field buffer is large enough to hold this buffer. */
831     /* -------------------------------------------------------------------- */
832     if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
833     {
834     nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
835     pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
836     }
837    
838     /* -------------------------------------------------------------------- */
839     /* Extract the requested field. */
840     /* -------------------------------------------------------------------- */
841     strncpy( pszStringField,
842     ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
843     psDBF->panFieldSize[iField] );
844     pszStringField[psDBF->panFieldSize[iField]] = '\0';
845    
846     pReturnField = pszStringField;
847    
848     /* -------------------------------------------------------------------- */
849     /* Decode the field. */
850     /* -------------------------------------------------------------------- */
851     if( chReqType == 'N' )
852     {
853 bernhard 2703 dDoubleField = (*atof_function)(pszStringField);
854 jan 1612
855     pReturnField = &dDoubleField;
856     }
857    
858     /* -------------------------------------------------------------------- */
859     /* Should we trim white space off the string attribute value? */
860     /* -------------------------------------------------------------------- */
861     #ifdef TRIM_DBF_WHITESPACE
862     else
863     {
864     char *pchSrc, *pchDst;
865    
866     pchDst = pchSrc = pszStringField;
867     while( *pchSrc == ' ' )
868     pchSrc++;
869    
870     while( *pchSrc != '\0' )
871     *(pchDst++) = *(pchSrc++);
872     *pchDst = '\0';
873    
874     while( pchDst != pszStringField && *(--pchDst) == ' ' )
875     *pchDst = '\0';
876     }
877     #endif
878    
879     return( pReturnField );
880     }
881    
882     /************************************************************************/
883     /* DBFReadIntAttribute() */
884     /* */
885     /* Read an integer attribute. */
886     /************************************************************************/
887    
888     int SHPAPI_CALL
889     DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
890    
891     {
892     double *pdValue;
893    
894     pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
895    
896     if( pdValue == NULL )
897     return 0;
898     else
899     return( (int) *pdValue );
900     }
901    
902     /************************************************************************/
903     /* DBFReadDoubleAttribute() */
904     /* */
905     /* Read a double attribute. */
906     /************************************************************************/
907    
908     double SHPAPI_CALL
909     DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
910    
911     {
912     double *pdValue;
913    
914     pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
915    
916     if( pdValue == NULL )
917     return 0.0;
918     else
919     return( *pdValue );
920     }
921    
922     /************************************************************************/
923     /* DBFReadStringAttribute() */
924     /* */
925     /* Read a string attribute. */
926     /************************************************************************/
927    
928     const char SHPAPI_CALL1(*)
929     DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
930    
931     {
932     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
933     }
934    
935     /************************************************************************/
936 bh 1769 /* DBFReadLogicalAttribute() */
937     /* */
938     /* Read a logical attribute. */
939     /************************************************************************/
940    
941     const char SHPAPI_CALL1(*)
942     DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
943    
944     {
945     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
946     }
947    
948     /************************************************************************/
949 jan 1612 /* DBFIsAttributeNULL() */
950     /* */
951     /* Return TRUE if value for field is NULL. */
952     /* */
953     /* Contributed by Jim Matthews. */
954     /************************************************************************/
955    
956     int SHPAPI_CALL
957     DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
958    
959     {
960     const char *pszValue;
961    
962     pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
963    
964 bh 2212 if( pszValue == NULL )
965     return TRUE;
966    
967 jan 1612 switch(psDBF->pachFieldType[iField])
968     {
969     case 'N':
970     case 'F':
971     /* NULL numeric fields have value "****************" */
972     return pszValue[0] == '*';
973    
974     case 'D':
975     /* NULL date fields have value "00000000" */
976     return strncmp(pszValue,"00000000",8) == 0;
977    
978     case 'L':
979     /* NULL boolean fields have value "?" */
980     return pszValue[0] == '?';
981    
982     default:
983     /* empty string fields are considered NULL */
984     return strlen(pszValue) == 0;
985     }
986     }
987    
988     /************************************************************************/
989     /* DBFGetFieldCount() */
990     /* */
991     /* Return the number of fields in this table. */
992     /************************************************************************/
993    
994     int SHPAPI_CALL
995     DBFGetFieldCount( DBFHandle psDBF )
996    
997     {
998     return( psDBF->nFields );
999     }
1000    
1001     /************************************************************************/
1002     /* DBFGetRecordCount() */
1003     /* */
1004     /* Return the number of records in this table. */
1005     /************************************************************************/
1006    
1007     int SHPAPI_CALL
1008     DBFGetRecordCount( DBFHandle psDBF )
1009    
1010     {
1011     return( psDBF->nRecords );
1012     }
1013    
1014     /************************************************************************/
1015     /* DBFGetFieldInfo() */
1016     /* */
1017     /* Return any requested information about the field. */
1018     /************************************************************************/
1019    
1020     DBFFieldType SHPAPI_CALL
1021     DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
1022     int * pnWidth, int * pnDecimals )
1023    
1024     {
1025     if( iField < 0 || iField >= psDBF->nFields )
1026     return( FTInvalid );
1027    
1028     if( pnWidth != NULL )
1029     *pnWidth = psDBF->panFieldSize[iField];
1030    
1031     if( pnDecimals != NULL )
1032     *pnDecimals = psDBF->panFieldDecimals[iField];
1033    
1034     if( pszFieldName != NULL )
1035     {
1036     int i;
1037    
1038     strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
1039     pszFieldName[11] = '\0';
1040     for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
1041     pszFieldName[i] = '\0';
1042     }
1043    
1044 bh 1769 if ( psDBF->pachFieldType[iField] == 'L' )
1045     return( FTLogical);
1046    
1047     else if( psDBF->pachFieldType[iField] == 'N'
1048     || psDBF->pachFieldType[iField] == 'F'
1049     || psDBF->pachFieldType[iField] == 'D' )
1050 jan 1612 {
1051     if( psDBF->panFieldDecimals[iField] > 0 )
1052     return( FTDouble );
1053     else
1054     return( FTInteger );
1055     }
1056     else
1057     {
1058     return( FTString );
1059     }
1060     }
1061    
1062     /************************************************************************/
1063     /* DBFWriteAttribute() */
1064     /* */
1065     /* Write an attribute record to the file. */
1066     /************************************************************************/
1067    
1068     static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
1069     void * pValue )
1070    
1071     {
1072 bh 1769 int nRecordOffset, i, j, nRetResult = TRUE;
1073 jan 1612 unsigned char *pabyRec;
1074     char szSField[400], szFormat[20];
1075    
1076     /* -------------------------------------------------------------------- */
1077     /* Is this a valid record? */
1078     /* -------------------------------------------------------------------- */
1079     if( hEntity < 0 || hEntity > psDBF->nRecords )
1080     return( FALSE );
1081    
1082     if( psDBF->bNoHeader )
1083     DBFWriteHeader(psDBF);
1084    
1085     /* -------------------------------------------------------------------- */
1086     /* Is this a brand new record? */
1087     /* -------------------------------------------------------------------- */
1088     if( hEntity == psDBF->nRecords )
1089     {
1090     DBFFlushRecord( psDBF );
1091    
1092     psDBF->nRecords++;
1093     for( i = 0; i < psDBF->nRecordLength; i++ )
1094     psDBF->pszCurrentRecord[i] = ' ';
1095    
1096     psDBF->nCurrentRecord = hEntity;
1097     }
1098    
1099     /* -------------------------------------------------------------------- */
1100     /* Is this an existing record, but different than the last one */
1101     /* we accessed? */
1102     /* -------------------------------------------------------------------- */
1103     if( psDBF->nCurrentRecord != hEntity )
1104     {
1105     DBFFlushRecord( psDBF );
1106    
1107     nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1108    
1109     fseek( psDBF->fp, nRecordOffset, 0 );
1110     fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1111    
1112     psDBF->nCurrentRecord = hEntity;
1113     }
1114    
1115     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1116    
1117     psDBF->bCurrentRecordModified = TRUE;
1118     psDBF->bUpdated = TRUE;
1119    
1120     /* -------------------------------------------------------------------- */
1121     /* Translate NULL value to valid DBF file representation. */
1122     /* */
1123     /* Contributed by Jim Matthews. */
1124     /* -------------------------------------------------------------------- */
1125     if( pValue == NULL )
1126     {
1127     switch(psDBF->pachFieldType[iField])
1128     {
1129     case 'N':
1130     case 'F':
1131     /* NULL numeric fields have value "****************" */
1132     memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
1133     psDBF->panFieldSize[iField] );
1134     break;
1135    
1136     case 'D':
1137     /* NULL date fields have value "00000000" */
1138     memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
1139     psDBF->panFieldSize[iField] );
1140     break;
1141    
1142     case 'L':
1143     /* NULL boolean fields have value "?" */
1144     memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
1145     psDBF->panFieldSize[iField] );
1146     break;
1147    
1148     default:
1149     /* empty string fields are considered NULL */
1150     memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0',
1151     psDBF->panFieldSize[iField] );
1152     break;
1153     }
1154     return TRUE;
1155     }
1156    
1157     /* -------------------------------------------------------------------- */
1158     /* Assign all the record fields. */
1159     /* -------------------------------------------------------------------- */
1160     switch( psDBF->pachFieldType[iField] )
1161     {
1162     case 'D':
1163     case 'N':
1164     case 'F':
1165     if( psDBF->panFieldDecimals[iField] == 0 )
1166     {
1167     int nWidth = psDBF->panFieldSize[iField];
1168    
1169     if( sizeof(szSField)-2 < nWidth )
1170     nWidth = sizeof(szSField)-2;
1171    
1172     sprintf( szFormat, "%%%dd", nWidth );
1173     sprintf(szSField, szFormat, (int) *((double *) pValue) );
1174     if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
1175 bh 1769 {
1176 jan 1612 szSField[psDBF->panFieldSize[iField]] = '\0';
1177 bh 1769 nRetResult = FALSE;
1178     }
1179 jan 1612
1180     strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1181     szSField, strlen(szSField) );
1182     }
1183     else
1184     {
1185     int nWidth = psDBF->panFieldSize[iField];
1186    
1187     if( sizeof(szSField)-2 < nWidth )
1188     nWidth = sizeof(szSField)-2;
1189    
1190     sprintf( szFormat, "%%%d.%df",
1191     nWidth, psDBF->panFieldDecimals[iField] );
1192     sprintf(szSField, szFormat, *((double *) pValue) );
1193     if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
1194 bh 1769 {
1195 jan 1612 szSField[psDBF->panFieldSize[iField]] = '\0';
1196 bh 1769 nRetResult = FALSE;
1197     }
1198 jan 1612 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1199     szSField, strlen(szSField) );
1200     }
1201     break;
1202    
1203 bh 1769 case 'L':
1204     if (psDBF->panFieldSize[iField] >= 1 &&
1205     (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
1206     *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
1207     break;
1208    
1209 jan 1612 default:
1210     if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1211 bh 1769 {
1212 jan 1612 j = psDBF->panFieldSize[iField];
1213 bh 1769 nRetResult = FALSE;
1214     }
1215 jan 1612 else
1216     {
1217     memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1218     psDBF->panFieldSize[iField] );
1219     j = strlen((char *) pValue);
1220     }
1221    
1222     strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1223     (char *) pValue, j );
1224     break;
1225     }
1226    
1227 bh 1769 return( nRetResult );
1228     }
1229    
1230     /************************************************************************/
1231     /* DBFWriteAttributeDirectly() */
1232     /* */
1233     /* Write an attribute record to the file, but without any */
1234     /* reformatting based on type. The provided buffer is written */
1235     /* as is to the field position in the record. */
1236     /************************************************************************/
1237    
1238 bh 2212 int SHPAPI_CALL
1239     DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1240 bh 1769 void * pValue )
1241    
1242     {
1243     int nRecordOffset, i, j;
1244     unsigned char *pabyRec;
1245    
1246     /* -------------------------------------------------------------------- */
1247     /* Is this a valid record? */
1248     /* -------------------------------------------------------------------- */
1249     if( hEntity < 0 || hEntity > psDBF->nRecords )
1250     return( FALSE );
1251    
1252     if( psDBF->bNoHeader )
1253     DBFWriteHeader(psDBF);
1254    
1255     /* -------------------------------------------------------------------- */
1256     /* Is this a brand new record? */
1257     /* -------------------------------------------------------------------- */
1258     if( hEntity == psDBF->nRecords )
1259     {
1260     DBFFlushRecord( psDBF );
1261    
1262     psDBF->nRecords++;
1263     for( i = 0; i < psDBF->nRecordLength; i++ )
1264     psDBF->pszCurrentRecord[i] = ' ';
1265    
1266     psDBF->nCurrentRecord = hEntity;
1267     }
1268    
1269     /* -------------------------------------------------------------------- */
1270     /* Is this an existing record, but different than the last one */
1271     /* we accessed? */
1272     /* -------------------------------------------------------------------- */
1273     if( psDBF->nCurrentRecord != hEntity )
1274     {
1275     DBFFlushRecord( psDBF );
1276    
1277     nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1278    
1279     fseek( psDBF->fp, nRecordOffset, 0 );
1280     fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1281    
1282     psDBF->nCurrentRecord = hEntity;
1283     }
1284    
1285     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1286    
1287     /* -------------------------------------------------------------------- */
1288     /* Assign all the record fields. */
1289     /* -------------------------------------------------------------------- */
1290     if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1291     j = psDBF->panFieldSize[iField];
1292     else
1293     {
1294     memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1295     psDBF->panFieldSize[iField] );
1296     j = strlen((char *) pValue);
1297     }
1298    
1299     strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1300     (char *) pValue, j );
1301    
1302     psDBF->bCurrentRecordModified = TRUE;
1303     psDBF->bUpdated = TRUE;
1304    
1305 jan 1612 return( TRUE );
1306     }
1307    
1308     /************************************************************************/
1309     /* DBFWriteDoubleAttribute() */
1310     /* */
1311     /* Write a double attribute. */
1312     /************************************************************************/
1313    
1314     int SHPAPI_CALL
1315     DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
1316     double dValue )
1317    
1318     {
1319     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1320     }
1321    
1322     /************************************************************************/
1323     /* DBFWriteIntegerAttribute() */
1324     /* */
1325     /* Write a integer attribute. */
1326     /************************************************************************/
1327    
1328     int SHPAPI_CALL
1329     DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
1330     int nValue )
1331    
1332     {
1333     double dValue = nValue;
1334    
1335     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1336     }
1337    
1338     /************************************************************************/
1339     /* DBFWriteStringAttribute() */
1340     /* */
1341     /* Write a string attribute. */
1342     /************************************************************************/
1343    
1344     int SHPAPI_CALL
1345     DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
1346     const char * pszValue )
1347    
1348     {
1349     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
1350     }
1351    
1352     /************************************************************************/
1353     /* DBFWriteNULLAttribute() */
1354     /* */
1355     /* Write a string attribute. */
1356     /************************************************************************/
1357    
1358     int SHPAPI_CALL
1359     DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
1360    
1361     {
1362     return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
1363     }
1364    
1365     /************************************************************************/
1366 bh 1769 /* DBFWriteLogicalAttribute() */
1367     /* */
1368     /* Write a logical attribute. */
1369     /************************************************************************/
1370    
1371     int SHPAPI_CALL
1372     DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
1373     const char lValue)
1374    
1375     {
1376     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
1377     }
1378    
1379     /************************************************************************/
1380 jan 1612 /* DBFWriteTuple() */
1381     /* */
1382     /* Write an attribute record to the file. */
1383     /************************************************************************/
1384    
1385     int SHPAPI_CALL
1386     DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
1387    
1388     {
1389     int nRecordOffset, i;
1390     unsigned char *pabyRec;
1391    
1392     /* -------------------------------------------------------------------- */
1393     /* Is this a valid record? */
1394     /* -------------------------------------------------------------------- */
1395     if( hEntity < 0 || hEntity > psDBF->nRecords )
1396     return( FALSE );
1397    
1398     if( psDBF->bNoHeader )
1399     DBFWriteHeader(psDBF);
1400    
1401     /* -------------------------------------------------------------------- */
1402     /* Is this a brand new record? */
1403     /* -------------------------------------------------------------------- */
1404     if( hEntity == psDBF->nRecords )
1405     {
1406     DBFFlushRecord( psDBF );
1407    
1408     psDBF->nRecords++;
1409     for( i = 0; i < psDBF->nRecordLength; i++ )
1410     psDBF->pszCurrentRecord[i] = ' ';
1411    
1412     psDBF->nCurrentRecord = hEntity;
1413     }
1414    
1415     /* -------------------------------------------------------------------- */
1416     /* Is this an existing record, but different than the last one */
1417     /* we accessed? */
1418     /* -------------------------------------------------------------------- */
1419     if( psDBF->nCurrentRecord != hEntity )
1420     {
1421     DBFFlushRecord( psDBF );
1422    
1423     nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1424    
1425     fseek( psDBF->fp, nRecordOffset, 0 );
1426     fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1427    
1428     psDBF->nCurrentRecord = hEntity;
1429     }
1430    
1431     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1432    
1433     memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
1434    
1435     psDBF->bCurrentRecordModified = TRUE;
1436     psDBF->bUpdated = TRUE;
1437    
1438     return( TRUE );
1439     }
1440    
1441     /************************************************************************/
1442     /* DBFReadTuple() */
1443     /* */
1444     /* Read one of the attribute fields of a record. */
1445     /************************************************************************/
1446    
1447     const char SHPAPI_CALL1(*)
1448     DBFReadTuple(DBFHandle psDBF, int hEntity )
1449    
1450     {
1451     int nRecordOffset;
1452     unsigned char *pabyRec;
1453     static char *pReturnTuple = NULL;
1454    
1455     static int nTupleLen = 0;
1456    
1457     /* -------------------------------------------------------------------- */
1458     /* Have we read the record? */
1459     /* -------------------------------------------------------------------- */
1460     if( hEntity < 0 || hEntity >= psDBF->nRecords )
1461     return( NULL );
1462    
1463     if( psDBF->nCurrentRecord != hEntity )
1464     {
1465     DBFFlushRecord( psDBF );
1466    
1467     nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1468    
1469     fseek( psDBF->fp, nRecordOffset, 0 );
1470     fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1471    
1472     psDBF->nCurrentRecord = hEntity;
1473     }
1474    
1475     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1476    
1477     if ( nTupleLen < psDBF->nRecordLength) {
1478     nTupleLen = psDBF->nRecordLength;
1479     pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
1480     }
1481    
1482     memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
1483    
1484     return( pReturnTuple );
1485     }
1486    
1487     /************************************************************************/
1488     /* DBFCloneEmpty() */
1489     /* */
1490     /* Read one of the attribute fields of a record. */
1491     /************************************************************************/
1492    
1493     DBFHandle SHPAPI_CALL
1494     DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
1495     {
1496     DBFHandle newDBF;
1497    
1498     newDBF = DBFCreate ( pszFilename );
1499     if ( newDBF == NULL ) return ( NULL );
1500    
1501 bh 1769 newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
1502 jan 1612 memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
1503    
1504     newDBF->nFields = psDBF->nFields;
1505     newDBF->nRecordLength = psDBF->nRecordLength;
1506 bh 1769 newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
1507 jan 1612
1508 bh 1769 newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
1509 jan 1612 memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1510 bh 1769 newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
1511 jan 1612 memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1512 bh 1769 newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
1513 jan 1612 memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1514 bh 1769 newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
1515 jan 1612 memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
1516    
1517     newDBF->bNoHeader = TRUE;
1518     newDBF->bUpdated = TRUE;
1519    
1520     DBFWriteHeader ( newDBF );
1521     DBFClose ( newDBF );
1522    
1523     newDBF = DBFOpen ( pszFilename, "rb+" );
1524    
1525     return ( newDBF );
1526     }
1527    
1528     /************************************************************************/
1529     /* DBFGetNativeFieldType() */
1530     /* */
1531     /* Return the DBase field type for the specified field. */
1532     /* */
1533     /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
1534     /* 'N' (Numeric, with or without decimal), */
1535     /* 'L' (Logical), */
1536     /* 'M' (Memo: 10 digits .DBT block ptr) */
1537     /************************************************************************/
1538    
1539     char SHPAPI_CALL
1540     DBFGetNativeFieldType( DBFHandle psDBF, int iField )
1541    
1542     {
1543     if( iField >=0 && iField < psDBF->nFields )
1544     return psDBF->pachFieldType[iField];
1545    
1546     return ' ';
1547     }
1548    
1549     /************************************************************************/
1550     /* str_to_upper() */
1551     /************************************************************************/
1552    
1553     static void str_to_upper (char *string)
1554     {
1555     int len;
1556     short i = -1;
1557    
1558     len = strlen (string);
1559    
1560     while (++i < len)
1561     if (isalpha(string[i]) && islower(string[i]))
1562 bh 2212 string[i] = (char) toupper ((int)string[i]);
1563 jan 1612 }
1564    
1565     /************************************************************************/
1566     /* DBFGetFieldIndex() */
1567     /* */
1568     /* Get the index number for a field in a .dbf file. */
1569     /* */
1570     /* Contributed by Jim Matthews. */
1571     /************************************************************************/
1572    
1573     int SHPAPI_CALL
1574     DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
1575    
1576     {
1577     char name[12], name1[12], name2[12];
1578     int i;
1579    
1580     strncpy(name1, pszFieldName,11);
1581 bh 1769 name1[11] = '\0';
1582 jan 1612 str_to_upper(name1);
1583    
1584     for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
1585     {
1586     DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
1587     strncpy(name2,name,11);
1588     str_to_upper(name2);
1589    
1590     if(!strncmp(name1,name2,10))
1591     return(i);
1592     }
1593     return(-1);
1594     }

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26