~ubuntu-branches/ubuntu/wily/qgis/wily

« back to all changes in this revision

Viewing changes to src/plugins/grid_maker/dbfopen.c

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************************************
2
 
 * $Id: dbfopen.c 1581 2004-06-14 04:35:20Z gsherman $
3
 
 *
4
 
 * Project:  Shapelib
5
 
 * Purpose:  Implementation of .dbf access API documented in dbf_api.html.
6
 
 * Author:   Frank Warmerdam, warmerda@home.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.2  2004/06/14 04:35:19  gsherman
38
 
 * Changes to support Windows version
39
 
 *
40
 
 * Revision 1.1  2004/04/05 15:39:45  timlinux
41
 
 * Initial commit of new plugin to build graticules - not working yet! And thus not added to higher level makefiles yet.
42
 
 *
43
 
 * Revision 1.2  2004/03/31 20:36:46  timlinux
44
 
 * Fix for knock on effects of change of filename from shapefil.h to shapefile.h
45
 
 *
46
 
 * Revision 1.1  2004/03/22 23:38:25  timlinux
47
 
 * This is a c++ first draft of a port of a perl script by Schuyler to import Garmin gps dump files as a shapefile. The resulting imported file will be displayed in the map view. At the moment it only generates a point layer of the waypoints but a future version will generate polylines and perhaps polygons too using similar logic to that used by Shuylers perl stuff. Note this plugin is still under construction and I am commiting it mainly so that other developers can assist me when I get stuck. Also note that the plugins Makefile builds a standalone app based on the plugin gui that can be run separately from qgis.
48
 
 *
49
 
 * Revision 1.22  1999/12/15 13:47:24  warmerda
50
 
 * Added stdlib.h to ensure that atof() is prototyped.
51
 
 *
52
 
 * Revision 1.21  1999/12/13 17:25:46  warmerda
53
 
 * Added support for upper case .DBF extention.
54
 
 *
55
 
 * Revision 1.20  1999/11/30 16:32:11  warmerda
56
 
 * Use atof() instead of sscanf().
57
 
 *
58
 
 * Revision 1.19  1999/11/05 14:12:04  warmerda
59
 
 * updated license terms
60
 
 *
61
 
 * Revision 1.18  1999/07/27 00:53:28  warmerda
62
 
 * ensure that whole old field value clear on write of string
63
 
 *
64
 
 * Revision 1.1  1999/07/05 18:58:07  warmerda
65
 
 * New
66
 
 *
67
 
 * Revision 1.17  1999/06/11 19:14:12  warmerda
68
 
 * Fixed some memory leaks.
69
 
 *
70
 
 * Revision 1.16  1999/06/11 19:04:11  warmerda
71
 
 * Remoted some unused variables.
72
 
 *
73
 
 * Revision 1.15  1999/05/11 03:19:28  warmerda
74
 
 * added new Tuple api, and improved extension handling - add from candrsn
75
 
 *
76
 
 * Revision 1.14  1999/05/04 15:01:48  warmerda
77
 
 * Added 'F' support.
78
 
 *
79
 
 * Revision 1.13  1999/03/23 17:38:59  warmerda
80
 
 * DBFAddField() now actually does return the new field number, or -1 if
81
 
 * it fails.
82
 
 *
83
 
 * Revision 1.12  1999/03/06 02:54:46  warmerda
84
 
 * Added logic to convert shapefile name to dbf filename in DBFOpen()
85
 
 * for convenience.
86
 
 *
87
 
 * Revision 1.11  1998/12/31 15:30:34  warmerda
88
 
 * Improved the interchangability of numeric and string attributes.  Add
89
 
 * white space trimming option for attributes.
90
 
 *
91
 
 * Revision 1.10  1998/12/03 16:36:44  warmerda
92
 
 * Use r+b instead of rb+ for binary access.
93
 
 *
94
 
 * Revision 1.9  1998/12/03 15:34:23  warmerda
95
 
 * Updated copyright message.
96
 
 *
97
 
 * Revision 1.8  1997/12/04 15:40:15  warmerda
98
 
 * Added newline character after field definitions.
99
 
 *
100
 
 * Revision 1.7  1997/03/06 14:02:10  warmerda
101
 
 * Ensure bUpdated is initialized.
102
 
 *
103
 
 * Revision 1.6  1996/02/12 04:54:41  warmerda
104
 
 * Ensure that DBFWriteAttribute() returns TRUE if it succeeds.
105
 
 *
106
 
 * Revision 1.5  1995/10/21  03:15:12  warmerda
107
 
 * Changed to use binary file access, and ensure that the
108
 
 * field name field is zero filled, and limited to 10 chars.
109
 
 *
110
 
 * Revision 1.4  1995/08/24  18:10:42  warmerda
111
 
 * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such
112
 
 * as on the Sun.
113
 
 *
114
 
 * Revision 1.3  1995/08/04  03:15:16  warmerda
115
 
 * Fixed up header.
116
 
 *
117
 
 * Revision 1.2  1995/08/04  03:14:43  warmerda
118
 
 * Added header.
119
 
 */
120
 
 
121
 
static char rcsid[] = 
122
 
  "$Id: dbfopen.c 1581 2004-06-14 04:35:20Z gsherman $";
123
 
 
124
 
#include "shapefile.h"
125
 
 
126
 
#include <math.h>
127
 
#include <stdlib.h>
128
 
#ifdef WIN32
129
 
#include <string.h>
130
 
#endif
131
 
typedef unsigned char uchar;
132
 
 
133
 
#ifndef FALSE
134
 
#  define FALSE         0
135
 
#  define TRUE          1
136
 
#endif
137
 
 
138
 
static int      nStringFieldLen = 0;
139
 
static char * pszStringField = NULL;
140
 
 
141
 
/************************************************************************/
142
 
/*                             SfRealloc()                              */
143
 
/*                                                                      */
144
 
/*      A realloc cover function that will access a NULL pointer as     */
145
 
/*      a valid input.                                                  */
146
 
/************************************************************************/
147
 
 
148
 
static void * SfRealloc( void * pMem, int nNewSize )
149
 
 
150
 
{
151
 
    if( pMem == NULL )
152
 
        return( (void *) malloc(nNewSize) );
153
 
    else
154
 
        return( (void *) realloc(pMem,nNewSize) );
155
 
}
156
 
 
157
 
/************************************************************************/
158
 
/*                           DBFWriteHeader()                           */
159
 
/*                                                                      */
160
 
/*      This is called to write out the file header, and field          */
161
 
/*      descriptions before writing any actual data records.  This      */
162
 
/*      also computes all the DBFDataSet field offset/size/decimals     */
163
 
/*      and so forth values.                                            */
164
 
/************************************************************************/
165
 
 
166
 
static void DBFWriteHeader(DBFHandle psDBF)
167
 
 
168
 
{
169
 
    uchar       abyHeader[XBASE_FLDHDR_SZ];
170
 
    int         i;
171
 
 
172
 
    if( !psDBF->bNoHeader )
173
 
        return;
174
 
 
175
 
    psDBF->bNoHeader = FALSE;
176
 
 
177
 
/* -------------------------------------------------------------------- */
178
 
/*      Initialize the file header information.                         */
179
 
/* -------------------------------------------------------------------- */
180
 
    for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
181
 
        abyHeader[i] = 0;
182
 
 
183
 
    abyHeader[0] = 0x03;                /* memo field? - just copying   */
184
 
 
185
 
    /* date updated on close, record count preset at zero */
186
 
 
187
 
    abyHeader[8] = psDBF->nHeaderLength % 256;
188
 
    abyHeader[9] = psDBF->nHeaderLength / 256;
189
 
    
190
 
    abyHeader[10] = psDBF->nRecordLength % 256;
191
 
    abyHeader[11] = psDBF->nRecordLength / 256;
192
 
 
193
 
/* -------------------------------------------------------------------- */
194
 
/*      Write the initial 32 byte file header, and all the field        */
195
 
/*      descriptions.                                                   */
196
 
/* -------------------------------------------------------------------- */
197
 
    fseek( psDBF->fp, 0, 0 );
198
 
    fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
199
 
    fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );
200
 
 
201
 
/* -------------------------------------------------------------------- */
202
 
/*      Write out the newline character if there is room for it.        */
203
 
/* -------------------------------------------------------------------- */
204
 
    if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
205
 
    {
206
 
        char    cNewline;
207
 
 
208
 
        cNewline = 0x0d;
209
 
        fwrite( &cNewline, 1, 1, psDBF->fp );
210
 
    }
211
 
}
212
 
 
213
 
/************************************************************************/
214
 
/*                           DBFFlushRecord()                           */
215
 
/*                                                                      */
216
 
/*      Write out the current record if there is one.                   */
217
 
/************************************************************************/
218
 
 
219
 
static void DBFFlushRecord( DBFHandle psDBF )
220
 
 
221
 
{
222
 
    int         nRecordOffset;
223
 
 
224
 
    if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
225
 
    {
226
 
        psDBF->bCurrentRecordModified = FALSE;
227
 
 
228
 
        nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord 
229
 
                                                     + psDBF->nHeaderLength;
230
 
 
231
 
        fseek( psDBF->fp, nRecordOffset, 0 );
232
 
        fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
233
 
    }
234
 
}
235
 
 
236
 
/************************************************************************/
237
 
/*                              DBFOpen()                               */
238
 
/*                                                                      */
239
 
/*      Open a .dbf file.                                               */
240
 
/************************************************************************/
241
 
   
242
 
DBFHandle DBFOpen( const char * pszFilename, const char * pszAccess )
243
 
 
244
 
{
245
 
    DBFHandle           psDBF;
246
 
    uchar               *pabyBuf;
247
 
    int                 nFields, nRecords, nHeadLen, nRecLen, iField, i;
248
 
    char                *pszBasename, *pszFullname;
249
 
 
250
 
/* -------------------------------------------------------------------- */
251
 
/*      We only allow the access strings "rb" and "r+".                  */
252
 
/* -------------------------------------------------------------------- */
253
 
    if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 
254
 
        && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
255
 
        && strcmp(pszAccess,"r+b") != 0 )
256
 
        return( NULL );
257
 
 
258
 
/* -------------------------------------------------------------------- */
259
 
/*      Compute the base (layer) name.  If there is any extension       */
260
 
/*      on the passed in filename we will strip it off.                 */
261
 
/* -------------------------------------------------------------------- */
262
 
    pszBasename = (char *) malloc(strlen(pszFilename)+5);
263
 
    strcpy( pszBasename, pszFilename );
264
 
    for( i = strlen(pszBasename)-1; 
265
 
         i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
266
 
               && pszBasename[i] != '\\';
267
 
         i-- ) {}
268
 
 
269
 
    if( pszBasename[i] == '.' )
270
 
        pszBasename[i] = '\0';
271
 
 
272
 
    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
273
 
    sprintf( pszFullname, "%s.dbf", pszBasename );
274
 
        
275
 
    psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
276
 
    psDBF->fp = fopen( pszFullname, pszAccess );
277
 
 
278
 
    if( psDBF->fp == NULL )
279
 
    {
280
 
        sprintf( pszFullname, "%s.DBF", pszBasename );
281
 
        psDBF->fp = fopen(pszFullname, pszAccess );
282
 
    }
283
 
    
284
 
    free( pszBasename );
285
 
    free( pszFullname );
286
 
    
287
 
    if( psDBF->fp == NULL )
288
 
    {
289
 
        free( psDBF );
290
 
        return( NULL );
291
 
    }
292
 
 
293
 
    psDBF->bNoHeader = FALSE;
294
 
    psDBF->nCurrentRecord = -1;
295
 
    psDBF->bCurrentRecordModified = FALSE;
296
 
 
297
 
/* -------------------------------------------------------------------- */
298
 
/*  Read Table Header info                                              */
299
 
/* -------------------------------------------------------------------- */
300
 
    pabyBuf = (uchar *) malloc(500);
301
 
    fread( pabyBuf, 32, 1, psDBF->fp );
302
 
 
303
 
    psDBF->nRecords = nRecords = 
304
 
     pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
305
 
 
306
 
    psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
307
 
    psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;
308
 
    
309
 
    psDBF->nFields = nFields = (nHeadLen - 32) / 32;
310
 
 
311
 
    psDBF->pszCurrentRecord = (char *) malloc(nRecLen);
312
 
 
313
 
/* -------------------------------------------------------------------- */
314
 
/*  Read in Field Definitions                                           */
315
 
/* -------------------------------------------------------------------- */
316
 
    
317
 
    pabyBuf = (uchar *) SfRealloc(pabyBuf,nHeadLen);
318
 
    psDBF->pszHeader = (char *) pabyBuf;
319
 
 
320
 
    fseek( psDBF->fp, 32, 0 );
321
 
    fread( pabyBuf, nHeadLen, 1, psDBF->fp );
322
 
 
323
 
    psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
324
 
    psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
325
 
    psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
326
 
    psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
327
 
 
328
 
    for( iField = 0; iField < nFields; iField++ )
329
 
    {
330
 
        uchar           *pabyFInfo;
331
 
 
332
 
        pabyFInfo = pabyBuf+iField*32;
333
 
 
334
 
        if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
335
 
        {
336
 
            psDBF->panFieldSize[iField] = pabyFInfo[16];
337
 
            psDBF->panFieldDecimals[iField] = pabyFInfo[17];
338
 
        }
339
 
        else
340
 
        {
341
 
            psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
342
 
            psDBF->panFieldDecimals[iField] = 0;
343
 
        }
344
 
 
345
 
        psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
346
 
        if( iField == 0 )
347
 
            psDBF->panFieldOffset[iField] = 1;
348
 
        else
349
 
            psDBF->panFieldOffset[iField] = 
350
 
              psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
351
 
    }
352
 
 
353
 
    return( psDBF );
354
 
}
355
 
 
356
 
/************************************************************************/
357
 
/*                              DBFClose()                              */
358
 
/************************************************************************/
359
 
 
360
 
void    DBFClose(DBFHandle psDBF)
361
 
{
362
 
/* -------------------------------------------------------------------- */
363
 
/*      Write out header if not already written.                        */
364
 
/* -------------------------------------------------------------------- */
365
 
    if( psDBF->bNoHeader )
366
 
        DBFWriteHeader( psDBF );
367
 
 
368
 
    DBFFlushRecord( psDBF );
369
 
 
370
 
/* -------------------------------------------------------------------- */
371
 
/*      Update last access date, and number of records if we have       */
372
 
/*      write access.                                                   */
373
 
/* -------------------------------------------------------------------- */
374
 
    if( psDBF->bUpdated )
375
 
    {
376
 
        uchar           abyFileHeader[32];
377
 
 
378
 
        fseek( psDBF->fp, 0, 0 );
379
 
        fread( abyFileHeader, 32, 1, psDBF->fp );
380
 
 
381
 
        abyFileHeader[1] = 95;                  /* YY */
382
 
        abyFileHeader[2] = 7;                   /* MM */
383
 
        abyFileHeader[3] = 26;                  /* DD */
384
 
 
385
 
        abyFileHeader[4] = psDBF->nRecords % 256;
386
 
        abyFileHeader[5] = (psDBF->nRecords/256) % 256;
387
 
        abyFileHeader[6] = (psDBF->nRecords/(256*256)) % 256;
388
 
        abyFileHeader[7] = (psDBF->nRecords/(256*256*256)) % 256;
389
 
 
390
 
        fseek( psDBF->fp, 0, 0 );
391
 
        fwrite( abyFileHeader, 32, 1, psDBF->fp );
392
 
    }
393
 
 
394
 
/* -------------------------------------------------------------------- */
395
 
/*      Close, and free resources.                                      */
396
 
/* -------------------------------------------------------------------- */
397
 
    fclose( psDBF->fp );
398
 
 
399
 
    if( psDBF->panFieldOffset != NULL )
400
 
    {
401
 
        free( psDBF->panFieldOffset );
402
 
        free( psDBF->panFieldSize );
403
 
        free( psDBF->panFieldDecimals );
404
 
        free( psDBF->pachFieldType );
405
 
    }
406
 
 
407
 
    free( psDBF->pszHeader );
408
 
    free( psDBF->pszCurrentRecord );
409
 
 
410
 
    free( psDBF );
411
 
 
412
 
    if( pszStringField != NULL )
413
 
    {
414
 
        free( pszStringField );
415
 
        pszStringField = NULL;
416
 
        nStringFieldLen = 0;
417
 
    }
418
 
}
419
 
 
420
 
/************************************************************************/
421
 
/*                             DBFCreate()                              */
422
 
/*                                                                      */
423
 
/*      Create a new .dbf file.                                         */
424
 
/************************************************************************/
425
 
 
426
 
DBFHandle DBFCreate( const char * pszFilename )
427
 
 
428
 
{
429
 
    DBFHandle   psDBF;
430
 
    FILE        *fp;
431
 
    char        *pszFullname, *pszBasename;
432
 
    int         i;
433
 
 
434
 
/* -------------------------------------------------------------------- */
435
 
/*      Compute the base (layer) name.  If there is any extension       */
436
 
/*      on the passed in filename we will strip it off.                 */
437
 
/* -------------------------------------------------------------------- */
438
 
    pszBasename = (char *) malloc(strlen(pszFilename)+5);
439
 
    strcpy( pszBasename, pszFilename );
440
 
    for( i = strlen(pszBasename)-1; 
441
 
         i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
442
 
               && pszBasename[i] != '\\';
443
 
         i-- ) {}
444
 
 
445
 
    if( pszBasename[i] == '.' )
446
 
        pszBasename[i] = '\0';
447
 
 
448
 
    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
449
 
    sprintf( pszFullname, "%s.dbf", pszBasename );
450
 
    free( pszBasename );
451
 
 
452
 
/* -------------------------------------------------------------------- */
453
 
/*      Create the file.                                                */
454
 
/* -------------------------------------------------------------------- */
455
 
    fp = fopen( pszFullname, "wb" );
456
 
    if( fp == NULL )
457
 
        return( NULL );
458
 
 
459
 
    fputc( 0, fp );
460
 
    fclose( fp );
461
 
 
462
 
    fp = fopen( pszFullname, "rb+" );
463
 
    if( fp == NULL )
464
 
        return( NULL );
465
 
 
466
 
    free( pszFullname );
467
 
 
468
 
/* -------------------------------------------------------------------- */
469
 
/*      Create the info structure.                                      */
470
 
/* -------------------------------------------------------------------- */
471
 
    psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
472
 
 
473
 
    psDBF->fp = fp;
474
 
    psDBF->nRecords = 0;
475
 
    psDBF->nFields = 0;
476
 
    psDBF->nRecordLength = 1;
477
 
    psDBF->nHeaderLength = 33;
478
 
    
479
 
    psDBF->panFieldOffset = NULL;
480
 
    psDBF->panFieldSize = NULL;
481
 
    psDBF->panFieldDecimals = NULL;
482
 
    psDBF->pachFieldType = NULL;
483
 
    psDBF->pszHeader = NULL;
484
 
 
485
 
    psDBF->nCurrentRecord = -1;
486
 
    psDBF->bCurrentRecordModified = FALSE;
487
 
    psDBF->pszCurrentRecord = NULL;
488
 
 
489
 
    psDBF->bNoHeader = TRUE;
490
 
 
491
 
    return( psDBF );
492
 
}
493
 
 
494
 
/************************************************************************/
495
 
/*                            DBFAddField()                             */
496
 
/*                                                                      */
497
 
/*      Add a field to a newly created .dbf file before any records     */
498
 
/*      are written.                                                    */
499
 
/************************************************************************/
500
 
 
501
 
int     DBFAddField(DBFHandle psDBF, const char * pszFieldName, 
502
 
                    DBFFieldType eType, int nWidth, int nDecimals )
503
 
 
504
 
{
505
 
    char        *pszFInfo;
506
 
    int         i;
507
 
 
508
 
/* -------------------------------------------------------------------- */
509
 
/*      Do some checking to ensure we can add records to this file.     */
510
 
/* -------------------------------------------------------------------- */
511
 
    if( psDBF->nRecords > 0 )
512
 
        return( -1 );
513
 
 
514
 
    if( !psDBF->bNoHeader )
515
 
        return( -1 );
516
 
 
517
 
    if( eType != FTDouble && nDecimals != 0 )
518
 
        return( -1 );
519
 
 
520
 
/* -------------------------------------------------------------------- */
521
 
/*      SfRealloc all the arrays larger to hold the additional field      */
522
 
/*      information.                                                    */
523
 
/* -------------------------------------------------------------------- */
524
 
    psDBF->nFields++;
525
 
 
526
 
    psDBF->panFieldOffset = (int *) 
527
 
      SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
528
 
 
529
 
    psDBF->panFieldSize = (int *) 
530
 
      SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
531
 
 
532
 
    psDBF->panFieldDecimals = (int *) 
533
 
      SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
534
 
 
535
 
    psDBF->pachFieldType = (char *) 
536
 
      SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
537
 
 
538
 
/* -------------------------------------------------------------------- */
539
 
/*      Assign the new field information fields.                        */
540
 
/* -------------------------------------------------------------------- */
541
 
    psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
542
 
    psDBF->nRecordLength += nWidth;
543
 
    psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
544
 
    psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
545
 
 
546
 
    if( eType == FTString )
547
 
        psDBF->pachFieldType[psDBF->nFields-1] = 'C';
548
 
    else
549
 
        psDBF->pachFieldType[psDBF->nFields-1] = 'N';
550
 
 
551
 
/* -------------------------------------------------------------------- */
552
 
/*      Extend the required header information.                         */
553
 
/* -------------------------------------------------------------------- */
554
 
    psDBF->nHeaderLength += 32;
555
 
    psDBF->bUpdated = FALSE;
556
 
 
557
 
    psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
558
 
 
559
 
    pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
560
 
 
561
 
    for( i = 0; i < 32; i++ )
562
 
        pszFInfo[i] = '\0';
563
 
 
564
 
    if( strlen(pszFieldName) < 10 )
565
 
        strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
566
 
    else
567
 
        strncpy( pszFInfo, pszFieldName, 10);
568
 
 
569
 
    pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
570
 
 
571
 
    if( eType == FTString )
572
 
    {
573
 
        pszFInfo[16] = nWidth % 256;
574
 
        pszFInfo[17] = nWidth / 256;
575
 
    }
576
 
    else
577
 
    {
578
 
        pszFInfo[16] = nWidth;
579
 
        pszFInfo[17] = nDecimals;
580
 
    }
581
 
    
582
 
/* -------------------------------------------------------------------- */
583
 
/*      Make the current record buffer appropriately larger.            */
584
 
/* -------------------------------------------------------------------- */
585
 
    psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
586
 
                                               psDBF->nRecordLength);
587
 
 
588
 
    return( psDBF->nFields-1 );
589
 
}
590
 
 
591
 
/************************************************************************/
592
 
/*                          DBFReadAttribute()                          */
593
 
/*                                                                      */
594
 
/*      Read one of the attribute fields of a record.                   */
595
 
/************************************************************************/
596
 
 
597
 
static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
598
 
                              char chReqType )
599
 
 
600
 
{
601
 
    int         nRecordOffset;
602
 
    uchar       *pabyRec;
603
 
    void        *pReturnField = NULL;
604
 
 
605
 
    static double dDoubleField;
606
 
 
607
 
/* -------------------------------------------------------------------- */
608
 
/*      Have we read the record?                                        */
609
 
/* -------------------------------------------------------------------- */
610
 
    if( hEntity < 0 || hEntity >= psDBF->nRecords )
611
 
        return( NULL );
612
 
 
613
 
    if( psDBF->nCurrentRecord != hEntity )
614
 
    {
615
 
        DBFFlushRecord( psDBF );
616
 
 
617
 
        nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
618
 
 
619
 
        fseek( psDBF->fp, nRecordOffset, 0 );
620
 
        fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
621
 
 
622
 
        psDBF->nCurrentRecord = hEntity;
623
 
    }
624
 
 
625
 
    pabyRec = (uchar *) psDBF->pszCurrentRecord;
626
 
 
627
 
/* -------------------------------------------------------------------- */
628
 
/*      Ensure our field buffer is large enough to hold this buffer.    */
629
 
/* -------------------------------------------------------------------- */
630
 
    if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
631
 
    {
632
 
        nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
633
 
        pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
634
 
    }
635
 
 
636
 
/* -------------------------------------------------------------------- */
637
 
/*      Extract the requested field.                                    */
638
 
/* -------------------------------------------------------------------- */
639
 
    strncpy( pszStringField, pabyRec+psDBF->panFieldOffset[iField],
640
 
             psDBF->panFieldSize[iField] );
641
 
    pszStringField[psDBF->panFieldSize[iField]] = '\0';
642
 
 
643
 
    pReturnField = pszStringField;
644
 
 
645
 
/* -------------------------------------------------------------------- */
646
 
/*      Decode the field.                                               */
647
 
/* -------------------------------------------------------------------- */
648
 
    if( chReqType == 'N' )
649
 
    {
650
 
        dDoubleField = atof(pszStringField);
651
 
 
652
 
        pReturnField = &dDoubleField;
653
 
    }
654
 
 
655
 
/* -------------------------------------------------------------------- */
656
 
/*      Should we trim white space off the string attribute value?      */
657
 
/* -------------------------------------------------------------------- */
658
 
#ifdef TRIM_DBF_WHITESPACE
659
 
    else
660
 
    {
661
 
        char    *pchSrc, *pchDst;
662
 
 
663
 
        pchDst = pchSrc = pszStringField;
664
 
        while( *pchSrc == ' ' )
665
 
            pchSrc++;
666
 
 
667
 
        while( *pchSrc != '\0' )
668
 
            *(pchDst++) = *(pchSrc++);
669
 
        *pchDst = '\0';
670
 
 
671
 
        while( *(--pchDst) == ' ' && pchDst != pszStringField )
672
 
            *pchDst = '\0';
673
 
 
674
 
    }
675
 
#endif
676
 
    
677
 
    return( pReturnField );
678
 
}
679
 
 
680
 
/************************************************************************/
681
 
/*                        DBFReadIntAttribute()                         */
682
 
/*                                                                      */
683
 
/*      Read an integer attribute.                                      */
684
 
/************************************************************************/
685
 
 
686
 
int     DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
687
 
 
688
 
{
689
 
    double      *pdValue;
690
 
 
691
 
    pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
692
 
 
693
 
    return( (int) *pdValue );
694
 
}
695
 
 
696
 
/************************************************************************/
697
 
/*                        DBFReadDoubleAttribute()                      */
698
 
/*                                                                      */
699
 
/*      Read a double attribute.                                        */
700
 
/************************************************************************/
701
 
 
702
 
double  DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
703
 
 
704
 
{
705
 
    double      *pdValue;
706
 
 
707
 
    pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
708
 
 
709
 
    return( *pdValue );
710
 
}
711
 
 
712
 
/************************************************************************/
713
 
/*                        DBFReadStringAttribute()                      */
714
 
/*                                                                      */
715
 
/*      Read a string attribute.                                        */
716
 
/************************************************************************/
717
 
 
718
 
const char *DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
719
 
 
720
 
{
721
 
    return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
722
 
}
723
 
 
724
 
/************************************************************************/
725
 
/*                          DBFGetFieldCount()                          */
726
 
/*                                                                      */
727
 
/*      Return the number of fields in this table.                      */
728
 
/************************************************************************/
729
 
 
730
 
int     DBFGetFieldCount( DBFHandle psDBF )
731
 
 
732
 
{
733
 
    return( psDBF->nFields );
734
 
}
735
 
 
736
 
/************************************************************************/
737
 
/*                         DBFGetRecordCount()                          */
738
 
/*                                                                      */
739
 
/*      Return the number of records in this table.                     */
740
 
/************************************************************************/
741
 
 
742
 
int     DBFGetRecordCount( DBFHandle psDBF )
743
 
 
744
 
{
745
 
    return( psDBF->nRecords );
746
 
}
747
 
 
748
 
/************************************************************************/
749
 
/*                          DBFGetFieldInfo()                           */
750
 
/*                                                                      */
751
 
/*      Return any requested information about the field.               */
752
 
/************************************************************************/
753
 
 
754
 
DBFFieldType DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
755
 
                              int * pnWidth, int * pnDecimals )
756
 
 
757
 
{
758
 
    if( iField < 0 || iField >= psDBF->nFields )
759
 
        return( FTInvalid );
760
 
 
761
 
    if( pnWidth != NULL )
762
 
        *pnWidth = psDBF->panFieldSize[iField];
763
 
 
764
 
    if( pnDecimals != NULL )
765
 
        *pnDecimals = psDBF->panFieldDecimals[iField];
766
 
 
767
 
    if( pszFieldName != NULL )
768
 
    {
769
 
        int     i;
770
 
 
771
 
        strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
772
 
        pszFieldName[11] = '\0';
773
 
        for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
774
 
            pszFieldName[i] = '\0';
775
 
    }
776
 
 
777
 
    if( psDBF->pachFieldType[iField] == 'N' 
778
 
        || psDBF->pachFieldType[iField] == 'F'
779
 
        || psDBF->pachFieldType[iField] == 'D' )
780
 
    {
781
 
        if( psDBF->panFieldDecimals[iField] > 0 )
782
 
            return( FTDouble );
783
 
        else
784
 
            return( FTInteger );
785
 
    }
786
 
    else
787
 
    {
788
 
        return( FTString );
789
 
    }
790
 
}
791
 
 
792
 
/************************************************************************/
793
 
/*                         DBFWriteAttribute()                          */
794
 
/*                                                                      */
795
 
/*      Write an attribute record to the file.                          */
796
 
/************************************************************************/
797
 
 
798
 
static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
799
 
                             void * pValue )
800
 
 
801
 
{
802
 
    int         nRecordOffset, i, j;
803
 
    uchar       *pabyRec;
804
 
    char        szSField[40], szFormat[12];
805
 
 
806
 
/* -------------------------------------------------------------------- */
807
 
/*      Is this a valid record?                                         */
808
 
/* -------------------------------------------------------------------- */
809
 
    if( hEntity < 0 || hEntity > psDBF->nRecords )
810
 
        return( FALSE );
811
 
 
812
 
    if( psDBF->bNoHeader )
813
 
        DBFWriteHeader(psDBF);
814
 
 
815
 
/* -------------------------------------------------------------------- */
816
 
/*      Is this a brand new record?                                     */
817
 
/* -------------------------------------------------------------------- */
818
 
    if( hEntity == psDBF->nRecords )
819
 
    {
820
 
        DBFFlushRecord( psDBF );
821
 
 
822
 
        psDBF->nRecords++;
823
 
        for( i = 0; i < psDBF->nRecordLength; i++ )
824
 
            psDBF->pszCurrentRecord[i] = ' ';
825
 
 
826
 
        psDBF->nCurrentRecord = hEntity;
827
 
    }
828
 
 
829
 
/* -------------------------------------------------------------------- */
830
 
/*      Is this an existing record, but different than the last one     */
831
 
/*      we accessed?                                                    */
832
 
/* -------------------------------------------------------------------- */
833
 
    if( psDBF->nCurrentRecord != hEntity )
834
 
    {
835
 
        DBFFlushRecord( psDBF );
836
 
 
837
 
        nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
838
 
 
839
 
        fseek( psDBF->fp, nRecordOffset, 0 );
840
 
        fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
841
 
 
842
 
        psDBF->nCurrentRecord = hEntity;
843
 
    }
844
 
 
845
 
    pabyRec = (uchar *) psDBF->pszCurrentRecord;
846
 
 
847
 
/* -------------------------------------------------------------------- */
848
 
/*      Assign all the record fields.                                   */
849
 
/* -------------------------------------------------------------------- */
850
 
    switch( psDBF->pachFieldType[iField] )
851
 
    {
852
 
      case 'D':
853
 
      case 'N':
854
 
      case 'F':
855
 
        if( psDBF->panFieldDecimals[iField] == 0 )
856
 
        {
857
 
            sprintf( szFormat, "%%%dd", psDBF->panFieldSize[iField] );
858
 
            sprintf(szSField, szFormat, (int) *((double *) pValue) );
859
 
            if( strlen(szSField) > psDBF->panFieldSize[iField] )
860
 
                szSField[psDBF->panFieldSize[iField]] = '\0';
861
 
 
862
 
            strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
863
 
                    szSField, strlen(szSField) );
864
 
        }
865
 
        else
866
 
        {
867
 
            sprintf( szFormat, "%%%d.%df", 
868
 
                     psDBF->panFieldSize[iField],
869
 
                     psDBF->panFieldDecimals[iField] );
870
 
            sprintf(szSField, szFormat, *((double *) pValue) );
871
 
            if( strlen(szSField) > psDBF->panFieldSize[iField] )
872
 
                szSField[psDBF->panFieldSize[iField]] = '\0';
873
 
            strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
874
 
                    szSField, strlen(szSField) );
875
 
        }
876
 
        break;
877
 
 
878
 
      default:
879
 
        if( strlen((char *) pValue) > psDBF->panFieldSize[iField] )
880
 
            j = psDBF->panFieldSize[iField];
881
 
        else
882
 
        {
883
 
            memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
884
 
                    psDBF->panFieldSize[iField] );
885
 
            j = strlen((char *) pValue);
886
 
        }
887
 
 
888
 
        strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
889
 
                (char *) pValue, j );
890
 
        break;
891
 
    }
892
 
 
893
 
    psDBF->bCurrentRecordModified = TRUE;
894
 
    psDBF->bUpdated = TRUE;
895
 
 
896
 
    return( TRUE );
897
 
}
898
 
 
899
 
/************************************************************************/
900
 
/*                      DBFWriteDoubleAttribute()                       */
901
 
/*                                                                      */
902
 
/*      Write a double attribute.                                       */
903
 
/************************************************************************/
904
 
 
905
 
int DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
906
 
                             double dValue )
907
 
 
908
 
{
909
 
    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
910
 
}
911
 
 
912
 
/************************************************************************/
913
 
/*                      DBFWriteIntegerAttribute()                      */
914
 
/*                                                                      */
915
 
/*      Write a integer attribute.                                      */
916
 
/************************************************************************/
917
 
 
918
 
int DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
919
 
                              int nValue )
920
 
 
921
 
{
922
 
    double      dValue = nValue;
923
 
 
924
 
    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
925
 
}
926
 
 
927
 
/************************************************************************/
928
 
/*                      DBFWriteStringAttribute()                       */
929
 
/*                                                                      */
930
 
/*      Write a string attribute.                                       */
931
 
/************************************************************************/
932
 
 
933
 
int DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
934
 
                             const char * pszValue )
935
 
 
936
 
{
937
 
    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
938
 
}
939
 
 
940
 
/************************************************************************/
941
 
/*                         DBFWriteTuple()                              */
942
 
/*                                                                      */
943
 
/*      Write an attribute record to the file.                          */
944
 
/************************************************************************/
945
 
 
946
 
int DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
947
 
 
948
 
{
949
 
    int         nRecordOffset, i;
950
 
    uchar       *pabyRec;
951
 
 
952
 
/* -------------------------------------------------------------------- */
953
 
/*      Is this a valid record?                                         */
954
 
/* -------------------------------------------------------------------- */
955
 
    if( hEntity < 0 || hEntity > psDBF->nRecords )
956
 
        return( FALSE );
957
 
 
958
 
    if( psDBF->bNoHeader )
959
 
        DBFWriteHeader(psDBF);
960
 
 
961
 
/* -------------------------------------------------------------------- */
962
 
/*      Is this a brand new record?                                     */
963
 
/* -------------------------------------------------------------------- */
964
 
    if( hEntity == psDBF->nRecords )
965
 
    {
966
 
        DBFFlushRecord( psDBF );
967
 
 
968
 
        psDBF->nRecords++;
969
 
        for( i = 0; i < psDBF->nRecordLength; i++ )
970
 
            psDBF->pszCurrentRecord[i] = ' ';
971
 
 
972
 
        psDBF->nCurrentRecord = hEntity;
973
 
    }
974
 
 
975
 
/* -------------------------------------------------------------------- */
976
 
/*      Is this an existing record, but different than the last one     */
977
 
/*      we accessed?                                                    */
978
 
/* -------------------------------------------------------------------- */
979
 
    if( psDBF->nCurrentRecord != hEntity )
980
 
    {
981
 
        DBFFlushRecord( psDBF );
982
 
 
983
 
        nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
984
 
 
985
 
        fseek( psDBF->fp, nRecordOffset, 0 );
986
 
        fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
987
 
 
988
 
        psDBF->nCurrentRecord = hEntity;
989
 
    }
990
 
 
991
 
    pabyRec = (uchar *) psDBF->pszCurrentRecord;
992
 
 
993
 
    memcpy ( pabyRec, pRawTuple,  psDBF->nRecordLength );
994
 
 
995
 
    psDBF->bCurrentRecordModified = TRUE;
996
 
    psDBF->bUpdated = TRUE;
997
 
 
998
 
    return( TRUE );
999
 
}
1000
 
 
1001
 
/************************************************************************/
1002
 
/*                          DBFReadTuple()                              */
1003
 
/*                                                                      */
1004
 
/*      Read one of the attribute fields of a record.                   */
1005
 
/************************************************************************/
1006
 
 
1007
 
const char *DBFReadTuple(DBFHandle psDBF, int hEntity )
1008
 
 
1009
 
{
1010
 
    int         nRecordOffset;
1011
 
    uchar       *pabyRec;
1012
 
    static char *pReturnTuple = NULL;
1013
 
 
1014
 
    static int  nTupleLen = 0;
1015
 
 
1016
 
/* -------------------------------------------------------------------- */
1017
 
/*      Have we read the record?                                        */
1018
 
/* -------------------------------------------------------------------- */
1019
 
    if( hEntity < 0 || hEntity >= psDBF->nRecords )
1020
 
        return( NULL );
1021
 
 
1022
 
    if( psDBF->nCurrentRecord != hEntity )
1023
 
    {
1024
 
        DBFFlushRecord( psDBF );
1025
 
 
1026
 
        nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
1027
 
 
1028
 
        fseek( psDBF->fp, nRecordOffset, 0 );
1029
 
        fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
1030
 
 
1031
 
        psDBF->nCurrentRecord = hEntity;
1032
 
    }
1033
 
 
1034
 
    pabyRec = (uchar *) psDBF->pszCurrentRecord;
1035
 
 
1036
 
    if ( nTupleLen < psDBF->nRecordLength) {
1037
 
      nTupleLen = psDBF->nRecordLength;
1038
 
      pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
1039
 
    }
1040
 
    
1041
 
    memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
1042
 
        
1043
 
    return( pReturnTuple );
1044
 
}
1045
 
 
1046
 
/************************************************************************/
1047
 
/*                          DBFCloneEmpty()                              */
1048
 
/*                                                                      */
1049
 
/*      Read one of the attribute fields of a record.                   */
1050
 
/************************************************************************/
1051
 
 
1052
 
DBFHandle DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) 
1053
 
{
1054
 
    DBFHandle   newDBF;
1055
 
 
1056
 
   newDBF = DBFCreate ( pszFilename );
1057
 
   if ( newDBF == NULL ) return ( NULL ); 
1058
 
   
1059
 
   newDBF->pszHeader = (void *) malloc ( 32 * psDBF->nFields );
1060
 
   memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
1061
 
   
1062
 
   newDBF->nFields = psDBF->nFields;
1063
 
   newDBF->nRecordLength = psDBF->nRecordLength;
1064
 
   newDBF->nHeaderLength = psDBF->nHeaderLength;
1065
 
    
1066
 
   newDBF->panFieldOffset = (void *) malloc ( sizeof(int) * psDBF->nFields ); 
1067
 
   memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
1068
 
   newDBF->panFieldSize = (void *) malloc ( sizeof(int) * psDBF->nFields );
1069
 
   memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
1070
 
   newDBF->panFieldDecimals = (void *) malloc ( sizeof(int) * psDBF->nFields );
1071
 
   memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
1072
 
   newDBF->pachFieldType = (void *) malloc ( sizeof(int) * psDBF->nFields );
1073
 
   memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
1074
 
 
1075
 
   newDBF->bNoHeader = TRUE;
1076
 
   newDBF->bUpdated = TRUE;
1077
 
   
1078
 
   DBFWriteHeader ( newDBF );
1079
 
   DBFClose ( newDBF );
1080
 
   
1081
 
   newDBF = DBFOpen ( pszFilename, "rb+" );
1082
 
 
1083
 
   return ( newDBF );
1084
 
}