LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - dbfopen.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 796 696 87.4 %
Date: 2012-12-26 Functions: 43 40 93.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 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.89  2011-07-24 05:59:25  fwarmerdam
      38                 :  * minimize use of CPLError in favor of SAHooks.Error()
      39                 :  *
      40                 :  * Revision 1.88  2011-05-13 17:35:17  fwarmerdam
      41                 :  * added DBFReorderFields() and DBFAlterFields() functions (from Even)
      42                 :  *
      43                 :  * Revision 1.87  2011-05-07 22:41:02  fwarmerdam
      44                 :  * ensure pending record is flushed when adding a native field (GDAL #4073)
      45                 :  *
      46                 :  * Revision 1.86  2011-04-17 15:15:29  fwarmerdam
      47                 :  * Removed unused variable.
      48                 :  *
      49                 :  * Revision 1.85  2010-12-06 16:09:34  fwarmerdam
      50                 :  * fix buffer read overrun fetching code page (bug 2276)
      51                 :  *
      52                 :  * Revision 1.84  2009-10-29 19:59:48  fwarmerdam
      53                 :  * avoid crash on truncated header (gdal #3093)
      54                 :  *
      55                 :  * Revision 1.83  2008/11/12 14:28:15  fwarmerdam
      56                 :  * DBFCreateField() now works on files with records
      57                 :  *
      58                 :  * Revision 1.82  2008/11/11 17:47:09  fwarmerdam
      59                 :  * added DBFDeleteField() function
      60                 :  *
      61                 :  * Revision 1.81  2008/01/03 17:48:13  bram
      62                 :  * in DBFCreate, use default code page LDID/87 (= 0x57, ANSI)
      63                 :  * instead of LDID/3.  This seems to be the same as what ESRI
      64                 :  * would be doing by default.
      65                 :  *
      66                 :  * Revision 1.80  2007/12/30 14:36:39  fwarmerdam
      67                 :  * avoid syntax issue with last comment.
      68                 :  *
      69                 :  * Revision 1.79  2007/12/30 14:35:48  fwarmerdam
      70                 :  * Avoid char* / unsigned char* warnings.
      71                 :  *
      72                 :  * Revision 1.78  2007/12/18 18:28:07  bram
      73                 :  * - create hook for client specific atof (bugzilla ticket 1615)
      74                 :  * - check for NULL handle before closing cpCPG file, and close after reading.
      75                 :  *
      76                 :  * Revision 1.77  2007/12/15 20:25:21  bram
      77                 :  * dbfopen.c now reads the Code Page information from the DBF file, and exports
      78                 :  * this information as a string through the DBFGetCodePage function.  This is 
      79                 :  * either the number from the LDID header field ("LDID/<number>") or as the 
      80                 :  * content of an accompanying .CPG file.  When creating a DBF file, the code can
      81                 :  * be set using DBFCreateEx.
      82                 :  *
      83                 :  * Revision 1.76  2007/12/12 22:21:32  bram
      84                 :  * DBFClose: check for NULL psDBF handle before trying to close it.
      85                 :  *
      86                 :  * Revision 1.75  2007/12/06 13:58:19  fwarmerdam
      87                 :  * make sure file offset calculations are done in as SAOffset
      88                 :  *
      89                 :  * Revision 1.74  2007/12/06 07:00:25  fwarmerdam
      90                 :  * dbfopen now using SAHooks for fileio
      91                 :  *
      92                 :  * Revision 1.73  2007/09/03 19:48:11  fwarmerdam
      93                 :  * move DBFReadAttribute() static dDoubleField into dbfinfo
      94                 :  *
      95                 :  * Revision 1.72  2007/09/03 19:34:06  fwarmerdam
      96                 :  * Avoid use of static tuple buffer in DBFReadTuple()
      97                 :  *
      98                 :  * Revision 1.71  2006/06/22 14:37:18  fwarmerdam
      99                 :  * avoid memory leak if dbfopen fread fails
     100                 :  *
     101                 :  * Revision 1.70  2006/06/17 17:47:05  fwarmerdam
     102                 :  * use calloc() for dbfinfo in DBFCreate
     103                 :  *
     104                 :  * Revision 1.69  2006/06/17 15:34:32  fwarmerdam
     105                 :  * disallow creating fields wider than 255
     106                 :  *
     107                 :  * Revision 1.68  2006/06/17 15:12:40  fwarmerdam
     108                 :  * Fixed C++ style comments.
     109                 :  *
     110                 :  * Revision 1.67  2006/06/17 00:24:53  fwarmerdam
     111                 :  * Don't treat non-zero decimals values as high order byte for length
     112                 :  * for strings.  It causes serious corruption for some files.
     113                 :  * http://bugzilla.remotesensing.org/show_bug.cgi?id=1202
     114                 :  *
     115                 :  * Revision 1.66  2006/03/29 18:26:20  fwarmerdam
     116                 :  * fixed bug with size of pachfieldtype in dbfcloneempty
     117                 :  *
     118                 :  * Revision 1.65  2006/02/15 01:14:30  fwarmerdam
     119                 :  * added DBFAddNativeFieldType
     120                 :  *
     121                 :  * Revision 1.64  2006/02/09 00:29:04  fwarmerdam
     122                 :  * Changed to put spaces into string fields that are NULL as
     123                 :  * per http://bugzilla.maptools.org/show_bug.cgi?id=316.
     124                 :  *
     125                 :  * Revision 1.63  2006/01/25 15:35:43  fwarmerdam
     126                 :  * check success on DBFFlushRecord
     127                 :  *
     128                 :  * Revision 1.62  2006/01/10 16:28:03  fwarmerdam
     129                 :  * Fixed typo in CPLError.
     130                 :  *
     131                 :  * Revision 1.61  2006/01/10 16:26:29  fwarmerdam
     132                 :  * Push loading record buffer into DBFLoadRecord.
     133                 :  * Implement CPL error reporting if USE_CPL defined.
     134                 :  *
     135                 :  * Revision 1.60  2006/01/05 01:27:27  fwarmerdam
     136                 :  * added dbf deletion mark/fetch
     137                 :  *
     138                 :  * Revision 1.59  2005/03/14 15:20:28  fwarmerdam
     139                 :  * Fixed last change.
     140                 :  *
     141                 :  * Revision 1.58  2005/03/14 15:18:54  fwarmerdam
     142                 :  * Treat very wide fields with no decimals as double.  This is
     143                 :  * more than 32bit integer fields.
     144                 :  *
     145                 :  * Revision 1.57  2005/02/10 20:16:54  fwarmerdam
     146                 :  * Make the pszStringField buffer for DBFReadAttribute() static char [256]
     147                 :  * as per bug 306.
     148                 :  *
     149                 :  * Revision 1.56  2005/02/10 20:07:56  fwarmerdam
     150                 :  * Fixed bug 305 in DBFCloneEmpty() - header length problem.
     151                 :  *
     152                 :  * Revision 1.55  2004/09/26 20:23:46  fwarmerdam
     153                 :  * avoid warnings with rcsid and signed/unsigned stuff
     154                 :  *
     155                 :  * Revision 1.54  2004/09/15 16:26:10  fwarmerdam
     156                 :  * Treat all blank numeric fields as null too.
     157                 :  */
     158                 : 
     159                 : #include "shapefil.h"
     160                 : 
     161                 : #include <math.h>
     162                 : #include <stdlib.h>
     163                 : #include <ctype.h>
     164                 : #include <string.h>
     165                 : 
     166                 : SHP_CVSID("$Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $")
     167                 : 
     168                 : #ifndef FALSE
     169                 : #  define FALSE   0
     170                 : #  define TRUE    1
     171                 : #endif
     172                 : 
     173                 : /************************************************************************/
     174                 : /*                             SfRealloc()                              */
     175                 : /*                                                                      */
     176                 : /*      A realloc cover function that will access a NULL pointer as     */
     177                 : /*      a valid input.                                                  */
     178                 : /************************************************************************/
     179                 : 
     180           29337 : static void * SfRealloc( void * pMem, int nNewSize )
     181                 : 
     182                 : {
     183           29337 :     if( pMem == NULL )
     184            7278 :         return( (void *) malloc(nNewSize) );
     185                 :     else
     186           22059 :         return( (void *) realloc(pMem,nNewSize) );
     187                 : }
     188                 : 
     189                 : /************************************************************************/
     190                 : /*                           DBFWriteHeader()                           */
     191                 : /*                                                                      */
     192                 : /*      This is called to write out the file header, and field          */
     193                 : /*      descriptions before writing any actual data records.  This      */
     194                 : /*      also computes all the DBFDataSet field offset/size/decimals     */
     195                 : /*      and so forth values.                                            */
     196                 : /************************************************************************/
     197                 : 
     198            1256 : static void DBFWriteHeader(DBFHandle psDBF)
     199                 : 
     200                 : {
     201                 :     unsigned char abyHeader[XBASE_FLDHDR_SZ];
     202                 :     int   i;
     203                 : 
     204            1256 :     if( !psDBF->bNoHeader )
     205               0 :         return;
     206                 : 
     207            1256 :     psDBF->bNoHeader = FALSE;
     208                 : 
     209                 : /* -------------------------------------------------------------------- */
     210                 : /*  Initialize the file header information.       */
     211                 : /* -------------------------------------------------------------------- */
     212           41448 :     for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
     213           40192 :         abyHeader[i] = 0;
     214                 : 
     215            1256 :     abyHeader[0] = 0x03;    /* memo field? - just copying   */
     216                 : 
     217                 :     /* write out a dummy date */
     218            1256 :     abyHeader[1] = 95;      /* YY */
     219            1256 :     abyHeader[2] = 7;     /* MM */
     220            1256 :     abyHeader[3] = 26;      /* DD */
     221                 : 
     222                 :     /* record count preset at zero */
     223                 : 
     224            1256 :     abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
     225            1256 :     abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
     226                 :     
     227            1256 :     abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
     228            1256 :     abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
     229                 : 
     230            1256 :     abyHeader[29] = (unsigned char) (psDBF->iLanguageDriver);
     231                 : 
     232                 : /* -------------------------------------------------------------------- */
     233                 : /*      Write the initial 32 byte file header, and all the field        */
     234                 : /*      descriptions.                                         */
     235                 : /* -------------------------------------------------------------------- */
     236            1256 :     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     237            1256 :     psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
     238            1256 :     psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, 
     239                 :                           psDBF->fp );
     240                 : 
     241                 : /* -------------------------------------------------------------------- */
     242                 : /*      Write out the newline character if there is room for it.        */
     243                 : /* -------------------------------------------------------------------- */
     244            1256 :     if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
     245                 :     {
     246                 :         char  cNewline;
     247                 : 
     248            1256 :         cNewline = 0x0d;
     249            1256 :         psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
     250                 :     }
     251                 : }
     252                 : 
     253                 : /************************************************************************/
     254                 : /*                           DBFFlushRecord()                           */
     255                 : /*                                                                      */
     256                 : /*      Write out the current record if there is one.                   */
     257                 : /************************************************************************/
     258                 : 
     259          118033 : static int DBFFlushRecord( DBFHandle psDBF )
     260                 : 
     261                 : {
     262                 :     SAOffset  nRecordOffset;
     263                 : 
     264          118033 :     if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
     265                 :     {
     266           29706 :   psDBF->bCurrentRecordModified = FALSE;
     267                 : 
     268           29706 :   nRecordOffset = 
     269           29706 :             psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord 
     270           29706 :             + psDBF->nHeaderLength;
     271                 : 
     272           59412 :   if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0 
     273           59412 :             || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord, 
     274           29706 :                                      psDBF->nRecordLength, 
     275           89118 :                                      1, psDBF->fp ) != 1 )
     276                 :         {
     277                 :             char szMessage[128];
     278               0 :             sprintf( szMessage, "Failure writing DBF record %d.", 
     279                 :                      psDBF->nCurrentRecord );
     280               0 :             psDBF->sHooks.Error( szMessage );
     281               0 :             return FALSE;
     282                 :         }
     283                 :     }
     284                 : 
     285          118033 :     return TRUE;
     286                 : }
     287                 : 
     288                 : /************************************************************************/
     289                 : /*                           DBFLoadRecord()                            */
     290                 : /************************************************************************/
     291                 : 
     292          419099 : static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
     293                 : 
     294                 : {
     295          419099 :     if( psDBF->nCurrentRecord != iRecord )
     296                 :     {
     297                 :         SAOffset nRecordOffset;
     298                 : 
     299           78681 :   if( !DBFFlushRecord( psDBF ) )
     300               0 :             return FALSE;
     301                 : 
     302           78681 :   nRecordOffset = 
     303           78681 :             psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
     304                 : 
     305           78681 :   if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
     306                 :         {
     307                 :             char szMessage[128];
     308               0 :             sprintf( szMessage, "fseek(%ld) failed on DBF file.\n",
     309                 :                      (long) nRecordOffset );
     310               0 :             psDBF->sHooks.Error( szMessage );
     311               0 :             return FALSE;
     312                 :         }
     313                 : 
     314          157362 :   if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord, 
     315           78681 :                                  psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
     316                 :         {
     317                 :             char szMessage[128];
     318               0 :             sprintf( szMessage, "fread(%d) failed on DBF file.\n",
     319                 :                      psDBF->nRecordLength );
     320               0 :             psDBF->sHooks.Error( szMessage );
     321               0 :             return FALSE;
     322                 :         }
     323                 : 
     324           78681 :   psDBF->nCurrentRecord = iRecord;
     325                 :     }
     326                 : 
     327          419099 :     return TRUE;
     328                 : }
     329                 : 
     330                 : /************************************************************************/
     331                 : /*                          DBFUpdateHeader()                           */
     332                 : /************************************************************************/
     333                 : 
     334                 : void SHPAPI_CALL
     335            1297 : DBFUpdateHeader( DBFHandle psDBF )
     336                 : 
     337                 : {
     338                 :     unsigned char   abyFileHeader[32];
     339                 : 
     340            1297 :     if( psDBF->bNoHeader )
     341              34 :         DBFWriteHeader( psDBF );
     342                 : 
     343            1297 :     DBFFlushRecord( psDBF );
     344                 : 
     345            1297 :     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     346            1297 :     psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
     347                 :     
     348            1297 :     abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
     349            1297 :     abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
     350            1297 :     abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
     351            1297 :     abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
     352                 :     
     353            1297 :     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     354            1297 :     psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
     355                 : 
     356            1297 :     psDBF->sHooks.FFlush( psDBF->fp );
     357            1297 : }
     358                 : 
     359                 : /************************************************************************/
     360                 : /*                              DBFOpen()                               */
     361                 : /*                                                                      */
     362                 : /*      Open a .dbf file.                                               */
     363                 : /************************************************************************/
     364                 :    
     365                 : DBFHandle SHPAPI_CALL
     366            2701 : DBFOpen( const char * pszFilename, const char * pszAccess )
     367                 : 
     368                 : {
     369                 :     SAHooks sHooks;
     370                 : 
     371            2701 :     SASetupDefaultHooks( &sHooks );
     372                 : 
     373            2701 :     return DBFOpenLL( pszFilename, pszAccess, &sHooks );
     374                 : }
     375                 : 
     376                 : /************************************************************************/
     377                 : /*                              DBFOpen()                               */
     378                 : /*                                                                      */
     379                 : /*      Open a .dbf file.                                               */
     380                 : /************************************************************************/
     381                 :    
     382                 : DBFHandle SHPAPI_CALL
     383            2701 : DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
     384                 : 
     385                 : {
     386                 :     DBFHandle   psDBF;
     387                 :     SAFile    pfCPG;
     388                 :     unsigned char *pabyBuf;
     389                 :     int     nFields, nHeadLen, iField, i;
     390                 :     char    *pszBasename, *pszFullname;
     391            2701 :     int                 nBufSize = 500;
     392                 : 
     393                 : /* -------------------------------------------------------------------- */
     394                 : /*      We only allow the access strings "rb" and "r+".                  */
     395                 : /* -------------------------------------------------------------------- */
     396            4424 :     if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 
     397            1720 :         && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
     398               3 :         && strcmp(pszAccess,"r+b") != 0 )
     399               0 :         return( NULL );
     400                 : 
     401            2701 :     if( strcmp(pszAccess,"r") == 0 )
     402             984 :         pszAccess = "rb";
     403                 :  
     404            2701 :     if( strcmp(pszAccess,"r+") == 0 )
     405            1714 :         pszAccess = "rb+";
     406                 : 
     407                 : /* -------------------------------------------------------------------- */
     408                 : /*  Compute the base (layer) name.  If there is any extension */
     409                 : /*  on the passed in filename we will strip it off.     */
     410                 : /* -------------------------------------------------------------------- */
     411            2701 :     pszBasename = (char *) malloc(strlen(pszFilename)+5);
     412            2701 :     strcpy( pszBasename, pszFilename );
     413           40515 :     for( i = strlen(pszBasename)-1; 
     414           18907 :    i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
     415            8103 :          && pszBasename[i] != '\\';
     416            8103 :    i-- ) {}
     417                 : 
     418            2701 :     if( pszBasename[i] == '.' )
     419            2701 :         pszBasename[i] = '\0';
     420                 : 
     421            2701 :     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
     422            2701 :     sprintf( pszFullname, "%s.dbf", pszBasename );
     423                 :         
     424            2701 :     psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
     425            2701 :     psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
     426            2701 :     memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
     427                 : 
     428            2701 :     if( psDBF->fp == NULL )
     429                 :     {
     430              23 :         sprintf( pszFullname, "%s.DBF", pszBasename );
     431              23 :         psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
     432                 :     }
     433                 : 
     434            2701 :     sprintf( pszFullname, "%s.cpg", pszBasename );
     435            2701 :     pfCPG = psHooks->FOpen( pszFullname, "r" );
     436            2701 :     if( pfCPG == NULL )
     437                 :     {
     438            2700 :         sprintf( pszFullname, "%s.CPG", pszBasename );
     439            2700 :         pfCPG = psHooks->FOpen( pszFullname, "r" );
     440                 :     }
     441                 : 
     442            2701 :     free( pszBasename );
     443            2701 :     free( pszFullname );
     444                 :     
     445            2701 :     if( psDBF->fp == NULL )
     446                 :     {
     447              21 :         free( psDBF );
     448              21 :         if( pfCPG ) psHooks->FClose( pfCPG );
     449              21 :         return( NULL );
     450                 :     }
     451                 : 
     452            2680 :     psDBF->bNoHeader = FALSE;
     453            2680 :     psDBF->nCurrentRecord = -1;
     454            2680 :     psDBF->bCurrentRecordModified = FALSE;
     455                 : 
     456                 : /* -------------------------------------------------------------------- */
     457                 : /*  Read Table Header info                                              */
     458                 : /* -------------------------------------------------------------------- */
     459            2680 :     pabyBuf = (unsigned char *) malloc(nBufSize);
     460            2680 :     if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
     461                 :     {
     462               0 :         psDBF->sHooks.FClose( psDBF->fp );
     463               0 :         if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
     464               0 :         free( pabyBuf );
     465               0 :         free( psDBF );
     466               0 :         return NULL;
     467                 :     }
     468                 : 
     469            2680 :     psDBF->nRecords = 
     470            2680 :      pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
     471                 : 
     472            2680 :     psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
     473            2680 :     psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
     474            2680 :     psDBF->iLanguageDriver = pabyBuf[29];
     475                 : 
     476            2680 :     if (nHeadLen < 32)
     477                 :     {
     478               0 :         psDBF->sHooks.FClose( psDBF->fp );
     479               0 :         if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
     480               0 :         free( pabyBuf );
     481               0 :         free( psDBF );
     482               0 :         return NULL;
     483                 :     }
     484                 : 
     485            2680 :     psDBF->nFields = nFields = (nHeadLen - 32) / 32;
     486                 : 
     487            2680 :     psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
     488                 : 
     489                 : /* -------------------------------------------------------------------- */
     490                 : /*  Figure out the code page from the LDID and CPG                      */
     491                 : /* -------------------------------------------------------------------- */
     492                 : 
     493            2680 :     psDBF->pszCodePage = NULL;
     494            2680 :     if( pfCPG )
     495                 :     {
     496                 :         size_t n;
     497               1 :         memset( pabyBuf, 0, nBufSize);
     498               1 :         psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
     499               1 :         n = strcspn( (char *) pabyBuf, "\n\r" );
     500               1 :         if( n > 0 )
     501                 :         {
     502               1 :             pabyBuf[n] = '\0';
     503               1 :             psDBF->pszCodePage = (char *) malloc(n + 1);
     504               1 :             memcpy( psDBF->pszCodePage, pabyBuf, n + 1 );
     505                 :         }
     506               1 :     psDBF->sHooks.FClose( pfCPG );
     507                 :     }
     508            2680 :     if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 )
     509                 :     {
     510            2427 :         sprintf( (char *) pabyBuf, "LDID/%d", psDBF->iLanguageDriver );
     511            2427 :         psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1);
     512            2427 :         strcpy( psDBF->pszCodePage, (char *) pabyBuf );
     513                 :     }
     514                 : 
     515                 : /* -------------------------------------------------------------------- */
     516                 : /*  Read in Field Definitions                                           */
     517                 : /* -------------------------------------------------------------------- */
     518                 :     
     519            2680 :     pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
     520            2680 :     psDBF->pszHeader = (char *) pabyBuf;
     521                 : 
     522            2680 :     psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
     523            2680 :     if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
     524                 :     {
     525               0 :         psDBF->sHooks.FClose( psDBF->fp );
     526               0 :         free( pabyBuf );
     527               0 :         free( psDBF->pszCurrentRecord );
     528               0 :         free( psDBF );
     529               0 :         return NULL;
     530                 :     }
     531                 : 
     532            2680 :     psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
     533            2680 :     psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
     534            2680 :     psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
     535            2680 :     psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
     536                 : 
     537            6528 :     for( iField = 0; iField < nFields; iField++ )
     538                 :     {
     539                 :   unsigned char   *pabyFInfo;
     540                 : 
     541            3848 :   pabyFInfo = pabyBuf+iField*32;
     542                 : 
     543            5412 :   if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
     544                 :   {
     545            1564 :       psDBF->panFieldSize[iField] = pabyFInfo[16];
     546            1564 :       psDBF->panFieldDecimals[iField] = pabyFInfo[17];
     547                 :   }
     548                 :   else
     549                 :   {
     550            2284 :       psDBF->panFieldSize[iField] = pabyFInfo[16];
     551            2284 :       psDBF->panFieldDecimals[iField] = 0;
     552                 : 
     553                 : /*
     554                 : ** The following seemed to be used sometimes to handle files with long
     555                 : ** string fields, but in other cases (such as bug 1202) the decimals field
     556                 : ** just seems to indicate some sort of preferred formatting, not very
     557                 : ** wide fields.  So I have disabled this code.  FrankW.
     558                 :       psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
     559                 :       psDBF->panFieldDecimals[iField] = 0;
     560                 : */
     561                 :   }
     562                 : 
     563            3848 :   psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
     564            3848 :   if( iField == 0 )
     565            2674 :       psDBF->panFieldOffset[iField] = 1;
     566                 :   else
     567            2348 :       psDBF->panFieldOffset[iField] = 
     568            1174 :         psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
     569                 :     }
     570                 : 
     571            2680 :     return( psDBF );
     572                 : }
     573                 : 
     574                 : /************************************************************************/
     575                 : /*                              DBFClose()                              */
     576                 : /************************************************************************/
     577                 : 
     578                 : void SHPAPI_CALL
     579            3902 : DBFClose(DBFHandle psDBF)
     580                 : {
     581            3902 :     if( psDBF == NULL )
     582               0 :         return;
     583                 : 
     584                 : /* -------------------------------------------------------------------- */
     585                 : /*      Write out header if not already written.                        */
     586                 : /* -------------------------------------------------------------------- */
     587            3902 :     if( psDBF->bNoHeader )
     588              10 :         DBFWriteHeader( psDBF );
     589                 : 
     590            3902 :     DBFFlushRecord( psDBF );
     591                 : 
     592                 : /* -------------------------------------------------------------------- */
     593                 : /*      Update last access date, and number of records if we have */
     594                 : /*  write access.                         */
     595                 : /* -------------------------------------------------------------------- */
     596            3902 :     if( psDBF->bUpdated )
     597            1239 :         DBFUpdateHeader( psDBF );
     598                 : 
     599                 : /* -------------------------------------------------------------------- */
     600                 : /*      Close, and free resources.                                      */
     601                 : /* -------------------------------------------------------------------- */
     602            3902 :     psDBF->sHooks.FClose( psDBF->fp );
     603                 : 
     604            3902 :     if( psDBF->panFieldOffset != NULL )
     605                 :     {
     606            3895 :         free( psDBF->panFieldOffset );
     607            3895 :         free( psDBF->panFieldSize );
     608            3895 :         free( psDBF->panFieldDecimals );
     609            3895 :         free( psDBF->pachFieldType );
     610                 :     }
     611                 : 
     612            3902 :     if( psDBF->pszWorkField != NULL )
     613            1437 :         free( psDBF->pszWorkField );
     614                 : 
     615            3902 :     free( psDBF->pszHeader );
     616            3902 :     free( psDBF->pszCurrentRecord );
     617            3902 :     free( psDBF->pszCodePage );
     618                 : 
     619            3902 :     free( psDBF );
     620                 : }
     621                 : 
     622                 : /************************************************************************/
     623                 : /*                             DBFCreate()                              */
     624                 : /*                                                                      */
     625                 : /* Create a new .dbf file with default code page LDID/87 (0x57)         */
     626                 : /************************************************************************/
     627                 : 
     628                 : DBFHandle SHPAPI_CALL
     629            1220 : DBFCreate( const char * pszFilename )
     630                 : 
     631                 : {
     632            1220 :     return DBFCreateEx( pszFilename, "LDID/87" ); // 0x57
     633                 : }
     634                 : 
     635                 : /************************************************************************/
     636                 : /*                            DBFCreateEx()                             */
     637                 : /*                                                                      */
     638                 : /*      Create a new .dbf file.                                         */
     639                 : /************************************************************************/
     640                 : 
     641                 : DBFHandle SHPAPI_CALL
     642            1223 : DBFCreateEx( const char * pszFilename, const char* pszCodePage )
     643                 : 
     644                 : {
     645                 :     SAHooks sHooks;
     646                 : 
     647            1223 :     SASetupDefaultHooks( &sHooks );
     648                 : 
     649            1223 :     return DBFCreateLL( pszFilename, pszCodePage , &sHooks );
     650                 : }
     651                 : 
     652                 : /************************************************************************/
     653                 : /*                             DBFCreate()                              */
     654                 : /*                                                                      */
     655                 : /*      Create a new .dbf file.                                         */
     656                 : /************************************************************************/
     657                 : 
     658                 : DBFHandle SHPAPI_CALL
     659            1223 : DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks )
     660                 : 
     661                 : {
     662                 :     DBFHandle psDBF;
     663                 :     SAFile  fp;
     664                 :     char  *pszFullname, *pszBasename;
     665            1223 :     int   i, ldid = -1;
     666            1223 :     char chZero = '\0';
     667                 : 
     668                 : /* -------------------------------------------------------------------- */
     669                 : /*  Compute the base (layer) name.  If there is any extension */
     670                 : /*  on the passed in filename we will strip it off.     */
     671                 : /* -------------------------------------------------------------------- */
     672            1223 :     pszBasename = (char *) malloc(strlen(pszFilename)+5);
     673            1223 :     strcpy( pszBasename, pszFilename );
     674           18345 :     for( i = strlen(pszBasename)-1; 
     675            8561 :    i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
     676            3669 :          && pszBasename[i] != '\\';
     677            3669 :    i-- ) {}
     678                 : 
     679            1223 :     if( pszBasename[i] == '.' )
     680            1223 :         pszBasename[i] = '\0';
     681                 : 
     682            1223 :     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
     683            1223 :     sprintf( pszFullname, "%s.dbf", pszBasename );
     684                 : 
     685                 : /* -------------------------------------------------------------------- */
     686                 : /*      Create the file.                                                */
     687                 : /* -------------------------------------------------------------------- */
     688            1223 :     fp = psHooks->FOpen( pszFullname, "wb" );
     689            1223 :     if( fp == NULL )
     690                 :     {
     691               1 :         free( pszBasename );
     692               1 :         free( pszFullname );
     693               1 :         return( NULL );
     694                 :     }
     695                 :     
     696            1222 :     psHooks->FWrite( &chZero, 1, 1, fp );
     697            1222 :     psHooks->FClose( fp );
     698                 : 
     699            1222 :     fp = psHooks->FOpen( pszFullname, "rb+" );
     700            1222 :     if( fp == NULL )
     701                 :     {
     702               0 :         free( pszBasename );
     703               0 :         free( pszFullname );
     704               0 :         return( NULL );
     705                 :     }
     706                 : 
     707            1222 :     sprintf( pszFullname, "%s.cpg", pszBasename );
     708            1222 :     if( pszCodePage != NULL )
     709                 :     {
     710            1220 :         if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
     711                 :         {
     712            1220 :             ldid = atoi( pszCodePage + 5 );
     713            1220 :             if( ldid > 255 )
     714               0 :                 ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one
     715                 :         }
     716            1220 :         if( ldid < 0 )
     717                 :         {
     718               0 :             SAFile fpCPG = psHooks->FOpen( pszFullname, "w" );
     719               0 :             psHooks->FWrite( (char*) pszCodePage, strlen(pszCodePage), 1, fpCPG );
     720               0 :             psHooks->FClose( fpCPG );
     721                 :         }
     722                 :     }
     723            1222 :     if( pszCodePage == NULL || ldid >= 0 )
     724                 :     {
     725            1222 :         psHooks->Remove( pszFullname );
     726                 :     }
     727                 : 
     728            1222 :     free( pszBasename );
     729            1222 :     free( pszFullname );
     730                 : 
     731                 : /* -------------------------------------------------------------------- */
     732                 : /*  Create the info structure.          */
     733                 : /* -------------------------------------------------------------------- */
     734            1222 :     psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo));
     735                 : 
     736            1222 :     memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
     737            1222 :     psDBF->fp = fp;
     738            1222 :     psDBF->nRecords = 0;
     739            1222 :     psDBF->nFields = 0;
     740            1222 :     psDBF->nRecordLength = 1;
     741            1222 :     psDBF->nHeaderLength = 33;
     742                 :     
     743            1222 :     psDBF->panFieldOffset = NULL;
     744            1222 :     psDBF->panFieldSize = NULL;
     745            1222 :     psDBF->panFieldDecimals = NULL;
     746            1222 :     psDBF->pachFieldType = NULL;
     747            1222 :     psDBF->pszHeader = NULL;
     748                 : 
     749            1222 :     psDBF->nCurrentRecord = -1;
     750            1222 :     psDBF->bCurrentRecordModified = FALSE;
     751            1222 :     psDBF->pszCurrentRecord = NULL;
     752                 : 
     753            1222 :     psDBF->bNoHeader = TRUE;
     754                 : 
     755            1222 :     psDBF->iLanguageDriver = ldid > 0 ? ldid : 0;
     756            1222 :     psDBF->pszCodePage = NULL;
     757            1222 :     if( pszCodePage )
     758                 :     {
     759            1220 :         psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
     760            1220 :         strcpy( psDBF->pszCodePage, pszCodePage );
     761                 :     }
     762                 : 
     763            1222 :     return( psDBF );
     764                 : }
     765                 : 
     766                 : /************************************************************************/
     767                 : /*                            DBFAddField()                             */
     768                 : /*                                                                      */
     769                 : /*      Add a field to a newly created .dbf or to an existing one       */
     770                 : /************************************************************************/
     771                 : 
     772                 : int SHPAPI_CALL
     773              85 : DBFAddField(DBFHandle psDBF, const char * pszFieldName, 
     774                 :             DBFFieldType eType, int nWidth, int nDecimals )
     775                 : 
     776                 : {
     777              85 :     char chNativeType = 'C';
     778                 : 
     779              85 :     if( eType == FTLogical )
     780               0 :         chNativeType = 'L';
     781              85 :     else if( eType == FTString )
     782               0 :         chNativeType = 'C';
     783                 :     else
     784              85 :         chNativeType = 'N';
     785                 : 
     786              85 :     return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType, 
     787                 :                                   nWidth, nDecimals );
     788                 : }
     789                 : 
     790                 : /************************************************************************/
     791                 : /*                        DBFGetNullCharacter()                         */
     792                 : /************************************************************************/
     793                 : 
     794             366 : static char DBFGetNullCharacter(char chType)
     795                 : {
     796             366 :     switch (chType)
     797                 :     {
     798                 :       case 'N':
     799                 :       case 'F':
     800              17 :         return '*';
     801                 :       case 'D':
     802               0 :         return '0';
     803                 :       case 'L':
     804               0 :        return '?';
     805                 :       default:
     806             349 :        return ' ';
     807                 :     }
     808                 : }
     809                 : 
     810                 : /************************************************************************/
     811                 : /*                            DBFAddField()                             */
     812                 : /*                                                                      */
     813                 : /*      Add a field to a newly created .dbf file before any records     */
     814                 : /*      are written.                                                    */
     815                 : /************************************************************************/
     816                 : 
     817                 : int SHPAPI_CALL
     818            4435 : DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, 
     819                 :                       char chType, int nWidth, int nDecimals )
     820                 : 
     821                 : {
     822                 :     char  *pszFInfo;
     823                 :     int   i;
     824                 :     int         nOldRecordLength, nOldHeaderLength;
     825                 :     char        *pszRecord;
     826                 :     char        chFieldFill;
     827                 :     SAOffset    nRecordOffset;
     828                 : 
     829                 :     /* make sure that everything is written in .dbf */
     830            4435 :     if( !DBFFlushRecord( psDBF ) )
     831               0 :         return -1;
     832                 : 
     833                 : /* -------------------------------------------------------------------- */
     834                 : /*      Do some checking to ensure we can add records to this file.     */
     835                 : /* -------------------------------------------------------------------- */
     836            4435 :     if( nWidth < 1 )
     837               0 :         return -1;
     838                 : 
     839            4435 :     if( nWidth > 255 )
     840               0 :         nWidth = 255;
     841                 : 
     842            4435 :     nOldRecordLength = psDBF->nRecordLength;
     843            4435 :     nOldHeaderLength = psDBF->nHeaderLength;
     844                 : 
     845                 : /* -------------------------------------------------------------------- */
     846                 : /*      SfRealloc all the arrays larger to hold the additional field      */
     847                 : /*      information.                                                    */
     848                 : /* -------------------------------------------------------------------- */
     849            4435 :     psDBF->nFields++;
     850                 : 
     851            8870 :     psDBF->panFieldOffset = (int *) 
     852            4435 :         SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
     853                 : 
     854            8870 :     psDBF->panFieldSize = (int *) 
     855            4435 :         SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
     856                 : 
     857            8870 :     psDBF->panFieldDecimals = (int *) 
     858            4435 :         SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
     859                 : 
     860            8870 :     psDBF->pachFieldType = (char *) 
     861            4435 :         SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
     862                 : 
     863                 : /* -------------------------------------------------------------------- */
     864                 : /*      Assign the new field information fields.                        */
     865                 : /* -------------------------------------------------------------------- */
     866            4435 :     psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
     867            4435 :     psDBF->nRecordLength += nWidth;
     868            4435 :     psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
     869            4435 :     psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
     870            4435 :     psDBF->pachFieldType[psDBF->nFields-1] = chType;
     871                 : 
     872                 : /* -------------------------------------------------------------------- */
     873                 : /*      Extend the required header information.                         */
     874                 : /* -------------------------------------------------------------------- */
     875            4435 :     psDBF->nHeaderLength += 32;
     876            4435 :     psDBF->bUpdated = FALSE;
     877                 : 
     878            4435 :     psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
     879                 : 
     880            4435 :     pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
     881                 : 
     882          146355 :     for( i = 0; i < 32; i++ )
     883          141920 :         pszFInfo[i] = '\0';
     884                 : 
     885            4435 :     if( (int) strlen(pszFieldName) < 10 )
     886            4373 :         strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
     887                 :     else
     888              62 :         strncpy( pszFInfo, pszFieldName, 10);
     889                 : 
     890            4435 :     pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
     891                 : 
     892            4435 :     if( chType == 'C' )
     893                 :     {
     894            2108 :         pszFInfo[16] = (unsigned char) (nWidth % 256);
     895            2108 :         pszFInfo[17] = (unsigned char) (nWidth / 256);
     896                 :     }
     897                 :     else
     898                 :     {
     899            2327 :         pszFInfo[16] = (unsigned char) nWidth;
     900            2327 :         pszFInfo[17] = (unsigned char) nDecimals;
     901                 :     }
     902                 :     
     903                 : /* -------------------------------------------------------------------- */
     904                 : /*      Make the current record buffer appropriately larger.            */
     905                 : /* -------------------------------------------------------------------- */
     906            4435 :     psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
     907                 :                                                  psDBF->nRecordLength);
     908                 : 
     909                 :     /* we're done if dealing with new .dbf */
     910            4435 :     if( psDBF->bNoHeader )
     911            4429 :         return( psDBF->nFields - 1 );
     912                 : 
     913                 : /* -------------------------------------------------------------------- */
     914                 : /*      For existing .dbf file, shift records                           */
     915                 : /* -------------------------------------------------------------------- */
     916                 : 
     917                 :     /* alloc record */
     918               6 :     pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
     919                 : 
     920               6 :     chFieldFill = DBFGetNullCharacter(chType);
     921                 : 
     922              30 :     for (i = psDBF->nRecords-1; i >= 0; --i)
     923                 :     {
     924              24 :         nRecordOffset = nOldRecordLength * (SAOffset) i + nOldHeaderLength;
     925                 : 
     926                 :         /* load record */
     927              24 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
     928              24 :         psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
     929                 : 
     930                 :         /* set new field's value to NULL */
     931              24 :         memset(pszRecord + nOldRecordLength, chFieldFill, nWidth);
     932                 : 
     933              24 :         nRecordOffset = psDBF->nRecordLength * (SAOffset) i + psDBF->nHeaderLength;
     934                 : 
     935                 :         /* move record to the new place*/
     936              24 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
     937              24 :         psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
     938                 :     }
     939                 : 
     940                 :     /* free record */
     941               6 :     free(pszRecord);
     942                 : 
     943                 :     /* force update of header with new header, record length and new field */
     944               6 :     psDBF->bNoHeader = TRUE;
     945               6 :     DBFUpdateHeader( psDBF );
     946                 : 
     947               6 :     psDBF->nCurrentRecord = -1;
     948               6 :     psDBF->bCurrentRecordModified = FALSE;
     949                 : 
     950               6 :     return( psDBF->nFields-1 );
     951                 : }
     952                 : 
     953                 : /************************************************************************/
     954                 : /*                          DBFReadAttribute()                          */
     955                 : /*                                                                      */
     956                 : /*      Read one of the attribute fields of a record.                   */
     957                 : /************************************************************************/
     958                 : 
     959          258435 : static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
     960                 :                               char chReqType )
     961                 : 
     962                 : {
     963                 :     unsigned char *pabyRec;
     964          258435 :     void  *pReturnField = NULL;
     965                 : 
     966                 : /* -------------------------------------------------------------------- */
     967                 : /*      Verify selection.                                               */
     968                 : /* -------------------------------------------------------------------- */
     969          258435 :     if( hEntity < 0 || hEntity >= psDBF->nRecords )
     970               0 :         return( NULL );
     971                 : 
     972          258435 :     if( iField < 0 || iField >= psDBF->nFields )
     973               0 :         return( NULL );
     974                 : 
     975                 : /* -------------------------------------------------------------------- */
     976                 : /*  Have we read the record?          */
     977                 : /* -------------------------------------------------------------------- */
     978          258435 :     if( !DBFLoadRecord( psDBF, hEntity ) )
     979               0 :         return NULL;
     980                 : 
     981          258435 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
     982                 : 
     983                 : /* -------------------------------------------------------------------- */
     984                 : /*      Ensure we have room to extract the target field.                */
     985                 : /* -------------------------------------------------------------------- */
     986          258435 :     if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
     987                 :     {
     988            1439 :         psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
     989            1439 :         if( psDBF->pszWorkField == NULL )
     990            1437 :             psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength);
     991                 :         else
     992               2 :             psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField,
     993               2 :                                                    psDBF->nWorkFieldLength);
     994                 :     }
     995                 : 
     996                 : /* -------------------------------------------------------------------- */
     997                 : /*  Extract the requested field.          */
     998                 : /* -------------------------------------------------------------------- */
     999          516870 :     strncpy( psDBF->pszWorkField,
    1000          258435 :        ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
    1001          258435 :        psDBF->panFieldSize[iField] );
    1002          258435 :     psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
    1003                 : 
    1004          258435 :     pReturnField = psDBF->pszWorkField;
    1005                 : 
    1006                 : /* -------------------------------------------------------------------- */
    1007                 : /*      Decode the field.                                               */
    1008                 : /* -------------------------------------------------------------------- */
    1009          258435 :     if( chReqType == 'N' )
    1010                 :     {
    1011          102393 :         psDBF->dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
    1012                 : 
    1013          102393 :   pReturnField = &(psDBF->dfDoubleField);
    1014                 :     }
    1015                 : 
    1016                 : /* -------------------------------------------------------------------- */
    1017                 : /*      Should we trim white space off the string attribute value?      */
    1018                 : /* -------------------------------------------------------------------- */
    1019                 : #ifdef TRIM_DBF_WHITESPACE
    1020                 :     else
    1021                 :     {
    1022                 :         char  *pchSrc, *pchDst;
    1023                 : 
    1024          156042 :         pchDst = pchSrc = psDBF->pszWorkField;
    1025          964044 :         while( *pchSrc == ' ' )
    1026          651960 :             pchSrc++;
    1027                 : 
    1028         5722643 :         while( *pchSrc != '\0' )
    1029         5410559 :             *(pchDst++) = *(pchSrc++);
    1030          156042 :         *pchDst = '\0';
    1031                 : 
    1032         4008279 :         while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
    1033         3696195 :             *pchDst = '\0';
    1034                 :     }
    1035                 : #endif
    1036                 :     
    1037          258435 :     return( pReturnField );
    1038                 : }
    1039                 : 
    1040                 : /************************************************************************/
    1041                 : /*                        DBFReadIntAttribute()                         */
    1042                 : /*                                                                      */
    1043                 : /*      Read an integer attribute.                                      */
    1044                 : /************************************************************************/
    1045                 : 
    1046                 : int SHPAPI_CALL
    1047           25741 : DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
    1048                 : 
    1049                 : {
    1050                 :     double  *pdValue;
    1051                 : 
    1052           25741 :     pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
    1053                 : 
    1054           25741 :     if( pdValue == NULL )
    1055               0 :         return 0;
    1056                 :     else
    1057           25741 :         return( (int) *pdValue );
    1058                 : }
    1059                 : 
    1060                 : /************************************************************************/
    1061                 : /*                        DBFReadDoubleAttribute()                      */
    1062                 : /*                                                                      */
    1063                 : /*      Read a double attribute.                                        */
    1064                 : /************************************************************************/
    1065                 : 
    1066                 : double SHPAPI_CALL
    1067           76652 : DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
    1068                 : 
    1069                 : {
    1070                 :     double  *pdValue;
    1071                 : 
    1072           76652 :     pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
    1073                 : 
    1074           76652 :     if( pdValue == NULL )
    1075               0 :         return 0.0;
    1076                 :     else
    1077           76652 :         return( *pdValue );
    1078                 : }
    1079                 : 
    1080                 : /************************************************************************/
    1081                 : /*                        DBFReadStringAttribute()                      */
    1082                 : /*                                                                      */
    1083                 : /*      Read a string attribute.                                        */
    1084                 : /************************************************************************/
    1085                 : 
    1086                 : const char SHPAPI_CALL1(*)
    1087          156042 : DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
    1088                 : 
    1089                 : {
    1090          156042 :     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
    1091                 : }
    1092                 : 
    1093                 : /************************************************************************/
    1094                 : /*                        DBFReadLogicalAttribute()                     */
    1095                 : /*                                                                      */
    1096                 : /*      Read a logical attribute.                                       */
    1097                 : /************************************************************************/
    1098                 : 
    1099                 : const char SHPAPI_CALL1(*)
    1100               0 : DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
    1101                 : 
    1102                 : {
    1103               0 :     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
    1104                 : }
    1105                 : 
    1106                 : 
    1107                 : /************************************************************************/
    1108                 : /*                         DBFIsValueNULL()                             */
    1109                 : /*                                                                      */
    1110                 : /*      Return TRUE if the passed string is NULL.                       */
    1111                 : /************************************************************************/
    1112                 : 
    1113          110412 : static int DBFIsValueNULL( char chType, const char* pszValue )
    1114                 : {
    1115                 :     int i;
    1116                 : 
    1117          110412 :     if( pszValue == NULL )
    1118               0 :         return TRUE;
    1119                 : 
    1120          110412 :     switch(chType)
    1121                 :     {
    1122                 :       case 'N':
    1123                 :       case 'F':
    1124                 :         /*
    1125                 :         ** We accept all asterisks or all blanks as NULL
    1126                 :         ** though according to the spec I think it should be all
    1127                 :         ** asterisks.
    1128                 :         */
    1129          110391 :         if( pszValue[0] == '*' )
    1130              52 :             return TRUE;
    1131                 : 
    1132          110374 :         for( i = 0; pszValue[i] != '\0'; i++ )
    1133                 :         {
    1134          102442 :             if( pszValue[i] != ' ' )
    1135          102407 :                 return FALSE;
    1136                 :         }
    1137            7932 :         return TRUE;
    1138                 : 
    1139                 :       case 'D':
    1140                 :         /* NULL date fields have value "00000000" */
    1141               2 :         return strncmp(pszValue,"00000000",8) == 0;
    1142                 : 
    1143                 :       case 'L':
    1144                 :         /* NULL boolean fields have value "?" */
    1145               0 :         return pszValue[0] == '?';
    1146                 : 
    1147                 :       default:
    1148                 :         /* empty string fields are considered NULL */
    1149              19 :         return strlen(pszValue) == 0;
    1150                 :     }
    1151                 : }
    1152                 : 
    1153                 : /************************************************************************/
    1154                 : /*                         DBFIsAttributeNULL()                         */
    1155                 : /*                                                                      */
    1156                 : /*      Return TRUE if value for field is NULL.                         */
    1157                 : /*                                                                      */
    1158                 : /*      Contributed by Jim Matthews.                                    */
    1159                 : /************************************************************************/
    1160                 : 
    1161                 : int SHPAPI_CALL
    1162          110373 : DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
    1163                 : 
    1164                 : {
    1165                 :     const char  *pszValue;
    1166                 : 
    1167          110373 :     pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
    1168                 : 
    1169          110373 :     if( pszValue == NULL )
    1170               0 :         return TRUE;
    1171                 : 
    1172          110373 :     return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue );
    1173                 : }
    1174                 : 
    1175                 : /************************************************************************/
    1176                 : /*                          DBFGetFieldCount()                          */
    1177                 : /*                                                                      */
    1178                 : /*      Return the number of fields in this table.                      */
    1179                 : /************************************************************************/
    1180                 : 
    1181                 : int SHPAPI_CALL
    1182         7349045 : DBFGetFieldCount( DBFHandle psDBF )
    1183                 : 
    1184                 : {
    1185         7349045 :     return( psDBF->nFields );
    1186                 : }
    1187                 : 
    1188                 : /************************************************************************/
    1189                 : /*                         DBFGetRecordCount()                          */
    1190                 : /*                                                                      */
    1191                 : /*      Return the number of records in this table.                     */
    1192                 : /************************************************************************/
    1193                 : 
    1194                 : int SHPAPI_CALL
    1195           59334 : DBFGetRecordCount( DBFHandle psDBF )
    1196                 : 
    1197                 : {
    1198           59334 :     return( psDBF->nRecords );
    1199                 : }
    1200                 : 
    1201                 : /************************************************************************/
    1202                 : /*                          DBFGetFieldInfo()                           */
    1203                 : /*                                                                      */
    1204                 : /*      Return any requested information about the field.               */
    1205                 : /************************************************************************/
    1206                 : 
    1207                 : DBFFieldType SHPAPI_CALL
    1208         7298257 : DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
    1209                 :                  int * pnWidth, int * pnDecimals )
    1210                 : 
    1211                 : {
    1212         7298257 :     if( iField < 0 || iField >= psDBF->nFields )
    1213               0 :         return( FTInvalid );
    1214                 : 
    1215         7298257 :     if( pnWidth != NULL )
    1216            6943 :         *pnWidth = psDBF->panFieldSize[iField];
    1217                 : 
    1218         7298257 :     if( pnDecimals != NULL )
    1219            6943 :         *pnDecimals = psDBF->panFieldDecimals[iField];
    1220                 : 
    1221         7298257 :     if( pszFieldName != NULL )
    1222                 :     {
    1223                 :   int i;
    1224                 : 
    1225         7298257 :   strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
    1226         7298257 :   pszFieldName[11] = '\0';
    1227         7298257 :   for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
    1228               0 :       pszFieldName[i] = '\0';
    1229                 :     }
    1230                 : 
    1231         7298257 :     if ( psDBF->pachFieldType[iField] == 'L' )
    1232               0 :   return( FTLogical);
    1233                 : 
    1234         8315805 :     else if( psDBF->pachFieldType[iField] == 'N' 
    1235         1017548 :              || psDBF->pachFieldType[iField] == 'F' )
    1236                 :     {
    1237        12560415 :   if( psDBF->panFieldDecimals[iField] > 0 
    1238         6279696 :             || psDBF->panFieldSize[iField] > 10 )
    1239            2833 :       return( FTDouble );
    1240                 :   else
    1241         6277886 :       return( FTInteger );
    1242                 :     }
    1243                 :     else
    1244                 :     {
    1245         1017538 :   return( FTString );
    1246                 :     }
    1247                 : }
    1248                 : 
    1249                 : /************************************************************************/
    1250                 : /*                         DBFWriteAttribute()                          */
    1251                 : /*                  */
    1252                 : /*  Write an attribute record to the file.        */
    1253                 : /************************************************************************/
    1254                 : 
    1255           32220 : static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
    1256                 :            void * pValue )
    1257                 : 
    1258                 : {
    1259           32220 :     int         i, j, nRetResult = TRUE;
    1260                 :     unsigned char *pabyRec;
    1261                 :     char  szSField[400], szFormat[20];
    1262                 : 
    1263                 : /* -------------------------------------------------------------------- */
    1264                 : /*  Is this a valid record?           */
    1265                 : /* -------------------------------------------------------------------- */
    1266           32220 :     if( hEntity < 0 || hEntity > psDBF->nRecords )
    1267               0 :         return( FALSE );
    1268                 : 
    1269           32220 :     if( psDBF->bNoHeader )
    1270            1191 :         DBFWriteHeader(psDBF);
    1271                 : 
    1272                 : /* -------------------------------------------------------------------- */
    1273                 : /*      Is this a brand new record?                                     */
    1274                 : /* -------------------------------------------------------------------- */
    1275           32220 :     if( hEntity == psDBF->nRecords )
    1276                 :     {
    1277           28742 :   if( !DBFFlushRecord( psDBF ) )
    1278               0 :             return FALSE;
    1279                 : 
    1280           28742 :   psDBF->nRecords++;
    1281          630506 :   for( i = 0; i < psDBF->nRecordLength; i++ )
    1282          601764 :       psDBF->pszCurrentRecord[i] = ' ';
    1283                 : 
    1284           28742 :   psDBF->nCurrentRecord = hEntity;
    1285                 :     }
    1286                 : 
    1287                 : /* -------------------------------------------------------------------- */
    1288                 : /*      Is this an existing record, but different than the last one     */
    1289                 : /*      we accessed?                                                    */
    1290                 : /* -------------------------------------------------------------------- */
    1291           32220 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1292               0 :         return FALSE;
    1293                 : 
    1294           32220 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
    1295                 : 
    1296           32220 :     psDBF->bCurrentRecordModified = TRUE;
    1297           32220 :     psDBF->bUpdated = TRUE;
    1298                 : 
    1299                 : /* -------------------------------------------------------------------- */
    1300                 : /*      Translate NULL value to valid DBF file representation.          */
    1301                 : /*                                                                      */
    1302                 : /*      Contributed by Jim Matthews.                                    */
    1303                 : /* -------------------------------------------------------------------- */
    1304           32220 :     if( pValue == NULL )
    1305                 :     {
    1306             694 :         memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1307             347 :                 DBFGetNullCharacter(psDBF->pachFieldType[iField]),
    1308             347 :                 psDBF->panFieldSize[iField] );
    1309             347 :         return TRUE;
    1310                 :     }
    1311                 : 
    1312                 : /* -------------------------------------------------------------------- */
    1313                 : /*      Assign all the record fields.                                   */
    1314                 : /* -------------------------------------------------------------------- */
    1315           31873 :     switch( psDBF->pachFieldType[iField] )
    1316                 :     {
    1317                 :       case 'D':
    1318                 :       case 'N':
    1319                 :       case 'F':
    1320           28430 :   if( psDBF->panFieldDecimals[iField] == 0 )
    1321                 :   {
    1322           27665 :             int   nWidth = psDBF->panFieldSize[iField];
    1323                 : 
    1324           27665 :             if( (int) sizeof(szSField)-2 < nWidth )
    1325               0 :                 nWidth = sizeof(szSField)-2;
    1326                 : 
    1327           27665 :       sprintf( szFormat, "%%%dd", nWidth );
    1328           27665 :       sprintf(szSField, szFormat, (int) *((double *) pValue) );
    1329           27665 :       if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
    1330                 :             {
    1331               0 :           szSField[psDBF->panFieldSize[iField]] = '\0';
    1332               0 :                 nRetResult = FALSE;
    1333                 :             }
    1334                 : 
    1335           27665 :       strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1336                 :         szSField, strlen(szSField) );
    1337                 :   }
    1338                 :   else
    1339                 :   {
    1340             765 :             int   nWidth = psDBF->panFieldSize[iField];
    1341                 : 
    1342             765 :             if( (int) sizeof(szSField)-2 < nWidth )
    1343               0 :                 nWidth = sizeof(szSField)-2;
    1344                 : 
    1345             765 :       sprintf( szFormat, "%%%d.%df", 
    1346             765 :                      nWidth, psDBF->panFieldDecimals[iField] );
    1347             765 :       sprintf(szSField, szFormat, *((double *) pValue) );
    1348             765 :       if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
    1349                 :             {
    1350               0 :           szSField[psDBF->panFieldSize[iField]] = '\0';
    1351               0 :                 nRetResult = FALSE;
    1352                 :             }
    1353             765 :       strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1354                 :         szSField, strlen(szSField) );
    1355                 :   }
    1356           28430 :   break;
    1357                 : 
    1358                 :       case 'L':
    1359               0 :         if (psDBF->panFieldSize[iField] >= 1  && 
    1360               0 :             (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
    1361               0 :             *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
    1362               0 :         break;
    1363                 : 
    1364                 :       default:
    1365            3443 :   if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
    1366                 :         {
    1367               1 :       j = psDBF->panFieldSize[iField];
    1368               1 :             nRetResult = FALSE;
    1369                 :         }
    1370                 :   else
    1371                 :         {
    1372            3442 :             memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
    1373            3442 :                     psDBF->panFieldSize[iField] );
    1374            3442 :       j = strlen((char *) pValue);
    1375                 :         }
    1376                 : 
    1377            3443 :   strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1378                 :     (char *) pValue, j );
    1379                 :   break;
    1380                 :     }
    1381                 : 
    1382           31873 :     return( nRetResult );
    1383                 : }
    1384                 : 
    1385                 : /************************************************************************/
    1386                 : /*                     DBFWriteAttributeDirectly()                      */
    1387                 : /*                                                                      */
    1388                 : /*      Write an attribute record to the file, but without any          */
    1389                 : /*      reformatting based on type.  The provided buffer is written     */
    1390                 : /*      as is to the field position in the record.                      */
    1391                 : /************************************************************************/
    1392                 : 
    1393                 : int SHPAPI_CALL
    1394            5083 : DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
    1395                 :                               void * pValue )
    1396                 : 
    1397                 : {
    1398                 :     int           i, j;
    1399                 :     unsigned char *pabyRec;
    1400                 : 
    1401                 : /* -------------------------------------------------------------------- */
    1402                 : /*  Is this a valid record?           */
    1403                 : /* -------------------------------------------------------------------- */
    1404            5083 :     if( hEntity < 0 || hEntity > psDBF->nRecords )
    1405               0 :         return( FALSE );
    1406                 : 
    1407            5083 :     if( psDBF->bNoHeader )
    1408              18 :         DBFWriteHeader(psDBF);
    1409                 : 
    1410                 : /* -------------------------------------------------------------------- */
    1411                 : /*      Is this a brand new record?                                     */
    1412                 : /* -------------------------------------------------------------------- */
    1413            5083 :     if( hEntity == psDBF->nRecords )
    1414                 :     {
    1415             919 :   if( !DBFFlushRecord( psDBF ) )
    1416               0 :             return FALSE;
    1417                 : 
    1418             919 :   psDBF->nRecords++;
    1419           53486 :   for( i = 0; i < psDBF->nRecordLength; i++ )
    1420           52567 :       psDBF->pszCurrentRecord[i] = ' ';
    1421                 : 
    1422             919 :   psDBF->nCurrentRecord = hEntity;
    1423                 :     }
    1424                 : 
    1425                 : /* -------------------------------------------------------------------- */
    1426                 : /*      Is this an existing record, but different than the last one     */
    1427                 : /*      we accessed?                                                    */
    1428                 : /* -------------------------------------------------------------------- */
    1429            5083 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1430               0 :         return FALSE;
    1431                 : 
    1432            5083 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
    1433                 : 
    1434                 : /* -------------------------------------------------------------------- */
    1435                 : /*      Assign all the record fields.                                   */
    1436                 : /* -------------------------------------------------------------------- */
    1437            5083 :     if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
    1438               0 :         j = psDBF->panFieldSize[iField];
    1439                 :     else
    1440                 :     {
    1441            5083 :         memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
    1442            5083 :                 psDBF->panFieldSize[iField] );
    1443            5083 :         j = strlen((char *) pValue);
    1444                 :     }
    1445                 : 
    1446            5083 :     strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1447                 :             (char *) pValue, j );
    1448                 : 
    1449            5083 :     psDBF->bCurrentRecordModified = TRUE;
    1450            5083 :     psDBF->bUpdated = TRUE;
    1451                 : 
    1452            5083 :     return( TRUE );
    1453                 : }
    1454                 : 
    1455                 : /************************************************************************/
    1456                 : /*                      DBFWriteDoubleAttribute()                       */
    1457                 : /*                                                                      */
    1458                 : /*      Write a double attribute.                                       */
    1459                 : /************************************************************************/
    1460                 : 
    1461                 : int SHPAPI_CALL
    1462            1398 : DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
    1463                 :                          double dValue )
    1464                 : 
    1465                 : {
    1466            1398 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
    1467                 : }
    1468                 : 
    1469                 : /************************************************************************/
    1470                 : /*                      DBFWriteIntegerAttribute()                      */
    1471                 : /*                                                                      */
    1472                 : /*      Write a integer attribute.                                      */
    1473                 : /************************************************************************/
    1474                 : 
    1475                 : int SHPAPI_CALL
    1476           27032 : DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
    1477                 :                           int nValue )
    1478                 : 
    1479                 : {
    1480           27032 :     double  dValue = nValue;
    1481                 : 
    1482           27032 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
    1483                 : }
    1484                 : 
    1485                 : /************************************************************************/
    1486                 : /*                      DBFWriteStringAttribute()                       */
    1487                 : /*                                                                      */
    1488                 : /*      Write a string attribute.                                       */
    1489                 : /************************************************************************/
    1490                 : 
    1491                 : int SHPAPI_CALL
    1492            3443 : DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
    1493                 :                          const char * pszValue )
    1494                 : 
    1495                 : {
    1496            3443 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
    1497                 : }
    1498                 : 
    1499                 : /************************************************************************/
    1500                 : /*                      DBFWriteNULLAttribute()                         */
    1501                 : /*                                                                      */
    1502                 : /*      Write a string attribute.                                       */
    1503                 : /************************************************************************/
    1504                 : 
    1505                 : int SHPAPI_CALL
    1506             347 : DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
    1507                 : 
    1508                 : {
    1509             347 :     return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
    1510                 : }
    1511                 : 
    1512                 : /************************************************************************/
    1513                 : /*                      DBFWriteLogicalAttribute()                      */
    1514                 : /*                                                                      */
    1515                 : /*      Write a logical attribute.                                      */
    1516                 : /************************************************************************/
    1517                 : 
    1518                 : int SHPAPI_CALL
    1519               0 : DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
    1520                 :            const char lValue)
    1521                 : 
    1522                 : {
    1523               0 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
    1524                 : }
    1525                 : 
    1526                 : /************************************************************************/
    1527                 : /*                         DBFWriteTuple()                              */
    1528                 : /*                  */
    1529                 : /*  Write an attribute record to the file.        */
    1530                 : /************************************************************************/
    1531                 : 
    1532                 : int SHPAPI_CALL
    1533              28 : DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
    1534                 : 
    1535                 : {
    1536                 :     int           i;
    1537                 :     unsigned char *pabyRec;
    1538                 : 
    1539                 : /* -------------------------------------------------------------------- */
    1540                 : /*  Is this a valid record?           */
    1541                 : /* -------------------------------------------------------------------- */
    1542              28 :     if( hEntity < 0 || hEntity > psDBF->nRecords )
    1543               0 :         return( FALSE );
    1544                 : 
    1545              28 :     if( psDBF->bNoHeader )
    1546               0 :         DBFWriteHeader(psDBF);
    1547                 : 
    1548                 : /* -------------------------------------------------------------------- */
    1549                 : /*      Is this a brand new record?                                     */
    1550                 : /* -------------------------------------------------------------------- */
    1551              28 :     if( hEntity == psDBF->nRecords )
    1552                 :     {
    1553              28 :   if( !DBFFlushRecord( psDBF ) )
    1554               0 :             return FALSE;
    1555                 : 
    1556              28 :   psDBF->nRecords++;
    1557            1898 :   for( i = 0; i < psDBF->nRecordLength; i++ )
    1558            1870 :       psDBF->pszCurrentRecord[i] = ' ';
    1559                 : 
    1560              28 :   psDBF->nCurrentRecord = hEntity;
    1561                 :     }
    1562                 : 
    1563                 : /* -------------------------------------------------------------------- */
    1564                 : /*      Is this an existing record, but different than the last one     */
    1565                 : /*      we accessed?                                                    */
    1566                 : /* -------------------------------------------------------------------- */
    1567              28 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1568               0 :         return FALSE;
    1569                 : 
    1570              28 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
    1571                 : 
    1572              28 :     memcpy ( pabyRec, pRawTuple,  psDBF->nRecordLength );
    1573                 : 
    1574              28 :     psDBF->bCurrentRecordModified = TRUE;
    1575              28 :     psDBF->bUpdated = TRUE;
    1576                 : 
    1577              28 :     return( TRUE );
    1578                 : }
    1579                 : 
    1580                 : /************************************************************************/
    1581                 : /*                            DBFReadTuple()                            */
    1582                 : /*                                                                      */
    1583                 : /*      Read a complete record.  Note that the result is only valid     */
    1584                 : /*      till the next record read for any reason.                       */
    1585                 : /************************************************************************/
    1586                 : 
    1587                 : const char SHPAPI_CALL1(*)
    1588              28 : DBFReadTuple(DBFHandle psDBF, int hEntity )
    1589                 : 
    1590                 : {
    1591              28 :     if( hEntity < 0 || hEntity >= psDBF->nRecords )
    1592               0 :         return( NULL );
    1593                 : 
    1594              28 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1595               0 :         return NULL;
    1596                 : 
    1597              28 :     return (const char *) psDBF->pszCurrentRecord;
    1598                 : }
    1599                 : 
    1600                 : /************************************************************************/
    1601                 : /*                          DBFCloneEmpty()                              */
    1602                 : /*                                                                      */
    1603                 : /*      Read one of the attribute fields of a record.                   */
    1604                 : /************************************************************************/
    1605                 : 
    1606                 : DBFHandle SHPAPI_CALL
    1607               3 : DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) 
    1608                 : {
    1609                 :     DBFHandle newDBF;
    1610                 : 
    1611               3 :    newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
    1612               3 :    if ( newDBF == NULL ) return ( NULL ); 
    1613                 :    
    1614               3 :    newDBF->nFields = psDBF->nFields;
    1615               3 :    newDBF->nRecordLength = psDBF->nRecordLength;
    1616               3 :    newDBF->nHeaderLength = psDBF->nHeaderLength;
    1617                 :     
    1618               3 :    newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength );
    1619               3 :    memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength );
    1620                 :    
    1621               3 :    newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); 
    1622               3 :    memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
    1623               3 :    newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
    1624               3 :    memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
    1625               3 :    newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
    1626               3 :    memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
    1627               3 :    newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields );
    1628               3 :    memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
    1629                 : 
    1630               3 :    newDBF->bNoHeader = TRUE;
    1631               3 :    newDBF->bUpdated = TRUE;
    1632                 :    
    1633               3 :    DBFWriteHeader ( newDBF );
    1634               3 :    DBFClose ( newDBF );
    1635                 :    
    1636               3 :    newDBF = DBFOpen ( pszFilename, "rb+" );
    1637                 : 
    1638               3 :    return ( newDBF );
    1639                 : }
    1640                 : 
    1641                 : /************************************************************************/
    1642                 : /*                       DBFGetNativeFieldType()                        */
    1643                 : /*                                                                      */
    1644                 : /*      Return the DBase field type for the specified field.            */
    1645                 : /*                                                                      */
    1646                 : /*      Value can be one of: 'C' (String), 'D' (Date), 'F' (Float),     */
    1647                 : /*                           'N' (Numeric, with or without decimal),    */
    1648                 : /*                           'L' (Logical),                             */
    1649                 : /*                           'M' (Memo: 10 digits .DBT block ptr)       */
    1650                 : /************************************************************************/
    1651                 : 
    1652                 : char SHPAPI_CALL
    1653            3843 : DBFGetNativeFieldType( DBFHandle psDBF, int iField )
    1654                 : 
    1655                 : {
    1656            3843 :     if( iField >=0 && iField < psDBF->nFields )
    1657            3843 :         return psDBF->pachFieldType[iField];
    1658                 : 
    1659               0 :     return  ' ';
    1660                 : }
    1661                 : 
    1662                 : /************************************************************************/
    1663                 : /*                            str_to_upper()                            */
    1664                 : /************************************************************************/
    1665                 : 
    1666         7304560 : static void str_to_upper (char *string)
    1667                 : {
    1668                 :     int len;
    1669         7304560 :     short i = -1;
    1670                 : 
    1671         7304560 :     len = strlen (string);
    1672                 : 
    1673        59176983 :     while (++i < len)
    1674        44567863 :         if (isalpha(string[i]) && islower(string[i]))
    1675        21942683 :             string[i] = (char) toupper ((int)string[i]);
    1676         7304560 : }
    1677                 : 
    1678                 : /************************************************************************/
    1679                 : /*                          DBFGetFieldIndex()                          */
    1680                 : /*                                                                      */
    1681                 : /*      Get the index number for a field in a .dbf file.                */
    1682                 : /*                                                                      */
    1683                 : /*      Contributed by Jim Matthews.                                    */
    1684                 : /************************************************************************/
    1685                 : 
    1686                 : int SHPAPI_CALL
    1687           13246 : DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
    1688                 : 
    1689                 : {
    1690                 :     char          name[12], name1[12], name2[12];
    1691                 :     int           i;
    1692                 : 
    1693           13246 :     strncpy(name1, pszFieldName,11);
    1694           13246 :     name1[11] = '\0';
    1695           13246 :     str_to_upper(name1);
    1696                 : 
    1697         7304374 :     for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
    1698                 :     {
    1699         7291314 :         DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
    1700         7291314 :         strncpy(name2,name,11);
    1701         7291314 :         str_to_upper(name2);
    1702                 : 
    1703         7291314 :         if(!strncmp(name1,name2,10))
    1704             186 :             return(i);
    1705                 :     }
    1706           13060 :     return(-1);
    1707                 : }
    1708                 : 
    1709                 : /************************************************************************/
    1710                 : /*                         DBFIsRecordDeleted()                         */
    1711                 : /*                                                                      */
    1712                 : /*      Returns TRUE if the indicated record is deleted, otherwise      */
    1713                 : /*      it returns FALSE.                                               */
    1714                 : /************************************************************************/
    1715                 : 
    1716          123298 : int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
    1717                 : 
    1718                 : {
    1719                 : /* -------------------------------------------------------------------- */
    1720                 : /*      Verify selection.                                               */
    1721                 : /* -------------------------------------------------------------------- */
    1722          123298 :     if( iShape < 0 || iShape >= psDBF->nRecords )
    1723               0 :         return TRUE;
    1724                 : 
    1725                 : /* -------------------------------------------------------------------- */
    1726                 : /*  Have we read the record?          */
    1727                 : /* -------------------------------------------------------------------- */
    1728          123298 :     if( !DBFLoadRecord( psDBF, iShape ) )
    1729               0 :         return FALSE;
    1730                 : 
    1731                 : /* -------------------------------------------------------------------- */
    1732                 : /*      '*' means deleted.                                              */
    1733                 : /* -------------------------------------------------------------------- */
    1734          123298 :     return psDBF->pszCurrentRecord[0] == '*';
    1735                 : }
    1736                 : 
    1737                 : /************************************************************************/
    1738                 : /*                        DBFMarkRecordDeleted()                        */
    1739                 : /************************************************************************/
    1740                 : 
    1741               7 : int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, 
    1742                 :                                       int bIsDeleted )
    1743                 : 
    1744                 : {
    1745                 :     char chNewFlag;
    1746                 : 
    1747                 : /* -------------------------------------------------------------------- */
    1748                 : /*      Verify selection.                                               */
    1749                 : /* -------------------------------------------------------------------- */
    1750               7 :     if( iShape < 0 || iShape >= psDBF->nRecords )
    1751               0 :         return FALSE;
    1752                 : 
    1753                 : /* -------------------------------------------------------------------- */
    1754                 : /*      Is this an existing record, but different than the last one     */
    1755                 : /*      we accessed?                                                    */
    1756                 : /* -------------------------------------------------------------------- */
    1757               7 :     if( !DBFLoadRecord( psDBF, iShape ) )
    1758               0 :         return FALSE;
    1759                 : 
    1760                 : /* -------------------------------------------------------------------- */
    1761                 : /*      Assign value, marking record as dirty if it changes.            */
    1762                 : /* -------------------------------------------------------------------- */
    1763               7 :     if( bIsDeleted )
    1764               7 :         chNewFlag = '*';
    1765                 :     else 
    1766               0 :         chNewFlag = ' ';
    1767                 : 
    1768               7 :     if( psDBF->pszCurrentRecord[0] != chNewFlag )
    1769                 :     {
    1770               7 :         psDBF->bCurrentRecordModified = TRUE;
    1771               7 :         psDBF->bUpdated = TRUE;
    1772               7 :         psDBF->pszCurrentRecord[0] = chNewFlag;
    1773                 :     }
    1774                 : 
    1775               7 :     return TRUE;
    1776                 : }
    1777                 : 
    1778                 : /************************************************************************/
    1779                 : /*                            DBFGetCodePage                            */
    1780                 : /************************************************************************/
    1781                 : 
    1782                 : const char SHPAPI_CALL1(*)
    1783               0 : DBFGetCodePage(DBFHandle psDBF )
    1784                 : {
    1785               0 :     if( psDBF == NULL )
    1786               0 :         return NULL;
    1787               0 :     return psDBF->pszCodePage;
    1788                 : }
    1789                 : 
    1790                 : /************************************************************************/
    1791                 : /*                          DBFDeleteField()                            */
    1792                 : /*                                                                      */
    1793                 : /*      Remove a field from a .dbf file                                 */
    1794                 : /************************************************************************/
    1795                 : 
    1796                 : int SHPAPI_CALL
    1797               6 : DBFDeleteField(DBFHandle psDBF, int iField)
    1798                 : {
    1799                 :     int nOldRecordLength, nOldHeaderLength;
    1800                 :     int nDeletedFieldOffset, nDeletedFieldSize;
    1801                 :     SAOffset nRecordOffset;
    1802                 :     char* pszRecord;
    1803                 :     int i, iRecord;
    1804                 : 
    1805               6 :     if (iField < 0 || iField >= psDBF->nFields)
    1806               0 :         return FALSE;
    1807                 : 
    1808                 :     /* make sure that everything is written in .dbf */
    1809               6 :     if( !DBFFlushRecord( psDBF ) )
    1810               0 :         return FALSE;
    1811                 : 
    1812                 :     /* get information about field to be deleted */
    1813               6 :     nOldRecordLength = psDBF->nRecordLength;
    1814               6 :     nOldHeaderLength = psDBF->nHeaderLength;
    1815               6 :     nDeletedFieldOffset = psDBF->panFieldOffset[iField];
    1816               6 :     nDeletedFieldSize = psDBF->panFieldSize[iField];
    1817                 : 
    1818                 :     /* update fields info */
    1819              15 :     for (i = iField + 1; i < psDBF->nFields; i++)
    1820                 :     {
    1821               9 :         psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize;
    1822               9 :         psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i];
    1823               9 :         psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i];
    1824               9 :         psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i];
    1825                 :     }
    1826                 : 
    1827                 :     /* resize fields arrays */
    1828               6 :     psDBF->nFields--;
    1829                 : 
    1830              12 :     psDBF->panFieldOffset = (int *) 
    1831               6 :         SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
    1832                 : 
    1833              12 :     psDBF->panFieldSize = (int *) 
    1834               6 :         SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
    1835                 : 
    1836              12 :     psDBF->panFieldDecimals = (int *) 
    1837               6 :         SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
    1838                 : 
    1839              12 :     psDBF->pachFieldType = (char *) 
    1840               6 :         SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
    1841                 : 
    1842                 :     /* update header information */
    1843               6 :     psDBF->nHeaderLength -= 32;
    1844               6 :     psDBF->nRecordLength -= nDeletedFieldSize;
    1845                 : 
    1846                 :     /* overwrite field information in header */
    1847              12 :     memmove(psDBF->pszHeader + iField*32,
    1848               6 :            psDBF->pszHeader + (iField+1)*32,
    1849               6 :            sizeof(char) * (psDBF->nFields - iField)*32);
    1850                 : 
    1851               6 :     psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
    1852                 : 
    1853                 :     /* update size of current record appropriately */
    1854               6 :     psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
    1855                 :                                                  psDBF->nRecordLength);
    1856                 : 
    1857                 :     /* we're done if we're dealing with not yet created .dbf */
    1858               6 :     if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
    1859               0 :         return TRUE;
    1860                 : 
    1861                 :     /* force update of header with new header and record length */
    1862               6 :     psDBF->bNoHeader = TRUE;
    1863               6 :     DBFUpdateHeader( psDBF );
    1864                 : 
    1865                 :     /* alloc record */
    1866               6 :     pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
    1867                 : 
    1868                 :     /* shift records to their new positions */
    1869              30 :     for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
    1870                 :     {
    1871              24 :         nRecordOffset = 
    1872              24 :             nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength;
    1873                 : 
    1874                 :         /* load record */
    1875              24 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    1876              24 :         psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
    1877                 : 
    1878              24 :         nRecordOffset = 
    1879              24 :             psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    1880                 : 
    1881                 :         /* move record in two steps */
    1882              24 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    1883              24 :         psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp );
    1884              48 :         psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize,
    1885              24 :                               nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize,
    1886                 :                               1, psDBF->fp );
    1887                 : 
    1888                 :     }
    1889                 : 
    1890                 :     /* TODO: truncate file */
    1891                 : 
    1892                 :     /* free record */
    1893               6 :     free(pszRecord);
    1894                 : 
    1895               6 :     psDBF->nCurrentRecord = -1;
    1896               6 :     psDBF->bCurrentRecordModified = FALSE;
    1897                 : 
    1898               6 :     return TRUE;
    1899                 : }
    1900                 : 
    1901                 : /************************************************************************/
    1902                 : /*                          DBFReorderFields()                          */
    1903                 : /*                                                                      */
    1904                 : /*      Reorder the fields of a .dbf file                               */
    1905                 : /*                                                                      */
    1906                 : /* panMap must be exactly psDBF->nFields long and be a permutation      */
    1907                 : /* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/
    1908                 : /* code of DBFReorderFields.                                            */
    1909                 : /************************************************************************/
    1910                 : 
    1911                 : int SHPAPI_CALL
    1912              10 : DBFReorderFields( DBFHandle psDBF, int* panMap )
    1913                 : {
    1914                 :     SAOffset nRecordOffset;
    1915                 :     int      i, iRecord;
    1916                 :     int     *panFieldOffsetNew;
    1917                 :     int     *panFieldSizeNew;
    1918                 :     int     *panFieldDecimalsNew;
    1919                 :     char    *pachFieldTypeNew;
    1920                 :     char    *pszHeaderNew;
    1921                 :     char    *pszRecord;
    1922                 :     char    *pszRecordNew;
    1923                 : 
    1924              10 :     if ( psDBF->nFields == 0 )
    1925               0 :         return TRUE;
    1926                 : 
    1927                 :     /* make sure that everything is written in .dbf */
    1928              10 :     if( !DBFFlushRecord( psDBF ) )
    1929               0 :         return FALSE;
    1930                 : 
    1931              10 :     panFieldOffsetNew = (int *) malloc(sizeof(int) * psDBF->nFields);
    1932              10 :     panFieldSizeNew = (int *) malloc(sizeof(int) *  psDBF->nFields);
    1933              10 :     panFieldDecimalsNew = (int *) malloc(sizeof(int) *  psDBF->nFields);
    1934              10 :     pachFieldTypeNew = (char *) malloc(sizeof(char) *  psDBF->nFields);
    1935              10 :     pszHeaderNew = (char*) malloc(sizeof(char) * 32 *  psDBF->nFields);
    1936                 : 
    1937                 :     /* shuffle fields definitions */
    1938              52 :     for(i=0; i < psDBF->nFields; i++)
    1939                 :     {
    1940              42 :         panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
    1941              42 :         panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
    1942              42 :         pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
    1943              84 :         memcpy(pszHeaderNew + i * 32,
    1944              42 :                psDBF->pszHeader + panMap[i] * 32, 32);
    1945                 :     }
    1946              10 :     panFieldOffsetNew[0] = 1;
    1947              42 :     for(i=1; i < psDBF->nFields; i++)
    1948                 :     {
    1949              32 :         panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
    1950                 :     }
    1951                 : 
    1952              10 :     free(psDBF->pszHeader);
    1953              10 :     psDBF->pszHeader = pszHeaderNew;
    1954                 : 
    1955                 :     /* we're done if we're dealing with not yet created .dbf */
    1956              10 :     if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) )
    1957                 :     {
    1958                 :         /* force update of header with new header and record length */
    1959              10 :         psDBF->bNoHeader = TRUE;
    1960              10 :         DBFUpdateHeader( psDBF );
    1961                 : 
    1962                 :         /* alloc record */
    1963              10 :         pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
    1964              10 :         pszRecordNew = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
    1965                 : 
    1966                 :         /* shuffle fields in records */
    1967              50 :         for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
    1968                 :         {
    1969              40 :             nRecordOffset =
    1970              40 :                 psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    1971                 : 
    1972                 :             /* load record */
    1973              40 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    1974              40 :             psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
    1975                 : 
    1976              40 :             pszRecordNew[0] = pszRecord[0];
    1977                 : 
    1978             208 :             for(i=0; i < psDBF->nFields; i++)
    1979                 :             {
    1980             336 :                 memcpy(pszRecordNew + panFieldOffsetNew[i],
    1981             168 :                        pszRecord + psDBF->panFieldOffset[panMap[i]],
    1982             168 :                        psDBF->panFieldSize[panMap[i]]);
    1983                 :             }
    1984                 : 
    1985                 :             /* write record */
    1986              40 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    1987              40 :             psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp );
    1988                 :         }
    1989                 : 
    1990                 :         /* free record */
    1991              10 :         free(pszRecord);
    1992              10 :         free(pszRecordNew);
    1993                 :     }
    1994                 : 
    1995              10 :     free(psDBF->panFieldOffset);
    1996              10 :     free(psDBF->panFieldSize);
    1997              10 :     free(psDBF->panFieldDecimals);
    1998              10 :     free(psDBF->pachFieldType);
    1999                 : 
    2000              10 :     psDBF->panFieldOffset = panFieldOffsetNew;
    2001              10 :     psDBF->panFieldSize = panFieldSizeNew;
    2002              10 :     psDBF->panFieldDecimals =panFieldDecimalsNew;
    2003              10 :     psDBF->pachFieldType = pachFieldTypeNew;
    2004                 : 
    2005              10 :     psDBF->nCurrentRecord = -1;
    2006              10 :     psDBF->bCurrentRecordModified = FALSE;
    2007                 : 
    2008              10 :     return TRUE;
    2009                 : }
    2010                 : 
    2011                 : 
    2012                 : /************************************************************************/
    2013                 : /*                          DBFAlterFieldDefn()                         */
    2014                 : /*                                                                      */
    2015                 : /*      Alter a field definition in a .dbf file                         */
    2016                 : /************************************************************************/
    2017                 : 
    2018                 : int SHPAPI_CALL
    2019              13 : DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
    2020                 :                     char chType, int nWidth, int nDecimals )
    2021                 : {
    2022                 :     int   i;
    2023                 :     int   iRecord;
    2024                 :     int   nOffset;
    2025                 :     int   nOldWidth;
    2026                 :     int   nOldRecordLength;
    2027                 :     int   nRecordOffset;
    2028                 :     char* pszFInfo;
    2029                 :     char  chOldType;
    2030                 :     int   bIsNULL;
    2031                 :     char chFieldFill;
    2032                 : 
    2033              13 :     if (iField < 0 || iField >= psDBF->nFields)
    2034               0 :         return FALSE;
    2035                 : 
    2036                 :     /* make sure that everything is written in .dbf */
    2037              13 :     if( !DBFFlushRecord( psDBF ) )
    2038               0 :         return FALSE;
    2039                 : 
    2040              13 :     chFieldFill = DBFGetNullCharacter(chType);
    2041                 : 
    2042              13 :     chOldType = psDBF->pachFieldType[iField];
    2043              13 :     nOffset = psDBF->panFieldOffset[iField];
    2044              13 :     nOldWidth = psDBF->panFieldSize[iField];
    2045              13 :     nOldRecordLength = psDBF->nRecordLength;
    2046                 : 
    2047                 : /* -------------------------------------------------------------------- */
    2048                 : /*      Do some checking to ensure we can add records to this file.     */
    2049                 : /* -------------------------------------------------------------------- */
    2050              13 :     if( nWidth < 1 )
    2051               0 :         return -1;
    2052                 : 
    2053              13 :     if( nWidth > 255 )
    2054               0 :         nWidth = 255;
    2055                 : 
    2056                 : /* -------------------------------------------------------------------- */
    2057                 : /*      Assign the new field information fields.                        */
    2058                 : /* -------------------------------------------------------------------- */
    2059              13 :     psDBF->panFieldSize[iField] = nWidth;
    2060              13 :     psDBF->panFieldDecimals[iField] = nDecimals;
    2061              13 :     psDBF->pachFieldType[iField] = chType;
    2062                 : 
    2063                 : /* -------------------------------------------------------------------- */
    2064                 : /*      Update the header information.                                  */
    2065                 : /* -------------------------------------------------------------------- */
    2066              13 :     pszFInfo = psDBF->pszHeader + 32 * iField;
    2067                 : 
    2068             429 :     for( i = 0; i < 32; i++ )
    2069             416 :         pszFInfo[i] = '\0';
    2070                 : 
    2071              13 :     if( (int) strlen(pszFieldName) < 10 )
    2072              13 :         strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
    2073                 :     else
    2074               0 :         strncpy( pszFInfo, pszFieldName, 10);
    2075                 : 
    2076              13 :     pszFInfo[11] = psDBF->pachFieldType[iField];
    2077                 : 
    2078              13 :     if( chType == 'C' )
    2079                 :     {
    2080               7 :         pszFInfo[16] = (unsigned char) (nWidth % 256);
    2081               7 :         pszFInfo[17] = (unsigned char) (nWidth / 256);
    2082                 :     }
    2083                 :     else
    2084                 :     {
    2085               6 :         pszFInfo[16] = (unsigned char) nWidth;
    2086               6 :         pszFInfo[17] = (unsigned char) nDecimals;
    2087                 :     }
    2088                 : 
    2089                 : /* -------------------------------------------------------------------- */
    2090                 : /*      Update offsets                                                  */
    2091                 : /* -------------------------------------------------------------------- */
    2092              13 :     if (nWidth != nOldWidth)
    2093                 :     {
    2094              33 :         for (i = iField + 1; i < psDBF->nFields; i++)
    2095              22 :              psDBF->panFieldOffset[i] += nWidth - nOldWidth;
    2096              11 :         psDBF->nRecordLength += nWidth - nOldWidth;
    2097                 : 
    2098              11 :         psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
    2099                 :                                                      psDBF->nRecordLength);
    2100                 :     }
    2101                 : 
    2102                 :     /* we're done if we're dealing with not yet created .dbf */
    2103              13 :     if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
    2104               1 :         return TRUE;
    2105                 : 
    2106                 :     /* force update of header with new header and record length */
    2107              12 :     psDBF->bNoHeader = TRUE;
    2108              12 :     DBFUpdateHeader( psDBF );
    2109                 : 
    2110              19 :     if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType))
    2111                 :     {
    2112               7 :         char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
    2113               7 :         char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
    2114                 : 
    2115               7 :         pszOldField[nOldWidth] = 0;
    2116                 : 
    2117                 :         /* move records to their new positions */
    2118              35 :         for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
    2119                 :         {
    2120              28 :             nRecordOffset =
    2121                 :                 nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    2122                 : 
    2123                 :             /* load record */
    2124              28 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    2125              28 :             psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
    2126                 : 
    2127              28 :             memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
    2128              28 :             bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
    2129                 : 
    2130              28 :             if (nWidth != nOldWidth)
    2131                 :             {
    2132              28 :                 if ((chOldType == 'N' || chOldType == 'F') && pszOldField[0] == ' ')
    2133                 :                 {
    2134                 :                     /* Strip leading spaces when truncating a numeric field */
    2135              20 :                     memmove( pszRecord + nOffset,
    2136              15 :                             pszRecord + nOffset + nOldWidth - nWidth,
    2137                 :                             nWidth );
    2138                 :                 }
    2139              28 :                 if (nOffset + nOldWidth < nOldRecordLength)
    2140                 :                 {
    2141              72 :                     memmove( pszRecord + nOffset + nWidth,
    2142              48 :                             pszRecord + nOffset + nOldWidth,
    2143              24 :                             nOldRecordLength - (nOffset + nOldWidth));
    2144                 :                 }
    2145                 :             }
    2146                 : 
    2147                 :             /* Convert null value to the appropriate value of the new type */
    2148              28 :             if (bIsNULL)
    2149                 :             {
    2150              14 :                 memset( pszRecord + nOffset, chFieldFill, nWidth);
    2151                 :             }
    2152                 : 
    2153              28 :             nRecordOffset =
    2154                 :                 psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    2155                 : 
    2156                 :             /* write record */
    2157              28 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    2158              28 :             psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
    2159                 :         }
    2160                 : 
    2161               7 :         free(pszRecord);
    2162               7 :         free(pszOldField);
    2163                 :     }
    2164               5 :     else if (nWidth > nOldWidth)
    2165                 :     {
    2166               4 :         char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
    2167               4 :         char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
    2168                 : 
    2169               4 :         pszOldField[nOldWidth] = 0;
    2170                 : 
    2171                 :         /* move records to their new positions */
    2172              15 :         for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
    2173                 :         {
    2174              11 :             nRecordOffset =
    2175                 :                 nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    2176                 : 
    2177                 :             /* load record */
    2178              11 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    2179              11 :             psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
    2180                 : 
    2181              11 :             memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
    2182              11 :             bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
    2183                 : 
    2184              11 :             if (nOffset + nOldWidth < nOldRecordLength)
    2185                 :             {
    2186              27 :                 memmove( pszRecord + nOffset + nWidth,
    2187              18 :                          pszRecord + nOffset + nOldWidth,
    2188               9 :                          nOldRecordLength - (nOffset + nOldWidth));
    2189                 :             }
    2190                 : 
    2191                 :             /* Convert null value to the appropriate value of the new type */
    2192              11 :             if (bIsNULL)
    2193                 :             {
    2194               4 :                 memset( pszRecord + nOffset, chFieldFill, nWidth);
    2195                 :             }
    2196                 :             else
    2197                 :             {
    2198               9 :                 if ((chOldType == 'N' || chOldType == 'F'))
    2199                 :                 {
    2200                 :                     /* Add leading spaces when expanding a numeric field */
    2201               4 :                     memmove( pszRecord + nOffset + nWidth - nOldWidth,
    2202               2 :                              pszRecord + nOffset, nOldWidth );
    2203               2 :                     memset( pszRecord + nOffset, ' ', nWidth - nOldWidth );
    2204                 :                 }
    2205                 :                 else
    2206                 :                 {
    2207                 :                     /* Add trailing spaces */
    2208               5 :                     memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth);
    2209                 :                 }
    2210                 :             }
    2211                 : 
    2212              11 :             nRecordOffset =
    2213                 :                 psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    2214                 : 
    2215                 :             /* write record */
    2216              11 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    2217              11 :             psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
    2218                 :         }
    2219                 : 
    2220               4 :         free(pszRecord);
    2221               4 :         free(pszOldField);
    2222                 :     }
    2223                 : 
    2224              12 :     psDBF->nCurrentRecord = -1;
    2225              12 :     psDBF->bCurrentRecordModified = FALSE;
    2226                 : 
    2227              12 :     return TRUE;
    2228                 : }

Generated by: LCOV version 1.7