LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - dbfopen.c
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 609
Code covered: 73.2 % Executed lines: 446

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

Generated by: LTP GCOV extension version 1.5