LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - dbfopen.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 792 682 86.1 %
Date: 2012-04-28 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           56100 : static void * SfRealloc( void * pMem, int nNewSize )
     181                 : 
     182                 : {
     183           56100 :     if( pMem == NULL )
     184           14256 :         return( (void *) malloc(nNewSize) );
     185                 :     else
     186           41844 :         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            2458 : static void DBFWriteHeader(DBFHandle psDBF)
     199                 : 
     200                 : {
     201                 :     unsigned char abyHeader[XBASE_FLDHDR_SZ];
     202                 :     int   i;
     203                 : 
     204            2458 :     if( !psDBF->bNoHeader )
     205               0 :         return;
     206                 : 
     207            2458 :     psDBF->bNoHeader = FALSE;
     208                 : 
     209                 : /* -------------------------------------------------------------------- */
     210                 : /*  Initialize the file header information.       */
     211                 : /* -------------------------------------------------------------------- */
     212           81114 :     for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
     213           78656 :         abyHeader[i] = 0;
     214                 : 
     215            2458 :     abyHeader[0] = 0x03;    /* memo field? - just copying   */
     216                 : 
     217                 :     /* write out a dummy date */
     218            2458 :     abyHeader[1] = 95;      /* YY */
     219            2458 :     abyHeader[2] = 7;     /* MM */
     220            2458 :     abyHeader[3] = 26;      /* DD */
     221                 : 
     222                 :     /* record count preset at zero */
     223                 : 
     224            2458 :     abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
     225            2458 :     abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
     226                 :     
     227            2458 :     abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
     228            2458 :     abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
     229                 : 
     230            2458 :     abyHeader[29] = (unsigned char) (psDBF->iLanguageDriver);
     231                 : 
     232                 : /* -------------------------------------------------------------------- */
     233                 : /*      Write the initial 32 byte file header, and all the field        */
     234                 : /*      descriptions.                                         */
     235                 : /* -------------------------------------------------------------------- */
     236            2458 :     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     237            2458 :     psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
     238            2458 :     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            2458 :     if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
     245                 :     {
     246                 :         char  cNewline;
     247                 : 
     248            2458 :         cNewline = 0x0d;
     249            2458 :         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          173409 : static int DBFFlushRecord( DBFHandle psDBF )
     260                 : 
     261                 : {
     262                 :     SAOffset  nRecordOffset;
     263                 : 
     264          173409 :     if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
     265                 :     {
     266           59114 :   psDBF->bCurrentRecordModified = FALSE;
     267                 : 
     268           59114 :   nRecordOffset = 
     269           59114 :             psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord 
     270           59114 :             + psDBF->nHeaderLength;
     271                 : 
     272          118228 :   if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0 
     273          118228 :             || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord, 
     274           59114 :                                      psDBF->nRecordLength, 
     275          177342 :                                      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          173409 :     return TRUE;
     286                 : }
     287                 : 
     288                 : /************************************************************************/
     289                 : /*                           DBFLoadRecord()                            */
     290                 : /************************************************************************/
     291                 : 
     292          423052 : static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
     293                 : 
     294                 : {
     295          423052 :     if( psDBF->nCurrentRecord != iRecord )
     296                 :     {
     297                 :         SAOffset nRecordOffset;
     298                 : 
     299           95843 :   if( !DBFFlushRecord( psDBF ) )
     300               0 :             return FALSE;
     301                 : 
     302           95843 :   nRecordOffset = 
     303           95843 :             psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
     304                 : 
     305           95843 :   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          191686 :   if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord, 
     315           95843 :                                  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           95843 :   psDBF->nCurrentRecord = iRecord;
     325                 :     }
     326                 : 
     327          423052 :     return TRUE;
     328                 : }
     329                 : 
     330                 : /************************************************************************/
     331                 : /*                          DBFUpdateHeader()                           */
     332                 : /************************************************************************/
     333                 : 
     334                 : void SHPAPI_CALL
     335            2532 : DBFUpdateHeader( DBFHandle psDBF )
     336                 : 
     337                 : {
     338                 :     unsigned char   abyFileHeader[32];
     339                 : 
     340            2532 :     if( psDBF->bNoHeader )
     341              68 :         DBFWriteHeader( psDBF );
     342                 : 
     343            2532 :     DBFFlushRecord( psDBF );
     344                 : 
     345            2532 :     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     346            2532 :     psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
     347                 :     
     348            2532 :     abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
     349            2532 :     abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
     350            2532 :     abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
     351            2532 :     abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
     352                 :     
     353            2532 :     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     354            2532 :     psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
     355                 : 
     356            2532 :     psDBF->sHooks.FFlush( psDBF->fp );
     357            2532 : }
     358                 : 
     359                 : /************************************************************************/
     360                 : /*                              DBFOpen()                               */
     361                 : /*                                                                      */
     362                 : /*      Open a .dbf file.                                               */
     363                 : /************************************************************************/
     364                 :    
     365                 : DBFHandle SHPAPI_CALL
     366            5030 : DBFOpen( const char * pszFilename, const char * pszAccess )
     367                 : 
     368                 : {
     369                 :     SAHooks sHooks;
     370                 : 
     371            5030 :     SASetupDefaultHooks( &sHooks );
     372                 : 
     373            5030 :     return DBFOpenLL( pszFilename, pszAccess, &sHooks );
     374                 : }
     375                 : 
     376                 : /************************************************************************/
     377                 : /*                              DBFOpen()                               */
     378                 : /*                                                                      */
     379                 : /*      Open a .dbf file.                                               */
     380                 : /************************************************************************/
     381                 :    
     382                 : DBFHandle SHPAPI_CALL
     383            5030 : 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            5030 :     int                 nBufSize = 500;
     392                 : 
     393                 : /* -------------------------------------------------------------------- */
     394                 : /*      We only allow the access strings "rb" and "r+".                  */
     395                 : /* -------------------------------------------------------------------- */
     396            8406 :     if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 
     397            3370 :         && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
     398               6 :         && strcmp(pszAccess,"r+b") != 0 )
     399               0 :         return( NULL );
     400                 : 
     401            5030 :     if( strcmp(pszAccess,"r") == 0 )
     402            1666 :         pszAccess = "rb";
     403                 :  
     404            5030 :     if( strcmp(pszAccess,"r+") == 0 )
     405            3358 :         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            5030 :     pszBasename = (char *) malloc(strlen(pszFilename)+5);
     412            5030 :     strcpy( pszBasename, pszFilename );
     413           75450 :     for( i = strlen(pszBasename)-1; 
     414           35210 :    i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
     415           15090 :          && pszBasename[i] != '\\';
     416           15090 :    i-- ) {}
     417                 : 
     418            5030 :     if( pszBasename[i] == '.' )
     419            5030 :         pszBasename[i] = '\0';
     420                 : 
     421            5030 :     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
     422            5030 :     sprintf( pszFullname, "%s.dbf", pszBasename );
     423                 :         
     424            5030 :     psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
     425            5030 :     psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
     426            5030 :     memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
     427                 : 
     428            5030 :     if( psDBF->fp == NULL )
     429                 :     {
     430              28 :         sprintf( pszFullname, "%s.DBF", pszBasename );
     431              28 :         psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
     432                 :     }
     433                 : 
     434            5030 :     sprintf( pszFullname, "%s.cpg", pszBasename );
     435            5030 :     pfCPG = psHooks->FOpen( pszFullname, "r" );
     436            5030 :     if( pfCPG == NULL )
     437                 :     {
     438            5030 :         sprintf( pszFullname, "%s.CPG", pszBasename );
     439            5030 :         pfCPG = psHooks->FOpen( pszFullname, "r" );
     440                 :     }
     441                 : 
     442            5030 :     free( pszBasename );
     443            5030 :     free( pszFullname );
     444                 :     
     445            5030 :     if( psDBF->fp == NULL )
     446                 :     {
     447              24 :         free( psDBF );
     448              24 :         if( pfCPG ) psHooks->FClose( pfCPG );
     449              24 :         return( NULL );
     450                 :     }
     451                 : 
     452            5006 :     psDBF->bNoHeader = FALSE;
     453            5006 :     psDBF->nCurrentRecord = -1;
     454            5006 :     psDBF->bCurrentRecordModified = FALSE;
     455                 : 
     456                 : /* -------------------------------------------------------------------- */
     457                 : /*  Read Table Header info                                              */
     458                 : /* -------------------------------------------------------------------- */
     459            5006 :     pabyBuf = (unsigned char *) malloc(nBufSize);
     460            5006 :     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            5006 :     psDBF->nRecords = 
     470            5006 :      pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
     471                 : 
     472            5006 :     psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
     473            5006 :     psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
     474            5006 :     psDBF->iLanguageDriver = pabyBuf[29];
     475                 : 
     476            5006 :     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            5006 :     psDBF->nFields = nFields = (nHeadLen - 32) / 32;
     486                 : 
     487            5006 :     psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
     488                 : 
     489                 : /* -------------------------------------------------------------------- */
     490                 : /*  Figure out the code page from the LDID and CPG                      */
     491                 : /* -------------------------------------------------------------------- */
     492                 : 
     493            5006 :     psDBF->pszCodePage = NULL;
     494            5006 :     if( pfCPG )
     495                 :     {
     496                 :         size_t n;
     497               0 :         memset( pabyBuf, 0, nBufSize);
     498               0 :         psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
     499               0 :         n = strcspn( (char *) pabyBuf, "\n\r" );
     500               0 :         if( n > 0 )
     501                 :         {
     502               0 :             pabyBuf[n] = '\0';
     503               0 :             psDBF->pszCodePage = (char *) malloc(n + 1);
     504               0 :             memcpy( psDBF->pszCodePage, pabyBuf, n + 1 );
     505                 :         }
     506               0 :     psDBF->sHooks.FClose( pfCPG );
     507                 :     }
     508            5006 :     if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 )
     509                 :     {
     510            4598 :         sprintf( (char *) pabyBuf, "LDID/%d", psDBF->iLanguageDriver );
     511            4598 :         psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1);
     512            4598 :         strcpy( psDBF->pszCodePage, (char *) pabyBuf );
     513                 :     }
     514                 : 
     515                 : /* -------------------------------------------------------------------- */
     516                 : /*  Read in Field Definitions                                           */
     517                 : /* -------------------------------------------------------------------- */
     518                 :     
     519            5006 :     pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
     520            5006 :     psDBF->pszHeader = (char *) pabyBuf;
     521                 : 
     522            5006 :     psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
     523            5006 :     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            5006 :     psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
     533            5006 :     psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
     534            5006 :     psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
     535            5006 :     psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
     536                 : 
     537           11590 :     for( iField = 0; iField < nFields; iField++ )
     538                 :     {
     539                 :   unsigned char   *pabyFInfo;
     540                 : 
     541            6584 :   pabyFInfo = pabyBuf+iField*32;
     542                 : 
     543            9126 :   if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
     544                 :   {
     545            2542 :       psDBF->panFieldSize[iField] = pabyFInfo[16];
     546            2542 :       psDBF->panFieldDecimals[iField] = pabyFInfo[17];
     547                 :   }
     548                 :   else
     549                 :   {
     550            4042 :       psDBF->panFieldSize[iField] = pabyFInfo[16];
     551            4042 :       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            6584 :   psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
     564            6584 :   if( iField == 0 )
     565            4996 :       psDBF->panFieldOffset[iField] = 1;
     566                 :   else
     567            3176 :       psDBF->panFieldOffset[iField] = 
     568            1588 :         psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
     569                 :     }
     570                 : 
     571            5006 :     return( psDBF );
     572                 : }
     573                 : 
     574                 : /************************************************************************/
     575                 : /*                              DBFClose()                              */
     576                 : /************************************************************************/
     577                 : 
     578                 : void SHPAPI_CALL
     579            7396 : DBFClose(DBFHandle psDBF)
     580                 : {
     581            7396 :     if( psDBF == NULL )
     582               0 :         return;
     583                 : 
     584                 : /* -------------------------------------------------------------------- */
     585                 : /*      Write out header if not already written.                        */
     586                 : /* -------------------------------------------------------------------- */
     587            7396 :     if( psDBF->bNoHeader )
     588              14 :         DBFWriteHeader( psDBF );
     589                 : 
     590            7396 :     DBFFlushRecord( psDBF );
     591                 : 
     592                 : /* -------------------------------------------------------------------- */
     593                 : /*      Update last access date, and number of records if we have */
     594                 : /*  write access.                         */
     595                 : /* -------------------------------------------------------------------- */
     596            7396 :     if( psDBF->bUpdated )
     597            2424 :         DBFUpdateHeader( psDBF );
     598                 : 
     599                 : /* -------------------------------------------------------------------- */
     600                 : /*      Close, and free resources.                                      */
     601                 : /* -------------------------------------------------------------------- */
     602            7396 :     psDBF->sHooks.FClose( psDBF->fp );
     603                 : 
     604            7396 :     if( psDBF->panFieldOffset != NULL )
     605                 :     {
     606            7386 :         free( psDBF->panFieldOffset );
     607            7386 :         free( psDBF->panFieldSize );
     608            7386 :         free( psDBF->panFieldDecimals );
     609            7386 :         free( psDBF->pachFieldType );
     610                 :     }
     611                 : 
     612            7396 :     if( psDBF->pszWorkField != NULL )
     613            2670 :         free( psDBF->pszWorkField );
     614                 : 
     615            7396 :     free( psDBF->pszHeader );
     616            7396 :     free( psDBF->pszCurrentRecord );
     617            7396 :     free( psDBF->pszCodePage );
     618                 : 
     619            7396 :     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            2384 : DBFCreate( const char * pszFilename )
     630                 : 
     631                 : {
     632            2384 :     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            2390 : DBFCreateEx( const char * pszFilename, const char* pszCodePage )
     643                 : 
     644                 : {
     645                 :     SAHooks sHooks;
     646                 : 
     647            2390 :     SASetupDefaultHooks( &sHooks );
     648                 : 
     649            2390 :     return DBFCreateLL( pszFilename, pszCodePage , &sHooks );
     650                 : }
     651                 : 
     652                 : /************************************************************************/
     653                 : /*                             DBFCreate()                              */
     654                 : /*                                                                      */
     655                 : /*      Create a new .dbf file.                                         */
     656                 : /************************************************************************/
     657                 : 
     658                 : DBFHandle SHPAPI_CALL
     659            2390 : DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks )
     660                 : 
     661                 : {
     662                 :     DBFHandle psDBF;
     663                 :     SAFile  fp;
     664                 :     char  *pszFullname, *pszBasename;
     665            2390 :     int   i, ldid = -1;
     666            2390 :     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            2390 :     pszBasename = (char *) malloc(strlen(pszFilename)+5);
     673            2390 :     strcpy( pszBasename, pszFilename );
     674           35850 :     for( i = strlen(pszBasename)-1; 
     675           16730 :    i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
     676            7170 :          && pszBasename[i] != '\\';
     677            7170 :    i-- ) {}
     678                 : 
     679            2390 :     if( pszBasename[i] == '.' )
     680            2390 :         pszBasename[i] = '\0';
     681                 : 
     682            2390 :     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
     683            2390 :     sprintf( pszFullname, "%s.dbf", pszBasename );
     684                 : 
     685                 : /* -------------------------------------------------------------------- */
     686                 : /*      Create the file.                                                */
     687                 : /* -------------------------------------------------------------------- */
     688            2390 :     fp = psHooks->FOpen( pszFullname, "wb" );
     689            2390 :     if( fp == NULL )
     690               0 :         return( NULL );
     691                 :     
     692            2390 :     psHooks->FWrite( &chZero, 1, 1, fp );
     693            2390 :     psHooks->FClose( fp );
     694                 : 
     695            2390 :     fp = psHooks->FOpen( pszFullname, "rb+" );
     696            2390 :     if( fp == NULL )
     697               0 :         return( NULL );
     698                 : 
     699                 : 
     700            2390 :     sprintf( pszFullname, "%s.cpg", pszBasename );
     701            2390 :     if( pszCodePage != NULL )
     702                 :     {
     703            2386 :         if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
     704                 :         {
     705            2386 :             ldid = atoi( pszCodePage + 5 );
     706            2386 :             if( ldid > 255 )
     707               0 :                 ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one
     708                 :         }
     709            2386 :         if( ldid < 0 )
     710                 :         {
     711               0 :             SAFile fpCPG = psHooks->FOpen( pszFullname, "w" );
     712               0 :             psHooks->FWrite( (char*) pszCodePage, strlen(pszCodePage), 1, fpCPG );
     713               0 :             psHooks->FClose( fpCPG );
     714                 :         }
     715                 :     }
     716            2390 :     if( pszCodePage == NULL || ldid >= 0 )
     717                 :     {
     718            2390 :         psHooks->Remove( pszFullname );
     719                 :     }
     720                 : 
     721            2390 :     free( pszBasename );
     722            2390 :     free( pszFullname );
     723                 : 
     724                 : /* -------------------------------------------------------------------- */
     725                 : /*  Create the info structure.          */
     726                 : /* -------------------------------------------------------------------- */
     727            2390 :     psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo));
     728                 : 
     729            2390 :     memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
     730            2390 :     psDBF->fp = fp;
     731            2390 :     psDBF->nRecords = 0;
     732            2390 :     psDBF->nFields = 0;
     733            2390 :     psDBF->nRecordLength = 1;
     734            2390 :     psDBF->nHeaderLength = 33;
     735                 :     
     736            2390 :     psDBF->panFieldOffset = NULL;
     737            2390 :     psDBF->panFieldSize = NULL;
     738            2390 :     psDBF->panFieldDecimals = NULL;
     739            2390 :     psDBF->pachFieldType = NULL;
     740            2390 :     psDBF->pszHeader = NULL;
     741                 : 
     742            2390 :     psDBF->nCurrentRecord = -1;
     743            2390 :     psDBF->bCurrentRecordModified = FALSE;
     744            2390 :     psDBF->pszCurrentRecord = NULL;
     745                 : 
     746            2390 :     psDBF->bNoHeader = TRUE;
     747                 : 
     748            2390 :     psDBF->iLanguageDriver = ldid > 0 ? ldid : 0;
     749            2390 :     psDBF->pszCodePage = NULL;
     750            2390 :     if( pszCodePage )
     751                 :     {
     752            2386 :         psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
     753            2386 :         strcpy( psDBF->pszCodePage, pszCodePage );
     754                 :     }
     755                 : 
     756            2390 :     return( psDBF );
     757                 : }
     758                 : 
     759                 : /************************************************************************/
     760                 : /*                            DBFAddField()                             */
     761                 : /*                                                                      */
     762                 : /*      Add a field to a newly created .dbf or to an existing one       */
     763                 : /************************************************************************/
     764                 : 
     765                 : int SHPAPI_CALL
     766             164 : DBFAddField(DBFHandle psDBF, const char * pszFieldName, 
     767                 :             DBFFieldType eType, int nWidth, int nDecimals )
     768                 : 
     769                 : {
     770             164 :     char chNativeType = 'C';
     771                 : 
     772             164 :     if( eType == FTLogical )
     773               0 :         chNativeType = 'L';
     774             164 :     else if( eType == FTString )
     775               0 :         chNativeType = 'C';
     776                 :     else
     777             164 :         chNativeType = 'N';
     778                 : 
     779             164 :     return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType, 
     780                 :                                   nWidth, nDecimals );
     781                 : }
     782                 : 
     783                 : /************************************************************************/
     784                 : /*                        DBFGetNullCharacter()                         */
     785                 : /************************************************************************/
     786                 : 
     787              70 : static char DBFGetNullCharacter(char chType)
     788                 : {
     789              70 :     switch (chType)
     790                 :     {
     791                 :       case 'N':
     792                 :       case 'F':
     793              30 :         return '*';
     794                 :       case 'D':
     795               0 :         return '0';
     796                 :       case 'L':
     797               0 :        return '?';
     798                 :       default:
     799              40 :        return ' ';
     800                 :     }
     801                 : }
     802                 : 
     803                 : /************************************************************************/
     804                 : /*                            DBFAddField()                             */
     805                 : /*                                                                      */
     806                 : /*      Add a field to a newly created .dbf file before any records     */
     807                 : /*      are written.                                                    */
     808                 : /************************************************************************/
     809                 : 
     810                 : int SHPAPI_CALL
     811            8500 : DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, 
     812                 :                       char chType, int nWidth, int nDecimals )
     813                 : 
     814                 : {
     815                 :     char  *pszFInfo;
     816                 :     int   i;
     817                 :     int         nOldRecordLength, nOldHeaderLength;
     818                 :     char        *pszRecord;
     819                 :     char        chFieldFill;
     820                 :     SAOffset    nRecordOffset;
     821                 : 
     822                 :     /* make sure that everything is written in .dbf */
     823            8500 :     if( !DBFFlushRecord( psDBF ) )
     824               0 :         return -1;
     825                 : 
     826                 : /* -------------------------------------------------------------------- */
     827                 : /*      Do some checking to ensure we can add records to this file.     */
     828                 : /* -------------------------------------------------------------------- */
     829            8500 :     if( nWidth < 1 )
     830               0 :         return -1;
     831                 : 
     832            8500 :     if( nWidth > 255 )
     833               0 :         nWidth = 255;
     834                 : 
     835            8500 :     nOldRecordLength = psDBF->nRecordLength;
     836            8500 :     nOldHeaderLength = psDBF->nHeaderLength;
     837                 : 
     838                 : /* -------------------------------------------------------------------- */
     839                 : /*      SfRealloc all the arrays larger to hold the additional field      */
     840                 : /*      information.                                                    */
     841                 : /* -------------------------------------------------------------------- */
     842            8500 :     psDBF->nFields++;
     843                 : 
     844           17000 :     psDBF->panFieldOffset = (int *) 
     845            8500 :         SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
     846                 : 
     847           17000 :     psDBF->panFieldSize = (int *) 
     848            8500 :         SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
     849                 : 
     850           17000 :     psDBF->panFieldDecimals = (int *) 
     851            8500 :         SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
     852                 : 
     853           17000 :     psDBF->pachFieldType = (char *) 
     854            8500 :         SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
     855                 : 
     856                 : /* -------------------------------------------------------------------- */
     857                 : /*      Assign the new field information fields.                        */
     858                 : /* -------------------------------------------------------------------- */
     859            8500 :     psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
     860            8500 :     psDBF->nRecordLength += nWidth;
     861            8500 :     psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
     862            8500 :     psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
     863            8500 :     psDBF->pachFieldType[psDBF->nFields-1] = chType;
     864                 : 
     865                 : /* -------------------------------------------------------------------- */
     866                 : /*      Extend the required header information.                         */
     867                 : /* -------------------------------------------------------------------- */
     868            8500 :     psDBF->nHeaderLength += 32;
     869            8500 :     psDBF->bUpdated = FALSE;
     870                 : 
     871            8500 :     psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
     872                 : 
     873            8500 :     pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
     874                 : 
     875          280500 :     for( i = 0; i < 32; i++ )
     876          272000 :         pszFInfo[i] = '\0';
     877                 : 
     878            8500 :     if( (int) strlen(pszFieldName) < 10 )
     879            8426 :         strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
     880                 :     else
     881              74 :         strncpy( pszFInfo, pszFieldName, 10);
     882                 : 
     883            8500 :     pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
     884                 : 
     885            8500 :     if( chType == 'C' )
     886                 :     {
     887            3878 :         pszFInfo[16] = (unsigned char) (nWidth % 256);
     888            3878 :         pszFInfo[17] = (unsigned char) (nWidth / 256);
     889                 :     }
     890                 :     else
     891                 :     {
     892            4622 :         pszFInfo[16] = (unsigned char) nWidth;
     893            4622 :         pszFInfo[17] = (unsigned char) nDecimals;
     894                 :     }
     895                 :     
     896                 : /* -------------------------------------------------------------------- */
     897                 : /*      Make the current record buffer appropriately larger.            */
     898                 : /* -------------------------------------------------------------------- */
     899            8500 :     psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
     900                 :                                                  psDBF->nRecordLength);
     901                 : 
     902                 :     /* we're done if dealing with new .dbf */
     903            8500 :     if( psDBF->bNoHeader )
     904            8488 :         return( psDBF->nFields - 1 );
     905                 : 
     906                 : /* -------------------------------------------------------------------- */
     907                 : /*      For existing .dbf file, shift records                           */
     908                 : /* -------------------------------------------------------------------- */
     909                 : 
     910                 :     /* alloc record */
     911              12 :     pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
     912                 : 
     913              12 :     chFieldFill = DBFGetNullCharacter(chType);
     914                 : 
     915              60 :     for (i = psDBF->nRecords-1; i >= 0; --i)
     916                 :     {
     917              48 :         nRecordOffset = nOldRecordLength * (SAOffset) i + nOldHeaderLength;
     918                 : 
     919                 :         /* load record */
     920              48 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
     921              48 :         psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
     922                 : 
     923                 :         /* set new field's value to NULL */
     924              48 :         memset(pszRecord + nOldRecordLength, chFieldFill, nWidth);
     925                 : 
     926              48 :         nRecordOffset = psDBF->nRecordLength * (SAOffset) i + psDBF->nHeaderLength;
     927                 : 
     928                 :         /* move record to the new place*/
     929              48 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
     930              48 :         psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
     931                 :     }
     932                 : 
     933                 :     /* free record */
     934              12 :     free(pszRecord);
     935                 : 
     936                 :     /* force update of header with new header, record length and new field */
     937              12 :     psDBF->bNoHeader = TRUE;
     938              12 :     DBFUpdateHeader( psDBF );
     939                 : 
     940              12 :     psDBF->nCurrentRecord = -1;
     941              12 :     psDBF->bCurrentRecordModified = FALSE;
     942                 : 
     943              12 :     return( psDBF->nFields-1 );
     944                 : }
     945                 : 
     946                 : /************************************************************************/
     947                 : /*                          DBFReadAttribute()                          */
     948                 : /*                                                                      */
     949                 : /*      Read one of the attribute fields of a record.                   */
     950                 : /************************************************************************/
     951                 : 
     952          186460 : static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
     953                 :                               char chReqType )
     954                 : 
     955                 : {
     956                 :     unsigned char *pabyRec;
     957          186460 :     void  *pReturnField = NULL;
     958                 : 
     959                 : /* -------------------------------------------------------------------- */
     960                 : /*      Verify selection.                                               */
     961                 : /* -------------------------------------------------------------------- */
     962          186460 :     if( hEntity < 0 || hEntity >= psDBF->nRecords )
     963               0 :         return( NULL );
     964                 : 
     965          186460 :     if( iField < 0 || iField >= psDBF->nFields )
     966               0 :         return( NULL );
     967                 : 
     968                 : /* -------------------------------------------------------------------- */
     969                 : /*  Have we read the record?          */
     970                 : /* -------------------------------------------------------------------- */
     971          186460 :     if( !DBFLoadRecord( psDBF, hEntity ) )
     972               0 :         return NULL;
     973                 : 
     974          186460 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
     975                 : 
     976                 : /* -------------------------------------------------------------------- */
     977                 : /*      Ensure we have room to extract the target field.                */
     978                 : /* -------------------------------------------------------------------- */
     979          186460 :     if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
     980                 :     {
     981            2670 :         psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
     982            2670 :         if( psDBF->pszWorkField == NULL )
     983            2670 :             psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength);
     984                 :         else
     985               0 :             psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField,
     986               0 :                                                    psDBF->nWorkFieldLength);
     987                 :     }
     988                 : 
     989                 : /* -------------------------------------------------------------------- */
     990                 : /*  Extract the requested field.          */
     991                 : /* -------------------------------------------------------------------- */
     992          372920 :     strncpy( psDBF->pszWorkField,
     993          186460 :        ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
     994          186460 :        psDBF->panFieldSize[iField] );
     995          186460 :     psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
     996                 : 
     997          186460 :     pReturnField = psDBF->pszWorkField;
     998                 : 
     999                 : /* -------------------------------------------------------------------- */
    1000                 : /*      Decode the field.                                               */
    1001                 : /* -------------------------------------------------------------------- */
    1002          186460 :     if( chReqType == 'N' )
    1003                 :     {
    1004           87056 :         psDBF->dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
    1005                 : 
    1006           87056 :   pReturnField = &(psDBF->dfDoubleField);
    1007                 :     }
    1008                 : 
    1009                 : /* -------------------------------------------------------------------- */
    1010                 : /*      Should we trim white space off the string attribute value?      */
    1011                 : /* -------------------------------------------------------------------- */
    1012                 : #ifdef TRIM_DBF_WHITESPACE
    1013                 :     else
    1014                 :     {
    1015                 :         char  *pchSrc, *pchDst;
    1016                 : 
    1017           99404 :         pchDst = pchSrc = psDBF->pszWorkField;
    1018          909638 :         while( *pchSrc == ' ' )
    1019          710830 :             pchSrc++;
    1020                 : 
    1021          942342 :         while( *pchSrc != '\0' )
    1022          743534 :             *(pchDst++) = *(pchSrc++);
    1023           99404 :         *pchDst = '\0';
    1024                 : 
    1025          492338 :         while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
    1026          293530 :             *pchDst = '\0';
    1027                 :     }
    1028                 : #endif
    1029                 :     
    1030          186460 :     return( pReturnField );
    1031                 : }
    1032                 : 
    1033                 : /************************************************************************/
    1034                 : /*                        DBFReadIntAttribute()                         */
    1035                 : /*                                                                      */
    1036                 : /*      Read an integer attribute.                                      */
    1037                 : /************************************************************************/
    1038                 : 
    1039                 : int SHPAPI_CALL
    1040            3836 : DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
    1041                 : 
    1042                 : {
    1043                 :     double  *pdValue;
    1044                 : 
    1045            3836 :     pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
    1046                 : 
    1047            3836 :     if( pdValue == NULL )
    1048               0 :         return 0;
    1049                 :     else
    1050            3836 :         return( (int) *pdValue );
    1051                 : }
    1052                 : 
    1053                 : /************************************************************************/
    1054                 : /*                        DBFReadDoubleAttribute()                      */
    1055                 : /*                                                                      */
    1056                 : /*      Read a double attribute.                                        */
    1057                 : /************************************************************************/
    1058                 : 
    1059                 : double SHPAPI_CALL
    1060           83220 : DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
    1061                 : 
    1062                 : {
    1063                 :     double  *pdValue;
    1064                 : 
    1065           83220 :     pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
    1066                 : 
    1067           83220 :     if( pdValue == NULL )
    1068               0 :         return 0.0;
    1069                 :     else
    1070           83220 :         return( *pdValue );
    1071                 : }
    1072                 : 
    1073                 : /************************************************************************/
    1074                 : /*                        DBFReadStringAttribute()                      */
    1075                 : /*                                                                      */
    1076                 : /*      Read a string attribute.                                        */
    1077                 : /************************************************************************/
    1078                 : 
    1079                 : const char SHPAPI_CALL1(*)
    1080           99404 : DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
    1081                 : 
    1082                 : {
    1083           99404 :     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
    1084                 : }
    1085                 : 
    1086                 : /************************************************************************/
    1087                 : /*                        DBFReadLogicalAttribute()                     */
    1088                 : /*                                                                      */
    1089                 : /*      Read a logical attribute.                                       */
    1090                 : /************************************************************************/
    1091                 : 
    1092                 : const char SHPAPI_CALL1(*)
    1093               0 : DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
    1094                 : 
    1095                 : {
    1096               0 :     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
    1097                 : }
    1098                 : 
    1099                 : 
    1100                 : /************************************************************************/
    1101                 : /*                         DBFIsValueNULL()                             */
    1102                 : /*                                                                      */
    1103                 : /*      Return TRUE if the passed string is NULL.                       */
    1104                 : /************************************************************************/
    1105                 : 
    1106           87232 : static int DBFIsValueNULL( char chType, const char* pszValue )
    1107                 : {
    1108                 :     int i;
    1109                 : 
    1110           87232 :     if( pszValue == NULL )
    1111               0 :         return TRUE;
    1112                 : 
    1113           87232 :     switch(chType)
    1114                 :     {
    1115                 :       case 'N':
    1116                 :       case 'F':
    1117                 :         /*
    1118                 :         ** We accept all asterisks or all blanks as NULL
    1119                 :         ** though according to the spec I think it should be all
    1120                 :         ** asterisks.
    1121                 :         */
    1122           87190 :         if( pszValue[0] == '*' )
    1123             104 :             return TRUE;
    1124                 : 
    1125           87156 :         for( i = 0; pszValue[i] != '\0'; i++ )
    1126                 :         {
    1127           87154 :             if( pszValue[i] != ' ' )
    1128           87084 :                 return FALSE;
    1129                 :         }
    1130               2 :         return TRUE;
    1131                 : 
    1132                 :       case 'D':
    1133                 :         /* NULL date fields have value "00000000" */
    1134               4 :         return strncmp(pszValue,"00000000",8) == 0;
    1135                 : 
    1136                 :       case 'L':
    1137                 :         /* NULL boolean fields have value "?" */
    1138               0 :         return pszValue[0] == '?';
    1139                 : 
    1140                 :       default:
    1141                 :         /* empty string fields are considered NULL */
    1142              38 :         return strlen(pszValue) == 0;
    1143                 :     }
    1144                 : }
    1145                 : 
    1146                 : /************************************************************************/
    1147                 : /*                         DBFIsAttributeNULL()                         */
    1148                 : /*                                                                      */
    1149                 : /*      Return TRUE if value for field is NULL.                         */
    1150                 : /*                                                                      */
    1151                 : /*      Contributed by Jim Matthews.                                    */
    1152                 : /************************************************************************/
    1153                 : 
    1154                 : int SHPAPI_CALL
    1155           87154 : DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
    1156                 : 
    1157                 : {
    1158                 :     const char  *pszValue;
    1159                 : 
    1160           87154 :     pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
    1161                 : 
    1162           87154 :     if( pszValue == NULL )
    1163               0 :         return TRUE;
    1164                 : 
    1165           87154 :     return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue );
    1166                 : }
    1167                 : 
    1168                 : /************************************************************************/
    1169                 : /*                          DBFGetFieldCount()                          */
    1170                 : /*                                                                      */
    1171                 : /*      Return the number of fields in this table.                      */
    1172                 : /************************************************************************/
    1173                 : 
    1174                 : int SHPAPI_CALL
    1175        14674398 : DBFGetFieldCount( DBFHandle psDBF )
    1176                 : 
    1177                 : {
    1178        14674398 :     return( psDBF->nFields );
    1179                 : }
    1180                 : 
    1181                 : /************************************************************************/
    1182                 : /*                         DBFGetRecordCount()                          */
    1183                 : /*                                                                      */
    1184                 : /*      Return the number of records in this table.                     */
    1185                 : /************************************************************************/
    1186                 : 
    1187                 : int SHPAPI_CALL
    1188          118072 : DBFGetRecordCount( DBFHandle psDBF )
    1189                 : 
    1190                 : {
    1191          118072 :     return( psDBF->nRecords );
    1192                 : }
    1193                 : 
    1194                 : /************************************************************************/
    1195                 : /*                          DBFGetFieldInfo()                           */
    1196                 : /*                                                                      */
    1197                 : /*      Return any requested information about the field.               */
    1198                 : /************************************************************************/
    1199                 : 
    1200                 : DBFFieldType SHPAPI_CALL
    1201        14580618 : DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
    1202                 :                  int * pnWidth, int * pnDecimals )
    1203                 : 
    1204                 : {
    1205        14580618 :     if( iField < 0 || iField >= psDBF->nFields )
    1206               0 :         return( FTInvalid );
    1207                 : 
    1208        14580618 :     if( pnWidth != NULL )
    1209            6570 :         *pnWidth = psDBF->panFieldSize[iField];
    1210                 : 
    1211        14580618 :     if( pnDecimals != NULL )
    1212            6570 :         *pnDecimals = psDBF->panFieldDecimals[iField];
    1213                 : 
    1214        14580618 :     if( pszFieldName != NULL )
    1215                 :     {
    1216                 :   int i;
    1217                 : 
    1218        14580618 :   strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
    1219        14580618 :   pszFieldName[11] = '\0';
    1220        14580618 :   for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
    1221               0 :       pszFieldName[i] = '\0';
    1222                 :     }
    1223                 : 
    1224        14580618 :     if ( psDBF->pachFieldType[iField] == 'L' )
    1225               0 :   return( FTLogical);
    1226                 : 
    1227        16602666 :     else if( psDBF->pachFieldType[iField] == 'N' 
    1228         2022048 :              || psDBF->pachFieldType[iField] == 'F' )
    1229                 :     {
    1230        25115522 :   if( psDBF->panFieldDecimals[iField] > 0 
    1231        12556952 :             || psDBF->panFieldSize[iField] > 10 )
    1232            3710 :       return( FTDouble );
    1233                 :   else
    1234        12554860 :       return( FTInteger );
    1235                 :     }
    1236                 :     else
    1237                 :     {
    1238         2022048 :   return( FTString );
    1239                 :     }
    1240                 : }
    1241                 : 
    1242                 : /************************************************************************/
    1243                 : /*                         DBFWriteAttribute()                          */
    1244                 : /*                  */
    1245                 : /*  Write an attribute record to the file.        */
    1246                 : /************************************************************************/
    1247                 : 
    1248           63412 : static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
    1249                 :            void * pValue )
    1250                 : 
    1251                 : {
    1252           63412 :     int         i, j, nRetResult = TRUE;
    1253                 :     unsigned char *pabyRec;
    1254                 :     char  szSField[400], szFormat[20];
    1255                 : 
    1256                 : /* -------------------------------------------------------------------- */
    1257                 : /*  Is this a valid record?           */
    1258                 : /* -------------------------------------------------------------------- */
    1259           63412 :     if( hEntity < 0 || hEntity > psDBF->nRecords )
    1260               0 :         return( FALSE );
    1261                 : 
    1262           63412 :     if( psDBF->bNoHeader )
    1263            2340 :         DBFWriteHeader(psDBF);
    1264                 : 
    1265                 : /* -------------------------------------------------------------------- */
    1266                 : /*      Is this a brand new record?                                     */
    1267                 : /* -------------------------------------------------------------------- */
    1268           63412 :     if( hEntity == psDBF->nRecords )
    1269                 :     {
    1270           57340 :   if( !DBFFlushRecord( psDBF ) )
    1271               0 :             return FALSE;
    1272                 : 
    1273           57340 :   psDBF->nRecords++;
    1274         1195362 :   for( i = 0; i < psDBF->nRecordLength; i++ )
    1275         1138022 :       psDBF->pszCurrentRecord[i] = ' ';
    1276                 : 
    1277           57340 :   psDBF->nCurrentRecord = hEntity;
    1278                 :     }
    1279                 : 
    1280                 : /* -------------------------------------------------------------------- */
    1281                 : /*      Is this an existing record, but different than the last one     */
    1282                 : /*      we accessed?                                                    */
    1283                 : /* -------------------------------------------------------------------- */
    1284           63412 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1285               0 :         return FALSE;
    1286                 : 
    1287           63412 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
    1288                 : 
    1289           63412 :     psDBF->bCurrentRecordModified = TRUE;
    1290           63412 :     psDBF->bUpdated = TRUE;
    1291                 : 
    1292                 : /* -------------------------------------------------------------------- */
    1293                 : /*      Translate NULL value to valid DBF file representation.          */
    1294                 : /*                                                                      */
    1295                 : /*      Contributed by Jim Matthews.                                    */
    1296                 : /* -------------------------------------------------------------------- */
    1297           63412 :     if( pValue == NULL )
    1298                 :     {
    1299              68 :         memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1300              34 :                 DBFGetNullCharacter(psDBF->pachFieldType[iField]),
    1301              34 :                 psDBF->panFieldSize[iField] );
    1302              34 :         return TRUE;
    1303                 :     }
    1304                 : 
    1305                 : /* -------------------------------------------------------------------- */
    1306                 : /*      Assign all the record fields.                                   */
    1307                 : /* -------------------------------------------------------------------- */
    1308           63378 :     switch( psDBF->pachFieldType[iField] )
    1309                 :     {
    1310                 :       case 'D':
    1311                 :       case 'N':
    1312                 :       case 'F':
    1313           56688 :   if( psDBF->panFieldDecimals[iField] == 0 )
    1314                 :   {
    1315           55238 :             int   nWidth = psDBF->panFieldSize[iField];
    1316                 : 
    1317           55238 :             if( (int) sizeof(szSField)-2 < nWidth )
    1318               0 :                 nWidth = sizeof(szSField)-2;
    1319                 : 
    1320           55238 :       sprintf( szFormat, "%%%dd", nWidth );
    1321           55238 :       sprintf(szSField, szFormat, (int) *((double *) pValue) );
    1322           55238 :       if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
    1323                 :             {
    1324               0 :           szSField[psDBF->panFieldSize[iField]] = '\0';
    1325               0 :                 nRetResult = FALSE;
    1326                 :             }
    1327                 : 
    1328           55238 :       strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1329                 :         szSField, strlen(szSField) );
    1330                 :   }
    1331                 :   else
    1332                 :   {
    1333            1450 :             int   nWidth = psDBF->panFieldSize[iField];
    1334                 : 
    1335            1450 :             if( (int) sizeof(szSField)-2 < nWidth )
    1336               0 :                 nWidth = sizeof(szSField)-2;
    1337                 : 
    1338            1450 :       sprintf( szFormat, "%%%d.%df", 
    1339            1450 :                      nWidth, psDBF->panFieldDecimals[iField] );
    1340            1450 :       sprintf(szSField, szFormat, *((double *) pValue) );
    1341            1450 :       if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
    1342                 :             {
    1343               0 :           szSField[psDBF->panFieldSize[iField]] = '\0';
    1344               0 :                 nRetResult = FALSE;
    1345                 :             }
    1346            1450 :       strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1347                 :         szSField, strlen(szSField) );
    1348                 :   }
    1349           56688 :   break;
    1350                 : 
    1351                 :       case 'L':
    1352               0 :         if (psDBF->panFieldSize[iField] >= 1  && 
    1353               0 :             (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
    1354               0 :             *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
    1355               0 :         break;
    1356                 : 
    1357                 :       default:
    1358            6690 :   if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
    1359                 :         {
    1360               2 :       j = psDBF->panFieldSize[iField];
    1361               2 :             nRetResult = FALSE;
    1362                 :         }
    1363                 :   else
    1364                 :         {
    1365            6688 :             memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
    1366            6688 :                     psDBF->panFieldSize[iField] );
    1367            6688 :       j = strlen((char *) pValue);
    1368                 :         }
    1369                 : 
    1370            6690 :   strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1371                 :     (char *) pValue, j );
    1372                 :   break;
    1373                 :     }
    1374                 : 
    1375           63378 :     return( nRetResult );
    1376                 : }
    1377                 : 
    1378                 : /************************************************************************/
    1379                 : /*                     DBFWriteAttributeDirectly()                      */
    1380                 : /*                                                                      */
    1381                 : /*      Write an attribute record to the file, but without any          */
    1382                 : /*      reformatting based on type.  The provided buffer is written     */
    1383                 : /*      as is to the field position in the record.                      */
    1384                 : /************************************************************************/
    1385                 : 
    1386                 : int SHPAPI_CALL
    1387            9910 : DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
    1388                 :                               void * pValue )
    1389                 : 
    1390                 : {
    1391                 :     int           i, j;
    1392                 :     unsigned char *pabyRec;
    1393                 : 
    1394                 : /* -------------------------------------------------------------------- */
    1395                 : /*  Is this a valid record?           */
    1396                 : /* -------------------------------------------------------------------- */
    1397            9910 :     if( hEntity < 0 || hEntity > psDBF->nRecords )
    1398               0 :         return( FALSE );
    1399                 : 
    1400            9910 :     if( psDBF->bNoHeader )
    1401              30 :         DBFWriteHeader(psDBF);
    1402                 : 
    1403                 : /* -------------------------------------------------------------------- */
    1404                 : /*      Is this a brand new record?                                     */
    1405                 : /* -------------------------------------------------------------------- */
    1406            9910 :     if( hEntity == psDBF->nRecords )
    1407                 :     {
    1408            1686 :   if( !DBFFlushRecord( psDBF ) )
    1409               0 :             return FALSE;
    1410                 : 
    1411            1686 :   psDBF->nRecords++;
    1412          104128 :   for( i = 0; i < psDBF->nRecordLength; i++ )
    1413          102442 :       psDBF->pszCurrentRecord[i] = ' ';
    1414                 : 
    1415            1686 :   psDBF->nCurrentRecord = hEntity;
    1416                 :     }
    1417                 : 
    1418                 : /* -------------------------------------------------------------------- */
    1419                 : /*      Is this an existing record, but different than the last one     */
    1420                 : /*      we accessed?                                                    */
    1421                 : /* -------------------------------------------------------------------- */
    1422            9910 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1423               0 :         return FALSE;
    1424                 : 
    1425            9910 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
    1426                 : 
    1427                 : /* -------------------------------------------------------------------- */
    1428                 : /*      Assign all the record fields.                                   */
    1429                 : /* -------------------------------------------------------------------- */
    1430            9910 :     if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
    1431               0 :         j = psDBF->panFieldSize[iField];
    1432                 :     else
    1433                 :     {
    1434            9910 :         memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
    1435            9910 :                 psDBF->panFieldSize[iField] );
    1436            9910 :         j = strlen((char *) pValue);
    1437                 :     }
    1438                 : 
    1439            9910 :     strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
    1440                 :             (char *) pValue, j );
    1441                 : 
    1442            9910 :     psDBF->bCurrentRecordModified = TRUE;
    1443            9910 :     psDBF->bUpdated = TRUE;
    1444                 : 
    1445            9910 :     return( TRUE );
    1446                 : }
    1447                 : 
    1448                 : /************************************************************************/
    1449                 : /*                      DBFWriteDoubleAttribute()                       */
    1450                 : /*                                                                      */
    1451                 : /*      Write a double attribute.                                       */
    1452                 : /************************************************************************/
    1453                 : 
    1454                 : int SHPAPI_CALL
    1455            2636 : DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
    1456                 :                          double dValue )
    1457                 : 
    1458                 : {
    1459            2636 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
    1460                 : }
    1461                 : 
    1462                 : /************************************************************************/
    1463                 : /*                      DBFWriteIntegerAttribute()                      */
    1464                 : /*                                                                      */
    1465                 : /*      Write a integer attribute.                                      */
    1466                 : /************************************************************************/
    1467                 : 
    1468                 : int SHPAPI_CALL
    1469           54052 : DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
    1470                 :                           int nValue )
    1471                 : 
    1472                 : {
    1473           54052 :     double  dValue = nValue;
    1474                 : 
    1475           54052 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
    1476                 : }
    1477                 : 
    1478                 : /************************************************************************/
    1479                 : /*                      DBFWriteStringAttribute()                       */
    1480                 : /*                                                                      */
    1481                 : /*      Write a string attribute.                                       */
    1482                 : /************************************************************************/
    1483                 : 
    1484                 : int SHPAPI_CALL
    1485            6690 : DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
    1486                 :                          const char * pszValue )
    1487                 : 
    1488                 : {
    1489            6690 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
    1490                 : }
    1491                 : 
    1492                 : /************************************************************************/
    1493                 : /*                      DBFWriteNULLAttribute()                         */
    1494                 : /*                                                                      */
    1495                 : /*      Write a string attribute.                                       */
    1496                 : /************************************************************************/
    1497                 : 
    1498                 : int SHPAPI_CALL
    1499              34 : DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
    1500                 : 
    1501                 : {
    1502              34 :     return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
    1503                 : }
    1504                 : 
    1505                 : /************************************************************************/
    1506                 : /*                      DBFWriteLogicalAttribute()                      */
    1507                 : /*                                                                      */
    1508                 : /*      Write a logical attribute.                                      */
    1509                 : /************************************************************************/
    1510                 : 
    1511                 : int SHPAPI_CALL
    1512               0 : DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
    1513                 :            const char lValue)
    1514                 : 
    1515                 : {
    1516               0 :     return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
    1517                 : }
    1518                 : 
    1519                 : /************************************************************************/
    1520                 : /*                         DBFWriteTuple()                              */
    1521                 : /*                  */
    1522                 : /*  Write an attribute record to the file.        */
    1523                 : /************************************************************************/
    1524                 : 
    1525                 : int SHPAPI_CALL
    1526              56 : DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
    1527                 : 
    1528                 : {
    1529                 :     int           i;
    1530                 :     unsigned char *pabyRec;
    1531                 : 
    1532                 : /* -------------------------------------------------------------------- */
    1533                 : /*  Is this a valid record?           */
    1534                 : /* -------------------------------------------------------------------- */
    1535              56 :     if( hEntity < 0 || hEntity > psDBF->nRecords )
    1536               0 :         return( FALSE );
    1537                 : 
    1538              56 :     if( psDBF->bNoHeader )
    1539               0 :         DBFWriteHeader(psDBF);
    1540                 : 
    1541                 : /* -------------------------------------------------------------------- */
    1542                 : /*      Is this a brand new record?                                     */
    1543                 : /* -------------------------------------------------------------------- */
    1544              56 :     if( hEntity == psDBF->nRecords )
    1545                 :     {
    1546              56 :   if( !DBFFlushRecord( psDBF ) )
    1547               0 :             return FALSE;
    1548                 : 
    1549              56 :   psDBF->nRecords++;
    1550            3796 :   for( i = 0; i < psDBF->nRecordLength; i++ )
    1551            3740 :       psDBF->pszCurrentRecord[i] = ' ';
    1552                 : 
    1553              56 :   psDBF->nCurrentRecord = hEntity;
    1554                 :     }
    1555                 : 
    1556                 : /* -------------------------------------------------------------------- */
    1557                 : /*      Is this an existing record, but different than the last one     */
    1558                 : /*      we accessed?                                                    */
    1559                 : /* -------------------------------------------------------------------- */
    1560              56 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1561               0 :         return FALSE;
    1562                 : 
    1563              56 :     pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
    1564                 : 
    1565              56 :     memcpy ( pabyRec, pRawTuple,  psDBF->nRecordLength );
    1566                 : 
    1567              56 :     psDBF->bCurrentRecordModified = TRUE;
    1568              56 :     psDBF->bUpdated = TRUE;
    1569                 : 
    1570              56 :     return( TRUE );
    1571                 : }
    1572                 : 
    1573                 : /************************************************************************/
    1574                 : /*                            DBFReadTuple()                            */
    1575                 : /*                                                                      */
    1576                 : /*      Read a complete record.  Note that the result is only valid     */
    1577                 : /*      till the next record read for any reason.                       */
    1578                 : /************************************************************************/
    1579                 : 
    1580                 : const char SHPAPI_CALL1(*)
    1581              56 : DBFReadTuple(DBFHandle psDBF, int hEntity )
    1582                 : 
    1583                 : {
    1584              56 :     if( hEntity < 0 || hEntity >= psDBF->nRecords )
    1585               0 :         return( NULL );
    1586                 : 
    1587              56 :     if( !DBFLoadRecord( psDBF, hEntity ) )
    1588               0 :         return NULL;
    1589                 : 
    1590              56 :     return (const char *) psDBF->pszCurrentRecord;
    1591                 : }
    1592                 : 
    1593                 : /************************************************************************/
    1594                 : /*                          DBFCloneEmpty()                              */
    1595                 : /*                                                                      */
    1596                 : /*      Read one of the attribute fields of a record.                   */
    1597                 : /************************************************************************/
    1598                 : 
    1599                 : DBFHandle SHPAPI_CALL
    1600               6 : DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) 
    1601                 : {
    1602                 :     DBFHandle newDBF;
    1603                 : 
    1604               6 :    newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
    1605               6 :    if ( newDBF == NULL ) return ( NULL ); 
    1606                 :    
    1607               6 :    newDBF->nFields = psDBF->nFields;
    1608               6 :    newDBF->nRecordLength = psDBF->nRecordLength;
    1609               6 :    newDBF->nHeaderLength = psDBF->nHeaderLength;
    1610                 :     
    1611               6 :    newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength );
    1612               6 :    memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength );
    1613                 :    
    1614               6 :    newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); 
    1615               6 :    memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
    1616               6 :    newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
    1617               6 :    memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
    1618               6 :    newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
    1619               6 :    memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
    1620               6 :    newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields );
    1621               6 :    memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
    1622                 : 
    1623               6 :    newDBF->bNoHeader = TRUE;
    1624               6 :    newDBF->bUpdated = TRUE;
    1625                 :    
    1626               6 :    DBFWriteHeader ( newDBF );
    1627               6 :    DBFClose ( newDBF );
    1628                 :    
    1629               6 :    newDBF = DBFOpen ( pszFilename, "rb+" );
    1630                 : 
    1631               6 :    return ( newDBF );
    1632                 : }
    1633                 : 
    1634                 : /************************************************************************/
    1635                 : /*                       DBFGetNativeFieldType()                        */
    1636                 : /*                                                                      */
    1637                 : /*      Return the DBase field type for the specified field.            */
    1638                 : /*                                                                      */
    1639                 : /*      Value can be one of: 'C' (String), 'D' (Date), 'F' (Float),     */
    1640                 : /*                           'N' (Numeric, with or without decimal),    */
    1641                 : /*                           'L' (Logical),                             */
    1642                 : /*                           'M' (Memo: 10 digits .DBT block ptr)       */
    1643                 : /************************************************************************/
    1644                 : 
    1645                 : char SHPAPI_CALL
    1646            6570 : DBFGetNativeFieldType( DBFHandle psDBF, int iField )
    1647                 : 
    1648                 : {
    1649            6570 :     if( iField >=0 && iField < psDBF->nFields )
    1650            6570 :         return psDBF->pachFieldType[iField];
    1651                 : 
    1652               0 :     return  ' ';
    1653                 : }
    1654                 : 
    1655                 : /************************************************************************/
    1656                 : /*                            str_to_upper()                            */
    1657                 : /************************************************************************/
    1658                 : 
    1659        14599448 : static void str_to_upper (char *string)
    1660                 : {
    1661                 :     int len;
    1662        14599448 :     short i = -1;
    1663                 : 
    1664        14599448 :     len = strlen (string);
    1665                 : 
    1666       118268256 :     while (++i < len)
    1667        89069360 :         if (isalpha(string[i]) && islower(string[i]))
    1668        43823098 :             string[i] = (char) toupper ((int)string[i]);
    1669        14599448 : }
    1670                 : 
    1671                 : /************************************************************************/
    1672                 : /*                          DBFGetFieldIndex()                          */
    1673                 : /*                                                                      */
    1674                 : /*      Get the index number for a field in a .dbf file.                */
    1675                 : /*                                                                      */
    1676                 : /*      Contributed by Jim Matthews.                                    */
    1677                 : /************************************************************************/
    1678                 : 
    1679                 : int SHPAPI_CALL
    1680           25400 : DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
    1681                 : 
    1682                 : {
    1683                 :     char          name[12], name1[12], name2[12];
    1684                 :     int           i;
    1685                 : 
    1686           25400 :     strncpy(name1, pszFieldName,11);
    1687           25400 :     name1[11] = '\0';
    1688           25400 :     str_to_upper(name1);
    1689                 : 
    1690        14599076 :     for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
    1691                 :     {
    1692        14574048 :         DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
    1693        14574048 :         strncpy(name2,name,11);
    1694        14574048 :         str_to_upper(name2);
    1695                 : 
    1696        14574048 :         if(!strncmp(name1,name2,10))
    1697             372 :             return(i);
    1698                 :     }
    1699           25028 :     return(-1);
    1700                 : }
    1701                 : 
    1702                 : /************************************************************************/
    1703                 : /*                         DBFIsRecordDeleted()                         */
    1704                 : /*                                                                      */
    1705                 : /*      Returns TRUE if the indicated record is deleted, otherwise      */
    1706                 : /*      it returns FALSE.                                               */
    1707                 : /************************************************************************/
    1708                 : 
    1709          163144 : int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
    1710                 : 
    1711                 : {
    1712                 : /* -------------------------------------------------------------------- */
    1713                 : /*      Verify selection.                                               */
    1714                 : /* -------------------------------------------------------------------- */
    1715          163144 :     if( iShape < 0 || iShape >= psDBF->nRecords )
    1716               0 :         return TRUE;
    1717                 : 
    1718                 : /* -------------------------------------------------------------------- */
    1719                 : /*  Have we read the record?          */
    1720                 : /* -------------------------------------------------------------------- */
    1721          163144 :     if( !DBFLoadRecord( psDBF, iShape ) )
    1722               0 :         return FALSE;
    1723                 : 
    1724                 : /* -------------------------------------------------------------------- */
    1725                 : /*      '*' means deleted.                                              */
    1726                 : /* -------------------------------------------------------------------- */
    1727          163144 :     return psDBF->pszCurrentRecord[0] == '*';
    1728                 : }
    1729                 : 
    1730                 : /************************************************************************/
    1731                 : /*                        DBFMarkRecordDeleted()                        */
    1732                 : /************************************************************************/
    1733                 : 
    1734              14 : int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, 
    1735                 :                                       int bIsDeleted )
    1736                 : 
    1737                 : {
    1738                 :     char chNewFlag;
    1739                 : 
    1740                 : /* -------------------------------------------------------------------- */
    1741                 : /*      Verify selection.                                               */
    1742                 : /* -------------------------------------------------------------------- */
    1743              14 :     if( iShape < 0 || iShape >= psDBF->nRecords )
    1744               0 :         return FALSE;
    1745                 : 
    1746                 : /* -------------------------------------------------------------------- */
    1747                 : /*      Is this an existing record, but different than the last one     */
    1748                 : /*      we accessed?                                                    */
    1749                 : /* -------------------------------------------------------------------- */
    1750              14 :     if( !DBFLoadRecord( psDBF, iShape ) )
    1751               0 :         return FALSE;
    1752                 : 
    1753                 : /* -------------------------------------------------------------------- */
    1754                 : /*      Assign value, marking record as dirty if it changes.            */
    1755                 : /* -------------------------------------------------------------------- */
    1756              14 :     if( bIsDeleted )
    1757              14 :         chNewFlag = '*';
    1758                 :     else 
    1759               0 :         chNewFlag = ' ';
    1760                 : 
    1761              14 :     if( psDBF->pszCurrentRecord[0] != chNewFlag )
    1762                 :     {
    1763              14 :         psDBF->bCurrentRecordModified = TRUE;
    1764              14 :         psDBF->bUpdated = TRUE;
    1765              14 :         psDBF->pszCurrentRecord[0] = chNewFlag;
    1766                 :     }
    1767                 : 
    1768              14 :     return TRUE;
    1769                 : }
    1770                 : 
    1771                 : /************************************************************************/
    1772                 : /*                            DBFGetCodePage                            */
    1773                 : /************************************************************************/
    1774                 : 
    1775                 : const char SHPAPI_CALL1(*)
    1776               0 : DBFGetCodePage(DBFHandle psDBF )
    1777                 : {
    1778               0 :     if( psDBF == NULL )
    1779               0 :         return NULL;
    1780               0 :     return psDBF->pszCodePage;
    1781                 : }
    1782                 : 
    1783                 : /************************************************************************/
    1784                 : /*                          DBFDeleteField()                            */
    1785                 : /*                                                                      */
    1786                 : /*      Remove a field from a .dbf file                                 */
    1787                 : /************************************************************************/
    1788                 : 
    1789                 : int SHPAPI_CALL
    1790              12 : DBFDeleteField(DBFHandle psDBF, int iField)
    1791                 : {
    1792                 :     int nOldRecordLength, nOldHeaderLength;
    1793                 :     int nDeletedFieldOffset, nDeletedFieldSize;
    1794                 :     SAOffset nRecordOffset;
    1795                 :     char* pszRecord;
    1796                 :     int i, iRecord;
    1797                 : 
    1798              12 :     if (iField < 0 || iField >= psDBF->nFields)
    1799               0 :         return FALSE;
    1800                 : 
    1801                 :     /* make sure that everything is written in .dbf */
    1802              12 :     if( !DBFFlushRecord( psDBF ) )
    1803               0 :         return FALSE;
    1804                 : 
    1805                 :     /* get information about field to be deleted */
    1806              12 :     nOldRecordLength = psDBF->nRecordLength;
    1807              12 :     nOldHeaderLength = psDBF->nHeaderLength;
    1808              12 :     nDeletedFieldOffset = psDBF->panFieldOffset[iField];
    1809              12 :     nDeletedFieldSize = psDBF->panFieldSize[iField];
    1810                 : 
    1811                 :     /* update fields info */
    1812              30 :     for (i = iField + 1; i < psDBF->nFields; i++)
    1813                 :     {
    1814              18 :         psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize;
    1815              18 :         psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i];
    1816              18 :         psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i];
    1817              18 :         psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i];
    1818                 :     }
    1819                 : 
    1820                 :     /* resize fields arrays */
    1821              12 :     psDBF->nFields--;
    1822                 : 
    1823              24 :     psDBF->panFieldOffset = (int *) 
    1824              12 :         SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
    1825                 : 
    1826              24 :     psDBF->panFieldSize = (int *) 
    1827              12 :         SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
    1828                 : 
    1829              24 :     psDBF->panFieldDecimals = (int *) 
    1830              12 :         SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
    1831                 : 
    1832              24 :     psDBF->pachFieldType = (char *) 
    1833              12 :         SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
    1834                 : 
    1835                 :     /* update header information */
    1836              12 :     psDBF->nHeaderLength -= 32;
    1837              12 :     psDBF->nRecordLength -= nDeletedFieldSize;
    1838                 : 
    1839                 :     /* overwrite field information in header */
    1840              24 :     memmove(psDBF->pszHeader + iField*32,
    1841              12 :            psDBF->pszHeader + (iField+1)*32,
    1842              12 :            sizeof(char) * (psDBF->nFields - iField)*32);
    1843                 : 
    1844              12 :     psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
    1845                 : 
    1846                 :     /* update size of current record appropriately */
    1847              12 :     psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
    1848                 :                                                  psDBF->nRecordLength);
    1849                 : 
    1850                 :     /* we're done if we're dealing with not yet created .dbf */
    1851              12 :     if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
    1852               0 :         return TRUE;
    1853                 : 
    1854                 :     /* force update of header with new header and record length */
    1855              12 :     psDBF->bNoHeader = TRUE;
    1856              12 :     DBFUpdateHeader( psDBF );
    1857                 : 
    1858                 :     /* alloc record */
    1859              12 :     pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
    1860                 : 
    1861                 :     /* shift records to their new positions */
    1862              60 :     for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
    1863                 :     {
    1864              48 :         nRecordOffset = 
    1865              48 :             nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength;
    1866                 : 
    1867                 :         /* load record */
    1868              48 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    1869              48 :         psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
    1870                 : 
    1871              48 :         nRecordOffset = 
    1872              48 :             psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    1873                 : 
    1874                 :         /* move record in two steps */
    1875              48 :         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    1876              48 :         psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp );
    1877              96 :         psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize,
    1878              48 :                               nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize,
    1879                 :                               1, psDBF->fp );
    1880                 : 
    1881                 :     }
    1882                 : 
    1883                 :     /* TODO: truncate file */
    1884                 : 
    1885                 :     /* free record */
    1886              12 :     free(pszRecord);
    1887                 : 
    1888              12 :     psDBF->nCurrentRecord = -1;
    1889              12 :     psDBF->bCurrentRecordModified = FALSE;
    1890                 : 
    1891              12 :     return TRUE;
    1892                 : }
    1893                 : 
    1894                 : /************************************************************************/
    1895                 : /*                          DBFReorderFields()                          */
    1896                 : /*                                                                      */
    1897                 : /*      Reorder the fields of a .dbf file                               */
    1898                 : /*                                                                      */
    1899                 : /* panMap must be exactly psDBF->nFields long and be a permutation      */
    1900                 : /* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/
    1901                 : /* code of DBFReorderFields.                                            */
    1902                 : /************************************************************************/
    1903                 : 
    1904                 : int SHPAPI_CALL
    1905              20 : DBFReorderFields( DBFHandle psDBF, int* panMap )
    1906                 : {
    1907                 :     SAOffset nRecordOffset;
    1908                 :     int      i, iRecord;
    1909                 :     int     *panFieldOffsetNew;
    1910                 :     int     *panFieldSizeNew;
    1911                 :     int     *panFieldDecimalsNew;
    1912                 :     char    *pachFieldTypeNew;
    1913                 :     char    *pszHeaderNew;
    1914                 :     char    *pszRecord;
    1915                 :     char    *pszRecordNew;
    1916                 : 
    1917              20 :     if ( psDBF->nFields == 0 )
    1918               0 :         return TRUE;
    1919                 : 
    1920                 :     /* make sure that everything is written in .dbf */
    1921              20 :     if( !DBFFlushRecord( psDBF ) )
    1922               0 :         return FALSE;
    1923                 : 
    1924              20 :     panFieldOffsetNew = (int *) malloc(sizeof(int) * psDBF->nFields);
    1925              20 :     panFieldSizeNew = (int *) malloc(sizeof(int) *  psDBF->nFields);
    1926              20 :     panFieldDecimalsNew = (int *) malloc(sizeof(int) *  psDBF->nFields);
    1927              20 :     pachFieldTypeNew = (char *) malloc(sizeof(char) *  psDBF->nFields);
    1928              20 :     pszHeaderNew = (char*) malloc(sizeof(char) * 32 *  psDBF->nFields);
    1929                 : 
    1930                 :     /* shuffle fields definitions */
    1931             104 :     for(i=0; i < psDBF->nFields; i++)
    1932                 :     {
    1933              84 :         panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
    1934              84 :         panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
    1935              84 :         pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
    1936             168 :         memcpy(pszHeaderNew + i * 32,
    1937              84 :                psDBF->pszHeader + panMap[i] * 32, 32);
    1938                 :     }
    1939              20 :     panFieldOffsetNew[0] = 1;
    1940              84 :     for(i=1; i < psDBF->nFields; i++)
    1941                 :     {
    1942              64 :         panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
    1943                 :     }
    1944                 : 
    1945              20 :     free(psDBF->pszHeader);
    1946              20 :     psDBF->pszHeader = pszHeaderNew;
    1947                 : 
    1948                 :     /* we're done if we're dealing with not yet created .dbf */
    1949              20 :     if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) )
    1950                 :     {
    1951                 :         /* force update of header with new header and record length */
    1952              20 :         psDBF->bNoHeader = TRUE;
    1953              20 :         DBFUpdateHeader( psDBF );
    1954                 : 
    1955                 :         /* alloc record */
    1956              20 :         pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
    1957              20 :         pszRecordNew = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
    1958                 : 
    1959                 :         /* shuffle fields in records */
    1960             100 :         for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
    1961                 :         {
    1962              80 :             nRecordOffset =
    1963              80 :                 psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    1964                 : 
    1965                 :             /* load record */
    1966              80 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    1967              80 :             psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
    1968                 : 
    1969              80 :             pszRecordNew[0] = pszRecord[0];
    1970                 : 
    1971             416 :             for(i=0; i < psDBF->nFields; i++)
    1972                 :             {
    1973             672 :                 memcpy(pszRecordNew + panFieldOffsetNew[i],
    1974             336 :                        pszRecord + psDBF->panFieldOffset[panMap[i]],
    1975             336 :                        psDBF->panFieldSize[panMap[i]]);
    1976                 :             }
    1977                 : 
    1978                 :             /* write record */
    1979              80 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    1980              80 :             psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp );
    1981                 :         }
    1982                 : 
    1983                 :         /* free record */
    1984              20 :         free(pszRecord);
    1985              20 :         free(pszRecordNew);
    1986                 :     }
    1987                 : 
    1988              20 :     free(psDBF->panFieldOffset);
    1989              20 :     free(psDBF->panFieldSize);
    1990              20 :     free(psDBF->panFieldDecimals);
    1991              20 :     free(psDBF->pachFieldType);
    1992                 : 
    1993              20 :     psDBF->panFieldOffset = panFieldOffsetNew;
    1994              20 :     psDBF->panFieldSize = panFieldSizeNew;
    1995              20 :     psDBF->panFieldDecimals =panFieldDecimalsNew;
    1996              20 :     psDBF->pachFieldType = pachFieldTypeNew;
    1997                 : 
    1998              20 :     psDBF->nCurrentRecord = -1;
    1999              20 :     psDBF->bCurrentRecordModified = FALSE;
    2000                 : 
    2001              20 :     return TRUE;
    2002                 : }
    2003                 : 
    2004                 : 
    2005                 : /************************************************************************/
    2006                 : /*                          DBFAlterFieldDefn()                         */
    2007                 : /*                                                                      */
    2008                 : /*      Alter a field definition in a .dbf file                         */
    2009                 : /************************************************************************/
    2010                 : 
    2011                 : int SHPAPI_CALL
    2012              24 : DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
    2013                 :                     char chType, int nWidth, int nDecimals )
    2014                 : {
    2015                 :     int   i;
    2016                 :     int   iRecord;
    2017                 :     int   nOffset;
    2018                 :     int   nOldWidth;
    2019                 :     int   nOldRecordLength;
    2020                 :     int   nRecordOffset;
    2021                 :     char* pszFInfo;
    2022                 :     char  chOldType;
    2023                 :     int   bIsNULL;
    2024                 :     char chFieldFill;
    2025                 : 
    2026              24 :     if (iField < 0 || iField >= psDBF->nFields)
    2027               0 :         return FALSE;
    2028                 : 
    2029                 :     /* make sure that everything is written in .dbf */
    2030              24 :     if( !DBFFlushRecord( psDBF ) )
    2031               0 :         return FALSE;
    2032                 : 
    2033              24 :     chFieldFill = DBFGetNullCharacter(chType);
    2034                 : 
    2035              24 :     chOldType = psDBF->pachFieldType[iField];
    2036              24 :     nOffset = psDBF->panFieldOffset[iField];
    2037              24 :     nOldWidth = psDBF->panFieldSize[iField];
    2038              24 :     nOldRecordLength = psDBF->nRecordLength;
    2039                 : 
    2040                 : /* -------------------------------------------------------------------- */
    2041                 : /*      Do some checking to ensure we can add records to this file.     */
    2042                 : /* -------------------------------------------------------------------- */
    2043              24 :     if( nWidth < 1 )
    2044               0 :         return -1;
    2045                 : 
    2046              24 :     if( nWidth > 255 )
    2047               0 :         nWidth = 255;
    2048                 : 
    2049                 : /* -------------------------------------------------------------------- */
    2050                 : /*      Assign the new field information fields.                        */
    2051                 : /* -------------------------------------------------------------------- */
    2052              24 :     psDBF->panFieldSize[iField] = nWidth;
    2053              24 :     psDBF->panFieldDecimals[iField] = nDecimals;
    2054              24 :     psDBF->pachFieldType[iField] = chType;
    2055                 : 
    2056                 : /* -------------------------------------------------------------------- */
    2057                 : /*      Update the header information.                                  */
    2058                 : /* -------------------------------------------------------------------- */
    2059              24 :     pszFInfo = psDBF->pszHeader + 32 * iField;
    2060                 : 
    2061             792 :     for( i = 0; i < 32; i++ )
    2062             768 :         pszFInfo[i] = '\0';
    2063                 : 
    2064              24 :     if( (int) strlen(pszFieldName) < 10 )
    2065              24 :         strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
    2066                 :     else
    2067               0 :         strncpy( pszFInfo, pszFieldName, 10);
    2068                 : 
    2069              24 :     pszFInfo[11] = psDBF->pachFieldType[iField];
    2070                 : 
    2071              24 :     if( chType == 'C' )
    2072                 :     {
    2073              12 :         pszFInfo[16] = (unsigned char) (nWidth % 256);
    2074              12 :         pszFInfo[17] = (unsigned char) (nWidth / 256);
    2075                 :     }
    2076                 :     else
    2077                 :     {
    2078              12 :         pszFInfo[16] = (unsigned char) nWidth;
    2079              12 :         pszFInfo[17] = (unsigned char) nDecimals;
    2080                 :     }
    2081                 : 
    2082                 : /* -------------------------------------------------------------------- */
    2083                 : /*      Update offsets                                                  */
    2084                 : /* -------------------------------------------------------------------- */
    2085              24 :     if (nWidth != nOldWidth)
    2086                 :     {
    2087              66 :         for (i = iField + 1; i < psDBF->nFields; i++)
    2088              44 :              psDBF->panFieldOffset[i] += nWidth - nOldWidth;
    2089              22 :         psDBF->nRecordLength += nWidth - nOldWidth;
    2090                 : 
    2091              22 :         psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
    2092                 :                                                      psDBF->nRecordLength);
    2093                 :     }
    2094                 : 
    2095                 :     /* we're done if we're dealing with not yet created .dbf */
    2096              24 :     if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
    2097               0 :         return TRUE;
    2098                 : 
    2099                 :     /* force update of header with new header and record length */
    2100              24 :     psDBF->bNoHeader = TRUE;
    2101              24 :     DBFUpdateHeader( psDBF );
    2102                 : 
    2103              38 :     if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType))
    2104                 :     {
    2105              14 :         char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
    2106              14 :         char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
    2107                 : 
    2108              14 :         pszOldField[nOldWidth] = 0;
    2109                 : 
    2110                 :         /* move records to their new positions */
    2111              70 :         for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
    2112                 :         {
    2113              56 :             nRecordOffset =
    2114                 :                 nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    2115                 : 
    2116                 :             /* load record */
    2117              56 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    2118              56 :             psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
    2119                 : 
    2120              56 :             memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
    2121              56 :             bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
    2122                 : 
    2123              56 :             if (nWidth != nOldWidth)
    2124                 :             {
    2125              56 :                 if ((chOldType == 'N' || chOldType == 'F') && pszOldField[0] == ' ')
    2126                 :                 {
    2127                 :                     /* Strip leading spaces when truncating a numeric field */
    2128              40 :                     memmove( pszRecord + nOffset,
    2129              30 :                             pszRecord + nOffset + nOldWidth - nWidth,
    2130                 :                             nWidth );
    2131                 :                 }
    2132              56 :                 if (nOffset + nOldWidth < nOldRecordLength)
    2133                 :                 {
    2134             144 :                     memmove( pszRecord + nOffset + nWidth,
    2135              96 :                             pszRecord + nOffset + nOldWidth,
    2136              48 :                             nOldRecordLength - (nOffset + nOldWidth));
    2137                 :                 }
    2138                 :             }
    2139                 : 
    2140                 :             /* Convert null value to the appropriate value of the new type */
    2141              56 :             if (bIsNULL)
    2142                 :             {
    2143              28 :                 memset( pszRecord + nOffset, chFieldFill, nWidth);
    2144                 :             }
    2145                 : 
    2146              56 :             nRecordOffset =
    2147                 :                 psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    2148                 : 
    2149                 :             /* write record */
    2150              56 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    2151              56 :             psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
    2152                 :         }
    2153                 : 
    2154              14 :         free(pszRecord);
    2155              14 :         free(pszOldField);
    2156                 :     }
    2157              10 :     else if (nWidth > nOldWidth)
    2158                 :     {
    2159               8 :         char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
    2160               8 :         char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
    2161                 : 
    2162               8 :         pszOldField[nOldWidth] = 0;
    2163                 : 
    2164                 :         /* move records to their new positions */
    2165              30 :         for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
    2166                 :         {
    2167              22 :             nRecordOffset =
    2168                 :                 nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    2169                 : 
    2170                 :             /* load record */
    2171              22 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    2172              22 :             psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
    2173                 : 
    2174              22 :             memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
    2175              22 :             bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
    2176                 : 
    2177              22 :             if (nOffset + nOldWidth < nOldRecordLength)
    2178                 :             {
    2179              54 :                 memmove( pszRecord + nOffset + nWidth,
    2180              36 :                          pszRecord + nOffset + nOldWidth,
    2181              18 :                          nOldRecordLength - (nOffset + nOldWidth));
    2182                 :             }
    2183                 : 
    2184                 :             /* Convert null value to the appropriate value of the new type */
    2185              22 :             if (bIsNULL)
    2186                 :             {
    2187               8 :                 memset( pszRecord + nOffset, chFieldFill, nWidth);
    2188                 :             }
    2189                 :             else
    2190                 :             {
    2191              18 :                 if ((chOldType == 'N' || chOldType == 'F'))
    2192                 :                 {
    2193                 :                     /* Add leading spaces when expanding a numeric field */
    2194               8 :                     memmove( pszRecord + nOffset + nWidth - nOldWidth,
    2195               4 :                              pszRecord + nOffset, nOldWidth );
    2196               4 :                     memset( pszRecord + nOffset, ' ', nWidth - nOldWidth );
    2197                 :                 }
    2198                 :                 else
    2199                 :                 {
    2200                 :                     /* Add trailing spaces */
    2201              10 :                     memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth);
    2202                 :                 }
    2203                 :             }
    2204                 : 
    2205              22 :             nRecordOffset =
    2206                 :                 psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
    2207                 : 
    2208                 :             /* write record */
    2209              22 :             psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
    2210              22 :             psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
    2211                 :         }
    2212                 : 
    2213               8 :         free(pszRecord);
    2214               8 :         free(pszOldField);
    2215                 :     }
    2216                 : 
    2217              24 :     psDBF->nCurrentRecord = -1;
    2218              24 :     psDBF->bCurrentRecordModified = FALSE;
    2219                 : 
    2220              24 :     return TRUE;
    2221                 : }

Generated by: LCOV version 1.7