LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - dbfopen.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 648 470 72.5 %
Date: 2010-01-09 Functions: 40 34 85.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: dbfopen.c,v 1.84 2009-10-29 19:59:48 fwarmerdam Exp $
       3                 :  *
       4                 :  * Project:  Shapelib
       5                 :  * Purpose:  Implementation of .dbf access API documented in dbf_api.html.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 1999, Frank Warmerdam
      10                 :  *
      11                 :  * This software is available under the following "MIT Style" license,
      12                 :  * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
      13                 :  * option is discussed in more detail in shapelib.html.
      14                 :  *
      15                 :  * --
      16                 :  * 
      17                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      18                 :  * copy of this software and associated documentation files (the "Software"),
      19                 :  * to deal in the Software without restriction, including without limitation
      20                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      21                 :  * and/or sell copies of the Software, and to permit persons to whom the
      22                 :  * Software is furnished to do so, subject to the following conditions:
      23                 :  *
      24                 :  * The above copyright notice and this permission notice shall be included
      25                 :  * in all copies or substantial portions of the Software.
      26                 :  *
      27                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      28                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      29                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      30                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      31                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      32                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      33                 :  * DEALINGS IN THE SOFTWARE.
      34                 :  ******************************************************************************
      35                 :  *
      36                 :  * $Log: dbfopen.c,v $
      37                 :  * Revision 1.84  2009-10-29 19:59:48  fwarmerdam
      38                 :  * avoid crash on truncated header (gdal #3093)
      39                 :  *
      40                 :  * Revision 1.83  2008/11/12 14:28:15  fwarmerdam
      41                 :  * DBFCreateField() now works on files with records
      42                 :  *
      43                 :  * Revision 1.82  2008/11/11 17:47:09  fwarmerdam
      44                 :  * added DBFDeleteField() function
      45                 :  *
      46                 :  * Revision 1.81  2008/01/03 17:48:13  bram
      47                 :  * in DBFCreate, use default code page LDID/87 (= 0x57, ANSI)
      48                 :  * instead of LDID/3.  This seems to be the same as what ESRI
      49                 :  * would be doing by default.
      50                 :  *
      51                 :  * Revision 1.80  2007/12/30 14:36:39  fwarmerdam
      52                 :  * avoid syntax issue with last comment.
      53                 :  *
      54                 :  * Revision 1.79  2007/12/30 14:35:48  fwarmerdam
      55                 :  * Avoid char* / unsigned char* warnings.
      56                 :  *
      57                 :  * Revision 1.78  2007/12/18 18:28:07  bram
      58                 :  * - create hook for client specific atof (bugzilla ticket 1615)
      59                 :  * - check for NULL handle before closing cpCPG file, and close after reading.
      60                 :  *
      61                 :  * Revision 1.77  2007/12/15 20:25:21  bram
      62                 :  * dbfopen.c now reads the Code Page information from the DBF file, and exports
      63                 :  * this information as a string through the DBFGetCodePage function.  This is 
      64                 :  * either the number from the LDID header field ("LDID/<number>") or as the 
      65                 :  * content of an accompanying .CPG file.  When creating a DBF file, the code can
      66                 :  * be set using DBFCreateEx.
      67                 :  *
      68                 :  * Revision 1.76  2007/12/12 22:21:32  bram
      69                 :  * DBFClose: check for NULL psDBF handle before trying to close it.
      70                 :  *
      71                 :  * Revision 1.75  2007/12/06 13:58:19  fwarmerdam
      72                 :  * make sure file offset calculations are done in as SAOffset
      73                 :  *
      74                 :  * Revision 1.74  2007/12/06 07:00:25  fwarmerdam
      75                 :  * dbfopen now using SAHooks for fileio
      76                 :  *
      77                 :  * Revision 1.73  2007/09/03 19:48:11  fwarmerdam
      78                 :  * move DBFReadAttribute() static dDoubleField into dbfinfo
      79                 :  *
      80                 :  * Revision 1.72  2007/09/03 19:34:06  fwarmerdam
      81                 :  * Avoid use of static tuple buffer in DBFReadTuple()
      82                 :  *
      83                 :  * Revision 1.71  2006/06/22 14:37:18  fwarmerdam
      84                 :  * avoid memory leak if dbfopen fread fails
      85                 :  *
      86                 :  * Revision 1.70  2006/06/17 17:47:05  fwarmerdam
      87                 :  * use calloc() for dbfinfo in DBFCreate
      88                 :  *
      89                 :  * Revision 1.69  2006/06/17 15:34:32  fwarmerdam
      90                 :  * disallow creating fields wider than 255
      91                 :  *
      92                 :  * Revision 1.68  2006/06/17 15:12:40  fwarmerdam
      93                 :  * Fixed C++ style comments.
      94                 :  *
      95                 :  * Revision 1.67  2006/06/17 00:24:53  fwarmerdam
      96                 :  * Don't treat non-zero decimals values as high order byte for length
      97                 :  * for strings.  It causes serious corruption for some files.
      98                 :  * http://bugzilla.remotesensing.org/show_bug.cgi?id=1202
      99                 :  *
     100                 :  * Revision 1.66  2006/03/29 18:26:20  fwarmerdam
     101                 :  * fixed bug with size of pachfieldtype in dbfcloneempty
     102                 :  *
     103                 :  * Revision 1.65  2006/02/15 01:14:30  fwarmerdam
     104                 :  * added DBFAddNativeFieldType
     105                 :  *
     106                 :  * Revision 1.64  2006/02/09 00:29:04  fwarmerdam
     107                 :  * Changed to put spaces into string fields that are NULL as
     108                 :  * per http://bugzilla.maptools.org/show_bug.cgi?id=316.
     109                 :  *
     110                 :  * Revision 1.63  2006/01/25 15:35:43  fwarmerdam
     111                 :  * check success on DBFFlushRecord
     112                 :  *
     113                 :  * Revision 1.62  2006/01/10 16:28:03  fwarmerdam
     114                 :  * Fixed typo in CPLError.
     115                 :  *
     116                 :  * Revision 1.61  2006/01/10 16:26:29  fwarmerdam
     117                 :  * Push loading record buffer into DBFLoadRecord.
     118                 :  * Implement CPL error reporting if USE_CPL defined.
     119                 :  *
     120                 :  * Revision 1.60  2006/01/05 01:27:27  fwarmerdam
     121                 :  * added dbf deletion mark/fetch
     122                 :  *
     123                 :  * Revision 1.59  2005/03/14 15:20:28  fwarmerdam
     124                 :  * Fixed last change.
     125                 :  *
     126                 :  * Revision 1.58  2005/03/14 15:18:54  fwarmerdam
     127                 :  * Treat very wide fields with no decimals as double.  This is
     128                 :  * more than 32bit integer fields.
     129                 :  *
     130                 :  * Revision 1.57  2005/02/10 20:16:54  fwarmerdam
     131                 :  * Make the pszStringField buffer for DBFReadAttribute() static char [256]
     132                 :  * as per bug 306.
     133                 :  *
     134                 :  * Revision 1.56  2005/02/10 20:07:56  fwarmerdam
     135                 :  * Fixed bug 305 in DBFCloneEmpty() - header length problem.
     136                 :  *
     137                 :  * Revision 1.55  2004/09/26 20:23:46  fwarmerdam
     138                 :  * avoid warnings with rcsid and signed/unsigned stuff
     139                 :  *
     140                 :  * Revision 1.54  2004/09/15 16:26:10  fwarmerdam
     141                 :  * Treat all blank numeric fields as null too.
     142                 :  */
     143                 : 
     144                 : #include "shapefil.h"
     145                 : 
     146                 : #include <math.h>
     147                 : #include <stdlib.h>
     148                 : #include <ctype.h>
     149                 : #include <string.h>
     150                 : 
     151               0 : SHP_CVSID("$Id: dbfopen.c,v 1.84 2009-10-29 19:59:48 fwarmerdam Exp $")
     152                 : 
     153                 : #ifndef FALSE
     154                 : #  define FALSE   0
     155                 : #  define TRUE    1
     156                 : #endif
     157                 : 
     158                 : /************************************************************************/
     159                 : /*                             SfRealloc()                              */
     160                 : /*                                                                      */
     161                 : /*      A realloc cover function that will access a NULL pointer as     */
     162                 : /*      a valid input.                                                  */
     163                 : /************************************************************************/
     164                 : 
     165            1808 : static void * SfRealloc( void * pMem, int nNewSize )
     166                 : 
     167                 : {
     168            1808 :     if( pMem == NULL )
     169             540 :         return( (void *) malloc(nNewSize) );
     170                 :     else
     171            1268 :         return( (void *) realloc(pMem,nNewSize) );
     172                 : }
     173                 : 
     174                 : /************************************************************************/
     175                 : /*                           DBFWriteHeader()                           */
     176                 : /*                                                                      */
     177                 : /*      This is called to write out the file header, and field          */
     178                 : /*      descriptions before writing any actual data records.  This      */
     179                 : /*      also computes all the DBFDataSet field offset/size/decimals     */
     180                 : /*      and so forth values.                                            */
     181                 : /************************************************************************/
     182                 : 
     183              94 : static void DBFWriteHeader(DBFHandle psDBF)
     184                 : 
     185                 : {
     186                 :     unsigned char abyHeader[XBASE_FLDHDR_SZ];
     187                 :     int   i;
     188                 : 
     189              94 :     if( !psDBF->bNoHeader )
     190               0 :         return;
     191                 : 
     192              94 :     psDBF->bNoHeader = FALSE;
     193                 : 
     194                 : /* -------------------------------------------------------------------- */
     195                 : /*  Initialize the file header information.       */
     196                 : /* -------------------------------------------------------------------- */
     197            3102 :     for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
     198            3008 :         abyHeader[i] = 0;
     199                 : 
     200              94 :     abyHeader[0] = 0x03;    /* memo field? - just copying   */
     201                 : 
     202                 :     /* write out a dummy date */
     203              94 :     abyHeader[1] = 95;      /* YY */
     204              94 :     abyHeader[2] = 7;     /* MM */
     205              94 :     abyHeader[3] = 26;      /* DD */
     206                 : 
     207                 :     /* record count preset at zero */
     208                 : 
     209              94 :     abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
     210              94 :     abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
     211                 :     
     212              94 :     abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
     213              94 :     abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
     214                 : 
     215              94 :     abyHeader[29] = (unsigned char) (psDBF->iLanguageDriver);
     216                 : 
     217                 : /* -------------------------------------------------------------------- */
     218                 : /*      Write the initial 32 byte file header, and all the field        */
     219                 : /*      descriptions.                                         */
     220                 : /* -------------------------------------------------------------------- */
     221              94 :     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     222              94 :     psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
     223              94 :     psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, 
     224                 :                           psDBF->fp );
     225                 : 
     226                 : /* -------------------------------------------------------------------- */
     227                 : /*      Write out the newline character if there is room for it.        */
     228                 : /* -------------------------------------------------------------------- */
     229              94 :     if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
     230                 :     {
     231                 :         char  cNewline;
     232                 : 
     233              94 :         cNewline = 0x0d;
     234              94 :         psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
     235                 :     }
     236                 : }
     237                 : 
     238                 : /************************************************************************/
     239                 : /*                           DBFFlushRecord()                           */
     240                 : /*                                                                      */
     241                 : /*      Write out the current record if there is one.                   */
     242                 : /************************************************************************/
     243                 : 
     244           32214 : static int DBFFlushRecord( DBFHandle psDBF )
     245                 : 
     246                 : {
     247                 :     SAOffset  nRecordOffset;
     248                 : 
     249           32214 :     if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
     250                 :     {
     251           15071 :   psDBF->bCurrentRecordModified = FALSE;
     252                 : 
     253           15071 :   nRecordOffset = 
     254           15071 :             psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord 
     255           15071 :             + psDBF->nHeaderLength;
     256                 : 
     257           30142 :   if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0 
     258           30142 :             || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord, 
     259           15071 :                                      psDBF->nRecordLength, 
     260           45213 :                                      1, psDBF->fp ) != 1 )
     261                 :         {
     262                 : #ifdef USE_CPL
     263               0 :             CPLError( CE_Failure, CPLE_FileIO, 
     264                 :                       "Failure writing DBF record %d.", 
     265                 :                       psDBF->nCurrentRecord );
     266                 : #else           
     267                 :             fprintf( stderr, "Failure writing DBF record %d.", 
     268                 :                      psDBF->nCurrentRecord );
     269                 : #endif
     270               0 :             return FALSE;
     271                 :         }
     272                 :     }
     273                 : 
     274           32214 :     return TRUE;
     275                 : }
     276                 : 
     277                 : /************************************************************************/
     278                 : /*                           DBFLoadRecord()                            */
     279                 : /************************************************************************/
     280                 : 
     281           84416 : static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
     282                 : 
     283                 : {
     284           84416 :     if( psDBF->nCurrentRecord != iRecord )
     285                 :     {
     286                 :         SAOffset nRecordOffset;
     287                 : 
     288           16137 :   if( !DBFFlushRecord( psDBF ) )
     289               0 :             return FALSE;
     290                 : 
     291           16137 :   nRecordOffset = 
     292           16137 :             psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
     293                 : 
     294           16137 :   if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
     295                 :         {
     296                 : #ifdef USE_CPL
     297               0 :             CPLError( CE_Failure, CPLE_FileIO,
     298                 :                       "fseek(%ld) failed on DBF file.\n",
     299                 :                       (long) nRecordOffset );
     300                 : #else
     301                 :             fprintf( stderr, "fseek(%ld) failed on DBF file.\n",
     302                 :                      (long) nRecordOffset );
     303                 : #endif
     304               0 :             return FALSE;
     305                 :         }
     306                 : 
     307           32274 :   if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord, 
     308           16137 :                                  psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
     309                 :         {
     310                 : #ifdef USE_CPL
     311               0 :             CPLError( CE_Failure, CPLE_FileIO, 
     312                 :                       "fread(%d) failed on DBF file.\n",
     313                 :                       psDBF->nRecordLength );
     314                 : #else
     315                 :             fprintf( stderr, "fread(%d) failed on DBF file.\n",
     316                 :                      psDBF->nRecordLength );
     317                 : #endif
     318               0 :             return FALSE;
     319                 :         }
     320                 : 
     321           16137 :   psDBF->nCurrentRecord = iRecord;
     322                 :     }
     323                 : 
     324           84416 :     return TRUE;
     325                 : }
     326                 : 
     327                 : /************************************************************************/
     328                 : /*                          DBFUpdateHeader()                           */
     329                 : /************************************************************************/
     330                 : 
     331                 : void SHPAPI_CALL
     332             107 : DBFUpdateHeader( DBFHandle psDBF )
     333                 : 
     334                 : {
     335                 :     unsigned char   abyFileHeader[32];
     336                 : 
     337             107 :     if( psDBF->bNoHeader )
     338               1 :         DBFWriteHeader( psDBF );
     339                 : 
     340             107 :     DBFFlushRecord( psDBF );
     341                 : 
     342             107 :     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     343             107 :     psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
     344                 :     
     345             107 :     abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
     346             107 :     abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
     347             107 :     abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
     348             107 :     abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
     349                 :     
     350             107 :     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     351             107 :     psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
     352                 : 
     353             107 :     psDBF->sHooks.FFlush( psDBF->fp );
     354             107 : }
     355                 : 
     356                 : /************************************************************************/
     357                 : /*                              DBFOpen()                               */
     358                 : /*                                                                      */
     359                 : /*      Open a .dbf file.                                               */
     360                 : /************************************************************************/
     361                 :    
     362                 : DBFHandle SHPAPI_CALL
     363             830 : DBFOpen( const char * pszFilename, const char * pszAccess )
     364                 : 
     365                 : {
     366                 :     SAHooks sHooks;
     367                 : 
     368             830 :     SASetupDefaultHooks( &sHooks );
     369                 : 
     370             830 :     return DBFOpenLL( pszFilename, pszAccess, &sHooks );
     371                 : }
     372                 : 
     373                 : /************************************************************************/
     374                 : /*                              DBFOpen()                               */
     375                 : /*                                                                      */
     376                 : /*      Open a .dbf file.                                               */
     377                 : /************************************************************************/
     378                 :    
     379                 : DBFHandle SHPAPI_CALL
     380             830 : DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
     381                 : 
     382                 : {
     383                 :     DBFHandle   psDBF;
     384                 :     SAFile    pfCPG;
     385                 :     unsigned char *pabyBuf;
     386                 :     int     nFields, nHeadLen, iField, i;
     387                 :     char    *pszBasename, *pszFullname;
     388             830 :     int                 nBufSize = 500;
     389                 : 
     390                 : /* -------------------------------------------------------------------- */
     391                 : /*      We only allow the access strings "rb" and "r+".                  */
     392                 : /* -------------------------------------------------------------------- */
     393            1508 :     if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 
     394             675 :         && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
     395               3 :         && strcmp(pszAccess,"r+b") != 0 )
     396               0 :         return( NULL );
     397                 : 
     398             830 :     if( strcmp(pszAccess,"r") == 0 )
     399             158 :         pszAccess = "rb";
     400                 :  
     401             830 :     if( strcmp(pszAccess,"r+") == 0 )
     402             669 :         pszAccess = "rb+";
     403                 : 
     404                 : /* -------------------------------------------------------------------- */
     405                 : /*  Compute the base (layer) name.  If there is any extension */
     406                 : /*  on the passed in filename we will strip it off.     */
     407                 : /* -------------------------------------------------------------------- */
     408             830 :     pszBasename = (char *) malloc(strlen(pszFilename)+5);
     409             830 :     strcpy( pszBasename, pszFilename );
     410           12450 :     for( i = strlen(pszBasename)-1; 
     411            5810 :    i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
     412            2490 :          && pszBasename[i] != '\\';
     413            2490 :    i-- ) {}
     414                 : 
     415             830 :     if( pszBasename[i] == '.' )
     416             830 :         pszBasename[i] = '\0';
     417                 : 
     418             830 :     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
     419             830 :     sprintf( pszFullname, "%s.dbf", pszBasename );
     420                 :         
     421             830 :     psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
     422             830 :     psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
     423             830 :     memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
     424                 : 
     425             830 :     if( psDBF->fp == NULL )
     426                 :     {
     427              20 :         sprintf( pszFullname, "%s.DBF", pszBasename );
     428              20 :         psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
     429                 :     }
     430                 : 
     431             830 :     sprintf( pszFullname, "%s.cpg", pszBasename );
     432             830 :     pfCPG = psHooks->FOpen( pszFullname, "r" );
     433             830 :     if( pfCPG == NULL )
     434                 :     {
     435             830 :         sprintf( pszFullname, "%s.CPG", pszBasename );
     436             830 :         pfCPG = psHooks->FOpen( pszFullname, "r" );
     437                 :     }
     438                 : 
     439             830 :     free( pszBasename );
     440             830 :     free( pszFullname );
     441                 :     
     442             830 :     if( psDBF->fp == NULL )
     443                 :     {
     444              18 :         free( psDBF );
     445              18 :         if( pfCPG ) psHooks->FClose( pfCPG );
     446              18 :         return( NULL );
     447                 :     }
     448                 : 
     449             812 :     psDBF->bNoHeader = FALSE;
     450             812 :     psDBF->nCurrentRecord = -1;
     451             812 :     psDBF->bCurrentRecordModified = FALSE;
     452                 : 
     453                 : /* -------------------------------------------------------------------- */
     454                 : /*  Read Table Header info                                              */
     455                 : /* -------------------------------------------------------------------- */
     456             812 :     pabyBuf = (unsigned char *) malloc(nBufSize);
     457             812 :     if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
     458                 :     {
     459               0 :         psDBF->sHooks.FClose( psDBF->fp );
     460               0 :         if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
     461               0 :         free( pabyBuf );
     462               0 :         free( psDBF );
     463               0 :         return NULL;
     464                 :     }
     465                 : 
     466             812 :     psDBF->nRecords = 
     467             812 :      pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
     468                 : 
     469             812 :     psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
     470             812 :     psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
     471             812 :     psDBF->iLanguageDriver = pabyBuf[29];
     472                 : 
     473             812 :     if (nHeadLen < 32)
     474                 :     {
     475               0 :         psDBF->sHooks.FClose( psDBF->fp );
     476               0 :         if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
     477               0 :         free( pabyBuf );
     478               0 :         free( psDBF );
     479               0 :         return NULL;
     480                 :     }
     481                 : 
     482             812 :     psDBF->nFields = nFields = (nHeadLen - 32) / 32;
     483                 : 
     484             812 :     psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
     485                 : 
     486                 : /* -------------------------------------------------------------------- */
     487                 : /*  Figure out the code page from the LDID and CPG                      */
     488                 : /* -------------------------------------------------------------------- */
     489                 : 
     490             812 :     psDBF->pszCodePage = NULL;
     491             812 :     if( pfCPG )
     492                 :     {
     493                 :         size_t n;
     494               0 :         char *buffer = (char *) pabyBuf;
     495               0 :         buffer[0] = '\0';
     496               0 :         psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
     497               0 :         n = strcspn( (char *) pabyBuf, "\n\r" );
     498               0 :         if( n > 0 )
     499                 :         {
     500               0 :             pabyBuf[n] = '\0';
     501               0 :             psDBF->pszCodePage = (char *) malloc(n + 1);
     502               0 :             memcpy( psDBF->pszCodePage, pabyBuf, n + 1 );
     503                 :         }
     504               0 :     psDBF->sHooks.FClose( pfCPG );
     505                 :     }
     506             812 :     if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 )
     507                 :     {
     508             704 :         sprintf( (char *) pabyBuf, "LDID/%d", psDBF->iLanguageDriver );
     509             704 :         psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1);
     510             704 :         strcpy( psDBF->pszCodePage, (char *) pabyBuf );
     511                 :     }
     512                 : 
     513                 : /* -------------------------------------------------------------------- */
     514                 : /*  Read in Field Definitions                                           */
     515                 : /* -------------------------------------------------------------------- */
     516                 :     
     517             812 :     pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
     518             812 :     psDBF->pszHeader = (char *) pabyBuf;
     519                 : 
     520             812 :     psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
     521             812 :     if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
     522                 :     {
     523               0 :         psDBF->sHooks.FClose( psDBF->fp );
     524               0 :         free( pabyBuf );
     525               0 :         free( psDBF->pszCurrentRecord );
     526               0 :         free( psDBF );
     527               0 :         return NULL;
     528                 :     }
     529                 : 
     530             812 :     psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
     531             812 :     psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
     532             812 :     psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
     533             812 :     psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
     534                 : 
     535            2069 :     for( iField = 0; iField < nFields; iField++ )
     536                 :     {
     537                 :   unsigned char   *pabyFInfo;
     538                 : 
     539            1257 :   pabyFInfo = pabyBuf+iField*32;
     540                 : 
     541            2223 :   if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
     542                 :   {
     543             966 :       psDBF->panFieldSize[iField] = pabyFInfo[16];
     544             966 :       psDBF->panFieldDecimals[iField] = pabyFInfo[17];
     545                 :   }
     546                 :   else
     547                 :   {
     548             291 :       psDBF->panFieldSize[iField] = pabyFInfo[16];
     549             291 :       psDBF->panFieldDecimals[iField] = 0;
     550                 : 
     551                 : /*
     552                 : ** The following seemed to be used sometimes to handle files with long
     553                 : ** string fields, but in other cases (such as bug 1202) the decimals field
     554                 : ** just seems to indicate some sort of preferred formatting, not very
     555                 : ** wide fields.  So I have disabled this code.  FrankW.
     556                 :       psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
     557                 :       psDBF->panFieldDecimals[iField] = 0;
     558                 : */
     559                 :   }
     560                 : 
     561            1257 :   psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
     562            1257 :   if( iField == 0 )
     563             812 :       psDBF->panFieldOffset[iField] = 1;
     564                 :   else
     565             890 :       psDBF->panFieldOffset[iField] = 
     566             445 :         psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
     567                 :     }
     568                 : 
     569             812 :     return( psDBF );
     570                 : }
     571                 : 
     572                 : /************************************************************************/
     573                 : /*                              DBFClose()                              */
     574                 : /************************************************************************/
     575                 : 
     576                 : void SHPAPI_CALL
     577             905 : DBFClose(DBFHandle psDBF)
     578                 : {
     579             905 :     if( psDBF == NULL )
     580               0 :         return;
     581                 : 
     582                 : /* -------------------------------------------------------------------- */
     583                 : /*      Write out header if not already written.                        */
     584                 : /* -------------------------------------------------------------------- */
     585             905 :     if( psDBF->bNoHeader )
     586               2 :         DBFWriteHeader( psDBF );
     587                 : 
     588             905 :     DBFFlushRecord( psDBF );
     589                 : 
     590                 : /* -------------------------------------------------------------------- */
     591                 : /*      Update last access date, and number of records if we have */
     592                 : /*  write access.                         */
     593                 : /* -------------------------------------------------------------------- */
     594             905 :     if( psDBF->bUpdated )
     595             101 :         DBFUpdateHeader( psDBF );
     596                 : 
     597                 : /* -------------------------------------------------------------------- */
     598                 : /*      Close, and free resources.                                      */
     599                 : /* -------------------------------------------------------------------- */
     600             905 :     psDBF->sHooks.FClose( psDBF->fp );
     601                 : 
     602             905 :     if( psDBF->panFieldOffset != NULL )
     603                 :     {
     604             905 :         free( psDBF->panFieldOffset );
     605             905 :         free( psDBF->panFieldSize );
     606             905 :         free( psDBF->panFieldDecimals );
     607             905 :         free( psDBF->pachFieldType );
     608                 :     }
     609                 : 
     610             905 :     if( psDBF->pszWorkField != NULL )
     611             142 :         free( psDBF->pszWorkField );
     612                 : 
     613             905 :     free( psDBF->pszHeader );
     614             905 :     free( psDBF->pszCurrentRecord );
     615             905 :     free( psDBF->pszCodePage );
     616                 : 
     617             905 :     free( psDBF );
     618                 : }
     619                 : 
     620                 : /************************************************************************/
     621                 : /*                             DBFCreate()                              */
     622                 : /*                                                                      */
     623                 : /* Create a new .dbf file with default code page LDID/87 (0x57)         */
     624                 : /************************************************************************/
     625                 : 
     626                 : DBFHandle SHPAPI_CALL
     627              90 : DBFCreate( const char * pszFilename )
     628                 : 
     629                 : {
     630              90 :     return DBFCreateEx( pszFilename, "LDID/87" ); // 0x57
     631                 : }
     632                 : 
     633                 : /************************************************************************/
     634                 : /*                            DBFCreateEx()                             */
     635                 : /*                                                                      */
     636                 : /*      Create a new .dbf file.                                         */
     637                 : /************************************************************************/
     638                 : 
     639                 : DBFHandle SHPAPI_CALL
     640              93 : DBFCreateEx( const char * pszFilename, const char* pszCodePage )
     641                 : 
     642                 : {
     643                 :     SAHooks sHooks;
     644                 : 
     645              93 :     SASetupDefaultHooks( &sHooks );
     646                 : 
     647              93 :     return DBFCreateLL( pszFilename, pszCodePage , &sHooks );
     648                 : }
     649                 : 
     650                 : /************************************************************************/
     651                 : /*                             DBFCreate()                              */
     652                 : /*                                                                      */
     653                 : /*      Create a new .dbf file.                                         */
     654                 : /************************************************************************/
     655                 : 
     656                 : DBFHandle SHPAPI_CALL
     657              93 : DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks )
     658                 : 
     659                 : {
     660                 :     DBFHandle psDBF;
     661                 :     SAFile  fp;
     662                 :     char  *pszFullname, *pszBasename;
     663              93 :     int   i, ldid = -1;
     664              93 :     char chZero = '\0';
     665                 : 
     666                 : /* -------------------------------------------------------------------- */
     667                 : /*  Compute the base (layer) name.  If there is any extension */
     668                 : /*  on the passed in filename we will strip it off.     */
     669                 : /* -------------------------------------------------------------------- */
     670              93 :     pszBasename = (char *) malloc(strlen(pszFilename)+5);
     671              93 :     strcpy( pszBasename, pszFilename );
     672            1395 :     for( i = strlen(pszBasename)-1; 
     673             651 :    i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
     674             279 :          && pszBasename[i] != '\\';
     675             279 :    i-- ) {}
     676                 : 
     677              93 :     if( pszBasename[i] == '.' )
     678              93 :         pszBasename[i] = '\0';
     679                 : 
     680              93 :     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
     681              93 :     sprintf( pszFullname, "%s.dbf", pszBasename );
     682                 : 
     683                 : /* -------------------------------------------------------------------- */
     684                 : /*      Create the file.                                                */
     685                 : /* -------------------------------------------------------------------- */
     686              93 :     fp = psHooks->FOpen( pszFullname, "wb" );
     687              93 :     if( fp == NULL )
     688               0 :         return( NULL );
     689                 :     
     690              93 :     psHooks->FWrite( &chZero, 1, 1, fp );
     691              93 :     psHooks->FClose( fp );
     692                 : 
     693              93 :     fp = psHooks->FOpen( pszFullname, "rb+" );
     694              93 :     if( fp == NULL )
     695               0 :         return( NULL );
     696                 : 
     697                 : 
     698              93 :     sprintf( pszFullname, "%s.cpg", pszBasename );
     699              93 :     if( pszCodePage != NULL )
     700                 :     {
     701              91 :         if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
     702                 :         {
     703              91 :             ldid = atoi( pszCodePage + 5 );
     704              91 :             if( ldid > 255 )
     705               0 :                 ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one
     706                 :         }
     707              91 :         if( ldid < 0 )
     708                 :         {
     709               0 :             SAFile fpCPG = psHooks->FOpen( pszFullname, "w" );
     710               0 :             psHooks->FWrite( (char*) pszCodePage, strlen(pszCodePage), 1, fpCPG );
     711               0 :             psHooks->FClose( fpCPG );
     712                 :         }
     713                 :     }
     714              93 :     if( pszCodePage == NULL || ldid >= 0 )
     715                 :     {
     716              93 :         psHooks->Remove( pszFullname );
     717                 :     }
     718                 : 
     719              93 :     free( pszBasename );
     720              93 :     free( pszFullname );
     721                 : 
     722                 : /* -------------------------------------------------------------------- */
     723                 : /*  Create the info structure.          */
     724                 : /* -------------------------------------------------------------------- */
     725              93 :     psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo));
     726                 : 
     727              93 :     memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
     728              93 :     psDBF->fp = fp;
     729              93 :     psDBF->nRecords = 0;
     730              93 :     psDBF->nFields = 0;
     731              93 :     psDBF->nRecordLength = 1;
     732              93 :     psDBF->nHeaderLength = 33;
     733                 :     
     734              93 :     psDBF->panFieldOffset = NULL;
     735              93 :     psDBF->panFieldSize = NULL;
     736              93 :     psDBF->panFieldDecimals = NULL;
     737              93 :     psDBF->pachFieldType = NULL;
     738              93 :     psDBF->pszHeader = NULL;
     739                 : 
     740              93 :     psDBF->nCurrentRecord = -1;
     741              93 :     psDBF->bCurrentRecordModified = FALSE;
     742              93 :     psDBF->pszCurrentRecord = NULL;
     743                 : 
     744              93 :     psDBF->bNoHeader = TRUE;
     745                 : 
     746              93 :     psDBF->iLanguageDriver = ldid > 0 ? ldid : 0;
     747              93 :     psDBF->pszCodePage = NULL;
     748              93 :     if( pszCodePage )
     749                 :     {
     750              91 :         psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
     751              91 :         strcpy( psDBF->pszCodePage, pszCodePage );
     752                 :     }
     753                 : 
     754              93 :     return( psDBF );
     755                 : }
     756                 : 
     757                 : /************************************************************************/
     758                 : /*                            DBFAddField()                             */
     759                 : /*                                                                      */
     760                 : /*      Add a field to a newly created .dbf or to an existing one       */
     761                 : /************************************************************************/
     762                 : 
     763                 : int SHPAPI_CALL
     764             165 : DBFAddField(DBFHandle psDBF, const char * pszFieldName, 
     765                 :             DBFFieldType eType, int nWidth, int nDecimals )
     766                 : 
     767                 : {
     768             165 :     char chNativeType = 'C';
     769                 : 
     770             165 :     if( eType == FTLogical )
     771               0 :         chNativeType = 'L';
     772             165 :     else if( eType == FTString )
     773              41 :         chNativeType = 'C';
     774                 :     else
     775             124 :         chNativeType = 'N';
     776                 : 
     777             165 :     return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType, 
     778                 :                                   nWidth, nDecimals );
     779                 : }
     780                 : 
     781                 : /************************************************************************/
     782                 : /*                            DBFAddField()                             */
     783                 : /*                                                                      */
     784                 : /*      Add a field to a newly created .dbf file before any records     */
     785                 : /*      are written.                                                    */
     786                 : /************************************************************************/
     787                 : 
     788                 : int SHPAPI_CALL
     789             166 : DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, 
     790                 :                       char chType, int nWidth, int nDecimals )
     791                 : 
     792                 : {
     793                 :     char  *pszFInfo;
     794                 :     int   i;
     795                 :     int         nOldRecordLength, nOldHeaderLength;
     796                 :     char        *pszRecord;
     797                 :     char        chFieldFill;
     798                 :     SAOffset    nRecordOffset;
     799                 : 
     800                 : /* -------------------------------------------------------------------- */
     801                 : /*      Do some checking to ensure we can add records to this file.     */
     802                 : /* -------------------------------------------------------------------- */
     803             166 :     if( nWidth < 1 )
     804               0 :         return -1;
     805                 : 
     806             166 :     if( nWidth > 255 )
     807               0 :         nWidth = 255;
     808                 : 
     809             166 :     nOldRecordLength = psDBF->nRecordLength;
     810             166 :     nOldHeaderLength = psDBF->nHeaderLength;
     811                 : 
     812                 : /* -------------------------------------------------------------------- */
     813                 : /*      SfRealloc all the arrays larger to hold the additional field      */
     814                 : /*      information.                                                    */
     815                 : /* -------------------------------------------------------------------- */
     816             166 :     psDBF->nFields++;
     817                 : 
     818             332 :     psDBF->panFieldOffset = (int *) 
     819             332 :         SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
     820                 : 
     821             332 :     psDBF->panFieldSize = (int *) 
     822             332 :         SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
     823                 : 
     824             332 :     psDBF->panFieldDecimals = (int *) 
     825             332 :         SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
     826                 : 
     827             332 :     psDBF->pachFieldType = (char *) 
     828             166 :         SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
     829                 : 
     830                 : /* -------------------------------------------------------------------- */
     831                 : /*      Assign the new field information fields.                        */
     832                 : /* -------------------------------------------------------------------- */
     833             166 :     psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
     834             166 :     psDBF->nRecordLength += nWidth;
     835             166 :     psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
     836             166 :     psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
     837             166 :     psDBF->pachFieldType[psDBF->nFields-1] = chType;
     838                 : 
     839                 : /* -------------------------------------------------------------------- */
     840                 : /*      Extend the required header information.                         */
     841                 : /* -------------------------------------------------------------------- */
     842             166 :     psDBF->nHeaderLength += 32;
     843             166 :     psDBF->bUpdated = FALSE;
     844                 : 
     845             166 :     psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
     846                 : 
     847             166 :     pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
     848                 : 
     849            5478 :     for( i = 0; i < 32; i++ )
     850            5312 :         pszFInfo[i] = '\0';
     851                 : 
     852             166 :     if( (int) strlen(pszFieldName) < 10 )
     853             141 :         strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
     854                 :     else
     855              25 :         strncpy( pszFInfo, pszFieldName, 10);
     856                 : 
     857             166 :     pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
     858                 : 
     859             166 :     if( chType == 'C' )
     860                 :     {
     861              41 :         pszFInfo[16] = (unsigned char) (nWidth % 256);
     862              41 :         pszFInfo[17] = (unsigned char) (nWidth / 256);
     863                 :     }
     864                 :     else
     865                 :     {
     866             125 :         pszFInfo[16] = (unsigned char) nWidth;
     867             125 :         pszFInfo[17] = (unsigned char) nDecimals;
     868                 :     }
     869                 :     
     870                 : /* -------------------------------------------------------------------- */
     871                 : /*      Make the current record buffer appropriately larger.            */
     872                 : /* -------------------------------------------------------------------- */
     873             166 :     psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
     874                 :                                                  psDBF->nRecordLength);
     875                 : 
     876                 :     /* we're done if dealing with new .dbf */
     877             166 :     if( psDBF->bNoHeader )
     878             165 :         return( psDBF->nFields - 1 );
     879                 : 
     880                 : /* -------------------------------------------------------------------- */
     881                 : /*      For existing .dbf file, shift records                           */
     882                 : /* -------------------------------------------------------------------- */
     883                 : 
     884                 :     /* alloc record */
     885               1 :     pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
     886                 : 
     887               1 :     switch (chType)
     888                 :     {
     889                 :       case 'N':
     890                 :       case 'F':
     891               0 :         chFieldFill = '*';
     892               0 :         break;
     893                 :       case 'D':
     894               0 :         chFieldFill = '0';
     895               0 :         break;
     896                 :       case 'L':
     897               0 :        chFieldFill = '?';
     898               0 :        break;
     899                 :       default:
     900               1 :        chFieldFill = ' ';
     901                 :        break;
     902                 :     }
     903                 : 
     904              11 :     for (i = psDBF->nRecords-1; i >= 0; --i)
     905                 :     {
     906              10 :         nRecordOffset = nOldRecordLength * (SAOffset) i + nOldHeaderLength;
     907                 : 
     908                 :         /* load record */
     909              10 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
     910              10 :         psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
     911                 : 
     912                 :         /* set new field's value to NULL */
     913              10 :         memset(pszRecord + nOldRecordLength, chFieldFill, nWidth);
     914                 : 
     915              10 :         nRecordOffset = psDBF->nRecordLength * (SAOffset) i + psDBF->nHeaderLength;
     916                 : 
     917                 :         /* move record to the new place*/
     918              10 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
     919              10 :         psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
     920                 :     }
     921                 : 
     922                 :     /* free record */
     923               1 :     free(pszRecord);
     924                 : 
     925                 :     /* force update of header with new header, record length and new field */
     926               1 :     psDBF->bNoHeader = TRUE;
     927               1 :     DBFUpdateHeader( psDBF );
     928                 : 
     929               1 :     return( psDBF->nFields-1 );
     930                 : }
     931                 : 
     932                 : /************************************************************************/
     933                 : /*                          DBFReadAttribute()                          */
     934                 : /*                                                                      */
     935                 : /*      Read one of the attribute fields of a record.                   */
     936                 : /************************************************************************/
     937                 : 
     938           36758 : static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
     939                 :                               char chReqType )
     940                 : 
     941                 : {
     942                 :     unsigned char *pabyRec;
     943           36758 :     void  *pReturnField = NULL;
     944                 : 
     945                 : /* -------------------------------------------------------------------- */
     946                 : /*      Verify selection.                                               */
     947                 : /* -------------------------------------------------------------------- */
     948           36758 :     if( hEntity < 0 || hEntity >= psDBF->nRecords )
     949               0 :         return( NULL );
     950                 : 
     951           36758 :     if( iField < 0 || iField >= psDBF->nFields )
     952               0 :         return( NULL );
     953                 : 
     954                 : /* -------------------------------------------------------------------- */
     955                 : /*  Have we read the record?          */
     956                 : /* -------------------------------------------------------------------- */
     957           36758 :     if( !DBFLoadRecord( psDBF, hEntity ) )
     958               0 :         return NULL;
     959                 : 
     960           36758 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
     961                 : 
     962                 : /* -------------------------------------------------------------------- */
     963                 : /*      Ensure we have room to extract the target field.                */
     964                 : /* -------------------------------------------------------------------- */
     965           36758 :     if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
     966                 :     {
     967             142 :         psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
     968             142 :         if( psDBF->pszWorkField == NULL )
     969             142 :             psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength);
     970                 :         else
     971               0 :             psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField,
     972               0 :                                                    psDBF->nWorkFieldLength);
     973                 :     }
     974                 : 
     975                 : /* -------------------------------------------------------------------- */
     976                 : /*  Extract the requested field.          */
     977                 : /* -------------------------------------------------------------------- */
     978           73516 :     strncpy( psDBF->pszWorkField,
     979           36758 :        ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
     980           36758 :        psDBF->panFieldSize[iField] );
     981           36758 :     psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
     982                 : 
     983           36758 :     pReturnField = psDBF->pszWorkField;
     984                 : 
     985                 : /* -------------------------------------------------------------------- */
     986                 : /*      Decode the field.                                               */
     987                 : /* -------------------------------------------------------------------- */
     988           36758 :     if( chReqType == 'N' )
     989                 :     {
     990           16890 :         psDBF->dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
     991                 : 
     992           16890 :   pReturnField = &(psDBF->dfDoubleField);
     993                 :     }
     994                 : 
     995                 : /* -------------------------------------------------------------------- */
     996                 : /*      Should we trim white space off the string attribute value?      */
     997                 : /* -------------------------------------------------------------------- */
     998                 : #ifdef TRIM_DBF_WHITESPACE
     999                 :     else
    1000                 :     {
    1001                 :         char  *pchSrc, *pchDst;
    1002                 : 
    1003           19868 :         pchDst = pchSrc = psDBF->pszWorkField;
    1004          179025 :         while( *pchSrc == ' ' )
    1005          139289 :             pchSrc++;
    1006                 : 
    1007          207642 :         while( *pchSrc != '\0' )
    1008          167906 :             *(pchDst++) = *(pchSrc++);
    1009           19868 :         *pchDst = '\0';
    1010                 : 
    1011          113002 :         while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
    1012           73266 :             *pchDst = '\0';
    1013                 :     }
    1014                 : #endif
    1015                 :     
    1016           36758 :     return( pReturnField );
    1017                 : }
    1018                 : 
    1019                 : /************************************************************************/
    1020                 : /*                        DBFReadIntAttribute()                         */
    1021                 : /*                                                                      */
    1022                 : /*      Read an integer attribute.                                      */
    1023                 : /************************************************************************/
    1024                 : 
    1025                 : int SHPAPI_CALL
    1026             432 : DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
    1027                 : 
    1028                 : {
    1029                 :     double  *pdValue;
    1030                 : 
    1031             432 :     pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
    1032                 : 
    1033             432 :     if( pdValue == NULL )
    1034               0 :         return 0;
    1035                 :     else
    1036             432 :         return( (int) *pdValue );
    1037                 : }
    1038                 : 
    1039                 : /************************************************************************/
    1040                 : /*                        DBFReadDoubleAttribute()                      */
    1041                 : /*                                                                      */
    1042                 : /*      Read a double attribute.                                        */
    1043                 : /************************************************************************/
    1044                 : 
    1045                 : double SHPAPI_CALL
    1046           16458 : DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
    1047                 : 
    1048                 : {
    1049                 :     double  *pdValue;
    1050                 : 
    1051           16458 :     pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
    1052                 : 
    1053           16458 :     if( pdValue == NULL )
    1054               0 :         return 0.0;
    1055                 :     else
    1056           16458 :         return( *pdValue );
    1057                 : }
    1058                 : 
    1059                 : /************************************************************************/
    1060                 : /*                        DBFReadStringAttribute()                      */
    1061                 : /*                                                                      */
    1062                 : /*      Read a string attribute.                                        */
    1063                 : /************************************************************************/
    1064                 : 
    1065                 : const char SHPAPI_CALL1(*)
    1066           19868 : DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
    1067                 : 
    1068                 : {
    1069           19868 :     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
    1070                 : }
    1071                 : 
    1072                 : /************************************************************************/
    1073                 : /*                        DBFReadLogicalAttribute()                     */
    1074                 : /*                                                                      */
    1075                 : /*      Read a logical attribute.                                       */
    1076                 : /************************************************************************/
    1077                 : 
    1078                 : const char SHPAPI_CALL1(*)
    1079               0 : DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
    1080                 : 
    1081                 : {
    1082               0 :     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
    1083                 : }
    1084                 : 
    1085                 : /************************************************************************/
    1086                 : /*                         DBFIsAttributeNULL()                         */
    1087                 : /*                                                                      */
    1088                 : /*      Return TRUE if value for field is NULL.                         */
    1089                 : /*                                                                      */
    1090                 : /*      Contributed by Jim Matthews.                                    */
    1091                 : /************************************************************************/
    1092                 : 
    1093                 : int SHPAPI_CALL
    1094           18564 : DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
    1095                 : 
    1096                 : {
    1097                 :     const char  *pszValue;
    1098                 :     int i;
    1099                 : 
    1100           18564 :     pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
    1101                 : 
    1102           18564 :     if( pszValue == NULL )
    1103               0 :         return TRUE;
    1104                 : 
    1105           18564 :     switch(psDBF->pachFieldType[iField])
    1106                 :     {
    1107                 :       case 'N':
    1108                 :       case 'F':
    1109                 :         /*
    1110                 :         ** We accept all asterisks or all blanks as NULL 
    1111                 :         ** though according to the spec I think it should be all 
    1112                 :         ** asterisks. 
    1113                 :         */
    1114           16906 :         if( pszValue[0] == '*' )
    1115              16 :             return TRUE;
    1116                 : 
    1117           16890 :         for( i = 0; pszValue[i] != '\0'; i++ )
    1118                 :         {
    1119           16890 :             if( pszValue[i] != ' ' )
    1120           16890 :                 return FALSE;
    1121                 :         }
    1122               0 :         return TRUE;
    1123                 : 
    1124                 :       case 'D':
    1125                 :         /* NULL date fields have value "00000000" */
    1126               2 :         return strncmp(pszValue,"00000000",8) == 0;
    1127                 : 
    1128                 :       case 'L':
    1129                 :         /* NULL boolean fields have value "?" */ 
    1130               0 :         return pszValue[0] == '?';
    1131                 : 
    1132                 :       default:
    1133                 :         /* empty string fields are considered NULL */
    1134            1656 :         return strlen(pszValue) == 0;
    1135                 :     }
    1136                 : }
    1137                 : 
    1138                 : /************************************************************************/
    1139                 : /*                          DBFGetFieldCount()                          */
    1140                 : /*                                                                      */
    1141                 : /*      Return the number of fields in this table.                      */
    1142                 : /************************************************************************/
    1143                 : 
    1144                 : int SHPAPI_CALL
    1145           19834 : DBFGetFieldCount( DBFHandle psDBF )
    1146                 : 
    1147                 : {
    1148           19834 :     return( psDBF->nFields );
    1149                 : }
    1150                 : 
    1151                 : /************************************************************************/
    1152                 : /*                         DBFGetRecordCount()                          */
    1153                 : /*                                                                      */
    1154                 : /*      Return the number of records in this table.                     */
    1155                 : /************************************************************************/
    1156                 : 
    1157                 : int SHPAPI_CALL
    1158           30077 : DBFGetRecordCount( DBFHandle psDBF )
    1159                 : 
    1160                 : {
    1161           30077 :     return( psDBF->nRecords );
    1162                 : }
    1163                 : 
    1164                 : /************************************************************************/
    1165                 : /*                          DBFGetFieldInfo()                           */
    1166                 : /*                                                                      */
    1167                 : /*      Return any requested information about the field.               */
    1168                 : /************************************************************************/
    1169                 : 
    1170                 : DBFFieldType SHPAPI_CALL
    1171            3481 : DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
    1172                 :                  int * pnWidth, int * pnDecimals )
    1173                 : 
    1174                 : {
    1175            3481 :     if( iField < 0 || iField >= psDBF->nFields )
    1176               0 :         return( FTInvalid );
    1177                 : 
    1178            3481 :     if( pnWidth != NULL )
    1179            1239 :         *pnWidth = psDBF->panFieldSize[iField];
    1180                 : 
    1181            3481 :     if( pnDecimals != NULL )
    1182            1239 :         *pnDecimals = psDBF->panFieldDecimals[iField];
    1183                 : 
    1184            3481 :     if( pszFieldName != NULL )
    1185                 :     {
    1186                 :   int i;
    1187                 : 
    1188            3481 :   strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
    1189            3481 :   pszFieldName[11] = '\0';
    1190            3481 :   for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
    1191               0 :       pszFieldName[i] = '\0';
    1192                 :     }
    1193                 : 
    1194            3481 :     if ( psDBF->pachFieldType[iField] == 'L' )
    1195               0 :   return( FTLogical);
    1196                 : 
    1197            4533 :     else if( psDBF->pachFieldType[iField] == 'N' 
    1198            1052 :              || psDBF->pachFieldType[iField] == 'F' )
    1199                 :     {
    1200            4473 :   if( psDBF->panFieldDecimals[iField] > 0 
    1201            2044 :             || psDBF->panFieldSize[iField] > 10 )
    1202            2362 :       return( FTDouble );
    1203                 :   else
    1204              67 :       return( FTInteger );
    1205                 :     }
    1206                 :     else
    1207                 :     {
    1208            1052 :   return( FTString );
    1209                 :     }
    1210                 : }
    1211                 : 
    1212                 : /************************************************************************/
    1213                 : /*                         DBFWriteAttribute()                          */
    1214                 : /*                  */
    1215                 : /*  Write an attribute record to the file.        */
    1216                 : /************************************************************************/
    1217                 : 
    1218           15519 : static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
    1219                 :            void * pValue )
    1220                 : 
    1221                 : {
    1222           15519 :     int         i, j, nRetResult = TRUE;
    1223                 :     unsigned char *pabyRec;
    1224                 :     char  szSField[400], szFormat[20];
    1225                 : 
    1226                 : /* -------------------------------------------------------------------- */
    1227                 : /*  Is this a valid record?           */
    1228                 : /* -------------------------------------------------------------------- */
    1229           15519 :     if( hEntity < 0 || hEntity > psDBF->nRecords )
    1230               0 :         return( FALSE );
    1231                 : 
    1232           15519 :     if( psDBF->bNoHeader )
    1233              88 :         DBFWriteHeader(psDBF);
    1234                 : 
    1235                 : /* -------------------------------------------------------------------- */
    1236                 : /*      Is this a brand new record?                                     */
    1237                 : /* -------------------------------------------------------------------- */
    1238           15519 :     if( hEntity == psDBF->nRecords )
    1239                 :     {
    1240           15037 :   if( !DBFFlushRecord( psDBF ) )
    1241               0 :             return FALSE;
    1242                 : 
    1243           15037 :   psDBF->nRecords++;
    1244          206864 :   for( i = 0; i < psDBF->nRecordLength; i++ )
    1245          191827 :       psDBF->pszCurrentRecord[i] = ' ';
    1246                 : 
    1247           15037 :   psDBF->nCurrentRecord = hEntity;
    1248                 :     }
    1249                 : 
    1250                 : /* -------------------------------------------------------------------- */
    1251                 : /*      Is this an existing record, but different than the last one     */
    1252                 : /*      we accessed?                                                    */
    1253                 : /* -------------------------------------------------------------------- */
    1254           15519 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1255               0 :         return FALSE;
    1256                 : 
    1257           15519 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
    1258                 : 
    1259           15519 :     psDBF->bCurrentRecordModified = TRUE;
    1260           15519 :     psDBF->bUpdated = TRUE;
    1261                 : 
    1262                 : /* -------------------------------------------------------------------- */
    1263                 : /*      Translate NULL value to valid DBF file representation.          */
    1264                 : /*                                                                      */
    1265                 : /*      Contributed by Jim Matthews.                                    */
    1266                 : /* -------------------------------------------------------------------- */
    1267           15519 :     if( pValue == NULL )
    1268                 :     {
    1269               2 :         switch(psDBF->pachFieldType[iField])
    1270                 :         {
    1271                 :           case 'N':
    1272                 :           case 'F':
    1273                 :       /* NULL numeric fields have value "****************" */
    1274               2 :             memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*', 
    1275               2 :                     psDBF->panFieldSize[iField] );
    1276               2 :             break;
    1277                 : 
    1278                 :           case 'D':
    1279                 :       /* NULL date fields have value "00000000" */
    1280               0 :             memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0', 
    1281               0 :                     psDBF->panFieldSize[iField] );
    1282               0 :             break;
    1283                 : 
    1284                 :           case 'L':
    1285                 :       /* NULL boolean fields have value "?" */ 
    1286               0 :             memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?', 
    1287               0 :                     psDBF->panFieldSize[iField] );
    1288               0 :             break;
    1289                 : 
    1290                 :           default:
    1291                 :             /* empty string fields are considered NULL */
    1292               0 :             memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), ' ', 
    1293               0 :                     psDBF->panFieldSize[iField] );
    1294                 :             break;
    1295                 :         }
    1296               2 :         return TRUE;
    1297                 :     }
    1298                 : 
    1299                 : /* -------------------------------------------------------------------- */
    1300                 : /*      Assign all the record fields.                                   */
    1301                 : /* -------------------------------------------------------------------- */
    1302           15517 :     switch( psDBF->pachFieldType[iField] )
    1303                 :     {
    1304                 :       case 'D':
    1305                 :       case 'N':
    1306                 :       case 'F':
    1307           15311 :   if( psDBF->panFieldDecimals[iField] == 0 )
    1308                 :   {
    1309           15012 :             int   nWidth = psDBF->panFieldSize[iField];
    1310                 : 
    1311           15012 :             if( (int) sizeof(szSField)-2 < nWidth )
    1312               0 :                 nWidth = sizeof(szSField)-2;
    1313                 : 
    1314           15012 :       sprintf( szFormat, "%%%dd", nWidth );
    1315           15012 :       sprintf(szSField, szFormat, (int) *((double *) pValue) );
    1316           15012 :       if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
    1317                 :             {
    1318               0 :           szSField[psDBF->panFieldSize[iField]] = '\0';
    1319               0 :                 nRetResult = FALSE;
    1320                 :             }
    1321                 : 
    1322           15012 :       strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1323                 :         szSField, strlen(szSField) );
    1324                 :   }
    1325                 :   else
    1326                 :   {
    1327             299 :             int   nWidth = psDBF->panFieldSize[iField];
    1328                 : 
    1329             299 :             if( (int) sizeof(szSField)-2 < nWidth )
    1330               0 :                 nWidth = sizeof(szSField)-2;
    1331                 : 
    1332             299 :       sprintf( szFormat, "%%%d.%df", 
    1333             299 :                      nWidth, psDBF->panFieldDecimals[iField] );
    1334             299 :       sprintf(szSField, szFormat, *((double *) pValue) );
    1335             299 :       if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
    1336                 :             {
    1337               0 :           szSField[psDBF->panFieldSize[iField]] = '\0';
    1338               0 :                 nRetResult = FALSE;
    1339                 :             }
    1340             299 :       strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1341                 :         szSField, strlen(szSField) );
    1342                 :   }
    1343           15311 :   break;
    1344                 : 
    1345                 :       case 'L':
    1346               0 :         if (psDBF->panFieldSize[iField] >= 1  && 
    1347               0 :             (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
    1348               0 :             *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
    1349               0 :         break;
    1350                 : 
    1351                 :       default:
    1352             206 :   if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
    1353                 :         {
    1354               0 :       j = psDBF->panFieldSize[iField];
    1355               0 :             nRetResult = FALSE;
    1356                 :         }
    1357                 :   else
    1358                 :         {
    1359             206 :             memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
    1360             206 :                     psDBF->panFieldSize[iField] );
    1361             206 :       j = strlen((char *) pValue);
    1362                 :         }
    1363                 : 
    1364             206 :   strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1365                 :     (char *) pValue, j );
    1366                 :   break;
    1367                 :     }
    1368                 : 
    1369           15517 :     return( nRetResult );
    1370                 : }
    1371                 : 
    1372                 : /************************************************************************/
    1373                 : /*                     DBFWriteAttributeDirectly()                      */
    1374                 : /*                                                                      */
    1375                 : /*      Write an attribute record to the file, but without any          */
    1376                 : /*      reformatting based on type.  The provided buffer is written     */
    1377                 : /*      as is to the field position in the record.                      */
    1378                 : /************************************************************************/
    1379                 : 
    1380                 : int SHPAPI_CALL
    1381               0 : DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
    1382                 :                               void * pValue )
    1383                 : 
    1384                 : {
    1385                 :     int           i, j;
    1386                 :     unsigned char *pabyRec;
    1387                 : 
    1388                 : /* -------------------------------------------------------------------- */
    1389                 : /*  Is this a valid record?           */
    1390                 : /* -------------------------------------------------------------------- */
    1391               0 :     if( hEntity < 0 || hEntity > psDBF->nRecords )
    1392               0 :         return( FALSE );
    1393                 : 
    1394               0 :     if( psDBF->bNoHeader )
    1395               0 :         DBFWriteHeader(psDBF);
    1396                 : 
    1397                 : /* -------------------------------------------------------------------- */
    1398                 : /*      Is this a brand new record?                                     */
    1399                 : /* -------------------------------------------------------------------- */
    1400               0 :     if( hEntity == psDBF->nRecords )
    1401                 :     {
    1402               0 :   if( !DBFFlushRecord( psDBF ) )
    1403               0 :             return FALSE;
    1404                 : 
    1405               0 :   psDBF->nRecords++;
    1406               0 :   for( i = 0; i < psDBF->nRecordLength; i++ )
    1407               0 :       psDBF->pszCurrentRecord[i] = ' ';
    1408                 : 
    1409               0 :   psDBF->nCurrentRecord = hEntity;
    1410                 :     }
    1411                 : 
    1412                 : /* -------------------------------------------------------------------- */
    1413                 : /*      Is this an existing record, but different than the last one     */
    1414                 : /*      we accessed?                                                    */
    1415                 : /* -------------------------------------------------------------------- */
    1416               0 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1417               0 :         return FALSE;
    1418                 : 
    1419               0 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
    1420                 : 
    1421                 : /* -------------------------------------------------------------------- */
    1422                 : /*      Assign all the record fields.                                   */
    1423                 : /* -------------------------------------------------------------------- */
    1424               0 :     if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
    1425               0 :         j = psDBF->panFieldSize[iField];
    1426                 :     else
    1427                 :     {
    1428               0 :         memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
    1429               0 :                 psDBF->panFieldSize[iField] );
    1430               0 :         j = strlen((char *) pValue);
    1431                 :     }
    1432                 : 
    1433               0 :     strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1434                 :             (char *) pValue, j );
    1435                 : 
    1436               0 :     psDBF->bCurrentRecordModified = TRUE;
    1437               0 :     psDBF->bUpdated = TRUE;
    1438                 : 
    1439               0 :     return( TRUE );
    1440                 : }
    1441                 : 
    1442                 : /************************************************************************/
    1443                 : /*                      DBFWriteDoubleAttribute()                       */
    1444                 : /*                                                                      */
    1445                 : /*      Write a double attribute.                                       */
    1446                 : /************************************************************************/
    1447                 : 
    1448                 : int SHPAPI_CALL
    1449             442 : DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
    1450                 :                          double dValue )
    1451                 : 
    1452                 : {
    1453             442 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
    1454                 : }
    1455                 : 
    1456                 : /************************************************************************/
    1457                 : /*                      DBFWriteIntegerAttribute()                      */
    1458                 : /*                                                                      */
    1459                 : /*      Write a integer attribute.                                      */
    1460                 : /************************************************************************/
    1461                 : 
    1462                 : int SHPAPI_CALL
    1463           14869 : DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
    1464                 :                           int nValue )
    1465                 : 
    1466                 : {
    1467           14869 :     double  dValue = nValue;
    1468                 : 
    1469           14869 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
    1470                 : }
    1471                 : 
    1472                 : /************************************************************************/
    1473                 : /*                      DBFWriteStringAttribute()                       */
    1474                 : /*                                                                      */
    1475                 : /*      Write a string attribute.                                       */
    1476                 : /************************************************************************/
    1477                 : 
    1478                 : int SHPAPI_CALL
    1479             206 : DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
    1480                 :                          const char * pszValue )
    1481                 : 
    1482                 : {
    1483             206 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
    1484                 : }
    1485                 : 
    1486                 : /************************************************************************/
    1487                 : /*                      DBFWriteNULLAttribute()                         */
    1488                 : /*                                                                      */
    1489                 : /*      Write a string attribute.                                       */
    1490                 : /************************************************************************/
    1491                 : 
    1492                 : int SHPAPI_CALL
    1493               2 : DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
    1494                 : 
    1495                 : {
    1496               2 :     return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
    1497                 : }
    1498                 : 
    1499                 : /************************************************************************/
    1500                 : /*                      DBFWriteLogicalAttribute()                      */
    1501                 : /*                                                                      */
    1502                 : /*      Write a logical attribute.                                      */
    1503                 : /************************************************************************/
    1504                 : 
    1505                 : int SHPAPI_CALL
    1506               0 : DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
    1507                 :            const char lValue)
    1508                 : 
    1509                 : {
    1510               0 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
    1511                 : }
    1512                 : 
    1513                 : /************************************************************************/
    1514                 : /*                         DBFWriteTuple()                              */
    1515                 : /*                  */
    1516                 : /*  Write an attribute record to the file.        */
    1517                 : /************************************************************************/
    1518                 : 
    1519                 : int SHPAPI_CALL
    1520              28 : DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
    1521                 : 
    1522                 : {
    1523                 :     int           i;
    1524                 :     unsigned char *pabyRec;
    1525                 : 
    1526                 : /* -------------------------------------------------------------------- */
    1527                 : /*  Is this a valid record?           */
    1528                 : /* -------------------------------------------------------------------- */
    1529              28 :     if( hEntity < 0 || hEntity > psDBF->nRecords )
    1530               0 :         return( FALSE );
    1531                 : 
    1532              28 :     if( psDBF->bNoHeader )
    1533               0 :         DBFWriteHeader(psDBF);
    1534                 : 
    1535                 : /* -------------------------------------------------------------------- */
    1536                 : /*      Is this a brand new record?                                     */
    1537                 : /* -------------------------------------------------------------------- */
    1538              28 :     if( hEntity == psDBF->nRecords )
    1539                 :     {
    1540              28 :   if( !DBFFlushRecord( psDBF ) )
    1541               0 :             return FALSE;
    1542                 : 
    1543              28 :   psDBF->nRecords++;
    1544            1908 :   for( i = 0; i < psDBF->nRecordLength; i++ )
    1545            1880 :       psDBF->pszCurrentRecord[i] = ' ';
    1546                 : 
    1547              28 :   psDBF->nCurrentRecord = hEntity;
    1548                 :     }
    1549                 : 
    1550                 : /* -------------------------------------------------------------------- */
    1551                 : /*      Is this an existing record, but different than the last one     */
    1552                 : /*      we accessed?                                                    */
    1553                 : /* -------------------------------------------------------------------- */
    1554              28 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1555               0 :         return FALSE;
    1556                 : 
    1557              28 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
    1558                 : 
    1559              28 :     memcpy ( pabyRec, pRawTuple,  psDBF->nRecordLength );
    1560                 : 
    1561              28 :     psDBF->bCurrentRecordModified = TRUE;
    1562              28 :     psDBF->bUpdated = TRUE;
    1563                 : 
    1564              28 :     return( TRUE );
    1565                 : }
    1566                 : 
    1567                 : /************************************************************************/
    1568                 : /*                            DBFReadTuple()                            */
    1569                 : /*                                                                      */
    1570                 : /*      Read a complete record.  Note that the result is only valid     */
    1571                 : /*      till the next record read for any reason.                       */
    1572                 : /************************************************************************/
    1573                 : 
    1574                 : const char SHPAPI_CALL1(*)
    1575              28 : DBFReadTuple(DBFHandle psDBF, int hEntity )
    1576                 : 
    1577                 : {
    1578              28 :     if( hEntity < 0 || hEntity >= psDBF->nRecords )
    1579               0 :         return( NULL );
    1580                 : 
    1581              28 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1582               0 :         return NULL;
    1583                 : 
    1584              28 :     return (const char *) psDBF->pszCurrentRecord;
    1585                 : }
    1586                 : 
    1587                 : /************************************************************************/
    1588                 : /*                          DBFCloneEmpty()                              */
    1589                 : /*                                                                      */
    1590                 : /*      Read one of the attribute fields of a record.                   */
    1591                 : /************************************************************************/
    1592                 : 
    1593                 : DBFHandle SHPAPI_CALL
    1594               3 : DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) 
    1595                 : {
    1596                 :     DBFHandle newDBF;
    1597                 : 
    1598               3 :    newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
    1599               3 :    if ( newDBF == NULL ) return ( NULL ); 
    1600                 :    
    1601               3 :    newDBF->nFields = psDBF->nFields;
    1602               3 :    newDBF->nRecordLength = psDBF->nRecordLength;
    1603               3 :    newDBF->nHeaderLength = psDBF->nHeaderLength;
    1604                 :     
    1605               3 :    newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength );
    1606               3 :    memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength );
    1607                 :    
    1608               3 :    newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); 
    1609               3 :    memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
    1610               3 :    newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
    1611               3 :    memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
    1612               3 :    newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
    1613               3 :    memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
    1614               3 :    newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields );
    1615               3 :    memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
    1616                 : 
    1617               3 :    newDBF->bNoHeader = TRUE;
    1618               3 :    newDBF->bUpdated = TRUE;
    1619                 :    
    1620               3 :    DBFWriteHeader ( newDBF );
    1621               3 :    DBFClose ( newDBF );
    1622                 :    
    1623               3 :    newDBF = DBFOpen ( pszFilename, "rb+" );
    1624                 : 
    1625               3 :    return ( newDBF );
    1626                 : }
    1627                 : 
    1628                 : /************************************************************************/
    1629                 : /*                       DBFGetNativeFieldType()                        */
    1630                 : /*                                                                      */
    1631                 : /*      Return the DBase field type for the specified field.            */
    1632                 : /*                                                                      */
    1633                 : /*      Value can be one of: 'C' (String), 'D' (Date), 'F' (Float),     */
    1634                 : /*                           'N' (Numeric, with or without decimal),    */
    1635                 : /*                           'L' (Logical),                             */
    1636                 : /*                           'M' (Memo: 10 digits .DBT block ptr)       */
    1637                 : /************************************************************************/
    1638                 : 
    1639                 : char SHPAPI_CALL
    1640            1239 : DBFGetNativeFieldType( DBFHandle psDBF, int iField )
    1641                 : 
    1642                 : {
    1643            1239 :     if( iField >=0 && iField < psDBF->nFields )
    1644            1239 :         return psDBF->pachFieldType[iField];
    1645                 : 
    1646               0 :     return  ' ';
    1647                 : }
    1648                 : 
    1649                 : /************************************************************************/
    1650                 : /*                            str_to_upper()                            */
    1651                 : /************************************************************************/
    1652                 : 
    1653            2701 : static void str_to_upper (char *string)
    1654                 : {
    1655                 :     int len;
    1656            2701 :     short i = -1;
    1657                 : 
    1658            2701 :     len = strlen (string);
    1659                 : 
    1660           24432 :     while (++i < len)
    1661           19030 :         if (isalpha(string[i]) && islower(string[i]))
    1662            7124 :             string[i] = (char) toupper ((int)string[i]);
    1663            2701 : }
    1664                 : 
    1665                 : /************************************************************************/
    1666                 : /*                          DBFGetFieldIndex()                          */
    1667                 : /*                                                                      */
    1668                 : /*      Get the index number for a field in a .dbf file.                */
    1669                 : /*                                                                      */
    1670                 : /*      Contributed by Jim Matthews.                                    */
    1671                 : /************************************************************************/
    1672                 : 
    1673                 : int SHPAPI_CALL
    1674             459 : DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
    1675                 : 
    1676                 : {
    1677                 :     char          name[12], name1[12], name2[12];
    1678                 :     int           i;
    1679                 : 
    1680             459 :     strncpy(name1, pszFieldName,11);
    1681             459 :     name1[11] = '\0';
    1682             459 :     str_to_upper(name1);
    1683                 : 
    1684            2571 :     for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
    1685                 :     {
    1686            2242 :         DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
    1687            2242 :         strncpy(name2,name,11);
    1688            2242 :         str_to_upper(name2);
    1689                 : 
    1690            2242 :         if(!strncmp(name1,name2,10))
    1691             130 :             return(i);
    1692                 :     }
    1693             329 :     return(-1);
    1694                 : }
    1695                 : 
    1696                 : /************************************************************************/
    1697                 : /*                         DBFIsRecordDeleted()                         */
    1698                 : /*                                                                      */
    1699                 : /*      Returns TRUE if the indicated record is deleted, otherwise      */
    1700                 : /*      it returns FALSE.                                               */
    1701                 : /************************************************************************/
    1702                 : 
    1703           32080 : int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
    1704                 : 
    1705                 : {
    1706                 : /* -------------------------------------------------------------------- */
    1707                 : /*      Verify selection.                                               */
    1708                 : /* -------------------------------------------------------------------- */
    1709           32080 :     if( iShape < 0 || iShape >= psDBF->nRecords )
    1710               0 :         return TRUE;
    1711                 : 
    1712                 : /* -------------------------------------------------------------------- */
    1713                 : /*  Have we read the record?          */
    1714                 : /* -------------------------------------------------------------------- */
    1715           32080 :     if( !DBFLoadRecord( psDBF, iShape ) )
    1716               0 :         return FALSE;
    1717                 : 
    1718                 : /* -------------------------------------------------------------------- */
    1719                 : /*      '*' means deleted.                                              */
    1720                 : /* -------------------------------------------------------------------- */
    1721           32080 :     return psDBF->pszCurrentRecord[0] == '*';
    1722                 : }
    1723                 : 
    1724                 : /************************************************************************/
    1725                 : /*                        DBFMarkRecordDeleted()                        */
    1726                 : /************************************************************************/
    1727                 : 
    1728               3 : int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, 
    1729                 :                                       int bIsDeleted )
    1730                 : 
    1731                 : {
    1732                 :     char chNewFlag;
    1733                 : 
    1734                 : /* -------------------------------------------------------------------- */
    1735                 : /*      Verify selection.                                               */
    1736                 : /* -------------------------------------------------------------------- */
    1737               3 :     if( iShape < 0 || iShape >= psDBF->nRecords )
    1738               0 :         return FALSE;
    1739                 : 
    1740                 : /* -------------------------------------------------------------------- */
    1741                 : /*      Is this an existing record, but different than the last one     */
    1742                 : /*      we accessed?                                                    */
    1743                 : /* -------------------------------------------------------------------- */
    1744               3 :     if( !DBFLoadRecord( psDBF, iShape ) )
    1745               0 :         return FALSE;
    1746                 : 
    1747                 : /* -------------------------------------------------------------------- */
    1748                 : /*      Assign value, marking record as dirty if it changes.            */
    1749                 : /* -------------------------------------------------------------------- */
    1750               3 :     if( bIsDeleted )
    1751               3 :         chNewFlag = '*';
    1752                 :     else 
    1753               0 :         chNewFlag = ' ';
    1754                 : 
    1755               3 :     if( psDBF->pszCurrentRecord[0] != chNewFlag )
    1756                 :     {
    1757               3 :         psDBF->bCurrentRecordModified = TRUE;
    1758               3 :         psDBF->bUpdated = TRUE;
    1759               3 :         psDBF->pszCurrentRecord[0] = chNewFlag;
    1760                 :     }
    1761                 : 
    1762               3 :     return TRUE;
    1763                 : }
    1764                 : 
    1765                 : /************************************************************************/
    1766                 : /*                            DBFGetCodePage                            */
    1767                 : /************************************************************************/
    1768                 : 
    1769                 : const char SHPAPI_CALL1(*)
    1770               0 : DBFGetCodePage(DBFHandle psDBF )
    1771                 : {
    1772               0 :     if( psDBF == NULL )
    1773               0 :         return NULL;
    1774               0 :     return psDBF->pszCodePage;
    1775                 : }
    1776                 : 
    1777                 : /************************************************************************/
    1778                 : /*                          DBFDeleteField()                            */
    1779                 : /*                                                                      */
    1780                 : /*      Remove a field from a .dbf file                                 */
    1781                 : /************************************************************************/
    1782                 : 
    1783                 : int SHPAPI_CALL
    1784               0 : DBFDeleteField(DBFHandle psDBF, int iField)
    1785                 : {
    1786                 :     int nOldRecordLength, nOldHeaderLength;
    1787                 :     int nDeletedFieldOffset, nDeletedFieldSize;
    1788                 :     SAOffset nRecordOffset;
    1789                 :     char* pszRecord;
    1790                 :     int i, iRecord;
    1791                 : 
    1792               0 :     if (iField < 0 || iField >= psDBF->nFields)
    1793               0 :         return FALSE;
    1794                 : 
    1795                 :     /* make sure that everything is written in .dbf */
    1796               0 :     if( !DBFFlushRecord( psDBF ) )
    1797               0 :         return FALSE;
    1798                 : 
    1799                 :     /* get information about field to be deleted */
    1800               0 :     nOldRecordLength = psDBF->nRecordLength;
    1801               0 :     nOldHeaderLength = psDBF->nHeaderLength;
    1802               0 :     nDeletedFieldOffset = psDBF->panFieldOffset[iField];
    1803               0 :     nDeletedFieldSize = psDBF->panFieldSize[iField];
    1804                 : 
    1805                 :     /* update fields info */
    1806               0 :     for (i = iField + 1; i < psDBF->nFields; i++)
    1807                 :     {
    1808               0 :         psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize;
    1809               0 :         psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i];
    1810               0 :         psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i];
    1811               0 :         psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i];
    1812                 :     }
    1813                 : 
    1814                 :     /* resize fields arrays */
    1815               0 :     psDBF->nFields--;
    1816                 : 
    1817               0 :     psDBF->panFieldOffset = (int *) 
    1818               0 :         SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
    1819                 : 
    1820               0 :     psDBF->panFieldSize = (int *) 
    1821               0 :         SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
    1822                 : 
    1823               0 :     psDBF->panFieldDecimals = (int *) 
    1824               0 :         SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
    1825                 : 
    1826               0 :     psDBF->pachFieldType = (char *) 
    1827               0 :         SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
    1828                 : 
    1829                 :     /* update header information */
    1830               0 :     psDBF->nHeaderLength -= 32;
    1831               0 :     psDBF->nRecordLength -= nDeletedFieldSize;
    1832                 : 
    1833                 :     /* overwrite field information in header */
    1834               0 :     memcpy(psDBF->pszHeader + iField*32,
    1835               0 :            psDBF->pszHeader + (iField+1)*32,
    1836               0 :            sizeof(char) * (psDBF->nFields - iField)*32);
    1837                 : 
    1838               0 :     psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
    1839                 : 
    1840                 :     /* update size of current record appropriately */
    1841               0 :     psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
    1842                 :                                                  psDBF->nRecordLength);
    1843                 : 
    1844                 :     /* we're done if we're dealing with not yet created .dbf */
    1845               0 :     if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
    1846               0 :         return TRUE;
    1847                 : 
    1848                 :     /* force update of header with new header and record length */
    1849               0 :     psDBF->bNoHeader = TRUE;
    1850               0 :     DBFUpdateHeader( psDBF );
    1851                 : 
    1852                 :     /* alloc record */
    1853               0 :     pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
    1854                 : 
    1855                 :     /* shift records to their new positions */
    1856               0 :     for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
    1857                 :     {
    1858               0 :         nRecordOffset = 
    1859               0 :             nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength;
    1860                 : 
    1861                 :         /* load record */
    1862               0 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    1863               0 :         psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
    1864                 : 
    1865               0 :         nRecordOffset = 
    1866               0 :             psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    1867                 : 
    1868                 :         /* move record in two steps */
    1869               0 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    1870               0 :         psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp );
    1871               0 :         psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize,
    1872               0 :                               nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize,
    1873                 :                               1, psDBF->fp );
    1874                 : 
    1875                 :     }
    1876                 : 
    1877                 :     /* TODO: truncate file */
    1878                 : 
    1879                 :     /* free record */
    1880               0 :     free(pszRecord);
    1881                 : 
    1882               0 :     return TRUE;
    1883                 : }

Generated by: LCOV version 1.7