LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - ogrshapelayer.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 496
Code covered: 80.0 % Executed lines: 397

       1                 : /******************************************************************************
       2                 :  * $Id: ogrshapelayer.cpp 19940 2010-06-27 21:16:19Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements OGRShapeLayer class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 1999,  Les Technologies SoftMap Inc.
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "ogrshape.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "cpl_string.h"
      33                 : 
      34                 : #if defined(_WIN32_WCE)
      35                 : #  include <wce_errno.h>
      36                 : #endif
      37                 : 
      38                 : #if defined(WIN32) || defined(WIN32CE)
      39                 : #define SEP_CHAR '\\'
      40                 : #else
      41                 : #define SEP_CHAR '/'
      42                 : #endif
      43                 : 
      44                 : 
      45                 : 
      46                 : CPL_CVSID("$Id: ogrshapelayer.cpp 19940 2010-06-27 21:16:19Z rouault $");
      47                 : 
      48                 : /************************************************************************/
      49                 : /*                           OGRShapeLayer()                            */
      50                 : /************************************************************************/
      51                 : 
      52                 : OGRShapeLayer::OGRShapeLayer( const char * pszName,
      53                 :                               SHPHandle hSHPIn, DBFHandle hDBFIn, 
      54                 :                               OGRSpatialReference *poSRSIn, int bUpdate,
      55            1023 :                               OGRwkbGeometryType eReqType )
      56                 : 
      57                 : {
      58            1023 :     poSRS = poSRSIn;
      59                 : 
      60            1023 :     pszFullName = CPLStrdup(pszName);
      61                 :     
      62            1023 :     hSHP = hSHPIn;
      63            1023 :     hDBF = hDBFIn;
      64            1023 :     bUpdateAccess = bUpdate;
      65                 : 
      66            1023 :     iNextShapeId = 0;
      67            1023 :     panMatchingFIDs = NULL;
      68                 : 
      69            1023 :     bCheckedForQIX = FALSE;
      70            1023 :     fpQIX = NULL;
      71                 : 
      72            1023 :     bHeaderDirty = FALSE;
      73                 : 
      74            1023 :     if( hSHP != NULL )
      75            1000 :         nTotalShapeCount = hSHP->nRecords;
      76                 :     else 
      77              23 :         nTotalShapeCount = hDBF->nRecords;
      78                 :     
      79                 :     poFeatureDefn = SHPReadOGRFeatureDefn( CPLGetBasename(pszName), 
      80            1023 :                                            hSHP, hDBF );
      81                 : 
      82            1023 :     eRequestedGeomType = eReqType;
      83            1023 : }
      84                 : 
      85                 : /************************************************************************/
      86                 : /*                           ~OGRShapeLayer()                           */
      87                 : /************************************************************************/
      88                 : 
      89            1023 : OGRShapeLayer::~OGRShapeLayer()
      90                 : 
      91                 : {
      92            1023 :     if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
      93                 :     {
      94                 :         CPLDebug( "Shape", "%d features read on layer '%s'.",
      95                 :                   (int) m_nFeaturesRead, 
      96             217 :                   poFeatureDefn->GetName() );
      97                 :     }
      98                 : 
      99            1023 :     CPLFree( panMatchingFIDs );
     100            1023 :     panMatchingFIDs = NULL;
     101                 : 
     102            1023 :     CPLFree( pszFullName );
     103                 : 
     104            1023 :     if( poFeatureDefn != NULL )
     105            1023 :         poFeatureDefn->Release();
     106                 : 
     107            1023 :     if( poSRS != NULL )
     108             233 :         poSRS->Release();
     109                 : 
     110            1023 :     if( hDBF != NULL )
     111            1005 :         DBFClose( hDBF );
     112                 : 
     113            1023 :     if( hSHP != NULL )
     114            1000 :         SHPClose( hSHP );
     115                 : 
     116            1023 :     if( fpQIX != NULL )
     117               4 :         VSIFClose( fpQIX );
     118            1023 : }
     119                 : 
     120                 : /************************************************************************/
     121                 : /*                            CheckForQIX()                             */
     122                 : /************************************************************************/
     123                 : 
     124              25 : int OGRShapeLayer::CheckForQIX()
     125                 : 
     126                 : {
     127                 :     const char *pszQIXFilename;
     128                 : 
     129              25 :     if( bCheckedForQIX )
     130               2 :         return fpQIX != NULL;
     131                 : 
     132              23 :     pszQIXFilename = CPLResetExtension( pszFullName, "qix" );
     133                 : 
     134              23 :     fpQIX = VSIFOpen( pszQIXFilename, "rb" );
     135                 : 
     136              23 :     bCheckedForQIX = TRUE;
     137                 : 
     138              23 :     return fpQIX != NULL;
     139                 : }
     140                 : 
     141                 : /************************************************************************/
     142                 : /*                            ScanIndices()                             */
     143                 : /*                                                                      */
     144                 : /*      Utilize optional spatial and attribute indices if they are      */
     145                 : /*      available.                                                      */
     146                 : /************************************************************************/
     147                 : 
     148             130 : int OGRShapeLayer::ScanIndices()
     149                 : 
     150                 : {
     151             130 :     iMatchingFID = 0;
     152                 : 
     153                 : /* -------------------------------------------------------------------- */
     154                 : /*      Utilize attribute index if appropriate.                         */
     155                 : /* -------------------------------------------------------------------- */
     156             130 :     if( m_poAttrQuery != NULL )
     157                 :     {
     158             106 :         CPLAssert( panMatchingFIDs == NULL );
     159                 :         panMatchingFIDs = m_poAttrQuery->EvaluateAgainstIndices( this,
     160             106 :                                                                  NULL );
     161                 :     }
     162                 : 
     163                 : /* -------------------------------------------------------------------- */
     164                 : /*      Check for spatial index if we have a spatial query.             */
     165                 : /* -------------------------------------------------------------------- */
     166             130 :     if( m_poFilterGeom != NULL && !bCheckedForQIX )
     167              14 :         CheckForQIX();
     168                 : 
     169                 : /* -------------------------------------------------------------------- */
     170                 : /*      Utilize spatial index if appropriate.                           */
     171                 : /* -------------------------------------------------------------------- */
     172             130 :     if( m_poFilterGeom && fpQIX )
     173                 :     {
     174                 :         int nSpatialFIDCount, *panSpatialFIDs;
     175                 :         double adfBoundsMin[4], adfBoundsMax[4];
     176              10 :         OGREnvelope oEnvelope;
     177                 : 
     178              10 :         m_poFilterGeom->getEnvelope( &oEnvelope );
     179                 : 
     180              10 :         adfBoundsMin[0] = oEnvelope.MinX;
     181              10 :         adfBoundsMin[1] = oEnvelope.MinY;
     182              10 :         adfBoundsMin[2] = 0.0;
     183              10 :         adfBoundsMin[3] = 0.0;
     184              10 :         adfBoundsMax[0] = oEnvelope.MaxX;
     185              10 :         adfBoundsMax[1] = oEnvelope.MaxY;
     186              10 :         adfBoundsMax[2] = 0.0;
     187              10 :         adfBoundsMax[3] = 0.0;
     188                 : 
     189                 :         panSpatialFIDs = SHPSearchDiskTree( fpQIX, 
     190                 :                                             adfBoundsMin, adfBoundsMax, 
     191              10 :                                             &nSpatialFIDCount );
     192                 :         CPLDebug( "SHAPE", "Used spatial index, got %d matches.", 
     193              10 :                   nSpatialFIDCount );
     194                 : 
     195                 :         // Use resulting list as matching FID list (but reallocate and
     196                 :         // terminate with OGRNullFID).
     197                 : 
     198              10 :         if( panMatchingFIDs == NULL )
     199                 :         {
     200                 :             int i;
     201                 : 
     202                 :             panMatchingFIDs = (long *) 
     203               8 :                 CPLMalloc(sizeof(long) * (nSpatialFIDCount+1) );
     204              42 :             for( i = 0; i < nSpatialFIDCount; i++ )
     205              34 :                 panMatchingFIDs[i] = (long) panSpatialFIDs[i];
     206               8 :             panMatchingFIDs[nSpatialFIDCount] = OGRNullFID;
     207                 :         }
     208                 : 
     209                 :         // Cull attribute index matches based on those in the spatial index
     210                 :         // result set.  We assume that the attribute results are in sorted
     211                 :         // order.
     212                 :         else
     213                 :         {
     214               2 :             int iRead, iWrite=0, iSpatial=0;
     215                 : 
     216               4 :             for( iRead = 0; panMatchingFIDs[iRead] != OGRNullFID; iRead++ )
     217                 :             {
     218               9 :                 while( iSpatial < nSpatialFIDCount
     219                 :                        && panSpatialFIDs[iSpatial] < panMatchingFIDs[iRead] )
     220               5 :                     iSpatial++;
     221                 : 
     222               2 :                 if( iSpatial == nSpatialFIDCount )
     223               0 :                     continue;
     224                 : 
     225               2 :                 if( panSpatialFIDs[iSpatial] == panMatchingFIDs[iRead] )
     226               2 :                     panMatchingFIDs[iWrite++] = panMatchingFIDs[iRead];
     227                 :             }
     228               2 :             panMatchingFIDs[iWrite] = OGRNullFID;
     229                 :         }
     230                 : 
     231              10 :         if ( panSpatialFIDs )
     232               9 :             free( panSpatialFIDs );
     233                 :     }
     234                 : 
     235             130 :     return TRUE;
     236                 : }
     237                 : 
     238                 : /************************************************************************/
     239                 : /*                            ResetReading()                            */
     240                 : /************************************************************************/
     241                 : 
     242             406 : void OGRShapeLayer::ResetReading()
     243                 : 
     244                 : {
     245                 : /* -------------------------------------------------------------------- */
     246                 : /*      Clear previous index search result, if any.                     */
     247                 : /* -------------------------------------------------------------------- */
     248             406 :     CPLFree( panMatchingFIDs );
     249             406 :     panMatchingFIDs = NULL;
     250             406 :     iMatchingFID = 0;
     251                 : 
     252             406 :     iNextShapeId = 0;
     253                 : 
     254             406 :     if( bHeaderDirty && bUpdateAccess )
     255               5 :         SyncToDisk();
     256             406 : }
     257                 : 
     258                 : /************************************************************************/
     259                 : /*                           SetNextByIndex()                           */
     260                 : /*                                                                      */
     261                 : /*      If we already have an FID list, we can easily resposition       */
     262                 : /*      ourselves in it.                                                */
     263                 : /************************************************************************/
     264                 : 
     265               0 : OGRErr OGRShapeLayer::SetNextByIndex( long nIndex )
     266                 : 
     267                 : {
     268                 :     // Eventually we should try to use panMatchingFIDs list 
     269                 :     // if available and appropriate. 
     270               0 :     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
     271               0 :         return OGRLayer::SetNextByIndex( nIndex );
     272                 : 
     273               0 :     iNextShapeId = nIndex;
     274                 : 
     275               0 :     return OGRERR_NONE;
     276                 : }
     277                 : 
     278                 : /************************************************************************/
     279                 : /*                             FetchShape()                             */
     280                 : /*                                                                      */
     281                 : /*      Take a shape id, a geometry, and a feature, and set the feature */
     282                 : /*      if the shapeid bbox intersects the geometry.                    */
     283                 : /************************************************************************/
     284                 : 
     285           17838 : OGRFeature *OGRShapeLayer::FetchShape(int iShapeId)
     286                 : 
     287                 : {
     288                 :     OGRFeature *poFeature;
     289                 : 
     290           17989 :     if (m_poFilterGeom != NULL && hSHP != NULL ) 
     291                 :     {
     292                 :         SHPObject   *psShape;
     293                 :         
     294             151 :         psShape = SHPReadObject( hSHP, iShapeId );
     295                 : 
     296                 :         // do not trust degenerate bounds or bounds on null shapes.
     297             173 :         if( psShape == NULL || psShape->dfXMin == psShape->dfXMax
     298                 :             || psShape->dfYMin == psShape->dfYMax 
     299                 :             || psShape->nSHPType == SHPT_NULL )
     300                 :         {
     301                 :             poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn,
     302              22 :                                            iShapeId, psShape );
     303                 :         }
     304             209 :         else if( m_sFilterEnvelope.MaxX < psShape->dfXMin 
     305                 :                  || m_sFilterEnvelope.MaxY < psShape->dfYMin
     306                 :                  || psShape->dfXMax  < m_sFilterEnvelope.MinX
     307                 :                  || psShape->dfYMax < m_sFilterEnvelope.MinY ) 
     308                 :         {
     309              80 :             SHPDestroyObject(psShape);
     310              80 :             poFeature = NULL;
     311                 :         } 
     312                 :         else 
     313                 :         {
     314                 :             poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn,
     315              49 :                                            iShapeId, psShape );
     316                 :         }                
     317                 :     } 
     318                 :     else 
     319                 :     {
     320                 :         poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn,
     321           17687 :                                        iShapeId, NULL );
     322                 :     }    
     323                 :     
     324           17838 :     return poFeature;
     325                 : }
     326                 : 
     327                 : /************************************************************************/
     328                 : /*                           GetNextFeature()                           */
     329                 : /************************************************************************/
     330                 : 
     331           17390 : OGRFeature *OGRShapeLayer::GetNextFeature()
     332                 : 
     333                 : {
     334           17390 :     OGRFeature  *poFeature = NULL;
     335                 : 
     336                 : /* -------------------------------------------------------------------- */
     337                 : /*      Collect a matching list if we have attribute or spatial         */
     338                 : /*      indices.  Only do this on the first request for a given pass    */
     339                 : /*      of course.                                                      */
     340                 : /* -------------------------------------------------------------------- */
     341           17390 :     if( (m_poAttrQuery != NULL || m_poFilterGeom != NULL)
     342                 :         && iNextShapeId == 0 && panMatchingFIDs == NULL )
     343                 :     {
     344             130 :         ScanIndices();
     345                 :     }
     346                 :     
     347                 : /* -------------------------------------------------------------------- */
     348                 : /*      Loop till we find a feature matching our criteria.              */
     349                 : /* -------------------------------------------------------------------- */
     350             645 :     while( TRUE )
     351                 :     {
     352           18035 :         if( panMatchingFIDs != NULL )
     353                 :         {
     354              54 :             if( panMatchingFIDs[iMatchingFID] == OGRNullFID )
     355                 :             {
     356              11 :                 return NULL;
     357                 :             }
     358                 :             
     359                 :             // Check the shape object's geometry, and if it matches
     360                 :             // any spatial filter, return it.  
     361              43 :             poFeature = FetchShape(panMatchingFIDs[iMatchingFID]);
     362                 :             
     363              43 :             iMatchingFID++;
     364                 : 
     365                 :         }
     366                 :         else
     367                 :         {
     368           17981 :             if( iNextShapeId >= nTotalShapeCount )
     369                 :             {
     370             185 :                 return NULL;
     371                 :             }
     372                 :     
     373           17796 :             if ( hDBF && DBFIsRecordDeleted( hDBF, iNextShapeId ) ) {
     374               1 :                 poFeature = NULL;
     375                 :             } else {
     376                 :                 // Check the shape object's geometry, and if it matches
     377                 :                 // any spatial filter, return it.  
     378           17795 :                 poFeature = FetchShape(iNextShapeId);
     379                 :             }
     380           17796 :             iNextShapeId++;
     381                 :         }
     382                 :         
     383           17839 :         if( poFeature != NULL )
     384                 :         {
     385           17758 :             if( poFeature->GetGeometryRef() != NULL )
     386                 :             {
     387           17239 :                 poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
     388                 :             }
     389                 : 
     390           17758 :             m_nFeaturesRead++;
     391                 : 
     392           17758 :             if( (m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) )
     393                 :                 && (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) )
     394                 :             {
     395           17194 :                 return poFeature;
     396                 :             }
     397                 : 
     398             564 :             delete poFeature;
     399                 :         }
     400                 :     }        
     401                 : 
     402                 :     /*
     403                 :      * NEVER SHOULD GET HERE
     404                 :      */
     405                 :     CPLAssert(!"OGRShapeLayer::GetNextFeature(): Execution never should get here!");
     406                 : }
     407                 : 
     408                 : /************************************************************************/
     409                 : /*                             GetFeature()                             */
     410                 : /************************************************************************/
     411                 : 
     412              51 : OGRFeature *OGRShapeLayer::GetFeature( long nFeatureId )
     413                 : 
     414                 : {
     415              51 :     OGRFeature *poFeature = NULL;
     416              51 :     poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn, nFeatureId, NULL);
     417                 : 
     418              51 :     if( poFeature != NULL )
     419                 :     {
     420              51 :         if( poFeature->GetGeometryRef() != NULL )
     421              48 :             poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
     422                 : 
     423              51 :         m_nFeaturesRead++;
     424                 :     
     425              51 :         return poFeature;
     426                 :     }
     427                 : 
     428                 :     /*
     429                 :      * Reading shape feature failed.
     430                 :      */
     431               0 :     return NULL;
     432                 : }
     433                 : 
     434                 : /************************************************************************/
     435                 : /*                             SetFeature()                             */
     436                 : /************************************************************************/
     437                 : 
     438              16 : OGRErr OGRShapeLayer::SetFeature( OGRFeature *poFeature )
     439                 : 
     440                 : {
     441              16 :     if( !bUpdateAccess )
     442                 :     {
     443                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     444               0 :             "The SetFeature() operation is not permitted on a read-only shapefile." );
     445               0 :         return OGRERR_FAILURE;
     446                 :     }
     447                 : 
     448              16 :     bHeaderDirty = TRUE;
     449                 : 
     450              16 :     return SHPWriteOGRFeature( hSHP, hDBF, poFeatureDefn, poFeature );
     451                 : }
     452                 : 
     453                 : /************************************************************************/
     454                 : /*                           DeleteFeature()                            */
     455                 : /************************************************************************/
     456                 : 
     457               3 : OGRErr OGRShapeLayer::DeleteFeature( long nFID )
     458                 : 
     459                 : {
     460               3 :     if( !bUpdateAccess )
     461                 :     {
     462                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     463               0 :             "The DeleteFeature() operation is not permitted on a read-only shapefile." );
     464               0 :         return OGRERR_FAILURE;
     465                 :     }
     466                 : 
     467               3 :     if( nFID < 0 
     468                 :         || (hSHP != NULL && nFID >= hSHP->nRecords)
     469                 :         || (hDBF != NULL && nFID >= hDBF->nRecords) )
     470                 :     {
     471                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     472                 :                   "Attempt to delete shape with feature id (%ld) which does "
     473               0 :                   "not exist.", nFID );
     474               0 :         return OGRERR_FAILURE;
     475                 :     }
     476                 : 
     477               3 :     if( !hDBF )
     478                 :     {
     479                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     480                 :                   "Attempt to delete shape in shapefile with no .dbf file.\n"
     481                 :                   "Deletion is done by marking record deleted in dbf\n"
     482               0 :                   "and is not supported without a .dbf file." );
     483               0 :         return OGRERR_FAILURE;
     484                 :     }
     485                 : 
     486               3 :     if( DBFIsRecordDeleted( hDBF, nFID ) )
     487                 :     {
     488                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     489                 :                   "Attempt to delete shape with feature id (%ld), but it is marked deleted already.",
     490               0 :                   nFID );
     491               0 :         return OGRERR_FAILURE;
     492                 :     }
     493                 : 
     494               3 :     if( !DBFMarkRecordDeleted( hDBF, nFID, TRUE ) )
     495               0 :         return OGRERR_FAILURE;
     496                 : 
     497               3 :     bHeaderDirty = TRUE;
     498                 : 
     499               3 :     return OGRERR_NONE;
     500                 : }
     501                 : 
     502                 : /************************************************************************/
     503                 : /*                           CreateFeature()                            */
     504                 : /************************************************************************/
     505                 : 
     506           15905 : OGRErr OGRShapeLayer::CreateFeature( OGRFeature *poFeature )
     507                 : 
     508                 : {
     509                 :     OGRErr eErr;
     510                 : 
     511           15905 :     if( !bUpdateAccess )
     512                 :     {
     513                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     514               0 :             "The CreateFeature() operation is not permitted on a read-only shapefile." );
     515               0 :         return OGRERR_FAILURE;
     516                 :     }
     517                 : 
     518           15905 :     bHeaderDirty = TRUE;
     519                 : 
     520           15905 :     poFeature->SetFID( OGRNullFID );
     521                 : 
     522           15905 :     if( nTotalShapeCount == 0 
     523                 :         && eRequestedGeomType == wkbUnknown 
     524                 :         && poFeature->GetGeometryRef() != NULL )
     525                 :     {
     526              48 :         OGRGeometry     *poGeom = poFeature->GetGeometryRef();
     527                 :         int             nShapeType;
     528                 :         
     529              48 :         switch( poGeom->getGeometryType() )
     530                 :         {
     531                 :           case wkbPoint:
     532              12 :             nShapeType = SHPT_POINT;
     533              12 :             eRequestedGeomType = wkbPoint;
     534              12 :             break;
     535                 : 
     536                 :           case wkbPoint25D:
     537               2 :             nShapeType = SHPT_POINTZ;
     538               2 :             eRequestedGeomType = wkbPoint25D;
     539               2 :             break;
     540                 : 
     541                 :           case wkbMultiPoint:
     542               3 :             nShapeType = SHPT_MULTIPOINT;
     543               3 :             eRequestedGeomType = wkbMultiPoint;
     544               3 :             break;
     545                 : 
     546                 :           case wkbMultiPoint25D:
     547               1 :             nShapeType = SHPT_MULTIPOINTZ;
     548               1 :             eRequestedGeomType = wkbMultiPoint25D;
     549               1 :             break;
     550                 : 
     551                 :           case wkbLineString:
     552                 :           case wkbMultiLineString:
     553               6 :             nShapeType = SHPT_ARC;
     554               6 :             eRequestedGeomType = wkbLineString;
     555               6 :             break;
     556                 : 
     557                 :           case wkbLineString25D:
     558                 :           case wkbMultiLineString25D:
     559               3 :             nShapeType = SHPT_ARCZ;
     560               3 :             eRequestedGeomType = wkbLineString25D;
     561               3 :             break;
     562                 : 
     563                 :           case wkbPolygon:
     564                 :           case wkbMultiPolygon:
     565              19 :             nShapeType = SHPT_POLYGON;
     566              19 :             eRequestedGeomType = wkbPolygon;
     567              19 :             break;
     568                 : 
     569                 :           case wkbPolygon25D:
     570                 :           case wkbMultiPolygon25D:
     571               2 :             nShapeType = SHPT_POLYGONZ;
     572               2 :             eRequestedGeomType = wkbPolygon25D;
     573               2 :             break;
     574                 : 
     575                 :           default:
     576               0 :             nShapeType = -1;
     577                 :             break;
     578                 :         }
     579                 : 
     580              48 :         if( nShapeType != -1 )
     581                 :         {
     582              48 :             ResetGeomType( nShapeType );
     583                 :         }
     584                 :     }
     585                 :     
     586           15905 :     eErr = SHPWriteOGRFeature( hSHP, hDBF, poFeatureDefn, poFeature );
     587                 : 
     588           15905 :     if( hSHP != NULL )
     589           15884 :         nTotalShapeCount = hSHP->nRecords;
     590                 :     else 
     591              21 :         nTotalShapeCount = hDBF->nRecords;
     592                 :     
     593           15905 :     return eErr;
     594                 : }
     595                 : 
     596                 : /************************************************************************/
     597                 : /*                          GetFeatureCount()                           */
     598                 : /*                                                                      */
     599                 : /*      If a spatial filter is in effect, we turn control over to       */
     600                 : /*      the generic counter.  Otherwise we return the total count.      */
     601                 : /*      Eventually we should consider implementing a more efficient     */
     602                 : /*      way of counting features matching a spatial query.              */
     603                 : /************************************************************************/
     604                 : 
     605             142 : int OGRShapeLayer::GetFeatureCount( int bForce )
     606                 : 
     607                 : {
     608             142 :     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
     609              15 :         return OGRLayer::GetFeatureCount( bForce );
     610                 :     else
     611             127 :         return nTotalShapeCount;
     612                 : }
     613                 : 
     614                 : /************************************************************************/
     615                 : /*                             GetExtent()                              */
     616                 : /*                                                                      */
     617                 : /*      Fetch extent of the data currently stored in the dataset.       */
     618                 : /*      The bForce flag has no effect on SHO files since that value     */
     619                 : /*      is always in the header.                                        */
     620                 : /*                                                                      */
     621                 : /*      Returns OGRERR_NONE/OGRRERR_FAILURE.                            */
     622                 : /************************************************************************/
     623                 : 
     624              39 : OGRErr OGRShapeLayer::GetExtent (OGREnvelope *psExtent, int bForce)
     625                 : 
     626                 : {
     627                 :     UNREFERENCED_PARAM( bForce );
     628                 : 
     629                 :     double adMin[4], adMax[4];
     630                 : 
     631              39 :     if( hSHP == NULL )
     632               0 :         return OGRERR_FAILURE;
     633                 : 
     634              39 :     SHPGetInfo(hSHP, NULL, NULL, adMin, adMax);
     635                 : 
     636              39 :     psExtent->MinX = adMin[0];
     637              39 :     psExtent->MinY = adMin[1];
     638              39 :     psExtent->MaxX = adMax[0];
     639              39 :     psExtent->MaxY = adMax[1];
     640                 : 
     641              39 :     return OGRERR_NONE;
     642                 : }
     643                 : 
     644                 : /************************************************************************/
     645                 : /*                           TestCapability()                           */
     646                 : /************************************************************************/
     647                 : 
     648              11 : int OGRShapeLayer::TestCapability( const char * pszCap )
     649                 : 
     650                 : {
     651              11 :     if( EQUAL(pszCap,OLCRandomRead) )
     652               2 :         return TRUE;
     653                 : 
     654               9 :     else if( EQUAL(pszCap,OLCSequentialWrite) 
     655                 :              || EQUAL(pszCap,OLCRandomWrite) )
     656               2 :         return bUpdateAccess;
     657                 : 
     658               7 :     else if( EQUAL(pszCap,OLCFastFeatureCount) )
     659               4 :         return m_poFilterGeom == NULL || CheckForQIX();
     660                 : 
     661               3 :     else if( EQUAL(pszCap,OLCDeleteFeature) )
     662               0 :         return bUpdateAccess;
     663                 : 
     664               3 :     else if( EQUAL(pszCap,OLCFastSpatialFilter) )
     665               1 :         return CheckForQIX();
     666                 : 
     667               2 :     else if( EQUAL(pszCap,OLCFastGetExtent) )
     668               2 :         return TRUE;
     669                 : 
     670               0 :     else if( EQUAL(pszCap,OLCFastSetNextByIndex) )
     671               0 :         return m_poFilterGeom == NULL && m_poAttrQuery == NULL;
     672                 : 
     673               0 :     else if( EQUAL(pszCap,OLCCreateField) )
     674               0 :         return bUpdateAccess;
     675                 : 
     676                 :     else 
     677               0 :         return FALSE;
     678                 : }
     679                 : 
     680                 : /************************************************************************/
     681                 : /*                            CreateField()                             */
     682                 : /************************************************************************/
     683                 : 
     684             190 : OGRErr OGRShapeLayer::CreateField( OGRFieldDefn *poFieldDefn, int bApproxOK )
     685                 : 
     686                 : {
     687             190 :     CPLAssert( NULL != poFieldDefn );
     688                 :     
     689                 :     int         iNewField;
     690                 : 
     691             190 :     if( !bUpdateAccess )
     692                 :     {
     693                 :         CPLError( CE_Failure, CPLE_NotSupported,
     694               0 :                   "Can't create fields on a read-only shapefile layer.\n");
     695               0 :         return OGRERR_FAILURE;
     696                 : 
     697                 :     }
     698                 : 
     699                 : /* -------------------------------------------------------------------- */
     700                 : /*      Normalize field name                                            */
     701                 : /* -------------------------------------------------------------------- */
     702                 :         
     703                 :     char szNewFieldName[10 + 1];
     704             190 :     char * pszTmp = NULL;
     705             190 :     int nRenameNum = 1;
     706                 : 
     707             190 :     size_t nNameSize = strlen( poFieldDefn->GetNameRef() );
     708                 :     pszTmp = CPLScanString( poFieldDefn->GetNameRef(),
     709             190 :                                      MIN( nNameSize, 10) , TRUE, TRUE);
     710             190 :     strncpy(szNewFieldName, pszTmp, 10);
     711             190 :     szNewFieldName[10] = '\0';
     712                 : 
     713             190 :     if( !bApproxOK &&
     714                 :         ( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 ||
     715                 :           !EQUAL(poFieldDefn->GetNameRef(),szNewFieldName) ) )
     716                 :     {
     717                 :         CPLError( CE_Failure, CPLE_NotSupported,
     718                 :                   "Failed to add field named '%s'",
     719               0 :                   poFieldDefn->GetNameRef() );
     720                 :                   
     721               0 :         CPLFree( pszTmp );
     722               0 :         return OGRERR_FAILURE;
     723                 :     }
     724                 : 
     725             503 :     while( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 && nRenameNum < 10 )
     726             123 :         sprintf( szNewFieldName, "%.8s_%.1d", pszTmp, nRenameNum++ );
     727             384 :     while( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 && nRenameNum < 100 )
     728               4 :         sprintf( szNewFieldName, "%.8s%.2d", pszTmp, nRenameNum++ );
     729                 : 
     730             190 :     CPLFree( pszTmp );
     731             190 :     pszTmp = NULL;
     732                 :     
     733             190 :     if( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 )
     734                 :     {
     735                 :         CPLError( CE_Failure, CPLE_NotSupported,
     736                 :                   "Too many field names like '%s' when truncated to 10 letters "
     737                 :                   "for Shapefile format.",
     738               0 :                   poFieldDefn->GetNameRef() );//One hundred similar field names!!?
     739                 :     }
     740                 : 
     741             190 :     if( !EQUAL(poFieldDefn->GetNameRef(),szNewFieldName) )
     742                 :         CPLError( CE_Warning, CPLE_NotSupported,
     743                 :                   "Normalized/laundered field name: '%s' to '%s'", 
     744                 :                   poFieldDefn->GetNameRef(),
     745              30 :                   szNewFieldName );
     746                 :                   
     747                 :     // Set field name with normalized value
     748             190 :     OGRFieldDefn oModFieldDefn(poFieldDefn);
     749             190 :     oModFieldDefn.SetName(szNewFieldName);
     750                 : 
     751                 : /* -------------------------------------------------------------------- */
     752                 : /*      Add field to layer                                              */
     753                 : /* -------------------------------------------------------------------- */
     754                 : 
     755             190 :     if( oModFieldDefn.GetType() == OFTInteger )
     756                 :     {
     757              31 :         if( oModFieldDefn.GetWidth() == 0 )
     758                 :             iNewField =
     759              25 :                 DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTInteger, 11, 0 );
     760                 :         else
     761                 :             iNewField = DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTInteger,
     762               6 :                                      oModFieldDefn.GetWidth(), 0 );
     763                 : 
     764              31 :         if( iNewField != -1 )
     765              31 :             poFeatureDefn->AddFieldDefn( &oModFieldDefn );
     766                 :     }
     767             159 :     else if( oModFieldDefn.GetType() == OFTReal )
     768                 :     {
     769              94 :         if( oModFieldDefn.GetWidth() == 0 )
     770                 :             iNewField =
     771               5 :                 DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTDouble, 24, 15 );
     772                 :         else
     773                 :             iNewField =
     774                 :                 DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTDouble,
     775              89 :                              oModFieldDefn.GetWidth(), oModFieldDefn.GetPrecision() );
     776                 : 
     777              94 :         if( iNewField != -1 )
     778              94 :             poFeatureDefn->AddFieldDefn( &oModFieldDefn );
     779                 :     }
     780              65 :     else if( oModFieldDefn.GetType() == OFTString )
     781                 :     {
     782              64 :         if( oModFieldDefn.GetWidth() < 1 )
     783                 :             iNewField =
     784              18 :                 DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTString, 80, 0 );
     785                 :         else
     786                 :             iNewField = DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTString, 
     787              46 :                                      oModFieldDefn.GetWidth(), 0 );
     788                 : 
     789              64 :         if( iNewField != -1 )
     790              64 :             poFeatureDefn->AddFieldDefn( &oModFieldDefn );
     791                 :     }
     792               1 :     else if( oModFieldDefn.GetType() == OFTDate )
     793                 :     {
     794                 :         iNewField =
     795               1 :             DBFAddNativeFieldType( hDBF, oModFieldDefn.GetNameRef(), 'D', 8, 0 );
     796                 : 
     797               1 :         if( iNewField != -1 )
     798               1 :             poFeatureDefn->AddFieldDefn( &oModFieldDefn );
     799                 :     }
     800               0 :     else if( oModFieldDefn.GetType() == OFTDateTime )
     801                 :     {
     802                 :         CPLError( CE_Warning, CPLE_NotSupported,
     803                 :                   "Field %s create as date field, though DateTime requested.\n",
     804               0 :                   oModFieldDefn.GetNameRef() );
     805                 : 
     806                 :         iNewField =
     807               0 :             DBFAddNativeFieldType( hDBF, oModFieldDefn.GetNameRef(), 'D', 8, 0 );
     808                 : 
     809               0 :         if( iNewField != -1 )
     810                 :         {
     811               0 :             oModFieldDefn.SetType( OFTDate );
     812               0 :             poFeatureDefn->AddFieldDefn( &oModFieldDefn );
     813                 :         }
     814                 :     }
     815                 :     else
     816                 :     {
     817                 :         CPLError( CE_Failure, CPLE_NotSupported,
     818                 :                   "Can't create fields of type %s on shapefile layers.\n",
     819               0 :                   OGRFieldDefn::GetFieldTypeName(oModFieldDefn.GetType()) );
     820                 : 
     821             190 :         return OGRERR_FAILURE;
     822                 :     }
     823                 : 
     824             190 :     if( iNewField != -1 )
     825                 :     {
     826             190 :         return OGRERR_NONE;
     827                 :     }
     828                 :     else        
     829                 :     {
     830                 :         CPLError( CE_Failure, CPLE_AppDefined,
     831                 :                   "Can't create field %s in Shape DBF file, reason unknown.\n",
     832               0 :                   oModFieldDefn.GetNameRef() );
     833                 : 
     834               0 :         return OGRERR_FAILURE;
     835               0 :     }
     836                 : }
     837                 : 
     838                 : /************************************************************************/
     839                 : /*                           GetSpatialRef()                            */
     840                 : /************************************************************************/
     841                 : 
     842             124 : OGRSpatialReference *OGRShapeLayer::GetSpatialRef()
     843                 : 
     844                 : {
     845             124 :     return poSRS;
     846                 : }
     847                 : 
     848                 : /************************************************************************/
     849                 : /*                           ResetGeomType()                            */
     850                 : /*                                                                      */
     851                 : /*      Modify the geometry type for this file.  Used to convert to     */
     852                 : /*      a different geometry type when a layer was created with a       */
     853                 : /*      type of unknown, and we get to the first feature to             */
     854                 : /*      establish the type.                                             */
     855                 : /************************************************************************/
     856                 : 
     857              48 : int OGRShapeLayer::ResetGeomType( int nNewGeomType )
     858                 : 
     859                 : {
     860                 :     char        abyHeader[100];
     861                 :     int         nStartPos;
     862                 : 
     863              48 :     if( nTotalShapeCount > 0 )
     864               0 :         return FALSE;
     865                 : 
     866              48 :     if( hSHP->fpSHX == NULL)
     867                 :     {
     868                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     869               0 :                   " OGRShapeLayer::ResetGeomType failed : SHX file is closed");
     870               0 :         return FALSE;
     871                 :     }
     872                 : 
     873                 : /* -------------------------------------------------------------------- */
     874                 : /*      Update .shp header.                                             */
     875                 : /* -------------------------------------------------------------------- */
     876              48 :     nStartPos = (int)( hSHP->sHooks.FTell( hSHP->fpSHP ) );
     877                 : 
     878              48 :     if( hSHP->sHooks.FSeek( hSHP->fpSHP, 0, SEEK_SET ) != 0
     879                 :         || hSHP->sHooks.FRead( abyHeader, 100, 1, hSHP->fpSHP ) != 1 )
     880               0 :         return FALSE;
     881                 : 
     882              48 :     *((GInt32 *) (abyHeader + 32)) = CPL_LSBWORD32( nNewGeomType );
     883                 : 
     884              48 :     if( hSHP->sHooks.FSeek( hSHP->fpSHP, 0, SEEK_SET ) != 0
     885                 :         || hSHP->sHooks.FWrite( abyHeader, 100, 1, hSHP->fpSHP ) != 1 )
     886               0 :         return FALSE;
     887                 : 
     888              48 :     if( hSHP->sHooks.FSeek( hSHP->fpSHP, nStartPos, SEEK_SET ) != 0 )
     889               0 :         return FALSE;
     890                 : 
     891                 : /* -------------------------------------------------------------------- */
     892                 : /*      Update .shx header.                                             */
     893                 : /* -------------------------------------------------------------------- */
     894              48 :     nStartPos = (int)( hSHP->sHooks.FTell( hSHP->fpSHX ) );
     895                 :     
     896              48 :     if( hSHP->sHooks.FSeek( hSHP->fpSHX, 0, SEEK_SET ) != 0
     897                 :         || hSHP->sHooks.FRead( abyHeader, 100, 1, hSHP->fpSHX ) != 1 )
     898               0 :         return FALSE;
     899                 : 
     900              48 :     *((GInt32 *) (abyHeader + 32)) = CPL_LSBWORD32( nNewGeomType );
     901                 : 
     902              48 :     if( hSHP->sHooks.FSeek( hSHP->fpSHX, 0, SEEK_SET ) != 0
     903                 :         || hSHP->sHooks.FWrite( abyHeader, 100, 1, hSHP->fpSHX ) != 1 )
     904               0 :         return FALSE;
     905                 : 
     906              48 :     if( hSHP->sHooks.FSeek( hSHP->fpSHX, nStartPos, SEEK_SET ) != 0 )
     907               0 :         return FALSE;
     908                 : 
     909                 : /* -------------------------------------------------------------------- */
     910                 : /*      Update other information.                                       */
     911                 : /* -------------------------------------------------------------------- */
     912              48 :     hSHP->nShapeType = nNewGeomType;
     913                 : 
     914              48 :     return TRUE;
     915                 : }
     916                 : 
     917                 : /************************************************************************/
     918                 : /*                             SyncToDisk()                             */
     919                 : /************************************************************************/
     920                 : 
     921               8 : OGRErr OGRShapeLayer::SyncToDisk()
     922                 : 
     923                 : {
     924               8 :     if( bHeaderDirty )
     925                 :     {
     926               7 :         if( hSHP != NULL )
     927               7 :             SHPWriteHeader( hSHP );
     928                 : 
     929               7 :         if( hDBF != NULL )
     930               7 :             DBFUpdateHeader( hDBF );
     931                 :         
     932               7 :         bHeaderDirty = FALSE;
     933                 :     }
     934                 : 
     935               8 :     if( hSHP != NULL )
     936                 :     {
     937               8 :         hSHP->sHooks.FFlush( hSHP->fpSHP );
     938               8 :         if( hSHP->fpSHX != NULL )
     939               8 :             hSHP->sHooks.FFlush( hSHP->fpSHX );
     940                 :     }
     941                 : 
     942               8 :     if( hDBF != NULL )
     943               8 :         hDBF->sHooks.FFlush( hDBF->fp );
     944                 : 
     945               8 :     return OGRERR_NONE;
     946                 : }
     947                 : 
     948                 : /************************************************************************/
     949                 : /*                          DropSpatialIndex()                          */
     950                 : /************************************************************************/
     951                 : 
     952               1 : OGRErr OGRShapeLayer::DropSpatialIndex()
     953                 : 
     954                 : {
     955               1 :     if( !CheckForQIX() )
     956                 :     {
     957                 :         CPLError( CE_Warning, CPLE_AppDefined, 
     958                 :                   "Layer %s has no spatial index, DROP SPATIAL INDEX failed.",
     959               0 :                   poFeatureDefn->GetName() );
     960               0 :         return OGRERR_FAILURE;
     961                 :     }
     962                 : 
     963               1 :     VSIFClose( fpQIX );
     964               1 :     fpQIX = NULL;
     965               1 :     bCheckedForQIX = FALSE;
     966                 :     
     967                 :     const char *pszQIXFilename;
     968                 : 
     969               1 :     pszQIXFilename = CPLResetExtension( pszFullName, "qix" );
     970               1 :     CPLDebug( "SHAPE", "Unlinking index file %s", pszQIXFilename );
     971                 : 
     972               1 :     if( VSIUnlink( pszQIXFilename ) != 0 )
     973                 :     {
     974                 :         CPLError( CE_Failure, CPLE_AppDefined,
     975                 :                   "Failed to delete file %s.\n%s", 
     976               0 :                   pszQIXFilename, VSIStrerror( errno ) );
     977               0 :         return OGRERR_FAILURE;
     978                 :     }
     979                 :     else
     980               1 :         return OGRERR_NONE;
     981                 : }
     982                 : 
     983                 : /************************************************************************/
     984                 : /*                         CreateSpatialIndex()                         */
     985                 : /************************************************************************/
     986                 : 
     987               3 : OGRErr OGRShapeLayer::CreateSpatialIndex( int nMaxDepth )
     988                 : 
     989                 : {
     990                 : /* -------------------------------------------------------------------- */
     991                 : /*      If we have an existing spatial index, blow it away first.       */
     992                 : /* -------------------------------------------------------------------- */
     993               3 :     if( CheckForQIX() )
     994               0 :         DropSpatialIndex();
     995                 : 
     996               3 :     bCheckedForQIX = FALSE;
     997                 : 
     998                 : /* -------------------------------------------------------------------- */
     999                 : /*      Build a quadtree structure for this file.                       */
    1000                 : /* -------------------------------------------------------------------- */
    1001                 :     SHPTree *psTree;
    1002                 : 
    1003               3 :     SyncToDisk();
    1004               3 :     psTree = SHPCreateTree( hSHP, 2, nMaxDepth, NULL, NULL );
    1005                 : 
    1006               3 :     if( NULL == psTree )
    1007                 :     {
    1008                 :         // TODO - mloskot: Is it better to return OGRERR_NOT_ENOUGH_MEMORY?
    1009                 : 
    1010                 :         CPLDebug( "SHAPE",
    1011               0 :                   "Index creation failure. Likely, memory allocation error." );
    1012                 : 
    1013               0 :         return OGRERR_FAILURE;
    1014                 :     }
    1015                 : 
    1016                 : /* -------------------------------------------------------------------- */
    1017                 : /*      Trim unused nodes from the tree.                                */
    1018                 : /* -------------------------------------------------------------------- */
    1019               3 :     SHPTreeTrimExtraNodes( psTree );
    1020                 : 
    1021                 : /* -------------------------------------------------------------------- */
    1022                 : /*      Dump tree to .qix file.                                         */
    1023                 : /* -------------------------------------------------------------------- */
    1024                 :     char *pszQIXFilename;
    1025                 : 
    1026               3 :     pszQIXFilename = CPLStrdup(CPLResetExtension( pszFullName, "qix" ));
    1027                 : 
    1028               3 :     CPLDebug( "SHAPE", "Creating index file %s", pszQIXFilename );
    1029                 : 
    1030               3 :     SHPWriteTree( psTree, pszQIXFilename );
    1031               3 :     CPLFree( pszQIXFilename );
    1032                 : 
    1033                 : 
    1034                 : /* -------------------------------------------------------------------- */
    1035                 : /*      cleanup                                                         */
    1036                 : /* -------------------------------------------------------------------- */
    1037               3 :     SHPDestroyTree( psTree );
    1038                 : 
    1039               3 :     CheckForQIX();
    1040                 : 
    1041               3 :     return OGRERR_NONE;
    1042                 : }
    1043                 : 
    1044                 : /************************************************************************/
    1045                 : /*                               Repack()                               */
    1046                 : /*                                                                      */
    1047                 : /*      Repack the shape and dbf file, dropping deleted records.        */
    1048                 : /*      FIDs may change.                                                */
    1049                 : /************************************************************************/
    1050                 : 
    1051               3 : OGRErr OGRShapeLayer::Repack()
    1052                 : 
    1053                 : {
    1054               3 :     if( !bUpdateAccess )
    1055                 :     {
    1056                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1057               0 :             "The REPACK operation is not permitted on a read-only shapefile." );
    1058               0 :         return OGRERR_FAILURE;
    1059                 :     }
    1060                 :     
    1061               3 :     if( hDBF == NULL )
    1062                 :     {
    1063                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    1064               0 :                   "Attempt to repack a shapefile with no .dbf file not supported.");
    1065               0 :         return OGRERR_FAILURE;
    1066                 :     }
    1067                 :     
    1068                 : /* -------------------------------------------------------------------- */
    1069                 : /*      Build a list of records to be dropped.                          */
    1070                 : /* -------------------------------------------------------------------- */
    1071                 :     int *panRecordsToDelete = (int *) 
    1072               3 :         CPLMalloc(sizeof(int)*(nTotalShapeCount+1));
    1073               3 :     int nDeleteCount = 0;
    1074               3 :     int iShape = 0;
    1075               3 :     OGRErr eErr = OGRERR_NONE;
    1076                 : 
    1077              34 :     for( iShape = 0; iShape < nTotalShapeCount; iShape++ )
    1078                 :     {
    1079              31 :         if( DBFIsRecordDeleted( hDBF, iShape ) )
    1080               3 :             panRecordsToDelete[nDeleteCount++] = iShape;
    1081                 :     }
    1082               3 :     panRecordsToDelete[nDeleteCount] = -1;
    1083                 : 
    1084                 : /* -------------------------------------------------------------------- */
    1085                 : /*      If there are no records marked for deletion, we take no         */
    1086                 : /*      action.                                                         */
    1087                 : /* -------------------------------------------------------------------- */
    1088               3 :     if( nDeleteCount == 0 )
    1089                 :     {
    1090               0 :         CPLFree( panRecordsToDelete );
    1091               0 :         return OGRERR_NONE;
    1092                 :     }
    1093                 : 
    1094                 : /* -------------------------------------------------------------------- */
    1095                 : /*      Find existing filenames with exact case (see #3293).            */
    1096                 : /* -------------------------------------------------------------------- */
    1097               3 :     CPLString osDirname(CPLGetPath(pszFullName));
    1098               3 :     CPLString osBasename(CPLGetBasename(pszFullName));
    1099                 :     
    1100               3 :     CPLString osDBFName, osSHPName, osSHXName;
    1101               3 :     char **papszCandidates = CPLReadDir( osDirname );
    1102               3 :     int i = 0;
    1103              21 :     while(papszCandidates != NULL && papszCandidates[i] != NULL)
    1104                 :     {
    1105              18 :         CPLString osCandidateBasename = CPLGetBasename(papszCandidates[i]);
    1106              18 :         CPLString osCandidateExtension = CPLGetExtension(papszCandidates[i]);
    1107              18 :         if (osCandidateBasename.compare(osBasename) == 0)
    1108                 :         {
    1109               9 :             if (EQUAL(osCandidateExtension, "dbf"))
    1110               3 :                 osDBFName = CPLFormFilename(osDirname, papszCandidates[i], NULL);
    1111               6 :             else if (EQUAL(osCandidateExtension, "shp"))
    1112               3 :                 osSHPName = CPLFormFilename(osDirname, papszCandidates[i], NULL);
    1113               3 :             else if (EQUAL(osCandidateExtension, "shx"))
    1114               3 :                 osSHXName = CPLFormFilename(osDirname, papszCandidates[i], NULL);
    1115                 :         }
    1116                 :         
    1117              18 :         i++;
    1118                 :     }
    1119               3 :     CSLDestroy(papszCandidates);
    1120               3 :     papszCandidates = NULL;
    1121                 :     
    1122               3 :     if (osDBFName.size() == 0)
    1123                 :     {
    1124                 :         /* Should not happen, really */
    1125               0 :         CPLFree( panRecordsToDelete );
    1126               3 :         return OGRERR_FAILURE;
    1127                 :     }
    1128                 :     
    1129                 : /* -------------------------------------------------------------------- */
    1130                 : /*      Cleanup any existing spatial index.  It will become             */
    1131                 : /*      meaningless when the fids change.                               */
    1132                 : /* -------------------------------------------------------------------- */
    1133               3 :     if( CheckForQIX() )
    1134               0 :         DropSpatialIndex();
    1135                 : 
    1136                 : /* -------------------------------------------------------------------- */
    1137                 : /*      Create a new dbf file, matching the old.                        */
    1138                 : /* -------------------------------------------------------------------- */
    1139               3 :     DBFHandle hNewDBF = NULL;
    1140                 :     
    1141               3 :     CPLString oTempFile(osDirname);
    1142               3 :     oTempFile += SEP_CHAR;
    1143               3 :     oTempFile += osBasename;
    1144               3 :     oTempFile += "_packed.dbf";
    1145                 : 
    1146               3 :     hNewDBF = DBFCloneEmpty( hDBF, oTempFile );
    1147               3 :     if( hNewDBF == NULL )
    1148                 :     {
    1149               0 :         CPLFree( panRecordsToDelete );
    1150                 : 
    1151                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
    1152                 :                   "Failed to create temp file %s.", 
    1153               0 :                   oTempFile.c_str() );
    1154               0 :         return OGRERR_FAILURE;
    1155                 :     }
    1156                 : 
    1157                 : /* -------------------------------------------------------------------- */
    1158                 : /*      Copy over all records that are not deleted.                     */
    1159                 : /* -------------------------------------------------------------------- */
    1160               3 :     int iDestShape = 0;
    1161               3 :     int iNextDeletedShape = 0;
    1162                 : 
    1163              34 :     for( iShape = 0; 
    1164                 :          iShape < nTotalShapeCount && eErr == OGRERR_NONE; 
    1165                 :          iShape++ )
    1166                 :     {
    1167              31 :         if( panRecordsToDelete[iNextDeletedShape] == iShape )
    1168               3 :             iNextDeletedShape++;
    1169                 :         else
    1170                 :         {
    1171              28 :             void *pTuple = (void *) DBFReadTuple( hDBF, iShape );
    1172              28 :             if( pTuple == NULL )
    1173               0 :                 eErr = OGRERR_FAILURE;
    1174              28 :             else if( !DBFWriteTuple( hNewDBF, iDestShape++, pTuple ) )
    1175               0 :                 eErr = OGRERR_FAILURE;
    1176                 :         }                           
    1177                 :     }
    1178                 : 
    1179               3 :     if( eErr != OGRERR_NONE )
    1180                 :     {
    1181               0 :         CPLFree( panRecordsToDelete );
    1182               0 :         VSIUnlink( oTempFile );
    1183               0 :         return eErr;
    1184                 :     }
    1185                 : 
    1186                 : /* -------------------------------------------------------------------- */
    1187                 : /*      Cleanup the old .dbf and rename the new one.                    */
    1188                 : /* -------------------------------------------------------------------- */
    1189               3 :     DBFClose( hDBF );
    1190               3 :     DBFClose( hNewDBF );
    1191               3 :     hDBF = hNewDBF = NULL;
    1192                 :     
    1193               3 :     VSIUnlink( osDBFName );
    1194                 :         
    1195               3 :     if( VSIRename( oTempFile, osDBFName ) != 0 )
    1196                 :     {
    1197               0 :         CPLDebug( "Shape", "Can not rename DBF file: %s", VSIStrerror( errno ) );
    1198               0 :         CPLFree( panRecordsToDelete );
    1199               0 :         return OGRERR_FAILURE;
    1200                 :     }
    1201                 :     
    1202                 : /* -------------------------------------------------------------------- */
    1203                 : /*      Now create a shapefile matching the old one.                    */
    1204                 : /* -------------------------------------------------------------------- */
    1205               3 :     if( hSHP != NULL )
    1206                 :     {
    1207               3 :         SHPHandle hNewSHP = NULL;
    1208                 :         
    1209               3 :         if (osSHPName.size() == 0 || osSHXName.size() == 0)
    1210                 :         {
    1211                 :             /* Should not happen, really */
    1212               0 :             CPLFree( panRecordsToDelete );
    1213               0 :             return OGRERR_FAILURE;
    1214                 :         }
    1215                 : 
    1216               3 :         oTempFile = osDirname;
    1217               3 :         oTempFile += SEP_CHAR;
    1218               3 :         oTempFile += osBasename;
    1219               3 :         oTempFile += "_packed.shp";
    1220                 : 
    1221               3 :         hNewSHP = SHPCreate( oTempFile, hSHP->nShapeType );
    1222               3 :         if( hNewSHP == NULL )
    1223                 :         {
    1224               0 :             CPLFree( panRecordsToDelete );
    1225               0 :             return OGRERR_FAILURE;
    1226                 :         }
    1227                 : 
    1228                 : /* -------------------------------------------------------------------- */
    1229                 : /*      Copy over all records that are not deleted.                     */
    1230                 : /* -------------------------------------------------------------------- */
    1231               3 :         iNextDeletedShape = 0;
    1232                 : 
    1233              34 :         for( iShape = 0; 
    1234                 :              iShape < nTotalShapeCount && eErr == OGRERR_NONE; 
    1235                 :              iShape++ )
    1236                 :         {
    1237              31 :             if( panRecordsToDelete[iNextDeletedShape] == iShape )
    1238               3 :                 iNextDeletedShape++;
    1239                 :             else
    1240                 :             {
    1241                 :                 SHPObject *hObject;
    1242                 : 
    1243              28 :                 hObject = SHPReadObject( hSHP, iShape );
    1244              28 :                 if( hObject == NULL )
    1245               0 :                     eErr = OGRERR_FAILURE;
    1246              28 :                 else if( SHPWriteObject( hNewSHP, -1, hObject ) == -1 )
    1247               0 :                     eErr = OGRERR_FAILURE;
    1248                 : 
    1249              28 :                 if( hObject )
    1250              28 :                     SHPDestroyObject( hObject );
    1251                 :             }
    1252                 :         }
    1253                 : 
    1254               3 :         if( eErr != OGRERR_NONE )
    1255                 :         {
    1256               0 :             CPLFree( panRecordsToDelete );
    1257               0 :             VSIUnlink( CPLResetExtension( oTempFile, "shp" ) );
    1258               0 :             VSIUnlink( CPLResetExtension( oTempFile, "shx" ) );
    1259               0 :             return eErr;
    1260                 :         }
    1261                 : 
    1262                 : /* -------------------------------------------------------------------- */
    1263                 : /*      Cleanup the old .shp/.shx and rename the new one.               */
    1264                 : /* -------------------------------------------------------------------- */
    1265               3 :         SHPClose( hSHP );
    1266               3 :         SHPClose( hNewSHP );
    1267               3 :         hSHP = hNewSHP = NULL;
    1268                 : 
    1269               3 :         VSIUnlink( osSHPName );
    1270               3 :         VSIUnlink( osSHXName );
    1271                 : 
    1272               3 :         oTempFile = CPLResetExtension( oTempFile, "shp" );
    1273               3 :         if( VSIRename( oTempFile, osSHPName ) != 0 )
    1274                 :         {
    1275               0 :             CPLDebug( "Shape", "Can not rename SHP file: %s", VSIStrerror( errno ) );
    1276               0 :             CPLFree( panRecordsToDelete );
    1277               0 :             return OGRERR_FAILURE;
    1278                 :         }
    1279                 :     
    1280               3 :         oTempFile = CPLResetExtension( oTempFile, "shx" );
    1281               3 :         if( VSIRename( oTempFile, osSHXName ) != 0 )
    1282                 :         {
    1283               0 :             CPLDebug( "Shape", "Can not rename SHX file: %s", VSIStrerror( errno ) );
    1284               0 :             CPLFree( panRecordsToDelete );
    1285               0 :             return OGRERR_FAILURE;
    1286                 :         }
    1287                 :     }
    1288                 :     
    1289               3 :     CPLFree( panRecordsToDelete );
    1290               3 :     panRecordsToDelete = NULL;
    1291                 : 
    1292                 : /* -------------------------------------------------------------------- */
    1293                 : /*      Reopen the shapefile                                            */
    1294                 : /*                                                                      */
    1295                 : /* We do not need to reimplement OGRShapeDataSource::OpenFile() here    */  
    1296                 : /* with the fully featured error checking.                              */
    1297                 : /* If all operations above succeeded, then all necessery files are      */
    1298                 : /* in the right place and accessible.                                   */
    1299                 : /* -------------------------------------------------------------------- */
    1300               3 :     CPLAssert( NULL == hSHP );
    1301               3 :     CPLAssert( NULL == hDBF && NULL == hNewDBF );
    1302                 :     
    1303               3 :     CPLPushErrorHandler( CPLQuietErrorHandler );
    1304                 :     
    1305               3 :     const char* pszAccess = NULL;
    1306               3 :     if( bUpdateAccess )
    1307               3 :         pszAccess = "r+";
    1308                 :     else
    1309               0 :         pszAccess = "r";
    1310                 :     
    1311               3 :     hSHP = SHPOpen ( CPLResetExtension( pszFullName, "shp" ) , pszAccess );
    1312               3 :     hDBF = DBFOpen ( CPLResetExtension( pszFullName, "dbf" ) , pszAccess );
    1313                 :     
    1314               3 :     CPLPopErrorHandler();
    1315                 :     
    1316               3 :     if( NULL == hSHP || NULL == hDBF )
    1317                 :     {
    1318               0 :         CPLString osMsg(CPLGetLastErrorMsg());
    1319               0 :         CPLError( CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str() );
    1320                 : 
    1321               0 :         return OGRERR_FAILURE;
    1322                 :     }
    1323                 : 
    1324                 : /* -------------------------------------------------------------------- */
    1325                 : /*      Update total shape count.                                       */
    1326                 : /* -------------------------------------------------------------------- */
    1327               3 :     nTotalShapeCount = hDBF->nRecords;
    1328                 : 
    1329               3 :     return OGRERR_NONE;
    1330                 : }

Generated by: LTP GCOV extension version 1.5