dbfopen.c

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

Generated on Sun Jul 29 04:01:04 2012 for TerraLib - Development Source by  doxygen 1.5.3