pihmLIBS/dbfopen.c

Go to the documentation of this file.
00001 /******************************************************************************
00002  * $Id: dbfopen.c,v 1.48 2003/03/10 14:51:27 warmerda Exp $
00003  *
00004  * Project:  Shapelib
00005  * Purpose:  Implementation of .dbf access API documented in dbf_api.html.
00006  * Author:   Frank Warmerdam, warmerdam@pobox.com
00007  *
00008  ******************************************************************************
00009  * Copyright (c) 1999, Frank Warmerdam
00010  *
00011  * This software is available under the following "MIT Style" license,
00012  * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
00013  * option is discussed in more detail in shapelib.html.
00014  *
00015  * --
00016  * 
00017  * Permission is hereby granted, free of charge, to any person obtaining a
00018  * copy of this software and associated documentation files (the "Software"),
00019  * to deal in the Software without restriction, including without limitation
00020  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00021  * and/or sell copies of the Software, and to permit persons to whom the
00022  * Software is furnished to do so, subject to the following conditions:
00023  *
00024  * The above copyright notice and this permission notice shall be included
00025  * in all copies or substantial portions of the Software.
00026  *
00027  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00028  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00029  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00030  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00031  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00032  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00033  * DEALINGS IN THE SOFTWARE.
00034  ******************************************************************************
00035  *
00036  * $Log: dbfopen.c,v $
00037  * Revision 1.48  2003/03/10 14:51:27  warmerda
00038  * DBFWrite* calls now return FALSE if they have to truncate
00039  *
00040  * Revision 1.47  2002/11/20 03:32:22  warmerda
00041  * Ensure field name in DBFGetFieldIndex() is properly terminated.
00042  *
00043  * Revision 1.46  2002/10/09 13:10:21  warmerda
00044  * Added check that width is positive.
00045  *
00046  * Revision 1.45  2002/09/29 00:00:08  warmerda
00047  * added FTLogical and logical attribute read/write calls
00048  *
00049  * Revision 1.44  2002/05/07 13:46:11  warmerda
00050  * Added DBFWriteAttributeDirectly().
00051  *
00052  * Revision 1.43  2002/02/13 19:39:21  warmerda
00053  * Fix casting issues in DBFCloneEmpty().
00054  *
00055  * Revision 1.42  2002/01/15 14:36:07  warmerda
00056  * updated email address
00057  *
00058  * Revision 1.41  2002/01/15 14:31:49  warmerda
00059  * compute rather than copying nHeaderLength in DBFCloneEmpty()
00060  *
00061  * Revision 1.40  2002/01/09 04:32:35  warmerda
00062  * fixed to read correct amount of header
00063  *
00064  * Revision 1.39  2001/12/11 22:41:03  warmerda
00065  * improve io related error checking when reading header
00066  *
00067  * Revision 1.38  2001/11/28 16:07:31  warmerda
00068  * Cleanup to avoid compiler warnings as suggested by Richard Hash.
00069  *
00070  * Revision 1.37  2001/07/04 05:18:09  warmerda
00071  * do last fix properly
00072  *
00073  * Revision 1.36  2001/07/04 05:16:09  warmerda
00074  * fixed fieldname comparison in DBFGetFieldIndex
00075  *
00076  * Revision 1.35  2001/06/22 02:10:06  warmerda
00077  * fixed NULL shape support with help from Jim Matthews
00078  *
00079  * Revision 1.33  2001/05/31 19:20:13  warmerda
00080  * added DBFGetFieldIndex()
00081  *
00082  * Revision 1.32  2001/05/31 18:15:40  warmerda
00083  * Added support for NULL fields in DBF files
00084  *
00085  * Revision 1.31  2001/05/23 13:36:52  warmerda
00086  * added use of SHPAPI_CALL
00087  *
00088  * Revision 1.30  2000/12/05 14:43:38  warmerda
00089  * DBReadAttribute() white space trimming bug fix
00090  *
00091  * Revision 1.29  2000/10/05 14:36:44  warmerda
00092  * fix bug with writing very wide numeric fields
00093  *
00094  * Revision 1.28  2000/09/25 14:18:07  warmerda
00095  * Added some casts of strlen() return result to fix warnings on some
00096  * systems, as submitted by Daniel.
00097  *
00098  * Revision 1.27  2000/09/25 14:15:51  warmerda
00099  * added DBFGetNativeFieldType()
00100  *
00101  * Revision 1.26  2000/07/07 13:39:45  warmerda
00102  * removed unused variables, and added system include files
00103  *
00104  * Revision 1.25  2000/05/29 18:19:13  warmerda
00105  * avoid use of uchar, and adding casting fix
00106  *
00107  * Revision 1.24  2000/05/23 13:38:27  warmerda
00108  * Added error checks on return results of fread() and fseek().
00109  *
00110  * Revision 1.23  2000/05/23 13:25:49  warmerda
00111  * Avoid crashing if field or record are out of range in dbfread*attribute().
00112  *
00113  * Revision 1.22  1999/12/15 13:47:24  warmerda
00114  * Added stdlib.h to ensure that atof() is prototyped.
00115  *
00116  * Revision 1.21  1999/12/13 17:25:46  warmerda
00117  * Added support for upper case .DBF extention.
00118  *
00119  * Revision 1.20  1999/11/30 16:32:11  warmerda
00120  * Use atof() instead of sscanf().
00121  *
00122  * Revision 1.19  1999/11/05 14:12:04  warmerda
00123  * updated license terms
00124  *
00125  * Revision 1.18  1999/07/27 00:53:28  warmerda
00126  * ensure that whole old field value clear on write of string
00127  *
00128  * Revision 1.1  1999/07/05 18:58:07  warmerda
00129  * New
00130  *
00131  * Revision 1.17  1999/06/11 19:14:12  warmerda
00132  * Fixed some memory leaks.
00133  *
00134  * Revision 1.16  1999/06/11 19:04:11  warmerda
00135  * Remoted some unused variables.
00136  *
00137  * Revision 1.15  1999/05/11 03:19:28  warmerda
00138  * added new Tuple api, and improved extension handling - add from candrsn
00139  *
00140  * Revision 1.14  1999/05/04 15:01:48  warmerda
00141  * Added 'F' support.
00142  *
00143  * Revision 1.13  1999/03/23 17:38:59  warmerda
00144  * DBFAddField() now actually does return the new field number, or -1 if
00145  * it fails.
00146  *
00147  * Revision 1.12  1999/03/06 02:54:46  warmerda
00148  * Added logic to convert shapefile name to dbf filename in DBFOpen()
00149  * for convenience.
00150  *
00151  * Revision 1.11  1998/12/31 15:30:34  warmerda
00152  * Improved the interchangability of numeric and string attributes.  Add
00153  * white space trimming option for attributes.
00154  *
00155  * Revision 1.10  1998/12/03 16:36:44  warmerda
00156  * Use r+b instead of rb+ for binary access.
00157  *
00158  * Revision 1.9  1998/12/03 15:34:23  warmerda
00159  * Updated copyright message.
00160  *
00161  * Revision 1.8  1997/12/04 15:40:15  warmerda
00162  * Added newline character after field definitions.
00163  *
00164  * Revision 1.7  1997/03/06 14:02:10  warmerda
00165  * Ensure bUpdated is initialized.
00166  *
00167  * Revision 1.6  1996/02/12 04:54:41  warmerda
00168  * Ensure that DBFWriteAttribute() returns TRUE if it succeeds.
00169  *
00170  * Revision 1.5  1995/10/21  03:15:12  warmerda
00171  * Changed to use binary file access, and ensure that the
00172  * field name field is zero filled, and limited to 10 chars.
00173  *
00174  * Revision 1.4  1995/08/24  18:10:42  warmerda
00175  * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such
00176  * as on the Sun.
00177  *
00178  * Revision 1.3  1995/08/04  03:15:16  warmerda
00179  * Fixed up header.
00180  *
00181  * Revision 1.2  1995/08/04  03:14:43  warmerda
00182  * Added header.
00183  */
00184 
00185 static char rcsid[] = 
00186   "$Id: dbfopen.c,v 1.48 2003/03/10 14:51:27 warmerda Exp $";
00187 
00188 #include "shapefil.h"
00189 
00190 #include <math.h>
00191 #include <stdlib.h>
00192 #include <ctype.h>
00193 #include <string.h>
00194 
00195 #ifndef FALSE
00196 #  define FALSE         0
00197 #  define TRUE          1
00198 #endif
00199 
00200 static int      nStringFieldLen = 0;
00201 static char * pszStringField = NULL;
00202 
00203 /************************************************************************/
00204 /*                             SfRealloc()                              */
00205 /*                                                                      */
00206 /*      A realloc cover function that will access a NULL pointer as     */
00207 /*      a valid input.                                                  */
00208 /************************************************************************/
00209 
00210 static void * SfRealloc( void * pMem, int nNewSize )
00211 
00212 {
00213     if( pMem == NULL )
00214         return( (void *) malloc(nNewSize) );
00215     else
00216         return( (void *) realloc(pMem,nNewSize) );
00217 }
00218 
00219 /************************************************************************/
00220 /*                           DBFWriteHeader()                           */
00221 /*                                                                      */
00222 /*      This is called to write out the file header, and field          */
00223 /*      descriptions before writing any actual data records.  This      */
00224 /*      also computes all the DBFDataSet field offset/size/decimals     */
00225 /*      and so forth values.                                            */
00226 /************************************************************************/
00227 
00228 static void DBFWriteHeader(DBFHandle psDBF)
00229 
00230 {
00231     unsigned char       abyHeader[XBASE_FLDHDR_SZ];
00232     int         i;
00233 
00234     if( !psDBF->bNoHeader )
00235         return;
00236 
00237     psDBF->bNoHeader = FALSE;
00238 
00239 /* -------------------------------------------------------------------- */
00240 /*      Initialize the file header information.                         */
00241 /* -------------------------------------------------------------------- */
00242     for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
00243         abyHeader[i] = 0;
00244 
00245     abyHeader[0] = 0x03;                /* memo field? - just copying   */
00246 
00247     /* date updated on close, record count preset at zero */
00248 
00249     abyHeader[8] = psDBF->nHeaderLength % 256;
00250     abyHeader[9] = psDBF->nHeaderLength / 256;
00251     
00252     abyHeader[10] = psDBF->nRecordLength % 256;
00253     abyHeader[11] = psDBF->nRecordLength / 256;
00254 
00255 /* -------------------------------------------------------------------- */
00256 /*      Write the initial 32 byte file header, and all the field        */
00257 /*      descriptions.                                                   */
00258 /* -------------------------------------------------------------------- */
00259     fseek( psDBF->fp, 0, 0 );
00260     fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
00261     fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );
00262 
00263 /* -------------------------------------------------------------------- */
00264 /*      Write out the newline character if there is room for it.        */
00265 /* -------------------------------------------------------------------- */
00266     if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
00267     {
00268         char    cNewline;
00269 
00270         cNewline = 0x0d;
00271         fwrite( &cNewline, 1, 1, psDBF->fp );
00272     }
00273 }
00274 
00275 /************************************************************************/
00276 /*                           DBFFlushRecord()                           */
00277 /*                                                                      */
00278 /*      Write out the current record if there is one.                   */
00279 /************************************************************************/
00280 
00281 static void DBFFlushRecord( DBFHandle psDBF )
00282 
00283 {
00284     int         nRecordOffset;
00285 
00286     if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
00287     {
00288         psDBF->bCurrentRecordModified = FALSE;
00289 
00290         nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord 
00291                                                      + psDBF->nHeaderLength;
00292 
00293         fseek( psDBF->fp, nRecordOffset, 0 );
00294         fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
00295     }
00296 }
00297 
00298 /************************************************************************/
00299 /*                              DBFOpen()                               */
00300 /*                                                                      */
00301 /*      Open a .dbf file.                                               */
00302 /************************************************************************/
00303    
00304 DBFHandle SHPAPI_CALL
00305 DBFOpen( const char * pszFilename, const char * pszAccess )
00306 
00307 {
00308     DBFHandle           psDBF;
00309     unsigned char               *pabyBuf;
00310     int                 nFields, nHeadLen, nRecLen, iField, i;
00311     char                *pszBasename, *pszFullname;
00312 
00313 /* -------------------------------------------------------------------- */
00314 /*      We only allow the access strings "rb" and "r+".                  */
00315 /* -------------------------------------------------------------------- */
00316     if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 
00317         && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
00318         && strcmp(pszAccess,"r+b") != 0 )
00319         return( NULL );
00320 
00321     if( strcmp(pszAccess,"r") == 0 )
00322         pszAccess = "rb";
00323  
00324     if( strcmp(pszAccess,"r+") == 0 )
00325         pszAccess = "rb+";
00326 
00327 /* -------------------------------------------------------------------- */
00328 /*      Compute the base (layer) name.  If there is any extension       */
00329 /*      on the passed in filename we will strip it off.                 */
00330 /* -------------------------------------------------------------------- */
00331     pszBasename = (char *) malloc(strlen(pszFilename)+5);
00332     strcpy( pszBasename, pszFilename );
00333     for( i = strlen(pszBasename)-1; 
00334          i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
00335                && pszBasename[i] != '\\';
00336          i-- ) {}
00337 
00338     if( pszBasename[i] == '.' )
00339         pszBasename[i] = '\0';
00340 
00341     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
00342     sprintf( pszFullname, "%s.dbf", pszBasename );
00343         
00344     psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
00345     psDBF->fp = fopen( pszFullname, pszAccess );
00346 
00347     if( psDBF->fp == NULL )
00348     {
00349         sprintf( pszFullname, "%s.DBF", pszBasename );
00350         psDBF->fp = fopen(pszFullname, pszAccess );
00351     }
00352     
00353     free( pszBasename );
00354     free( pszFullname );
00355     
00356     if( psDBF->fp == NULL )
00357     {
00358         free( psDBF );
00359         return( NULL );
00360     }
00361 
00362     psDBF->bNoHeader = FALSE;
00363     psDBF->nCurrentRecord = -1;
00364     psDBF->bCurrentRecordModified = FALSE;
00365 
00366 /* -------------------------------------------------------------------- */
00367 /*  Read Table Header info                                              */
00368 /* -------------------------------------------------------------------- */
00369     pabyBuf = (unsigned char *) malloc(500);
00370     if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
00371     {
00372         fclose( psDBF->fp );
00373         free( pabyBuf );
00374         free( psDBF );
00375         return NULL;
00376     }
00377 
00378     psDBF->nRecords = 
00379      pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
00380 
00381     psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
00382     psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;
00383     
00384     psDBF->nFields = nFields = (nHeadLen - 32) / 32;
00385 
00386     psDBF->pszCurrentRecord = (char *) malloc(nRecLen);
00387 
00388 /* -------------------------------------------------------------------- */
00389 /*  Read in Field Definitions                                           */
00390 /* -------------------------------------------------------------------- */
00391     
00392     pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
00393     psDBF->pszHeader = (char *) pabyBuf;
00394 
00395     fseek( psDBF->fp, 32, 0 );
00396     if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
00397     {
00398         fclose( psDBF->fp );
00399         free( pabyBuf );
00400         free( psDBF );
00401         return NULL;
00402     }
00403 
00404     psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
00405     psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
00406     psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
00407     psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
00408 
00409     for( iField = 0; iField < nFields; iField++ )
00410     {
00411         unsigned char           *pabyFInfo;
00412 
00413         pabyFInfo = pabyBuf+iField*32;
00414 
00415         if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
00416         {
00417             psDBF->panFieldSize[iField] = pabyFInfo[16];
00418             psDBF->panFieldDecimals[iField] = pabyFInfo[17];
00419         }
00420         else
00421         {
00422             psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
00423             psDBF->panFieldDecimals[iField] = 0;
00424         }
00425 
00426         psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
00427         if( iField == 0 )
00428             psDBF->panFieldOffset[iField] = 1;
00429         else
00430             psDBF->panFieldOffset[iField] = 
00431               psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
00432     }
00433 
00434     return( psDBF );
00435 }
00436 
00437 /************************************************************************/
00438 /*                              DBFClose()                              */
00439 /************************************************************************/
00440 
00441 void SHPAPI_CALL
00442 DBFClose(DBFHandle psDBF)
00443 {
00444 /* -------------------------------------------------------------------- */
00445 /*      Write out header if not already written.                        */
00446 /* -------------------------------------------------------------------- */
00447     if( psDBF->bNoHeader )
00448         DBFWriteHeader( psDBF );
00449 
00450     DBFFlushRecord( psDBF );
00451 
00452 /* -------------------------------------------------------------------- */
00453 /*      Update last access date, and number of records if we have       */
00454 /*      write access.                                                   */
00455 /* -------------------------------------------------------------------- */
00456     if( psDBF->bUpdated )
00457     {
00458         unsigned char           abyFileHeader[32];
00459 
00460         fseek( psDBF->fp, 0, 0 );
00461         fread( abyFileHeader, 32, 1, psDBF->fp );
00462 
00463         abyFileHeader[1] = 95;                  /* YY */
00464         abyFileHeader[2] = 7;                   /* MM */
00465         abyFileHeader[3] = 26;                  /* DD */
00466 
00467         abyFileHeader[4] = psDBF->nRecords % 256;
00468         abyFileHeader[5] = (psDBF->nRecords/256) % 256;
00469         abyFileHeader[6] = (psDBF->nRecords/(256*256)) % 256;
00470         abyFileHeader[7] = (psDBF->nRecords/(256*256*256)) % 256;
00471 
00472         fseek( psDBF->fp, 0, 0 );
00473         fwrite( abyFileHeader, 32, 1, psDBF->fp );
00474     }
00475 
00476 /* -------------------------------------------------------------------- */
00477 /*      Close, and free resources.                                      */
00478 /* -------------------------------------------------------------------- */
00479     fclose( psDBF->fp );
00480 
00481     if( psDBF->panFieldOffset != NULL )
00482     {
00483         free( psDBF->panFieldOffset );
00484         free( psDBF->panFieldSize );
00485         free( psDBF->panFieldDecimals );
00486         free( psDBF->pachFieldType );
00487     }
00488 
00489     free( psDBF->pszHeader );
00490     free( psDBF->pszCurrentRecord );
00491 
00492     free( psDBF );
00493 
00494     if( pszStringField != NULL )
00495     {
00496         free( pszStringField );
00497         pszStringField = NULL;
00498         nStringFieldLen = 0;
00499     }
00500 }
00501 
00502 /************************************************************************/
00503 /*                             DBFCreate()                              */
00504 /*                                                                      */
00505 /*      Create a new .dbf file.                                         */
00506 /************************************************************************/
00507 
00508 DBFHandle SHPAPI_CALL
00509 DBFCreate( const char * pszFilename )
00510 
00511 {
00512     DBFHandle   psDBF;
00513     FILE        *fp;
00514     char        *pszFullname, *pszBasename;
00515     int         i;
00516 
00517 /* -------------------------------------------------------------------- */
00518 /*      Compute the base (layer) name.  If there is any extension       */
00519 /*      on the passed in filename we will strip it off.                 */
00520 /* -------------------------------------------------------------------- */
00521     pszBasename = (char *) malloc(strlen(pszFilename)+5);
00522     strcpy( pszBasename, pszFilename );
00523     for( i = strlen(pszBasename)-1; 
00524          i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
00525                && pszBasename[i] != '\\';
00526          i-- ) {}
00527 
00528     if( pszBasename[i] == '.' )
00529         pszBasename[i] = '\0';
00530 
00531     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
00532     sprintf( pszFullname, "%s.dbf", pszBasename );
00533     free( pszBasename );
00534 
00535 /* -------------------------------------------------------------------- */
00536 /*      Create the file.                                                */
00537 /* -------------------------------------------------------------------- */
00538     fp = fopen( pszFullname, "wb" );
00539     if( fp == NULL )
00540         return( NULL );
00541 
00542     fputc( 0, fp );
00543     fclose( fp );
00544 
00545     fp = fopen( pszFullname, "rb+" );
00546     if( fp == NULL )
00547         return( NULL );
00548 
00549     free( pszFullname );
00550 
00551 /* -------------------------------------------------------------------- */
00552 /*      Create the info structure.                                      */
00553 /* -------------------------------------------------------------------- */
00554     psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
00555 
00556     psDBF->fp = fp;
00557     psDBF->nRecords = 0;
00558     psDBF->nFields = 0;
00559     psDBF->nRecordLength = 1;
00560     psDBF->nHeaderLength = 33;
00561     
00562     psDBF->panFieldOffset = NULL;
00563     psDBF->panFieldSize = NULL;
00564     psDBF->panFieldDecimals = NULL;
00565     psDBF->pachFieldType = NULL;
00566     psDBF->pszHeader = NULL;
00567 
00568     psDBF->nCurrentRecord = -1;
00569     psDBF->bCurrentRecordModified = FALSE;
00570     psDBF->pszCurrentRecord = NULL;
00571 
00572     psDBF->bNoHeader = TRUE;
00573 
00574     return( psDBF );
00575 }
00576 
00577 /************************************************************************/
00578 /*                            DBFAddField()                             */
00579 /*                                                                      */
00580 /*      Add a field to a newly created .dbf file before any records     */
00581 /*      are written.                                                    */
00582 /************************************************************************/
00583 
00584 int SHPAPI_CALL
00585 DBFAddField(DBFHandle psDBF, const char * pszFieldName, 
00586             DBFFieldType eType, int nWidth, int nDecimals )
00587 
00588 {
00589     char        *pszFInfo;
00590     int         i;
00591 
00592 /* -------------------------------------------------------------------- */
00593 /*      Do some checking to ensure we can add records to this file.     */
00594 /* -------------------------------------------------------------------- */
00595     if( psDBF->nRecords > 0 )
00596         return( -1 );
00597 
00598     if( !psDBF->bNoHeader )
00599         return( -1 );
00600 
00601     if( eType != FTDouble && nDecimals != 0 )
00602         return( -1 );
00603 
00604     if( nWidth < 1 )
00605         return -1;
00606 
00607 /* -------------------------------------------------------------------- */
00608 /*      SfRealloc all the arrays larger to hold the additional field      */
00609 /*      information.                                                    */
00610 /* -------------------------------------------------------------------- */
00611     psDBF->nFields++;
00612 
00613     psDBF->panFieldOffset = (int *) 
00614       SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
00615 
00616     psDBF->panFieldSize = (int *) 
00617       SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
00618 
00619     psDBF->panFieldDecimals = (int *) 
00620       SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
00621 
00622     psDBF->pachFieldType = (char *) 
00623       SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
00624 
00625 /* -------------------------------------------------------------------- */
00626 /*      Assign the new field information fields.                        */
00627 /* -------------------------------------------------------------------- */
00628     psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
00629     psDBF->nRecordLength += nWidth;
00630     psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
00631     psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
00632 
00633     if( eType == FTLogical )
00634         psDBF->pachFieldType[psDBF->nFields-1] = 'L';
00635     else if( eType == FTString )
00636         psDBF->pachFieldType[psDBF->nFields-1] = 'C';
00637     else
00638         psDBF->pachFieldType[psDBF->nFields-1] = 'N';
00639 
00640 /* -------------------------------------------------------------------- */
00641 /*      Extend the required header information.                         */
00642 /* -------------------------------------------------------------------- */
00643     psDBF->nHeaderLength += 32;
00644     psDBF->bUpdated = FALSE;
00645 
00646     psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
00647 
00648     pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
00649 
00650     for( i = 0; i < 32; i++ )
00651         pszFInfo[i] = '\0';
00652 
00653     if( (int) strlen(pszFieldName) < 10 )
00654         strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
00655     else
00656         strncpy( pszFInfo, pszFieldName, 10);
00657 
00658     pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
00659 
00660     if( eType == FTString )
00661     {
00662         pszFInfo[16] = nWidth % 256;
00663         pszFInfo[17] = nWidth / 256;
00664     }
00665     else
00666     {
00667         pszFInfo[16] = nWidth;
00668         pszFInfo[17] = nDecimals;
00669     }
00670     
00671 /* -------------------------------------------------------------------- */
00672 /*      Make the current record buffer appropriately larger.            */
00673 /* -------------------------------------------------------------------- */
00674     psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
00675                                                psDBF->nRecordLength);
00676 
00677     return( psDBF->nFields-1 );
00678 }
00679 
00680 /************************************************************************/
00681 /*                          DBFReadAttribute()                          */
00682 /*                                                                      */
00683 /*      Read one of the attribute fields of a record.                   */
00684 /************************************************************************/
00685 
00686 static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
00687                               char chReqType )
00688 
00689 {
00690     int         nRecordOffset;
00691     unsigned char       *pabyRec;
00692     void        *pReturnField = NULL;
00693 
00694     static double dDoubleField;
00695 
00696 /* -------------------------------------------------------------------- */
00697 /*      Verify selection.                                               */
00698 /* -------------------------------------------------------------------- */
00699     if( hEntity < 0 || hEntity >= psDBF->nRecords )
00700         return( NULL );
00701 
00702     if( iField < 0 || iField >= psDBF->nFields )
00703         return( NULL );
00704 
00705 /* -------------------------------------------------------------------- */
00706 /*      Have we read the record?                                        */
00707 /* -------------------------------------------------------------------- */
00708     if( psDBF->nCurrentRecord != hEntity )
00709     {
00710         DBFFlushRecord( psDBF );
00711 
00712         nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
00713 
00714         if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
00715         {
00716             fprintf( stderr, "fseek(%d) failed on DBF file.\n",
00717                      nRecordOffset );
00718             return NULL;
00719         }
00720 
00721         if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 
00722                    1, psDBF->fp ) != 1 )
00723         {
00724             fprintf( stderr, "fread(%d) failed on DBF file.\n",
00725                      psDBF->nRecordLength );
00726             return NULL;
00727         }
00728 
00729         psDBF->nCurrentRecord = hEntity;
00730     }
00731 
00732     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
00733 
00734 /* -------------------------------------------------------------------- */
00735 /*      Ensure our field buffer is large enough to hold this buffer.    */
00736 /* -------------------------------------------------------------------- */
00737     if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
00738     {
00739         nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
00740         pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
00741     }
00742 
00743 /* -------------------------------------------------------------------- */
00744 /*      Extract the requested field.                                    */
00745 /* -------------------------------------------------------------------- */
00746     strncpy( pszStringField, 
00747              ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
00748              psDBF->panFieldSize[iField] );
00749     pszStringField[psDBF->panFieldSize[iField]] = '\0';
00750 
00751     pReturnField = pszStringField;
00752 
00753 /* -------------------------------------------------------------------- */
00754 /*      Decode the field.                                               */
00755 /* -------------------------------------------------------------------- */
00756     if( chReqType == 'N' )
00757     {
00758         dDoubleField = atof(pszStringField);
00759 
00760         pReturnField = &dDoubleField;
00761     }
00762 
00763 /* -------------------------------------------------------------------- */
00764 /*      Should we trim white space off the string attribute value?      */
00765 /* -------------------------------------------------------------------- */
00766 #ifdef TRIM_DBF_WHITESPACE
00767     else
00768     {
00769         char    *pchSrc, *pchDst;
00770 
00771         pchDst = pchSrc = pszStringField;
00772         while( *pchSrc == ' ' )
00773             pchSrc++;
00774 
00775         while( *pchSrc != '\0' )
00776             *(pchDst++) = *(pchSrc++);
00777         *pchDst = '\0';
00778 
00779         while( pchDst != pszStringField && *(--pchDst) == ' ' )
00780             *pchDst = '\0';
00781     }
00782 #endif
00783     
00784     return( pReturnField );
00785 }
00786 
00787 /************************************************************************/
00788 /*                        DBFReadIntAttribute()                         */
00789 /*                                                                      */
00790 /*      Read an integer attribute.                                      */
00791 /************************************************************************/
00792 
00793 int SHPAPI_CALL
00794 DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
00795 
00796 {
00797     double      *pdValue;
00798 
00799     pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
00800 
00801     if( pdValue == NULL )
00802         return 0;
00803     else
00804         return( (int) *pdValue );
00805 }
00806 
00807 /************************************************************************/
00808 /*                        DBFReadDoubleAttribute()                      */
00809 /*                                                                      */
00810 /*      Read a double attribute.                                        */
00811 /************************************************************************/
00812 
00813 double SHPAPI_CALL
00814 DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
00815 
00816 {
00817     double      *pdValue;
00818 
00819     pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
00820 
00821     if( pdValue == NULL )
00822         return 0.0;
00823     else
00824         return( *pdValue );
00825 }
00826 
00827 /************************************************************************/
00828 /*                        DBFReadStringAttribute()                      */
00829 /*                                                                      */
00830 /*      Read a string attribute.                                        */
00831 /************************************************************************/
00832 
00833 const char SHPAPI_CALL1(*)
00834 DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
00835 
00836 {
00837     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
00838 }
00839 
00840 /************************************************************************/
00841 /*                        DBFReadLogicalAttribute()                     */
00842 /*                                                                      */
00843 /*      Read a logical attribute.                                       */
00844 /************************************************************************/
00845 
00846 const char SHPAPI_CALL1(*)
00847 DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
00848 
00849 {
00850     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
00851 }
00852 
00853 /************************************************************************/
00854 /*                         DBFIsAttributeNULL()                         */
00855 /*                                                                      */
00856 /*      Return TRUE if value for field is NULL.                         */
00857 /*                                                                      */
00858 /*      Contributed by Jim Matthews.                                    */
00859 /************************************************************************/
00860 
00861 int SHPAPI_CALL
00862 DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
00863 
00864 {
00865     const char  *pszValue;
00866 
00867     pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
00868 
00869     switch(psDBF->pachFieldType[iField])
00870     {
00871       case 'N':
00872       case 'F':
00873         /* NULL numeric fields have value "****************" */
00874         return pszValue[0] == '*';
00875 
00876       case 'D':
00877         /* NULL date fields have value "00000000" */
00878         return strncmp(pszValue,"00000000",8) == 0;
00879 
00880       case 'L':
00881         /* NULL boolean fields have value "?" */ 
00882         return pszValue[0] == '?';
00883 
00884       default:
00885         /* empty string fields are considered NULL */
00886         return strlen(pszValue) == 0;
00887     }
00888 }
00889 
00890 /************************************************************************/
00891 /*                          DBFGetFieldCount()                          */
00892 /*                                                                      */
00893 /*      Return the number of fields in this table.                      */
00894 /************************************************************************/
00895 
00896 int SHPAPI_CALL
00897 DBFGetFieldCount( DBFHandle psDBF )
00898 
00899 {
00900     return( psDBF->nFields );
00901 }
00902 
00903 /************************************************************************/
00904 /*                         DBFGetRecordCount()                          */
00905 /*                                                                      */
00906 /*      Return the number of records in this table.                     */
00907 /************************************************************************/
00908 
00909 int SHPAPI_CALL
00910 DBFGetRecordCount( DBFHandle psDBF )
00911 
00912 {
00913     return( psDBF->nRecords );
00914 }
00915 
00916 /************************************************************************/
00917 /*                          DBFGetFieldInfo()                           */
00918 /*                                                                      */
00919 /*      Return any requested information about the field.               */
00920 /************************************************************************/
00921 
00922 DBFFieldType SHPAPI_CALL
00923 DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
00924                  int * pnWidth, int * pnDecimals )
00925 
00926 {
00927     if( iField < 0 || iField >= psDBF->nFields )
00928         return( FTInvalid );
00929 
00930     if( pnWidth != NULL )
00931         *pnWidth = psDBF->panFieldSize[iField];
00932 
00933     if( pnDecimals != NULL )
00934         *pnDecimals = psDBF->panFieldDecimals[iField];
00935 
00936     if( pszFieldName != NULL )
00937     {
00938         int     i;
00939 
00940         strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
00941         pszFieldName[11] = '\0';
00942         for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
00943             pszFieldName[i] = '\0';
00944     }
00945 
00946     if ( psDBF->pachFieldType[iField] == 'L' )
00947         return( FTLogical);
00948 
00949     else if( psDBF->pachFieldType[iField] == 'N' 
00950              || psDBF->pachFieldType[iField] == 'F'
00951              || psDBF->pachFieldType[iField] == 'D' )
00952     {
00953         if( psDBF->panFieldDecimals[iField] > 0 )
00954             return( FTDouble );
00955         else
00956             return( FTInteger );
00957     }
00958     else
00959     {
00960         return( FTString );
00961     }
00962 }
00963 
00964 /************************************************************************/
00965 /*                         DBFWriteAttribute()                          */
00966 /*                                                                      */
00967 /*      Write an attribute record to the file.                          */
00968 /************************************************************************/
00969 
00970 static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
00971                              void * pValue )
00972 
00973 {
00974     int         nRecordOffset, i, j, nRetResult = TRUE;
00975     unsigned char       *pabyRec;
00976     char        szSField[400], szFormat[20];
00977 
00978 /* -------------------------------------------------------------------- */
00979 /*      Is this a valid record?                                         */
00980 /* -------------------------------------------------------------------- */
00981     if( hEntity < 0 || hEntity > psDBF->nRecords )
00982         return( FALSE );
00983 
00984     if( psDBF->bNoHeader )
00985         DBFWriteHeader(psDBF);
00986 
00987 /* -------------------------------------------------------------------- */
00988 /*      Is this a brand new record?                                     */
00989 /* -------------------------------------------------------------------- */
00990     if( hEntity == psDBF->nRecords )
00991     {
00992         DBFFlushRecord( psDBF );
00993 
00994         psDBF->nRecords++;
00995         for( i = 0; i < psDBF->nRecordLength; i++ )
00996             psDBF->pszCurrentRecord[i] = ' ';
00997 
00998         psDBF->nCurrentRecord = hEntity;
00999     }
01000 
01001 /* -------------------------------------------------------------------- */
01002 /*      Is this an existing record, but different than the last one     */
01003 /*      we accessed?                                                    */
01004 /* -------------------------------------------------------------------- */
01005     if( psDBF->nCurrentRecord != hEntity )
01006     {
01007         DBFFlushRecord( psDBF );
01008 
01009         nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
01010 
01011         fseek( psDBF->fp, nRecordOffset, 0 );
01012         fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
01013 
01014         psDBF->nCurrentRecord = hEntity;
01015     }
01016 
01017     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
01018 
01019     psDBF->bCurrentRecordModified = TRUE;
01020     psDBF->bUpdated = TRUE;
01021 
01022 /* -------------------------------------------------------------------- */
01023 /*      Translate NULL value to valid DBF file representation.          */
01024 /*                                                                      */
01025 /*      Contributed by Jim Matthews.                                    */
01026 /* -------------------------------------------------------------------- */
01027     if( pValue == NULL )
01028     {
01029         switch(psDBF->pachFieldType[iField])
01030         {
01031           case 'N':
01032           case 'F':
01033             /* NULL numeric fields have value "****************" */
01034             memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*', 
01035                     psDBF->panFieldSize[iField] );
01036             break;
01037 
01038           case 'D':
01039             /* NULL date fields have value "00000000" */
01040             memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0', 
01041                     psDBF->panFieldSize[iField] );
01042             break;
01043 
01044           case 'L':
01045             /* NULL boolean fields have value "?" */ 
01046             memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?', 
01047                     psDBF->panFieldSize[iField] );
01048             break;
01049 
01050           default:
01051             /* empty string fields are considered NULL */
01052             memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0', 
01053                     psDBF->panFieldSize[iField] );
01054             break;
01055         }
01056         return TRUE;
01057     }
01058 
01059 /* -------------------------------------------------------------------- */
01060 /*      Assign all the record fields.                                   */
01061 /* -------------------------------------------------------------------- */
01062     switch( psDBF->pachFieldType[iField] )
01063     {
01064       case 'D':
01065       case 'N':
01066       case 'F':
01067         if( psDBF->panFieldDecimals[iField] == 0 )
01068         {
01069             int         nWidth = psDBF->panFieldSize[iField];
01070 
01071             if( sizeof(szSField)-2 < nWidth )
01072                 nWidth = sizeof(szSField)-2;
01073 
01074             sprintf( szFormat, "%%%dd", nWidth );
01075             sprintf(szSField, szFormat, (int) *((double *) pValue) );
01076             if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
01077             {
01078                 szSField[psDBF->panFieldSize[iField]] = '\0';
01079                 nRetResult = FALSE;
01080             }
01081 
01082             strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
01083                     szSField, strlen(szSField) );
01084         }
01085         else
01086         {
01087             int         nWidth = psDBF->panFieldSize[iField];
01088 
01089             if( sizeof(szSField)-2 < nWidth )
01090                 nWidth = sizeof(szSField)-2;
01091 
01092             sprintf( szFormat, "%%%d.%df", 
01093                      nWidth, psDBF->panFieldDecimals[iField] );
01094             sprintf(szSField, szFormat, *((double *) pValue) );
01095             if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
01096             {
01097                 szSField[psDBF->panFieldSize[iField]] = '\0';
01098                 nRetResult = FALSE;
01099             }
01100             strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
01101                     szSField, strlen(szSField) );
01102         }
01103         break;
01104 
01105       case 'L':
01106         if (psDBF->panFieldSize[iField] >= 1  && 
01107             (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
01108             *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
01109         break;
01110 
01111       default:
01112         if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
01113         {
01114             j = psDBF->panFieldSize[iField];
01115             nRetResult = FALSE;
01116         }
01117         else
01118         {
01119             memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
01120                     psDBF->panFieldSize[iField] );
01121             j = strlen((char *) pValue);
01122         }
01123 
01124         strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
01125                 (char *) pValue, j );
01126         break;
01127     }
01128 
01129     return( nRetResult );
01130 }
01131 
01132 /************************************************************************/
01133 /*                     DBFWriteAttributeDirectly()                      */
01134 /*                                                                      */
01135 /*      Write an attribute record to the file, but without any          */
01136 /*      reformatting based on type.  The provided buffer is written     */
01137 /*      as is to the field position in the record.                      */
01138 /************************************************************************/
01139 
01140 int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
01141                               void * pValue )
01142 
01143 {
01144     int         nRecordOffset, i, j;
01145     unsigned char       *pabyRec;
01146 
01147 /* -------------------------------------------------------------------- */
01148 /*      Is this a valid record?                                         */
01149 /* -------------------------------------------------------------------- */
01150     if( hEntity < 0 || hEntity > psDBF->nRecords )
01151         return( FALSE );
01152 
01153     if( psDBF->bNoHeader )
01154         DBFWriteHeader(psDBF);
01155 
01156 /* -------------------------------------------------------------------- */
01157 /*      Is this a brand new record?                                     */
01158 /* -------------------------------------------------------------------- */
01159     if( hEntity == psDBF->nRecords )
01160     {
01161         DBFFlushRecord( psDBF );
01162 
01163         psDBF->nRecords++;
01164         for( i = 0; i < psDBF->nRecordLength; i++ )
01165             psDBF->pszCurrentRecord[i] = ' ';
01166 
01167         psDBF->nCurrentRecord = hEntity;
01168     }
01169 
01170 /* -------------------------------------------------------------------- */
01171 /*      Is this an existing record, but different than the last one     */
01172 /*      we accessed?                                                    */
01173 /* -------------------------------------------------------------------- */
01174     if( psDBF->nCurrentRecord != hEntity )
01175     {
01176         DBFFlushRecord( psDBF );
01177 
01178         nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
01179 
01180         fseek( psDBF->fp, nRecordOffset, 0 );
01181         fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
01182 
01183         psDBF->nCurrentRecord = hEntity;
01184     }
01185 
01186     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
01187 
01188 /* -------------------------------------------------------------------- */
01189 /*      Assign all the record fields.                                   */
01190 /* -------------------------------------------------------------------- */
01191     if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
01192         j = psDBF->panFieldSize[iField];
01193     else
01194     {
01195         memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
01196                 psDBF->panFieldSize[iField] );
01197         j = strlen((char *) pValue);
01198     }
01199 
01200     strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
01201             (char *) pValue, j );
01202 
01203     psDBF->bCurrentRecordModified = TRUE;
01204     psDBF->bUpdated = TRUE;
01205 
01206     return( TRUE );
01207 }
01208 
01209 /************************************************************************/
01210 /*                      DBFWriteDoubleAttribute()                       */
01211 /*                                                                      */
01212 /*      Write a double attribute.                                       */
01213 /************************************************************************/
01214 
01215 int SHPAPI_CALL
01216 DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
01217                          double dValue )
01218 
01219 {
01220     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
01221 }
01222 
01223 /************************************************************************/
01224 /*                      DBFWriteIntegerAttribute()                      */
01225 /*                                                                      */
01226 /*      Write a integer attribute.                                      */
01227 /************************************************************************/
01228 
01229 int SHPAPI_CALL
01230 DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
01231                           int nValue )
01232 
01233 {
01234     double      dValue = nValue;
01235 
01236     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
01237 }
01238 
01239 /************************************************************************/
01240 /*                      DBFWriteStringAttribute()                       */
01241 /*                                                                      */
01242 /*      Write a string attribute.                                       */
01243 /************************************************************************/
01244 
01245 int SHPAPI_CALL
01246 DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
01247                          const char * pszValue )
01248 
01249 {
01250     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
01251 }
01252 
01253 /************************************************************************/
01254 /*                      DBFWriteNULLAttribute()                         */
01255 /*                                                                      */
01256 /*      Write a string attribute.                                       */
01257 /************************************************************************/
01258 
01259 int SHPAPI_CALL
01260 DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
01261 
01262 {
01263     return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
01264 }
01265 
01266 /************************************************************************/
01267 /*                      DBFWriteLogicalAttribute()                      */
01268 /*                                                                      */
01269 /*      Write a logical attribute.                                      */
01270 /************************************************************************/
01271 
01272 int SHPAPI_CALL
01273 DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
01274                        const char lValue)
01275 
01276 {
01277     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
01278 }
01279 
01280 /************************************************************************/
01281 /*                         DBFWriteTuple()                              */
01282 /*                                                                      */
01283 /*      Write an attribute record to the file.                          */
01284 /************************************************************************/
01285 
01286 int SHPAPI_CALL
01287 DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
01288 
01289 {
01290     int         nRecordOffset, i;
01291     unsigned char       *pabyRec;
01292 
01293 /* -------------------------------------------------------------------- */
01294 /*      Is this a valid record?                                         */
01295 /* -------------------------------------------------------------------- */
01296     if( hEntity < 0 || hEntity > psDBF->nRecords )
01297         return( FALSE );
01298 
01299     if( psDBF->bNoHeader )
01300         DBFWriteHeader(psDBF);
01301 
01302 /* -------------------------------------------------------------------- */
01303 /*      Is this a brand new record?                                     */
01304 /* -------------------------------------------------------------------- */
01305     if( hEntity == psDBF->nRecords )
01306     {
01307         DBFFlushRecord( psDBF );
01308 
01309         psDBF->nRecords++;
01310         for( i = 0; i < psDBF->nRecordLength; i++ )
01311             psDBF->pszCurrentRecord[i] = ' ';
01312 
01313         psDBF->nCurrentRecord = hEntity;
01314     }
01315 
01316 /* -------------------------------------------------------------------- */
01317 /*      Is this an existing record, but different than the last one     */
01318 /*      we accessed?                                                    */
01319 /* -------------------------------------------------------------------- */
01320     if( psDBF->nCurrentRecord != hEntity )
01321     {
01322         DBFFlushRecord( psDBF );
01323 
01324         nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
01325 
01326         fseek( psDBF->fp, nRecordOffset, 0 );
01327         fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
01328 
01329         psDBF->nCurrentRecord = hEntity;
01330     }
01331 
01332     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
01333 
01334     memcpy ( pabyRec, pRawTuple,  psDBF->nRecordLength );
01335 
01336     psDBF->bCurrentRecordModified = TRUE;
01337     psDBF->bUpdated = TRUE;
01338 
01339     return( TRUE );
01340 }
01341 
01342 /************************************************************************/
01343 /*                          DBFReadTuple()                              */
01344 /*                                                                      */
01345 /*      Read one of the attribute fields of a record.                   */
01346 /************************************************************************/
01347 
01348 const char SHPAPI_CALL1(*)
01349 DBFReadTuple(DBFHandle psDBF, int hEntity )
01350 
01351 {
01352     int         nRecordOffset;
01353     unsigned char       *pabyRec;
01354     static char *pReturnTuple = NULL;
01355 
01356     static int  nTupleLen = 0;
01357 
01358 /* -------------------------------------------------------------------- */
01359 /*      Have we read the record?                                        */
01360 /* -------------------------------------------------------------------- */
01361     if( hEntity < 0 || hEntity >= psDBF->nRecords )
01362         return( NULL );
01363 
01364     if( psDBF->nCurrentRecord != hEntity )
01365     {
01366         DBFFlushRecord( psDBF );
01367 
01368         nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
01369 
01370         fseek( psDBF->fp, nRecordOffset, 0 );
01371         fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
01372 
01373         psDBF->nCurrentRecord = hEntity;
01374     }
01375 
01376     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
01377 
01378     if ( nTupleLen < psDBF->nRecordLength) {
01379       nTupleLen = psDBF->nRecordLength;
01380       pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
01381     }
01382     
01383     memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
01384         
01385     return( pReturnTuple );
01386 }
01387 
01388 /************************************************************************/
01389 /*                          DBFCloneEmpty()                              */
01390 /*                                                                      */
01391 /*      Read one of the attribute fields of a record.                   */
01392 /************************************************************************/
01393 
01394 DBFHandle SHPAPI_CALL
01395 DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) 
01396 {
01397     DBFHandle   newDBF;
01398 
01399    newDBF = DBFCreate ( pszFilename );
01400    if ( newDBF == NULL ) return ( NULL ); 
01401    
01402    newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
01403    memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
01404    
01405    newDBF->nFields = psDBF->nFields;
01406    newDBF->nRecordLength = psDBF->nRecordLength;
01407    newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
01408     
01409    newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); 
01410    memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
01411    newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
01412    memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
01413    newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
01414    memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
01415    newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
01416    memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
01417 
01418    newDBF->bNoHeader = TRUE;
01419    newDBF->bUpdated = TRUE;
01420    
01421    DBFWriteHeader ( newDBF );
01422    DBFClose ( newDBF );
01423    
01424    newDBF = DBFOpen ( pszFilename, "rb+" );
01425 
01426    return ( newDBF );
01427 }
01428 
01429 /************************************************************************/
01430 /*                       DBFGetNativeFieldType()                        */
01431 /*                                                                      */
01432 /*      Return the DBase field type for the specified field.            */
01433 /*                                                                      */
01434 /*      Value can be one of: 'C' (String), 'D' (Date), 'F' (Float),     */
01435 /*                           'N' (Numeric, with or without decimal),    */
01436 /*                           'L' (Logical),                             */
01437 /*                           'M' (Memo: 10 digits .DBT block ptr)       */
01438 /************************************************************************/
01439 
01440 char SHPAPI_CALL
01441 DBFGetNativeFieldType( DBFHandle psDBF, int iField )
01442 
01443 {
01444     if( iField >=0 && iField < psDBF->nFields )
01445         return psDBF->pachFieldType[iField];
01446 
01447     return  ' ';
01448 }
01449 
01450 /************************************************************************/
01451 /*                            str_to_upper()                            */
01452 /************************************************************************/
01453 
01454 static void str_to_upper (char *string)
01455 {
01456     int len;
01457     short i = -1;
01458 
01459     len = strlen (string);
01460 
01461     while (++i < len)
01462         if (isalpha(string[i]) && islower(string[i]))
01463             string[i] = toupper ((int)string[i]);
01464 }
01465 
01466 /************************************************************************/
01467 /*                          DBFGetFieldIndex()                          */
01468 /*                                                                      */
01469 /*      Get the index number for a field in a .dbf file.                */
01470 /*                                                                      */
01471 /*      Contributed by Jim Matthews.                                    */
01472 /************************************************************************/
01473 
01474 int SHPAPI_CALL
01475 DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
01476 
01477 {
01478     char          name[12], name1[12], name2[12];
01479     int           i;
01480 
01481     strncpy(name1, pszFieldName,11);
01482     name1[11] = '\0';
01483     str_to_upper(name1);
01484 
01485     for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
01486     {
01487         DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
01488         strncpy(name2,name,11);
01489         str_to_upper(name2);
01490 
01491         if(!strncmp(name1,name2,10))
01492             return(i);
01493     }
01494     return(-1);
01495 }

Generated on Sun Aug 5 17:33:59 2007 for PIHMgis by  doxygen 1.5.2