source: branches/1.5/loader/dbfopen.c @ 5668

Last change on this file since 5668 was 5668, checked in by pramsey, 6 years ago

Accept "0" as a null DBF date value.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mime-type set to text/plain
File size: 52.4 KB
Line 
1/******************************************************************************
2 * $Id: dbfopen.c 5668 2010-06-01 20:00:35Z pramsey $
3 *
4 * Project:  Shapelib
5 * Purpose:  Implementation of .dbf access API documented in dbf_api.html.
6 * Author:   Frank Warmerdam, warmerdam@pobox.com
7 *
8 ******************************************************************************
9 * Copyright (c) 1999, Frank Warmerdam
10 *
11 * This software is available under the following "MIT Style" license,
12 * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
13 * option is discussed in more detail in shapelib.html.
14 *
15 * --
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining a
18 * copy of this software and associated documentation files (the "Software"),
19 * to deal in the Software without restriction, including without limitation
20 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21 * and/or sell copies of the Software, and to permit persons to whom the
22 * Software is furnished to do so, subject to the following conditions:
23 *
24 * The above copyright notice and this permission notice shall be included
25 * in all copies or substantial portions of the Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33 * DEALINGS IN THE SOFTWARE.
34 ******************************************************************************
35 *
36 * $Log$
37 * Revision 1.8  2006/01/16 10:42:57  strk
38 * Added support for Bool and Date DBF<=>PGIS mapping
39 *
40 * Revision 1.7  2006/01/09 16:40:16  strk
41 * ISO C90 comments, signedness mismatch fixes
42 *
43 * Revision 1.6  2003/12/01 20:52:00  strk
44 * shapelib put in sync with gdal cvs
45 *
46 * Revision 1.52  2003/07/08 15:20:03  warmerda
47 * avoid warnings about downcasting to unsigned char
48 *
49 * Revision 1.51  2003/07/08 13:50:15  warmerda
50 * DBFIsAttributeNULL check for pszValue==NULL - bug 360
51 *
52 * Revision 1.50  2003/04/21 18:58:25  warmerda
53 * ensure current record is flushed at same time as header is updated
54 *
55 * Revision 1.49  2003/04/21 18:30:37  warmerda
56 * added header write/update public methods
57 *
58 * Revision 1.48  2003/03/10 14:51:27  warmerda
59 * DBFWrite* calls now return FALSE if they have to truncate
60 *
61 * Revision 1.47  2002/11/20 03:32:22  warmerda
62 * Ensure field name in DBFGetFieldIndex() is properly terminated.
63 *
64 * Revision 1.46  2002/10/09 13:10:21  warmerda
65 * Added check that width is positive.
66 *
67 * Revision 1.45  2002/09/29 00:00:08  warmerda
68 * added FTLogical and logical attribute read/write calls
69 *
70 * Revision 1.44  2002/05/07 13:46:11  warmerda
71 * Added DBFWriteAttributeDirectly().
72 *
73 * Revision 1.43  2002/02/13 19:39:21  warmerda
74 * Fix casting issues in DBFCloneEmpty().
75 *
76 * Revision 1.42  2002/01/15 14:36:07  warmerda
77 * updated email address
78 *
79 * Revision 1.41  2002/01/15 14:31:49  warmerda
80 * compute rather than copying nHeaderLength in DBFCloneEmpty()
81 *
82 * Revision 1.40  2002/01/09 04:32:35  warmerda
83 * fixed to read correct amount of header
84 *
85 * Revision 1.39  2001/12/11 22:41:03  warmerda
86 * improve io related error checking when reading header
87 *
88 * Revision 1.38  2001/11/28 16:07:31  warmerda
89 * Cleanup to avoid compiler warnings as suggested by Richard Hash.
90 *
91 * Revision 1.37  2001/07/04 05:18:09  warmerda
92 * do last fix properly
93 *
94 * Revision 1.36  2001/07/04 05:16:09  warmerda
95 * fixed fieldname comparison in DBFGetFieldIndex
96 *
97 * Revision 1.35  2001/06/22 02:10:06  warmerda
98 * fixed NULL shape support with help from Jim Matthews
99 *
100 * Revision 1.33  2001/05/31 19:20:13  warmerda
101 * added DBFGetFieldIndex()
102 *
103 * Revision 1.32  2001/05/31 18:15:40  warmerda
104 * Added support for NULL fields in DBF files
105 *
106 * Revision 1.31  2001/05/23 13:36:52  warmerda
107 * added use of SHPAPI_CALL
108 *
109 * Revision 1.30  2000/12/05 14:43:38  warmerda
110 * DBReadAttribute() white space trimming bug fix
111 *
112 * Revision 1.29  2000/10/05 14:36:44  warmerda
113 * fix bug with writing very wide numeric fields
114 *
115 * Revision 1.28  2000/09/25 14:18:07  warmerda
116 * Added some casts of strlen() return result to fix warnings on some
117 * systems, as submitted by Daniel.
118 *
119 * Revision 1.27  2000/09/25 14:15:51  warmerda
120 * added DBFGetNativeFieldType()
121 *
122 * Revision 1.26  2000/07/07 13:39:45  warmerda
123 * removed unused variables, and added system include files
124 *
125 * Revision 1.25  2000/05/29 18:19:13  warmerda
126 * avoid use of uchar, and adding casting fix
127 *
128 * Revision 1.24  2000/05/23 13:38:27  warmerda
129 * Added error checks on return results of fread() and fseek().
130 *
131 * Revision 1.23  2000/05/23 13:25:49  warmerda
132 * Avoid crashing if field or record are out of range in dbfread*attribute().
133 *
134 * Revision 1.22  1999/12/15 13:47:24  warmerda
135 * Added stdlib.h to ensure that atof() is prototyped.
136 *
137 * Revision 1.21  1999/12/13 17:25:46  warmerda
138 * Added support for upper case .DBF extention.
139 *
140 * Revision 1.20  1999/11/30 16:32:11  warmerda
141 * Use atof() instead of sscanf().
142 *
143 * Revision 1.19  1999/11/05 14:12:04  warmerda
144 * updated license terms
145 *
146 * Revision 1.18  1999/07/27 00:53:28  warmerda
147 * ensure that whole old field value clear on write of string
148 *
149 * Revision 1.1  1999/07/05 18:58:07  warmerda
150 * New
151 *
152 * Revision 1.17  1999/06/11 19:14:12  warmerda
153 * Fixed some memory leaks.
154 *
155 * Revision 1.16  1999/06/11 19:04:11  warmerda
156 * Remoted some unused variables.
157 *
158 * Revision 1.15  1999/05/11 03:19:28  warmerda
159 * added new Tuple api, and improved extension handling - add from candrsn
160 *
161 * Revision 1.14  1999/05/04 15:01:48  warmerda
162 * Added 'F' support.
163 *
164 * Revision 1.13  1999/03/23 17:38:59  warmerda
165 * DBFAddField() now actually does return the new field number, or -1 if
166 * it fails.
167 *
168 * Revision 1.12  1999/03/06 02:54:46  warmerda
169 * Added logic to convert shapefile name to dbf filename in DBFOpen()
170 * for convenience.
171 *
172 * Revision 1.11  1998/12/31 15:30:34  warmerda
173 * Improved the interchangability of numeric and string attributes.  Add
174 * white space trimming option for attributes.
175 *
176 * Revision 1.10  1998/12/03 16:36:44  warmerda
177 * Use r+b instead of rb+ for binary access.
178 *
179 * Revision 1.9  1998/12/03 15:34:23  warmerda
180 * Updated copyright message.
181 *
182 * Revision 1.8  1997/12/04 15:40:15  warmerda
183 * Added newline character after field definitions.
184 *
185 * Revision 1.7  1997/03/06 14:02:10  warmerda
186 * Ensure bUpdated is initialized.
187 *
188 * Revision 1.6  1996/02/12 04:54:41  warmerda
189 * Ensure that DBFWriteAttribute() returns TRUE if it succeeds.
190 *
191 * Revision 1.5  1995/10/21  03:15:12  warmerda
192 * Changed to use binary file access, and ensure that the
193 * field name field is zero filled, and limited to 10 chars.
194 *
195 * Revision 1.4  1995/08/24  18:10:42  warmerda
196 * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such
197 * as on the Sun.
198 *
199 * Revision 1.3  1995/08/04  03:15:16  warmerda
200 * Fixed up header.
201 *
202 * Revision 1.2  1995/08/04  03:14:43  warmerda
203 * Added header.
204 */
205
206#include "shapefil.h"
207
208#include <math.h>
209#include <stdlib.h>
210#include <ctype.h>
211#include <string.h>
212
213#ifndef FALSE
214#  define FALSE         0
215#  define TRUE          1
216#endif
217
218static int      nStringFieldLen = 0;
219static char * pszStringField = NULL;
220
221/************************************************************************/
222/*                             SfRealloc()                              */
223/*                                                                      */
224/*      A realloc cover function that will access a NULL pointer as     */
225/*      a valid input.                                                  */
226/************************************************************************/
227
228static void * SfRealloc( void * pMem, int nNewSize )
229
230{
231        if ( pMem == NULL )
232                return( (void *) malloc(nNewSize) );
233        else
234                return( (void *) realloc(pMem,nNewSize) );
235}
236
237/************************************************************************/
238/*                           DBFWriteHeader()                           */
239/*                                                                      */
240/*      This is called to write out the file header, and field          */
241/*      descriptions before writing any actual data records.  This      */
242/*      also computes all the DBFDataSet field offset/size/decimals     */
243/*      and so forth values.                                            */
244/************************************************************************/
245
246static void DBFWriteHeader(DBFHandle psDBF)
247
248{
249        unsigned char   abyHeader[XBASE_FLDHDR_SZ];
250        int             i;
251
252        if ( !psDBF->bNoHeader )
253                return;
254
255        psDBF->bNoHeader = FALSE;
256
257        /* -------------------------------------------------------------------- */
258        /*      Initialize the file header information.                         */
259        /* -------------------------------------------------------------------- */
260        for ( i = 0; i < XBASE_FLDHDR_SZ; i++ )
261                abyHeader[i] = 0;
262
263        abyHeader[0] = 0x03;            /* memo field? - just copying   */
264
265        /* write out a dummy date */
266        abyHeader[1] = 95;                      /* YY */
267        abyHeader[2] = 7;                       /* MM */
268        abyHeader[3] = 26;                      /* DD */
269
270        /* record count preset at zero */
271
272        abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
273        abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
274
275        abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
276        abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
277
278        /* -------------------------------------------------------------------- */
279        /*      Write the initial 32 byte file header, and all the field        */
280        /*      descriptions.                                                   */
281        /* -------------------------------------------------------------------- */
282        fseek( psDBF->fp, 0, 0 );
283        fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
284        fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );
285
286        /* -------------------------------------------------------------------- */
287        /*      Write out the newline character if there is room for it.        */
288        /* -------------------------------------------------------------------- */
289        if ( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
290        {
291                char    cNewline;
292
293                cNewline = 0x0d;
294                fwrite( &cNewline, 1, 1, psDBF->fp );
295        }
296}
297
298/************************************************************************/
299/*                           DBFFlushRecord()                           */
300/*                                                                      */
301/*      Write out the current record if there is one.                   */
302/************************************************************************/
303
304static void DBFFlushRecord( DBFHandle psDBF )
305
306{
307        int             nRecordOffset;
308
309        if ( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
310        {
311                psDBF->bCurrentRecordModified = FALSE;
312
313                nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord
314                                + psDBF->nHeaderLength;
315
316                fseek( psDBF->fp, nRecordOffset, 0 );
317                fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
318        }
319}
320
321/************************************************************************/
322/*                          DBFUpdateHeader()                           */
323/************************************************************************/
324
325void SHPAPI_CALL
326DBFUpdateHeader( DBFHandle psDBF )
327
328{
329        unsigned char           abyFileHeader[32];
330
331        if ( psDBF->bNoHeader )
332                DBFWriteHeader( psDBF );
333
334        DBFFlushRecord( psDBF );
335
336        fseek( psDBF->fp, 0, 0 );
337        fread( abyFileHeader, 32, 1, psDBF->fp );
338
339        abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
340        abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
341        abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
342        abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
343
344        fseek( psDBF->fp, 0, 0 );
345        fwrite( abyFileHeader, 32, 1, psDBF->fp );
346
347        fflush( psDBF->fp );
348}
349
350/************************************************************************/
351/*                              DBFOpen()                               */
352/*                                                                      */
353/*      Open a .dbf file.                                               */
354/************************************************************************/
355
356DBFHandle SHPAPI_CALL
357DBFOpen( const char * pszFilename, const char * pszAccess )
358
359{
360        DBFHandle               psDBF;
361        unsigned char           *pabyBuf;
362        int                     nFields, nHeadLen, nRecLen, iField, i;
363        char            *pszBasename, *pszFullname;
364
365        /* -------------------------------------------------------------------- */
366        /*      We only allow the access strings "rb" and "r+".                  */
367        /* -------------------------------------------------------------------- */
368        if ( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
369                && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
370                && strcmp(pszAccess,"r+b") != 0 )
371                return( NULL );
372
373        if ( strcmp(pszAccess,"r") == 0 )
374                pszAccess = "rb";
375
376        if ( strcmp(pszAccess,"r+") == 0 )
377                pszAccess = "rb+";
378
379        /* -------------------------------------------------------------------- */
380        /*      Compute the base (layer) name.  If there is any extension       */
381        /*      on the passed in filename we will strip it off.                 */
382        /* -------------------------------------------------------------------- */
383        pszBasename = (char *) malloc(strlen(pszFilename)+5);
384        strcpy( pszBasename, pszFilename );
385        for ( i = strlen(pszBasename)-1;
386                i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
387                && pszBasename[i] != '\\';
388                i-- )
389                {}
390
391        if ( pszBasename[i] == '.' )
392                pszBasename[i] = '\0';
393
394        pszFullname = (char *) malloc(strlen(pszBasename) + 5);
395        sprintf( pszFullname, "%s.dbf", pszBasename );
396
397        psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
398        psDBF->fp = fopen( pszFullname, pszAccess );
399
400        if ( psDBF->fp == NULL )
401        {
402                sprintf( pszFullname, "%s.DBF", pszBasename );
403                psDBF->fp = fopen(pszFullname, pszAccess );
404        }
405
406        free( pszBasename );
407        free( pszFullname );
408
409        if ( psDBF->fp == NULL )
410        {
411                free( psDBF );
412                return( NULL );
413        }
414
415        psDBF->bNoHeader = FALSE;
416        psDBF->nCurrentRecord = -1;
417        psDBF->bCurrentRecordModified = FALSE;
418
419        /* -------------------------------------------------------------------- */
420        /*  Read Table Header info                                              */
421        /* -------------------------------------------------------------------- */
422        pabyBuf = (unsigned char *) malloc(500);
423        if ( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
424        {
425                fclose( psDBF->fp );
426                free( pabyBuf );
427                free( psDBF );
428                return NULL;
429        }
430
431        psDBF->nRecords =
432            pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
433
434        psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
435        psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;
436
437        psDBF->nFields = nFields = (nHeadLen - 32) / 32;
438
439        psDBF->pszCurrentRecord = (char *) malloc(nRecLen);
440
441        /* -------------------------------------------------------------------- */
442        /*  Read in Field Definitions                                           */
443        /* -------------------------------------------------------------------- */
444
445        pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
446        psDBF->pszHeader = (char *) pabyBuf;
447
448        fseek( psDBF->fp, 32, 0 );
449        if ( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
450        {
451                fclose( psDBF->fp );
452                free( pabyBuf );
453                free( psDBF );
454                return NULL;
455        }
456
457        psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
458        psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
459        psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
460        psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
461
462        for ( iField = 0; iField < nFields; iField++ )
463        {
464                unsigned char           *pabyFInfo;
465
466                pabyFInfo = pabyBuf+iField*32;
467
468                if ( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
469                {
470                        psDBF->panFieldSize[iField] = pabyFInfo[16];
471                        psDBF->panFieldDecimals[iField] = pabyFInfo[17];
472                }
473                else
474                {
475                        psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
476                        psDBF->panFieldDecimals[iField] = 0;
477                }
478
479                psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
480                if ( iField == 0 )
481                        psDBF->panFieldOffset[iField] = 1;
482                else
483                        psDBF->panFieldOffset[iField] =
484                            psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
485        }
486
487        return( psDBF );
488}
489
490/************************************************************************/
491/*                              DBFClose()                              */
492/************************************************************************/
493
494void SHPAPI_CALL
495DBFClose(DBFHandle psDBF)
496{
497        static char eof = 0x1a;
498        char eof_test;
499
500        /* -------------------------------------------------------------------- */
501        /*      Write out header if not already written.                        */
502        /* -------------------------------------------------------------------- */
503        if ( psDBF->bNoHeader )
504                DBFWriteHeader( psDBF );
505
506        DBFFlushRecord( psDBF );
507
508        /* -------------------------------------------------------------------- */
509        /*      Update last access date, and number of records if we have       */
510        /*      write access.                                                   */
511        /* -------------------------------------------------------------------- */
512        if ( psDBF->bUpdated )
513                DBFUpdateHeader( psDBF );
514
515        /* -------------------------------------------------------------------- */
516        /*  Add the DBF end-of-file marker after the last record.               */
517        /* -------------------------------------------------------------------- */
518
519        fseek(psDBF->fp, -1, SEEK_END);
520        fread(&eof_test, 1, 1, psDBF->fp);
521        if ( eof_test != 0x1a ) /* no EOF exists, so write one */
522        {
523                fseek(psDBF->fp, 0, SEEK_END);
524                fwrite(&eof, 1, 1, psDBF->fp);
525        }
526
527        /* -------------------------------------------------------------------- */
528        /*      Close, and free resources.                                      */
529        /* -------------------------------------------------------------------- */
530        fclose( psDBF->fp );
531
532        if ( psDBF->panFieldOffset != NULL )
533        {
534                free( psDBF->panFieldOffset );
535                free( psDBF->panFieldSize );
536                free( psDBF->panFieldDecimals );
537                free( psDBF->pachFieldType );
538        }
539
540        free( psDBF->pszHeader );
541        free( psDBF->pszCurrentRecord );
542
543        free( psDBF );
544
545        if ( pszStringField != NULL )
546        {
547                free( pszStringField );
548                pszStringField = NULL;
549                nStringFieldLen = 0;
550        }
551}
552
553/************************************************************************/
554/*                             DBFCreate()                              */
555/*                                                                      */
556/*      Create a new .dbf file.                                         */
557/************************************************************************/
558
559DBFHandle SHPAPI_CALL
560DBFCreate( const char * pszFilename )
561
562{
563        DBFHandle       psDBF;
564        FILE    *fp;
565        char    *pszFullname, *pszBasename;
566        int             i;
567
568        /* -------------------------------------------------------------------- */
569        /*      Compute the base (layer) name.  If there is any extension       */
570        /*      on the passed in filename we will strip it off.                 */
571        /* -------------------------------------------------------------------- */
572        pszBasename = (char *) malloc(strlen(pszFilename)+5);
573        strcpy( pszBasename, pszFilename );
574        for ( i = strlen(pszBasename)-1;
575                i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
576                && pszBasename[i] != '\\';
577                i-- )
578                {}
579
580        if ( pszBasename[i] == '.' )
581                pszBasename[i] = '\0';
582
583        pszFullname = (char *) malloc(strlen(pszBasename) + 5);
584        sprintf( pszFullname, "%s.dbf", pszBasename );
585        free( pszBasename );
586
587        /* -------------------------------------------------------------------- */
588        /*      Create the file.                                                */
589        /* -------------------------------------------------------------------- */
590        fp = fopen( pszFullname, "wb" );
591        if ( fp == NULL )
592                return( NULL );
593
594        fputc( 0, fp );
595        fclose( fp );
596
597        fp = fopen( pszFullname, "rb+" );
598        if ( fp == NULL )
599                return( NULL );
600
601        free( pszFullname );
602
603        /* -------------------------------------------------------------------- */
604        /*      Create the info structure.                                      */
605        /* -------------------------------------------------------------------- */
606        psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
607
608        psDBF->fp = fp;
609        psDBF->nRecords = 0;
610        psDBF->nFields = 0;
611        psDBF->nRecordLength = 1;
612        psDBF->nHeaderLength = 33;
613        psDBF->bUpdated = FALSE;
614
615        psDBF->panFieldOffset = NULL;
616        psDBF->panFieldSize = NULL;
617        psDBF->panFieldDecimals = NULL;
618        psDBF->pachFieldType = NULL;
619        psDBF->pszHeader = NULL;
620
621        psDBF->nCurrentRecord = -1;
622        psDBF->bCurrentRecordModified = FALSE;
623        psDBF->pszCurrentRecord = NULL;
624
625        psDBF->bNoHeader = TRUE;
626
627        return( psDBF );
628}
629
630/************************************************************************/
631/*                            DBFAddField()                             */
632/*                                                                      */
633/*      Add a field to a newly created .dbf file before any records     */
634/*      are written.                                                    */
635/************************************************************************/
636
637int SHPAPI_CALL
638DBFAddField(DBFHandle psDBF, const char * pszFieldName,
639            DBFFieldType eType, int nWidth, int nDecimals )
640
641{
642        char    *pszFInfo;
643        int             i;
644
645        /* -------------------------------------------------------------------- */
646        /*      Do some checking to ensure we can add records to this file.     */
647        /* -------------------------------------------------------------------- */
648        if ( psDBF->nRecords > 0 )
649                return( -1 );
650
651        if ( !psDBF->bNoHeader )
652                return( -1 );
653
654        if ( eType != FTDouble && nDecimals != 0 )
655                return( -1 );
656
657        if ( nWidth < 1 )
658                return -1;
659
660        /* -------------------------------------------------------------------- */
661        /*      SfRealloc all the arrays larger to hold the additional field      */
662        /*      information.                                                    */
663        /* -------------------------------------------------------------------- */
664        psDBF->nFields++;
665
666        psDBF->panFieldOffset = (int *)
667                                SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
668
669        psDBF->panFieldSize = (int *)
670                              SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
671
672        psDBF->panFieldDecimals = (int *)
673                                  SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
674
675        psDBF->pachFieldType = (char *)
676                               SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
677
678        /* -------------------------------------------------------------------- */
679        /*      Assign the new field information fields.                        */
680        /* -------------------------------------------------------------------- */
681        psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
682        psDBF->nRecordLength += nWidth;
683        psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
684        psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
685
686        if ( eType == FTLogical )
687                psDBF->pachFieldType[psDBF->nFields-1] = 'L';
688        else if ( eType == FTString )
689                psDBF->pachFieldType[psDBF->nFields-1] = 'C';
690        else if ( eType == FTDate )
691                psDBF->pachFieldType[psDBF->nFields-1] = 'D';
692        else
693                psDBF->pachFieldType[psDBF->nFields-1] = 'N';
694
695        /* -------------------------------------------------------------------- */
696        /*      Extend the required header information.                         */
697        /* -------------------------------------------------------------------- */
698        psDBF->nHeaderLength += 32;
699        psDBF->bUpdated = FALSE;
700
701        psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
702
703        pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
704
705        for ( i = 0; i < 32; i++ )
706                pszFInfo[i] = '\0';
707
708        if ( (int) strlen(pszFieldName) < 10 )
709                strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
710        else
711                strncpy( pszFInfo, pszFieldName, 10);
712
713        pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
714
715        if ( eType == FTString )
716        {
717                pszFInfo[16] = (unsigned char) (nWidth % 256);
718                pszFInfo[17] = (unsigned char) (nWidth / 256);
719        }
720        else
721        {
722                pszFInfo[16] = (unsigned char) nWidth;
723                pszFInfo[17] = (unsigned char) nDecimals;
724        }
725
726        /* -------------------------------------------------------------------- */
727        /*      Make the current record buffer appropriately larger.            */
728        /* -------------------------------------------------------------------- */
729        psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
730                                  psDBF->nRecordLength);
731
732        return( psDBF->nFields-1 );
733}
734
735
736/************************************************************************/
737/*                        DBFReadSetup()                                */
738/*                                                                      */
739/*      Prep a record for reading.                                      */
740/************************************************************************/
741
742int DBFReadSetup(DBFHandle psDBF, int hEntity)
743{
744        int             nRecordOffset;
745
746        /* -------------------------------------------------------------------- */
747        /*      Verify selection.                                               */
748        /* -------------------------------------------------------------------- */
749        if ( hEntity < 0 || hEntity >= psDBF->nRecords )
750                return( 0 );
751
752        /* -------------------------------------------------------------------- */
753        /*      Have we read the record?                                        */
754        /* -------------------------------------------------------------------- */
755        if ( psDBF->nCurrentRecord != hEntity )
756        {
757                DBFFlushRecord( psDBF );
758
759                nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
760
761                if ( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
762                {
763                        fprintf( stderr, "fseek(%d) failed on DBF file.\n",
764                                 nRecordOffset );
765                        return 0;
766                }
767
768                if ( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength,
769                            1, psDBF->fp ) != 1 )
770                {
771                        fprintf( stderr, "fread(%d) failed on DBF file.\n",
772                                 psDBF->nRecordLength );
773                        return 0;
774                }
775
776                psDBF->nCurrentRecord = hEntity;
777        }
778
779        return 1;
780
781}
782
783
784/************************************************************************/
785/*                        DBFReadDeleted()                              */
786/*                                                                      */
787/*      Read whether a record is deleted.                               */
788/************************************************************************/
789
790int DBFReadDeleted(DBFHandle psDBF, int hEntity)
791{
792        unsigned char   *pabyRec;
793
794        if ( ! DBFReadSetup( psDBF, hEntity) )
795                return 0;
796
797        /* get reference to current record */
798        pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
799
800        /* 0x20 => not deleted, 0x24 => deleted */
801        return *pabyRec == 0x20 ? 0 : 1;
802
803}
804
805/************************************************************************/
806/*                          DBFReadAttribute()                          */
807/*                                                                      */
808/*      Read one of the attribute fields of a record.                   */
809/************************************************************************/
810
811static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
812                              char chReqType )
813
814{
815        unsigned char   *pabyRec;
816        void    *pReturnField = NULL;
817
818        static double dDoubleField;
819
820        /* -------------------------------------------------------------------- */
821        /*      Verify selection.                                               */
822        /* -------------------------------------------------------------------- */
823        if ( iField < 0 || iField >= psDBF->nFields )
824                return( NULL );
825
826        if ( ! DBFReadSetup( psDBF, hEntity) )
827                return( NULL );
828
829        /* get reference to current record */
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                dDoubleField = atof(pszStringField);
857                pReturnField = &dDoubleField;
858        }
859
860        /* -------------------------------------------------------------------- */
861        /*      Should we trim white space off the string attribute value?      */
862        /* -------------------------------------------------------------------- */
863#ifdef TRIM_DBF_WHITESPACE
864        else
865        {
866                char    *pchSrc, *pchDst;
867
868                pchDst = pchSrc = pszStringField;
869                while ( *pchSrc == ' ' )
870                        pchSrc++;
871
872                while ( *pchSrc != '\0' )
873                        *(pchDst++) = *(pchSrc++);
874                *pchDst = '\0';
875
876                while ( pchDst != pszStringField && *(--pchDst) == ' ' )
877                        *pchDst = '\0';
878        }
879#endif
880
881        return( pReturnField );
882}
883
884/************************************************************************/
885/*                        DBFReadIntAttribute()                         */
886/*                                                                      */
887/*      Read an integer attribute.                                      */
888/************************************************************************/
889
890int SHPAPI_CALL
891DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
892
893{
894        double  *pdValue;
895
896        pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
897
898        if ( pdValue == NULL )
899                return 0;
900        else
901                return( (int) *pdValue );
902}
903
904/************************************************************************/
905/*                        DBFReadDoubleAttribute()                      */
906/*                                                                      */
907/*      Read a double attribute.                                        */
908/************************************************************************/
909
910double SHPAPI_CALL
911DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
912
913{
914        double  *pdValue;
915
916        pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
917
918        if ( pdValue == NULL )
919                return 0.0;
920        else
921                return( *pdValue );
922}
923
924/************************************************************************/
925/*                        DBFReadStringAttribute()                      */
926/*                                                                      */
927/*      Read a string attribute.                                        */
928/************************************************************************/
929
930const char SHPAPI_CALL1(*)
931DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
932
933{
934        return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
935}
936
937/************************************************************************/
938/*                        DBFReadLogicalAttribute()                     */
939/*                                                                      */
940/*      Read a logical attribute.                                       */
941/************************************************************************/
942
943const char SHPAPI_CALL1(*)
944DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
945
946{
947        return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
948}
949
950/************************************************************************/
951/*                         DBFIsAttributeNULL()                         */
952/*                                                                      */
953/*      Return TRUE if value for field is NULL.                         */
954/*                                                                      */
955/*      Contributed by Jim Matthews.                                    */
956/************************************************************************/
957
958int SHPAPI_CALL
959DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
960
961{
962        const char      *pszValue;
963
964        pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
965
966        if ( pszValue == NULL )
967                return TRUE;
968
969        switch (psDBF->pachFieldType[iField])
970        {
971        case 'N':
972        case 'F':
973                /* NULL numeric fields have value "****************" */
974                return pszValue[0] == '*';
975
976        case 'D':
977                /* NULL date fields have value "00000000" */
978                return (strncmp(pszValue,"0",1) == 0 || strncmp(pszValue,"00000000",8) == 0 || strlen(pszValue) == 0);
979
980        case 'L':
981                /* NULL boolean fields have value "?" */
982                return pszValue[0] == '?';
983
984        default:
985                /* empty string fields are considered NULL */
986                return strlen(pszValue) == 0;
987        }
988}
989
990/************************************************************************/
991/*                          DBFGetFieldCount()                          */
992/*                                                                      */
993/*      Return the number of fields in this table.                      */
994/************************************************************************/
995
996int SHPAPI_CALL
997DBFGetFieldCount( DBFHandle psDBF )
998
999{
1000        return( psDBF->nFields );
1001}
1002
1003/************************************************************************/
1004/*                         DBFGetRecordCount()                          */
1005/*                                                                      */
1006/*      Return the number of records in this table.                     */
1007/************************************************************************/
1008
1009int SHPAPI_CALL
1010DBFGetRecordCount( DBFHandle psDBF )
1011
1012{
1013        return( psDBF->nRecords );
1014}
1015
1016/************************************************************************/
1017/*                          DBFGetFieldInfo()                           */
1018/*                                                                      */
1019/*      Return any requested information about the field.               */
1020/************************************************************************/
1021
1022DBFFieldType SHPAPI_CALL
1023DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
1024                 int * pnWidth, int * pnDecimals )
1025
1026{
1027        if ( iField < 0 || iField >= psDBF->nFields )
1028                return( FTInvalid );
1029
1030        if ( pnWidth != NULL )
1031                *pnWidth = psDBF->panFieldSize[iField];
1032
1033        if ( pnDecimals != NULL )
1034                *pnDecimals = psDBF->panFieldDecimals[iField];
1035
1036        if ( pszFieldName != NULL )
1037        {
1038                int     i;
1039
1040                strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
1041                pszFieldName[11] = '\0';
1042                for ( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
1043                        pszFieldName[i] = '\0';
1044        }
1045
1046        if ( psDBF->pachFieldType[iField] == 'L' )
1047                return( FTLogical);
1048
1049        else if ( psDBF->pachFieldType[iField] == 'D'  )
1050                return ( FTDate );
1051
1052        else if ( psDBF->pachFieldType[iField] == 'N'
1053                  || psDBF->pachFieldType[iField] == 'F' )
1054        {
1055                if ( psDBF->panFieldDecimals[iField] > 0 )
1056                        return( FTDouble );
1057                else
1058                        return( FTInteger );
1059        }
1060        else
1061        {
1062                return( FTString );
1063        }
1064}
1065
1066/************************************************************************/
1067/*                         DBFWriteAttribute()                          */
1068/*                                                                      */
1069/*      Write an attribute record to the file.                          */
1070/************************************************************************/
1071
1072static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
1073                             void * pValue )
1074
1075{
1076        int             nRecordOffset, i, j, nRetResult = TRUE;
1077        unsigned char   *pabyRec;
1078        char    szSField[400], szFormat[20];
1079
1080        /* -------------------------------------------------------------------- */
1081        /*      Is this a valid record?                                         */
1082        /* -------------------------------------------------------------------- */
1083        if ( hEntity < 0 || hEntity > psDBF->nRecords )
1084                return( FALSE );
1085
1086        if ( psDBF->bNoHeader )
1087                DBFWriteHeader(psDBF);
1088
1089        /* -------------------------------------------------------------------- */
1090        /*      Is this a brand new record?                                     */
1091        /* -------------------------------------------------------------------- */
1092        if ( hEntity == psDBF->nRecords )
1093        {
1094                DBFFlushRecord( psDBF );
1095
1096                psDBF->nRecords++;
1097                for ( i = 0; i < psDBF->nRecordLength; i++ )
1098                        psDBF->pszCurrentRecord[i] = ' ';
1099
1100                psDBF->nCurrentRecord = hEntity;
1101        }
1102
1103        /* -------------------------------------------------------------------- */
1104        /*      Is this an existing record, but different than the last one     */
1105        /*      we accessed?                                                    */
1106        /* -------------------------------------------------------------------- */
1107        if ( psDBF->nCurrentRecord != hEntity )
1108        {
1109                DBFFlushRecord( psDBF );
1110
1111                nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1112
1113                fseek( psDBF->fp, nRecordOffset, 0 );
1114                fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1115
1116                psDBF->nCurrentRecord = hEntity;
1117        }
1118
1119        pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1120
1121        psDBF->bCurrentRecordModified = TRUE;
1122        psDBF->bUpdated = TRUE;
1123
1124        /* -------------------------------------------------------------------- */
1125        /*      Translate NULL value to valid DBF file representation.          */
1126        /*                                                                      */
1127        /*      Contributed by Jim Matthews.                                    */
1128        /* -------------------------------------------------------------------- */
1129        if ( pValue == NULL )
1130        {
1131                switch (psDBF->pachFieldType[iField])
1132                {
1133                case 'N':
1134                case 'F':
1135                        /* NULL numeric fields have value "****************" */
1136                        memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
1137                                psDBF->panFieldSize[iField] );
1138                        break;
1139
1140                case 'D':
1141                        /* NULL date fields have value "00000000" */
1142                        memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
1143                                psDBF->panFieldSize[iField] );
1144                        break;
1145
1146                case 'L':
1147                        /* NULL boolean fields have value "?" */
1148                        memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
1149                                psDBF->panFieldSize[iField] );
1150                        break;
1151
1152                default:
1153                        /* empty string fields are considered NULL */
1154                        memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0',
1155                                psDBF->panFieldSize[iField] );
1156                        break;
1157                }
1158                return TRUE;
1159        }
1160
1161        /* -------------------------------------------------------------------- */
1162        /*      Assign all the record fields.                                   */
1163        /* -------------------------------------------------------------------- */
1164        switch ( psDBF->pachFieldType[iField] )
1165        {
1166        case 'D':
1167        case 'N':
1168        case 'F':
1169                if ( psDBF->panFieldDecimals[iField] == 0 )
1170                {
1171                        int             nWidth = psDBF->panFieldSize[iField];
1172
1173                        if ( sizeof(szSField)-2 < nWidth )
1174                                nWidth = sizeof(szSField)-2;
1175
1176                        sprintf( szFormat, "%%%dd", nWidth );
1177                        sprintf(szSField, szFormat, (int) *((double *) pValue) );
1178                        if ( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
1179                        {
1180                                szSField[psDBF->panFieldSize[iField]] = '\0';
1181                                nRetResult = FALSE;
1182                        }
1183
1184                        strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1185                                szSField, strlen(szSField) );
1186                }
1187                else
1188                {
1189                        int             nWidth = psDBF->panFieldSize[iField];
1190
1191                        if ( sizeof(szSField)-2 < nWidth )
1192                                nWidth = sizeof(szSField)-2;
1193
1194                        sprintf( szFormat, "%%%d.%df",
1195                                 nWidth, psDBF->panFieldDecimals[iField] );
1196                        sprintf(szSField, szFormat, *((double *) pValue) );
1197                        if ( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
1198                        {
1199                                szSField[psDBF->panFieldSize[iField]] = '\0';
1200                                nRetResult = FALSE;
1201                        }
1202                        strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1203                                szSField, strlen(szSField) );
1204                }
1205                break;
1206
1207        case 'L':
1208                if (psDBF->panFieldSize[iField] >= 1  &&
1209                        (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
1210                        *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
1211                break;
1212
1213        default:
1214                if ( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1215                {
1216                        j = psDBF->panFieldSize[iField];
1217                        nRetResult = FALSE;
1218                }
1219                else
1220                {
1221                        memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1222                                psDBF->panFieldSize[iField] );
1223                        j = strlen((char *) pValue);
1224                }
1225
1226                strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1227                        (char *) pValue, j );
1228                break;
1229        }
1230
1231        return( nRetResult );
1232}
1233
1234/************************************************************************/
1235/*                     DBFWriteAttributeDirectly()                      */
1236/*                                                                      */
1237/*      Write an attribute record to the file, but without any          */
1238/*      reformatting based on type.  The provided buffer is written     */
1239/*      as is to the field position in the record.                      */
1240/************************************************************************/
1241
1242int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1243                              const 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        return( TRUE );
1309}
1310
1311/************************************************************************/
1312/*                      DBFWriteDoubleAttribute()                       */
1313/*                                                                      */
1314/*      Write a double attribute.                                       */
1315/************************************************************************/
1316
1317int SHPAPI_CALL
1318DBFWriteDoubleAttribute( 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
1331int SHPAPI_CALL
1332DBFWriteIntegerAttribute( 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
1347int SHPAPI_CALL
1348DBFWriteStringAttribute( 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
1361int SHPAPI_CALL
1362DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
1363
1364{
1365        return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
1366}
1367
1368/************************************************************************/
1369/*                      DBFWriteLogicalAttribute()                      */
1370/*                                                                      */
1371/*      Write a logical attribute.                                      */
1372/************************************************************************/
1373
1374int SHPAPI_CALL
1375DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
1376                          const char lValue)
1377
1378{
1379        return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
1380}
1381
1382/************************************************************************/
1383/*                         DBFWriteTuple()                              */
1384/*                                                                      */
1385/*      Write an attribute record to the file.                          */
1386/************************************************************************/
1387
1388int SHPAPI_CALL
1389DBFWriteTuple(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
1450const char SHPAPI_CALL1(*)
1451DBFReadTuple(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        {
1482                nTupleLen = psDBF->nRecordLength;
1483                pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
1484        }
1485
1486        memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
1487
1488        return( pReturnTuple );
1489}
1490
1491/************************************************************************/
1492/*                          DBFCloneEmpty()                              */
1493/*                                                                      */
1494/*      Read one of the attribute fields of a record.                   */
1495/************************************************************************/
1496
1497DBFHandle SHPAPI_CALL
1498DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
1499{
1500        DBFHandle       newDBF;
1501
1502        newDBF = DBFCreate ( pszFilename );
1503        if ( newDBF == NULL ) return ( NULL );
1504
1505        newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
1506        memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
1507
1508        newDBF->nFields = psDBF->nFields;
1509        newDBF->nRecordLength = psDBF->nRecordLength;
1510        newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
1511
1512        newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
1513        memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1514        newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
1515        memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1516        newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
1517        memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1518        newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
1519        memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
1520
1521        newDBF->bNoHeader = TRUE;
1522        newDBF->bUpdated = TRUE;
1523
1524        DBFWriteHeader ( newDBF );
1525        DBFClose ( newDBF );
1526
1527        newDBF = DBFOpen ( pszFilename, "rb+" );
1528
1529        return ( newDBF );
1530}
1531
1532/************************************************************************/
1533/*                       DBFGetNativeFieldType()                        */
1534/*                                                                      */
1535/*      Return the DBase field type for the specified field.            */
1536/*                                                                      */
1537/*      Value can be one of: 'C' (String), 'D' (Date), 'F' (Float),     */
1538/*                           'N' (Numeric, with or without decimal),    */
1539/*                           'L' (Logical),                             */
1540/*                           'M' (Memo: 10 digits .DBT block ptr)       */
1541/************************************************************************/
1542
1543char SHPAPI_CALL
1544DBFGetNativeFieldType( DBFHandle psDBF, int iField )
1545
1546{
1547        if ( iField >=0 && iField < psDBF->nFields )
1548                return psDBF->pachFieldType[iField];
1549
1550        return  ' ';
1551}
1552
1553/************************************************************************/
1554/*                            str_to_upper()                            */
1555/************************************************************************/
1556
1557static void str_to_upper (char *string)
1558{
1559        int len;
1560        short i = -1;
1561
1562        len = strlen (string);
1563
1564        while (++i < len)
1565                if (isalpha(string[i]) && islower(string[i]))
1566                        string[i] = (char) toupper ((int)string[i]);
1567}
1568
1569/************************************************************************/
1570/*                          DBFGetFieldIndex()                          */
1571/*                                                                      */
1572/*      Get the index number for a field in a .dbf file.                */
1573/*                                                                      */
1574/*      Contributed by Jim Matthews.                                    */
1575/************************************************************************/
1576
1577int SHPAPI_CALL
1578DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
1579
1580{
1581        char          name[12], name1[12], name2[12];
1582        int           i;
1583
1584        strncpy(name1, pszFieldName,11);
1585        name1[11] = '\0';
1586        str_to_upper(name1);
1587
1588        for ( i = 0; i < DBFGetFieldCount(psDBF); i++ )
1589        {
1590                DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
1591                strncpy(name2,name,11);
1592                str_to_upper(name2);
1593
1594                if (!strncmp(name1,name2,10))
1595                        return(i);
1596        }
1597        return(-1);
1598}
Note: See TracBrowser for help on using the repository browser.