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