source: subversion/applications/utils/import/and2osm/dbfopen.c @ 4349

Last change on this file since 4349 was 3846, checked in by jeroen, 13 years ago

and2osm, version 1

File size: 50.8 KB
Line 
1/******************************************************************************
2 * $Id: dbfopen.c,v 1.48 2003/03/10 14:51:27 warmerda Exp $
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: dbfopen.c,v $
37 * Revision 1.48  2003/03/10 14:51:27  warmerda
38 * DBFWrite* calls now return FALSE if they have to truncate
39 *
40 * Revision 1.47  2002/11/20 03:32:22  warmerda
41 * Ensure field name in DBFGetFieldIndex() is properly terminated.
42 *
43 * Revision 1.46  2002/10/09 13:10:21  warmerda
44 * Added check that width is positive.
45 *
46 * Revision 1.45  2002/09/29 00:00:08  warmerda
47 * added FTLogical and logical attribute read/write calls
48 *
49 * Revision 1.44  2002/05/07 13:46:11  warmerda
50 * Added DBFWriteAttributeDirectly().
51 *
52 * Revision 1.43  2002/02/13 19:39:21  warmerda
53 * Fix casting issues in DBFCloneEmpty().
54 *
55 * Revision 1.42  2002/01/15 14:36:07  warmerda
56 * updated email address
57 *
58 * Revision 1.41  2002/01/15 14:31:49  warmerda
59 * compute rather than copying nHeaderLength in DBFCloneEmpty()
60 *
61 * Revision 1.40  2002/01/09 04:32:35  warmerda
62 * fixed to read correct amount of header
63 *
64 * Revision 1.39  2001/12/11 22:41:03  warmerda
65 * improve io related error checking when reading header
66 *
67 * Revision 1.38  2001/11/28 16:07:31  warmerda
68 * Cleanup to avoid compiler warnings as suggested by Richard Hash.
69 *
70 * Revision 1.37  2001/07/04 05:18:09  warmerda
71 * do last fix properly
72 *
73 * Revision 1.36  2001/07/04 05:16:09  warmerda
74 * fixed fieldname comparison in DBFGetFieldIndex
75 *
76 * Revision 1.35  2001/06/22 02:10:06  warmerda
77 * fixed NULL shape support with help from Jim Matthews
78 *
79 * Revision 1.33  2001/05/31 19:20:13  warmerda
80 * added DBFGetFieldIndex()
81 *
82 * Revision 1.32  2001/05/31 18:15:40  warmerda
83 * Added support for NULL fields in DBF files
84 *
85 * Revision 1.31  2001/05/23 13:36:52  warmerda
86 * added use of SHPAPI_CALL
87 *
88 * Revision 1.30  2000/12/05 14:43:38  warmerda
89 * DBReadAttribute() white space trimming bug fix
90 *
91 * Revision 1.29  2000/10/05 14:36:44  warmerda
92 * fix bug with writing very wide numeric fields
93 *
94 * Revision 1.28  2000/09/25 14:18:07  warmerda
95 * Added some casts of strlen() return result to fix warnings on some
96 * systems, as submitted by Daniel.
97 *
98 * Revision 1.27  2000/09/25 14:15:51  warmerda
99 * added DBFGetNativeFieldType()
100 *
101 * Revision 1.26  2000/07/07 13:39:45  warmerda
102 * removed unused variables, and added system include files
103 *
104 * Revision 1.25  2000/05/29 18:19:13  warmerda
105 * avoid use of uchar, and adding casting fix
106 *
107 * Revision 1.24  2000/05/23 13:38:27  warmerda
108 * Added error checks on return results of fread() and fseek().
109 *
110 * Revision 1.23  2000/05/23 13:25:49  warmerda
111 * Avoid crashing if field or record are out of range in dbfread*attribute().
112 *
113 * Revision 1.22  1999/12/15 13:47:24  warmerda
114 * Added stdlib.h to ensure that atof() is prototyped.
115 *
116 * Revision 1.21  1999/12/13 17:25:46  warmerda
117 * Added support for upper case .DBF extention.
118 *
119 * Revision 1.20  1999/11/30 16:32:11  warmerda
120 * Use atof() instead of sscanf().
121 *
122 * Revision 1.19  1999/11/05 14:12:04  warmerda
123 * updated license terms
124 *
125 * Revision 1.18  1999/07/27 00:53:28  warmerda
126 * ensure that whole old field value clear on write of string
127 *
128 * Revision 1.1  1999/07/05 18:58:07  warmerda
129 * New
130 *
131 * Revision 1.17  1999/06/11 19:14:12  warmerda
132 * Fixed some memory leaks.
133 *
134 * Revision 1.16  1999/06/11 19:04:11  warmerda
135 * Remoted some unused variables.
136 *
137 * Revision 1.15  1999/05/11 03:19:28  warmerda
138 * added new Tuple api, and improved extension handling - add from candrsn
139 *
140 * Revision 1.14  1999/05/04 15:01:48  warmerda
141 * Added 'F' support.
142 *
143 * Revision 1.13  1999/03/23 17:38:59  warmerda
144 * DBFAddField() now actually does return the new field number, or -1 if
145 * it fails.
146 *
147 * Revision 1.12  1999/03/06 02:54:46  warmerda
148 * Added logic to convert shapefile name to dbf filename in DBFOpen()
149 * for convenience.
150 *
151 * Revision 1.11  1998/12/31 15:30:34  warmerda
152 * Improved the interchangability of numeric and string attributes.  Add
153 * white space trimming option for attributes.
154 *
155 * Revision 1.10  1998/12/03 16:36:44  warmerda
156 * Use r+b instead of rb+ for binary access.
157 *
158 * Revision 1.9  1998/12/03 15:34:23  warmerda
159 * Updated copyright message.
160 *
161 * Revision 1.8  1997/12/04 15:40:15  warmerda
162 * Added newline character after field definitions.
163 *
164 * Revision 1.7  1997/03/06 14:02:10  warmerda
165 * Ensure bUpdated is initialized.
166 *
167 * Revision 1.6  1996/02/12 04:54:41  warmerda
168 * Ensure that DBFWriteAttribute() returns TRUE if it succeeds.
169 *
170 * Revision 1.5  1995/10/21  03:15:12  warmerda
171 * Changed to use binary file access, and ensure that the
172 * field name field is zero filled, and limited to 10 chars.
173 *
174 * Revision 1.4  1995/08/24  18:10:42  warmerda
175 * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such
176 * as on the Sun.
177 *
178 * Revision 1.3  1995/08/04  03:15:16  warmerda
179 * Fixed up header.
180 *
181 * Revision 1.2  1995/08/04  03:14:43  warmerda
182 * Added header.
183 */
184
185static char rcsid[] = 
186  "$Id: dbfopen.c,v 1.48 2003/03/10 14:51:27 warmerda Exp $";
187
188#include "shapefil.h"
189
190#include <math.h>
191#include <stdlib.h>
192#include <ctype.h>
193#include <string.h>
194
195#ifndef FALSE
196#  define FALSE         0
197#  define TRUE          1
198#endif
199
200static int      nStringFieldLen = 0;
201static char * pszStringField = NULL;
202
203/************************************************************************/
204/*                             SfRealloc()                              */
205/*                                                                      */
206/*      A realloc cover function that will access a NULL pointer as     */
207/*      a valid input.                                                  */
208/************************************************************************/
209
210static void * SfRealloc( void * pMem, int nNewSize )
211
212{
213    if( pMem == NULL )
214        return( (void *) malloc(nNewSize) );
215    else
216        return( (void *) realloc(pMem,nNewSize) );
217}
218
219/************************************************************************/
220/*                           DBFWriteHeader()                           */
221/*                                                                      */
222/*      This is called to write out the file header, and field          */
223/*      descriptions before writing any actual data records.  This      */
224/*      also computes all the DBFDataSet field offset/size/decimals     */
225/*      and so forth values.                                            */
226/************************************************************************/
227
228static void DBFWriteHeader(DBFHandle psDBF)
229
230{
231    unsigned char       abyHeader[XBASE_FLDHDR_SZ];
232    int         i;
233
234    if( !psDBF->bNoHeader )
235        return;
236
237    psDBF->bNoHeader = FALSE;
238
239/* -------------------------------------------------------------------- */
240/*      Initialize the file header information.                         */
241/* -------------------------------------------------------------------- */
242    for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
243        abyHeader[i] = 0;
244
245    abyHeader[0] = 0x03;                /* memo field? - just copying   */
246
247    /* date updated on close, record count preset at zero */
248
249    abyHeader[8] = psDBF->nHeaderLength % 256;
250    abyHeader[9] = psDBF->nHeaderLength / 256;
251   
252    abyHeader[10] = psDBF->nRecordLength % 256;
253    abyHeader[11] = psDBF->nRecordLength / 256;
254
255/* -------------------------------------------------------------------- */
256/*      Write the initial 32 byte file header, and all the field        */
257/*      descriptions.                                                   */
258/* -------------------------------------------------------------------- */
259    fseek( psDBF->fp, 0, 0 );
260    fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
261    fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );
262
263/* -------------------------------------------------------------------- */
264/*      Write out the newline character if there is room for it.        */
265/* -------------------------------------------------------------------- */
266    if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
267    {
268        char    cNewline;
269
270        cNewline = 0x0d;
271        fwrite( &cNewline, 1, 1, psDBF->fp );
272    }
273}
274
275/************************************************************************/
276/*                           DBFFlushRecord()                           */
277/*                                                                      */
278/*      Write out the current record if there is one.                   */
279/************************************************************************/
280
281static void DBFFlushRecord( DBFHandle psDBF )
282
283{
284    int         nRecordOffset;
285
286    if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
287    {
288        psDBF->bCurrentRecordModified = FALSE;
289
290        nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord
291                                                     + psDBF->nHeaderLength;
292
293        fseek( psDBF->fp, nRecordOffset, 0 );
294        fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
295    }
296}
297
298/************************************************************************/
299/*                              DBFOpen()                               */
300/*                                                                      */
301/*      Open a .dbf file.                                               */
302/************************************************************************/
303   
304DBFHandle SHPAPI_CALL
305DBFOpen( const char * pszFilename, const char * pszAccess )
306
307{
308    DBFHandle           psDBF;
309    unsigned char               *pabyBuf;
310    int                 nFields, nHeadLen, nRecLen, iField, i;
311    char                *pszBasename, *pszFullname;
312
313/* -------------------------------------------------------------------- */
314/*      We only allow the access strings "rb" and "r+".                  */
315/* -------------------------------------------------------------------- */
316    if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 
317        && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
318        && strcmp(pszAccess,"r+b") != 0 )
319        return( NULL );
320
321    if( strcmp(pszAccess,"r") == 0 )
322        pszAccess = "rb";
323 
324    if( strcmp(pszAccess,"r+") == 0 )
325        pszAccess = "rb+";
326
327/* -------------------------------------------------------------------- */
328/*      Compute the base (layer) name.  If there is any extension       */
329/*      on the passed in filename we will strip it off.                 */
330/* -------------------------------------------------------------------- */
331    pszBasename = (char *) malloc(strlen(pszFilename)+5);
332    strcpy( pszBasename, pszFilename );
333    for( i = strlen(pszBasename)-1; 
334         i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
335               && pszBasename[i] != '\\';
336         i-- ) {}
337
338    if( pszBasename[i] == '.' )
339        pszBasename[i] = '\0';
340
341    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
342    sprintf( pszFullname, "%s.dbf", pszBasename );
343       
344    psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
345    psDBF->fp = fopen( pszFullname, pszAccess );
346
347    if( psDBF->fp == NULL )
348    {
349        sprintf( pszFullname, "%s.DBF", pszBasename );
350        psDBF->fp = fopen(pszFullname, pszAccess );
351    }
352   
353    free( pszBasename );
354    free( pszFullname );
355   
356    if( psDBF->fp == NULL )
357    {
358        free( psDBF );
359        return( NULL );
360    }
361
362    psDBF->bNoHeader = FALSE;
363    psDBF->nCurrentRecord = -1;
364    psDBF->bCurrentRecordModified = FALSE;
365
366/* -------------------------------------------------------------------- */
367/*  Read Table Header info                                              */
368/* -------------------------------------------------------------------- */
369    pabyBuf = (unsigned char *) malloc(500);
370    if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
371    {
372        fclose( psDBF->fp );
373        free( pabyBuf );
374        free( psDBF );
375        return NULL;
376    }
377
378    psDBF->nRecords = 
379     pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
380
381    psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
382    psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;
383   
384    psDBF->nFields = nFields = (nHeadLen - 32) / 32;
385
386    psDBF->pszCurrentRecord = (char *) malloc(nRecLen);
387
388/* -------------------------------------------------------------------- */
389/*  Read in Field Definitions                                           */
390/* -------------------------------------------------------------------- */
391   
392    pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
393    psDBF->pszHeader = (char *) pabyBuf;
394
395    fseek( psDBF->fp, 32, 0 );
396    if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
397    {
398        fclose( psDBF->fp );
399        free( pabyBuf );
400        free( psDBF );
401        return NULL;
402    }
403
404    psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
405    psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
406    psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
407    psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
408
409    for( iField = 0; iField < nFields; iField++ )
410    {
411        unsigned char           *pabyFInfo;
412
413        pabyFInfo = pabyBuf+iField*32;
414
415        if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
416        {
417            psDBF->panFieldSize[iField] = pabyFInfo[16];
418            psDBF->panFieldDecimals[iField] = pabyFInfo[17];
419        }
420        else
421        {
422            psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
423            psDBF->panFieldDecimals[iField] = 0;
424        }
425
426        psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
427        if( iField == 0 )
428            psDBF->panFieldOffset[iField] = 1;
429        else
430            psDBF->panFieldOffset[iField] = 
431              psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
432    }
433
434    return( psDBF );
435}
436
437/************************************************************************/
438/*                              DBFClose()                              */
439/************************************************************************/
440
441void SHPAPI_CALL
442DBFClose(DBFHandle psDBF)
443{
444/* -------------------------------------------------------------------- */
445/*      Write out header if not already written.                        */
446/* -------------------------------------------------------------------- */
447    if( psDBF->bNoHeader )
448        DBFWriteHeader( psDBF );
449
450    DBFFlushRecord( psDBF );
451
452/* -------------------------------------------------------------------- */
453/*      Update last access date, and number of records if we have       */
454/*      write access.                                                   */
455/* -------------------------------------------------------------------- */
456    if( psDBF->bUpdated )
457    {
458        unsigned char           abyFileHeader[32];
459
460        fseek( psDBF->fp, 0, 0 );
461        fread( abyFileHeader, 32, 1, psDBF->fp );
462
463        abyFileHeader[1] = 95;                  /* YY */
464        abyFileHeader[2] = 7;                   /* MM */
465        abyFileHeader[3] = 26;                  /* DD */
466
467        abyFileHeader[4] = psDBF->nRecords % 256;
468        abyFileHeader[5] = (psDBF->nRecords/256) % 256;
469        abyFileHeader[6] = (psDBF->nRecords/(256*256)) % 256;
470        abyFileHeader[7] = (psDBF->nRecords/(256*256*256)) % 256;
471
472        fseek( psDBF->fp, 0, 0 );
473        fwrite( abyFileHeader, 32, 1, psDBF->fp );
474    }
475
476/* -------------------------------------------------------------------- */
477/*      Close, and free resources.                                      */
478/* -------------------------------------------------------------------- */
479    fclose( psDBF->fp );
480
481    if( psDBF->panFieldOffset != NULL )
482    {
483        free( psDBF->panFieldOffset );
484        free( psDBF->panFieldSize );
485        free( psDBF->panFieldDecimals );
486        free( psDBF->pachFieldType );
487    }
488
489    free( psDBF->pszHeader );
490    free( psDBF->pszCurrentRecord );
491
492    free( psDBF );
493
494    if( pszStringField != NULL )
495    {
496        free( pszStringField );
497        pszStringField = NULL;
498        nStringFieldLen = 0;
499    }
500}
501
502/************************************************************************/
503/*                             DBFCreate()                              */
504/*                                                                      */
505/*      Create a new .dbf file.                                         */
506/************************************************************************/
507
508DBFHandle SHPAPI_CALL
509DBFCreate( const char * pszFilename )
510
511{
512    DBFHandle   psDBF;
513    FILE        *fp;
514    char        *pszFullname, *pszBasename;
515    int         i;
516
517/* -------------------------------------------------------------------- */
518/*      Compute the base (layer) name.  If there is any extension       */
519/*      on the passed in filename we will strip it off.                 */
520/* -------------------------------------------------------------------- */
521    pszBasename = (char *) malloc(strlen(pszFilename)+5);
522    strcpy( pszBasename, pszFilename );
523    for( i = strlen(pszBasename)-1; 
524         i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
525               && pszBasename[i] != '\\';
526         i-- ) {}
527
528    if( pszBasename[i] == '.' )
529        pszBasename[i] = '\0';
530
531    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
532    sprintf( pszFullname, "%s.dbf", pszBasename );
533    free( pszBasename );
534
535/* -------------------------------------------------------------------- */
536/*      Create the file.                                                */
537/* -------------------------------------------------------------------- */
538    fp = fopen( pszFullname, "wb" );
539    if( fp == NULL )
540        return( NULL );
541
542    fputc( 0, fp );
543    fclose( fp );
544
545    fp = fopen( pszFullname, "rb+" );
546    if( fp == NULL )
547        return( NULL );
548
549    free( pszFullname );
550
551/* -------------------------------------------------------------------- */
552/*      Create the info structure.                                      */
553/* -------------------------------------------------------------------- */
554    psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
555
556    psDBF->fp = fp;
557    psDBF->nRecords = 0;
558    psDBF->nFields = 0;
559    psDBF->nRecordLength = 1;
560    psDBF->nHeaderLength = 33;
561   
562    psDBF->panFieldOffset = NULL;
563    psDBF->panFieldSize = NULL;
564    psDBF->panFieldDecimals = NULL;
565    psDBF->pachFieldType = NULL;
566    psDBF->pszHeader = NULL;
567
568    psDBF->nCurrentRecord = -1;
569    psDBF->bCurrentRecordModified = FALSE;
570    psDBF->pszCurrentRecord = NULL;
571
572    psDBF->bNoHeader = TRUE;
573
574    return( psDBF );
575}
576
577/************************************************************************/
578/*                            DBFAddField()                             */
579/*                                                                      */
580/*      Add a field to a newly created .dbf file before any records     */
581/*      are written.                                                    */
582/************************************************************************/
583
584int SHPAPI_CALL
585DBFAddField(DBFHandle psDBF, const char * pszFieldName, 
586            DBFFieldType eType, int nWidth, int nDecimals )
587
588{
589    char        *pszFInfo;
590    int         i;
591
592/* -------------------------------------------------------------------- */
593/*      Do some checking to ensure we can add records to this file.     */
594/* -------------------------------------------------------------------- */
595    if( psDBF->nRecords > 0 )
596        return( -1 );
597
598    if( !psDBF->bNoHeader )
599        return( -1 );
600
601    if( eType != FTDouble && nDecimals != 0 )
602        return( -1 );
603
604    if( nWidth < 1 )
605        return -1;
606
607/* -------------------------------------------------------------------- */
608/*      SfRealloc all the arrays larger to hold the additional field      */
609/*      information.                                                    */
610/* -------------------------------------------------------------------- */
611    psDBF->nFields++;
612
613    psDBF->panFieldOffset = (int *) 
614      SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
615
616    psDBF->panFieldSize = (int *) 
617      SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
618
619    psDBF->panFieldDecimals = (int *) 
620      SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
621
622    psDBF->pachFieldType = (char *) 
623      SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
624
625/* -------------------------------------------------------------------- */
626/*      Assign the new field information fields.                        */
627/* -------------------------------------------------------------------- */
628    psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
629    psDBF->nRecordLength += nWidth;
630    psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
631    psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
632
633    if( eType == FTLogical )
634        psDBF->pachFieldType[psDBF->nFields-1] = 'L';
635    else if( eType == FTString )
636        psDBF->pachFieldType[psDBF->nFields-1] = 'C';
637    else
638        psDBF->pachFieldType[psDBF->nFields-1] = 'N';
639
640/* -------------------------------------------------------------------- */
641/*      Extend the required header information.                         */
642/* -------------------------------------------------------------------- */
643    psDBF->nHeaderLength += 32;
644    psDBF->bUpdated = FALSE;
645
646    psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
647
648    pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
649
650    for( i = 0; i < 32; i++ )
651        pszFInfo[i] = '\0';
652
653    if( (int) strlen(pszFieldName) < 10 )
654        strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
655    else
656        strncpy( pszFInfo, pszFieldName, 10);
657
658    pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
659
660    if( eType == FTString )
661    {
662        pszFInfo[16] = nWidth % 256;
663        pszFInfo[17] = nWidth / 256;
664    }
665    else
666    {
667        pszFInfo[16] = nWidth;
668        pszFInfo[17] = nDecimals;
669    }
670   
671/* -------------------------------------------------------------------- */
672/*      Make the current record buffer appropriately larger.            */
673/* -------------------------------------------------------------------- */
674    psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
675                                               psDBF->nRecordLength);
676
677    return( psDBF->nFields-1 );
678}
679
680/************************************************************************/
681/*                          DBFReadAttribute()                          */
682/*                                                                      */
683/*      Read one of the attribute fields of a record.                   */
684/************************************************************************/
685
686static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
687                              char chReqType )
688
689{
690    int         nRecordOffset;
691    unsigned char       *pabyRec;
692    void        *pReturnField = NULL;
693
694    static double dDoubleField;
695
696/* -------------------------------------------------------------------- */
697/*      Verify selection.                                               */
698/* -------------------------------------------------------------------- */
699    if( hEntity < 0 || hEntity >= psDBF->nRecords )
700        return( NULL );
701
702    if( iField < 0 || iField >= psDBF->nFields )
703        return( NULL );
704
705/* -------------------------------------------------------------------- */
706/*      Have we read the record?                                        */
707/* -------------------------------------------------------------------- */
708    if( psDBF->nCurrentRecord != hEntity )
709    {
710        DBFFlushRecord( psDBF );
711
712        nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
713
714        if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
715        {
716            fprintf( stderr, "fseek(%d) failed on DBF file.\n",
717                     nRecordOffset );
718            return NULL;
719        }
720
721        if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 
722                   1, psDBF->fp ) != 1 )
723        {
724            fprintf( stderr, "fread(%d) failed on DBF file.\n",
725                     psDBF->nRecordLength );
726            return NULL;
727        }
728
729        psDBF->nCurrentRecord = hEntity;
730    }
731
732    pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
733
734/* -------------------------------------------------------------------- */
735/*      Ensure our field buffer is large enough to hold this buffer.    */
736/* -------------------------------------------------------------------- */
737    if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
738    {
739        nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
740        pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
741    }
742
743/* -------------------------------------------------------------------- */
744/*      Extract the requested field.                                    */
745/* -------------------------------------------------------------------- */
746    strncpy( pszStringField, 
747             ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
748             psDBF->panFieldSize[iField] );
749    pszStringField[psDBF->panFieldSize[iField]] = '\0';
750
751    pReturnField = pszStringField;
752
753/* -------------------------------------------------------------------- */
754/*      Decode the field.                                               */
755/* -------------------------------------------------------------------- */
756    if( chReqType == 'N' )
757    {
758        dDoubleField = atof(pszStringField);
759
760        pReturnField = &dDoubleField;
761    }
762
763/* -------------------------------------------------------------------- */
764/*      Should we trim white space off the string attribute value?      */
765/* -------------------------------------------------------------------- */
766#ifdef TRIM_DBF_WHITESPACE
767    else
768    {
769        char    *pchSrc, *pchDst;
770
771        pchDst = pchSrc = pszStringField;
772        while( *pchSrc == ' ' )
773            pchSrc++;
774
775        while( *pchSrc != '\0' )
776            *(pchDst++) = *(pchSrc++);
777        *pchDst = '\0';
778
779        while( pchDst != pszStringField && *(--pchDst) == ' ' )
780            *pchDst = '\0';
781    }
782#endif
783   
784    return( pReturnField );
785}
786
787/************************************************************************/
788/*                        DBFReadIntAttribute()                         */
789/*                                                                      */
790/*      Read an integer attribute.                                      */
791/************************************************************************/
792
793int SHPAPI_CALL
794DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
795
796{
797    double      *pdValue;
798
799    pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
800
801    if( pdValue == NULL )
802        return 0;
803    else
804        return( (int) *pdValue );
805}
806
807/************************************************************************/
808/*                        DBFReadDoubleAttribute()                      */
809/*                                                                      */
810/*      Read a double attribute.                                        */
811/************************************************************************/
812
813double SHPAPI_CALL
814DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
815
816{
817    double      *pdValue;
818
819    pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
820
821    if( pdValue == NULL )
822        return 0.0;
823    else
824        return( *pdValue );
825}
826
827/************************************************************************/
828/*                        DBFReadStringAttribute()                      */
829/*                                                                      */
830/*      Read a string attribute.                                        */
831/************************************************************************/
832
833const char SHPAPI_CALL1(*)
834DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
835
836{
837    return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
838}
839
840/************************************************************************/
841/*                        DBFReadLogicalAttribute()                     */
842/*                                                                      */
843/*      Read a logical attribute.                                       */
844/************************************************************************/
845
846const char SHPAPI_CALL1(*)
847DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
848
849{
850    return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
851}
852
853/************************************************************************/
854/*                         DBFIsAttributeNULL()                         */
855/*                                                                      */
856/*      Return TRUE if value for field is NULL.                         */
857/*                                                                      */
858/*      Contributed by Jim Matthews.                                    */
859/************************************************************************/
860
861int SHPAPI_CALL
862DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
863
864{
865    const char  *pszValue;
866
867    pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
868
869    switch(psDBF->pachFieldType[iField])
870    {
871      case 'N':
872      case 'F':
873        /* NULL numeric fields have value "****************" */
874        return pszValue[0] == '*';
875
876      case 'D':
877        /* NULL date fields have value "00000000" */
878        return strncmp(pszValue,"00000000",8) == 0;
879
880      case 'L':
881        /* NULL boolean fields have value "?" */ 
882        return pszValue[0] == '?';
883
884      default:
885        /* empty string fields are considered NULL */
886        return strlen(pszValue) == 0;
887    }
888}
889
890/************************************************************************/
891/*                          DBFGetFieldCount()                          */
892/*                                                                      */
893/*      Return the number of fields in this table.                      */
894/************************************************************************/
895
896int SHPAPI_CALL
897DBFGetFieldCount( DBFHandle psDBF )
898
899{
900    return( psDBF->nFields );
901}
902
903/************************************************************************/
904/*                         DBFGetRecordCount()                          */
905/*                                                                      */
906/*      Return the number of records in this table.                     */
907/************************************************************************/
908
909int SHPAPI_CALL
910DBFGetRecordCount( DBFHandle psDBF )
911
912{
913    return( psDBF->nRecords );
914}
915
916/************************************************************************/
917/*                          DBFGetFieldInfo()                           */
918/*                                                                      */
919/*      Return any requested information about the field.               */
920/************************************************************************/
921
922DBFFieldType SHPAPI_CALL
923DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
924                 int * pnWidth, int * pnDecimals )
925
926{
927    if( iField < 0 || iField >= psDBF->nFields )
928        return( FTInvalid );
929
930    if( pnWidth != NULL )
931        *pnWidth = psDBF->panFieldSize[iField];
932
933    if( pnDecimals != NULL )
934        *pnDecimals = psDBF->panFieldDecimals[iField];
935
936    if( pszFieldName != NULL )
937    {
938        int     i;
939
940        strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
941        pszFieldName[11] = '\0';
942        for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
943            pszFieldName[i] = '\0';
944    }
945
946    if ( psDBF->pachFieldType[iField] == 'L' )
947        return( FTLogical);
948
949    else if( psDBF->pachFieldType[iField] == 'N' 
950             || psDBF->pachFieldType[iField] == 'F'
951             || psDBF->pachFieldType[iField] == 'D' )
952    {
953        if( psDBF->panFieldDecimals[iField] > 0 )
954            return( FTDouble );
955        else
956            return( FTInteger );
957    }
958    else
959    {
960        return( FTString );
961    }
962}
963
964/************************************************************************/
965/*                         DBFWriteAttribute()                          */
966/*                                                                      */
967/*      Write an attribute record to the file.                          */
968/************************************************************************/
969
970static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
971                             void * pValue )
972
973{
974    int         nRecordOffset, i, j, nRetResult = TRUE;
975    unsigned char       *pabyRec;
976    char        szSField[400], szFormat[20];
977
978/* -------------------------------------------------------------------- */
979/*      Is this a valid record?                                         */
980/* -------------------------------------------------------------------- */
981    if( hEntity < 0 || hEntity > psDBF->nRecords )
982        return( FALSE );
983
984    if( psDBF->bNoHeader )
985        DBFWriteHeader(psDBF);
986
987/* -------------------------------------------------------------------- */
988/*      Is this a brand new record?                                     */
989/* -------------------------------------------------------------------- */
990    if( hEntity == psDBF->nRecords )
991    {
992        DBFFlushRecord( psDBF );
993
994        psDBF->nRecords++;
995        for( i = 0; i < psDBF->nRecordLength; i++ )
996            psDBF->pszCurrentRecord[i] = ' ';
997
998        psDBF->nCurrentRecord = hEntity;
999    }
1000
1001/* -------------------------------------------------------------------- */
1002/*      Is this an existing record, but different than the last one     */
1003/*      we accessed?                                                    */
1004/* -------------------------------------------------------------------- */
1005    if( psDBF->nCurrentRecord != hEntity )
1006    {
1007        DBFFlushRecord( psDBF );
1008
1009        nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1010
1011        fseek( psDBF->fp, nRecordOffset, 0 );
1012        fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1013
1014        psDBF->nCurrentRecord = hEntity;
1015    }
1016
1017    pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1018
1019    psDBF->bCurrentRecordModified = TRUE;
1020    psDBF->bUpdated = TRUE;
1021
1022/* -------------------------------------------------------------------- */
1023/*      Translate NULL value to valid DBF file representation.          */
1024/*                                                                      */
1025/*      Contributed by Jim Matthews.                                    */
1026/* -------------------------------------------------------------------- */
1027    if( pValue == NULL )
1028    {
1029        switch(psDBF->pachFieldType[iField])
1030        {
1031          case 'N':
1032          case 'F':
1033            /* NULL numeric fields have value "****************" */
1034            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*', 
1035                    psDBF->panFieldSize[iField] );
1036            break;
1037
1038          case 'D':
1039            /* NULL date fields have value "00000000" */
1040            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0', 
1041                    psDBF->panFieldSize[iField] );
1042            break;
1043
1044          case 'L':
1045            /* NULL boolean fields have value "?" */ 
1046            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?', 
1047                    psDBF->panFieldSize[iField] );
1048            break;
1049
1050          default:
1051            /* empty string fields are considered NULL */
1052            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0', 
1053                    psDBF->panFieldSize[iField] );
1054            break;
1055        }
1056        return TRUE;
1057    }
1058
1059/* -------------------------------------------------------------------- */
1060/*      Assign all the record fields.                                   */
1061/* -------------------------------------------------------------------- */
1062    switch( psDBF->pachFieldType[iField] )
1063    {
1064      case 'D':
1065      case 'N':
1066      case 'F':
1067        if( psDBF->panFieldDecimals[iField] == 0 )
1068        {
1069            int         nWidth = psDBF->panFieldSize[iField];
1070
1071            if( sizeof(szSField)-2 < nWidth )
1072                nWidth = sizeof(szSField)-2;
1073
1074            sprintf( szFormat, "%%%dd", nWidth );
1075            sprintf(szSField, szFormat, (int) *((double *) pValue) );
1076            if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
1077            {
1078                szSField[psDBF->panFieldSize[iField]] = '\0';
1079                nRetResult = FALSE;
1080            }
1081
1082            strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1083                    szSField, strlen(szSField) );
1084        }
1085        else
1086        {
1087            int         nWidth = psDBF->panFieldSize[iField];
1088
1089            if( sizeof(szSField)-2 < nWidth )
1090                nWidth = sizeof(szSField)-2;
1091
1092            sprintf( szFormat, "%%%d.%df", 
1093                     nWidth, psDBF->panFieldDecimals[iField] );
1094            sprintf(szSField, szFormat, *((double *) pValue) );
1095            if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
1096            {
1097                szSField[psDBF->panFieldSize[iField]] = '\0';
1098                nRetResult = FALSE;
1099            }
1100            strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1101                    szSField, strlen(szSField) );
1102        }
1103        break;
1104
1105      case 'L':
1106        if (psDBF->panFieldSize[iField] >= 1  && 
1107            (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
1108            *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
1109        break;
1110
1111      default:
1112        if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1113        {
1114            j = psDBF->panFieldSize[iField];
1115            nRetResult = FALSE;
1116        }
1117        else
1118        {
1119            memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1120                    psDBF->panFieldSize[iField] );
1121            j = strlen((char *) pValue);
1122        }
1123
1124        strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1125                (char *) pValue, j );
1126        break;
1127    }
1128
1129    return( nRetResult );
1130}
1131
1132/************************************************************************/
1133/*                     DBFWriteAttributeDirectly()                      */
1134/*                                                                      */
1135/*      Write an attribute record to the file, but without any          */
1136/*      reformatting based on type.  The provided buffer is written     */
1137/*      as is to the field position in the record.                      */
1138/************************************************************************/
1139
1140int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
1141                              void * pValue )
1142
1143{
1144    int         nRecordOffset, i, j;
1145    unsigned char       *pabyRec;
1146
1147/* -------------------------------------------------------------------- */
1148/*      Is this a valid record?                                         */
1149/* -------------------------------------------------------------------- */
1150    if( hEntity < 0 || hEntity > psDBF->nRecords )
1151        return( FALSE );
1152
1153    if( psDBF->bNoHeader )
1154        DBFWriteHeader(psDBF);
1155
1156/* -------------------------------------------------------------------- */
1157/*      Is this a brand new record?                                     */
1158/* -------------------------------------------------------------------- */
1159    if( hEntity == psDBF->nRecords )
1160    {
1161        DBFFlushRecord( psDBF );
1162
1163        psDBF->nRecords++;
1164        for( i = 0; i < psDBF->nRecordLength; i++ )
1165            psDBF->pszCurrentRecord[i] = ' ';
1166
1167        psDBF->nCurrentRecord = hEntity;
1168    }
1169
1170/* -------------------------------------------------------------------- */
1171/*      Is this an existing record, but different than the last one     */
1172/*      we accessed?                                                    */
1173/* -------------------------------------------------------------------- */
1174    if( psDBF->nCurrentRecord != hEntity )
1175    {
1176        DBFFlushRecord( psDBF );
1177
1178        nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1179
1180        fseek( psDBF->fp, nRecordOffset, 0 );
1181        fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1182
1183        psDBF->nCurrentRecord = hEntity;
1184    }
1185
1186    pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1187
1188/* -------------------------------------------------------------------- */
1189/*      Assign all the record fields.                                   */
1190/* -------------------------------------------------------------------- */
1191    if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
1192        j = psDBF->panFieldSize[iField];
1193    else
1194    {
1195        memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
1196                psDBF->panFieldSize[iField] );
1197        j = strlen((char *) pValue);
1198    }
1199
1200    strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
1201            (char *) pValue, j );
1202
1203    psDBF->bCurrentRecordModified = TRUE;
1204    psDBF->bUpdated = TRUE;
1205
1206    return( TRUE );
1207}
1208
1209/************************************************************************/
1210/*                      DBFWriteDoubleAttribute()                       */
1211/*                                                                      */
1212/*      Write a double attribute.                                       */
1213/************************************************************************/
1214
1215int SHPAPI_CALL
1216DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
1217                         double dValue )
1218
1219{
1220    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1221}
1222
1223/************************************************************************/
1224/*                      DBFWriteIntegerAttribute()                      */
1225/*                                                                      */
1226/*      Write a integer attribute.                                      */
1227/************************************************************************/
1228
1229int SHPAPI_CALL
1230DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
1231                          int nValue )
1232
1233{
1234    double      dValue = nValue;
1235
1236    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
1237}
1238
1239/************************************************************************/
1240/*                      DBFWriteStringAttribute()                       */
1241/*                                                                      */
1242/*      Write a string attribute.                                       */
1243/************************************************************************/
1244
1245int SHPAPI_CALL
1246DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
1247                         const char * pszValue )
1248
1249{
1250    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
1251}
1252
1253/************************************************************************/
1254/*                      DBFWriteNULLAttribute()                         */
1255/*                                                                      */
1256/*      Write a string attribute.                                       */
1257/************************************************************************/
1258
1259int SHPAPI_CALL
1260DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
1261
1262{
1263    return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
1264}
1265
1266/************************************************************************/
1267/*                      DBFWriteLogicalAttribute()                      */
1268/*                                                                      */
1269/*      Write a logical attribute.                                      */
1270/************************************************************************/
1271
1272int SHPAPI_CALL
1273DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
1274                       const char lValue)
1275
1276{
1277    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
1278}
1279
1280/************************************************************************/
1281/*                         DBFWriteTuple()                              */
1282/*                                                                      */
1283/*      Write an attribute record to the file.                          */
1284/************************************************************************/
1285
1286int SHPAPI_CALL
1287DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
1288
1289{
1290    int         nRecordOffset, i;
1291    unsigned char       *pabyRec;
1292
1293/* -------------------------------------------------------------------- */
1294/*      Is this a valid record?                                         */
1295/* -------------------------------------------------------------------- */
1296    if( hEntity < 0 || hEntity > psDBF->nRecords )
1297        return( FALSE );
1298
1299    if( psDBF->bNoHeader )
1300        DBFWriteHeader(psDBF);
1301
1302/* -------------------------------------------------------------------- */
1303/*      Is this a brand new record?                                     */
1304/* -------------------------------------------------------------------- */
1305    if( hEntity == psDBF->nRecords )
1306    {
1307        DBFFlushRecord( psDBF );
1308
1309        psDBF->nRecords++;
1310        for( i = 0; i < psDBF->nRecordLength; i++ )
1311            psDBF->pszCurrentRecord[i] = ' ';
1312
1313        psDBF->nCurrentRecord = hEntity;
1314    }
1315
1316/* -------------------------------------------------------------------- */
1317/*      Is this an existing record, but different than the last one     */
1318/*      we accessed?                                                    */
1319/* -------------------------------------------------------------------- */
1320    if( psDBF->nCurrentRecord != hEntity )
1321    {
1322        DBFFlushRecord( psDBF );
1323
1324        nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1325
1326        fseek( psDBF->fp, nRecordOffset, 0 );
1327        fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1328
1329        psDBF->nCurrentRecord = hEntity;
1330    }
1331
1332    pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1333
1334    memcpy ( pabyRec, pRawTuple,  psDBF->nRecordLength );
1335
1336    psDBF->bCurrentRecordModified = TRUE;
1337    psDBF->bUpdated = TRUE;
1338
1339    return( TRUE );
1340}
1341
1342/************************************************************************/
1343/*                          DBFReadTuple()                              */
1344/*                                                                      */
1345/*      Read one of the attribute fields of a record.                   */
1346/************************************************************************/
1347
1348const char SHPAPI_CALL1(*)
1349DBFReadTuple(DBFHandle psDBF, int hEntity )
1350
1351{
1352    int         nRecordOffset;
1353    unsigned char       *pabyRec;
1354    static char *pReturnTuple = NULL;
1355
1356    static int  nTupleLen = 0;
1357
1358/* -------------------------------------------------------------------- */
1359/*      Have we read the record?                                        */
1360/* -------------------------------------------------------------------- */
1361    if( hEntity < 0 || hEntity >= psDBF->nRecords )
1362        return( NULL );
1363
1364    if( psDBF->nCurrentRecord != hEntity )
1365    {
1366        DBFFlushRecord( psDBF );
1367
1368        nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1369
1370        fseek( psDBF->fp, nRecordOffset, 0 );
1371        fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1372
1373        psDBF->nCurrentRecord = hEntity;
1374    }
1375
1376    pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
1377
1378    if ( nTupleLen < psDBF->nRecordLength) {
1379      nTupleLen = psDBF->nRecordLength;
1380      pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
1381    }
1382   
1383    memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
1384       
1385    return( pReturnTuple );
1386}
1387
1388/************************************************************************/
1389/*                          DBFCloneEmpty()                              */
1390/*                                                                      */
1391/*      Read one of the attribute fields of a record.                   */
1392/************************************************************************/
1393
1394DBFHandle SHPAPI_CALL
1395DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) 
1396{
1397    DBFHandle   newDBF;
1398
1399   newDBF = DBFCreate ( pszFilename );
1400   if ( newDBF == NULL ) return ( NULL ); 
1401   
1402   newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
1403   memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
1404   
1405   newDBF->nFields = psDBF->nFields;
1406   newDBF->nRecordLength = psDBF->nRecordLength;
1407   newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
1408   
1409   newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); 
1410   memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1411   newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
1412   memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1413   newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
1414   memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1415   newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
1416   memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
1417
1418   newDBF->bNoHeader = TRUE;
1419   newDBF->bUpdated = TRUE;
1420   
1421   DBFWriteHeader ( newDBF );
1422   DBFClose ( newDBF );
1423   
1424   newDBF = DBFOpen ( pszFilename, "rb+" );
1425
1426   return ( newDBF );
1427}
1428
1429/************************************************************************/
1430/*                       DBFGetNativeFieldType()                        */
1431/*                                                                      */
1432/*      Return the DBase field type for the specified field.            */
1433/*                                                                      */
1434/*      Value can be one of: 'C' (String), 'D' (Date), 'F' (Float),     */
1435/*                           'N' (Numeric, with or without decimal),    */
1436/*                           'L' (Logical),                             */
1437/*                           'M' (Memo: 10 digits .DBT block ptr)       */
1438/************************************************************************/
1439
1440char SHPAPI_CALL
1441DBFGetNativeFieldType( DBFHandle psDBF, int iField )
1442
1443{
1444    if( iField >=0 && iField < psDBF->nFields )
1445        return psDBF->pachFieldType[iField];
1446
1447    return  ' ';
1448}
1449
1450/************************************************************************/
1451/*                            str_to_upper()                            */
1452/************************************************************************/
1453
1454static void str_to_upper (char *string)
1455{
1456    int len;
1457    short i = -1;
1458
1459    len = strlen (string);
1460
1461    while (++i < len)
1462        if (isalpha(string[i]) && islower(string[i]))
1463            string[i] = toupper ((int)string[i]);
1464}
1465
1466/************************************************************************/
1467/*                          DBFGetFieldIndex()                          */
1468/*                                                                      */
1469/*      Get the index number for a field in a .dbf file.                */
1470/*                                                                      */
1471/*      Contributed by Jim Matthews.                                    */
1472/************************************************************************/
1473
1474int SHPAPI_CALL
1475DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
1476
1477{
1478    char          name[12], name1[12], name2[12];
1479    int           i;
1480
1481    strncpy(name1, pszFieldName,11);
1482    name1[11] = '\0';
1483    str_to_upper(name1);
1484
1485    for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
1486    {
1487        DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
1488        strncpy(name2,name,11);
1489        str_to_upper(name2);
1490
1491        if(!strncmp(name1,name2,10))
1492            return(i);
1493    }
1494    return(-1);
1495}
Note: See TracBrowser for help on using the repository browser.