LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - ogrshapelayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 494 392 79.4 %
Date: 2010-01-09 Functions: 23 22 95.7 %

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

Generated by: LCOV version 1.7