LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - ogrshapelayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1121 922 82.2 %
Date: 2012-12-26 Functions: 41 38 92.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrshapelayer.cpp 25268 2012-11-29 20:21:41Z 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                 : #include "ogr_p.h"
      34                 : 
      35                 : #if defined(_WIN32_WCE)
      36                 : #  include <wce_errno.h>
      37                 : #endif
      38                 : 
      39                 : #define FD_OPENED           0
      40                 : #define FD_CLOSED           1
      41                 : #define FD_CANNOT_REOPEN    2
      42                 : 
      43                 : #define UNSUPPORTED_OP_READ_ONLY "%s : unsupported operation on a read-only datasource."
      44                 : 
      45                 : CPL_CVSID("$Id: ogrshapelayer.cpp 25268 2012-11-29 20:21:41Z rouault $");
      46                 : 
      47                 : /************************************************************************/
      48                 : /*                           OGRShapeLayer()                            */
      49                 : /************************************************************************/
      50                 : 
      51            3908 : OGRShapeLayer::OGRShapeLayer( OGRShapeDataSource* poDSIn,
      52                 :                               const char * pszFullNameIn,
      53                 :                               SHPHandle hSHPIn, DBFHandle hDBFIn, 
      54                 :                               OGRSpatialReference *poSRSIn, int bSRSSetIn,
      55                 :                               int bUpdate,
      56                 :                               OGRwkbGeometryType eReqType ) :
      57            3908 :                                 OGRAbstractProxiedLayer(poDSIn->GetPool())
      58                 : 
      59                 : {
      60            3908 :     poDS = poDSIn;
      61            3908 :     poSRS = poSRSIn;
      62            3908 :     bSRSSet = bSRSSetIn;
      63                 : 
      64            3908 :     pszFullName = CPLStrdup(pszFullNameIn);
      65                 :     
      66            3908 :     hSHP = hSHPIn;
      67            3908 :     hDBF = hDBFIn;
      68            3908 :     bUpdateAccess = bUpdate;
      69                 : 
      70            3908 :     iNextShapeId = 0;
      71            3908 :     panMatchingFIDs = NULL;
      72                 : 
      73            3908 :     nSpatialFIDCount = 0;
      74            3908 :     panSpatialFIDs = NULL;
      75            3908 :     m_poFilterGeomLastValid = NULL;
      76                 : 
      77            3908 :     bCheckedForQIX = FALSE;
      78            3908 :     hQIX = NULL;
      79                 : 
      80            3908 :     bCheckedForSBN = FALSE;
      81            3908 :     hSBN = NULL;
      82                 : 
      83            3908 :     bSbnSbxDeleted = FALSE;
      84                 : 
      85            3908 :     bHeaderDirty = FALSE;
      86                 : 
      87            3908 :     if( hSHP != NULL )
      88                 :     {
      89            3870 :         nTotalShapeCount = hSHP->nRecords;
      90            3870 :         if( hDBF != NULL && hDBF->nRecords != nTotalShapeCount )
      91                 :         {
      92                 :             CPLDebug("Shape", "Inconsistant record number in .shp (%d) and in .dbf (%d)",
      93               0 :                      hSHP->nRecords, hDBF->nRecords);
      94                 :         }
      95                 :     }
      96                 :     else 
      97              38 :         nTotalShapeCount = hDBF->nRecords;
      98                 :     
      99            3908 :     eRequestedGeomType = eReqType;
     100                 : 
     101            3908 :     bTruncationWarningEmitted = FALSE;
     102                 : 
     103            3908 :     bHSHPWasNonNULL = hSHPIn != NULL;
     104            3908 :     bHDBFWasNonNULL = hDBFIn != NULL;
     105            3908 :     eFileDescriptorsState = FD_OPENED;
     106            3908 :     TouchLayer();
     107                 : 
     108            3908 :     bResizeAtClose = FALSE;
     109                 : 
     110            3908 :     if( hDBF != NULL && hDBF->pszCodePage != NULL )
     111                 :     {
     112                 :         CPLDebug( "Shape", "DBF Codepage = %s for %s", 
     113            3639 :                   hDBF->pszCodePage, pszFullName );
     114                 : 
     115                 :         // Not too sure about this, but it seems like better than nothing.
     116            3639 :         osEncoding = ConvertCodePage( hDBF->pszCodePage );
     117                 :     }
     118                 :     
     119            3908 :     if( CPLGetConfigOption( "SHAPE_ENCODING", NULL ) != NULL )
     120               0 :         osEncoding = CPLGetConfigOption( "SHAPE_ENCODING", "" );
     121                 : 
     122            3908 :     if( osEncoding != "" )
     123                 :     {
     124            3639 :         CPLDebug( "Shape", "Treating as encoding '%s'.", osEncoding.c_str() );
     125                 : 
     126            3639 :         if (!TestCapability(OLCStringsAsUTF8))
     127                 :         {
     128               1 :             CPLDebug( "Shape", "Cannot recode from '%s'. Disabling recoding", osEncoding.c_str() );
     129               1 :             osEncoding = "";
     130                 :         }
     131                 :     }
     132                 : 
     133                 :     poFeatureDefn = SHPReadOGRFeatureDefn( CPLGetBasename(pszFullName),
     134            3908 :                                            hSHP, hDBF, osEncoding );
     135            3908 : }
     136                 : 
     137                 : /************************************************************************/
     138                 : /*                           ~OGRShapeLayer()                           */
     139                 : /************************************************************************/
     140                 : 
     141            3908 : OGRShapeLayer::~OGRShapeLayer()
     142                 : 
     143                 : {
     144            3908 :     if( bResizeAtClose && hDBF != NULL )
     145                 :     {
     146               1 :         ResizeDBF();
     147                 :     }
     148                 : 
     149            3908 :     if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
     150                 :     {
     151                 :         CPLDebug( "Shape", "%d features read on layer '%s'.",
     152                 :                   (int) m_nFeaturesRead, 
     153            1442 :                   poFeatureDefn->GetName() );
     154                 :     }
     155                 : 
     156            3908 :     ClearMatchingFIDs();
     157            3908 :     ClearSpatialFIDs();
     158                 : 
     159            3908 :     CPLFree( pszFullName );
     160                 : 
     161            3908 :     if( poFeatureDefn != NULL )
     162            3908 :         poFeatureDefn->Release();
     163                 : 
     164            3908 :     if( poSRS != NULL )
     165             418 :         poSRS->Release();
     166                 : 
     167            3908 :     if( hDBF != NULL )
     168            1887 :         DBFClose( hDBF );
     169                 : 
     170            3908 :     if( hSHP != NULL )
     171            1869 :         SHPClose( hSHP );
     172                 : 
     173            3908 :     if( hQIX != NULL )
     174              23 :         SHPCloseDiskTree( hQIX );
     175                 : 
     176            3908 :     if( hSBN != NULL )
     177               8 :         SBNCloseDiskTree( hSBN );
     178            3908 : }
     179                 : 
     180                 : /************************************************************************/
     181                 : /*                          ConvertCodePage()                           */
     182                 : /************************************************************************/
     183                 : 
     184            3639 : CPLString OGRShapeLayer::ConvertCodePage( const char *pszCodePage )
     185                 : 
     186                 : {
     187            3639 :     CPLString osEncoding;
     188                 : 
     189            3639 :     if( pszCodePage == NULL )
     190               0 :         return osEncoding;
     191                 : 
     192            3639 :     if( EQUALN(pszCodePage,"LDID/",5) )
     193                 :     {
     194            3638 :         int nCP = -1; // windows code page. 
     195                 : 
     196                 :         //http://www.autopark.ru/ASBProgrammerGuide/DBFSTRUC.HTM
     197            3638 :         switch( atoi(pszCodePage+5) )
     198                 :         {
     199               0 :           case 1: nCP = 437;      break;
     200               0 :           case 2: nCP = 850;      break;
     201               0 :           case 3: nCP = 1252;     break;
     202               0 :           case 4: nCP = 10000;    break;
     203               0 :           case 8: nCP = 865;      break;
     204               0 :           case 10: nCP = 850;     break;
     205               0 :           case 11: nCP = 437;     break;
     206               0 :           case 13: nCP = 437;     break;
     207               0 :           case 14: nCP = 850;     break;
     208               0 :           case 15: nCP = 437;     break;
     209               0 :           case 16: nCP = 850;     break;
     210               0 :           case 17: nCP = 437;     break;
     211               0 :           case 18: nCP = 850;     break;
     212               0 :           case 19: nCP = 932;     break;
     213               0 :           case 20: nCP = 850;     break;
     214               0 :           case 21: nCP = 437;     break;
     215               0 :           case 22: nCP = 850;     break;
     216               0 :           case 23: nCP = 865;     break;
     217               0 :           case 24: nCP = 437;     break;
     218               0 :           case 25: nCP = 437;     break;
     219               0 :           case 26: nCP = 850;     break;
     220               0 :           case 27: nCP = 437;     break;
     221               0 :           case 28: nCP = 863;     break;
     222               0 :           case 29: nCP = 850;     break;
     223               0 :           case 31: nCP = 852;     break;
     224               0 :           case 34: nCP = 852;     break;
     225               0 :           case 35: nCP = 852;     break;
     226               0 :           case 36: nCP = 860;     break;
     227               0 :           case 37: nCP = 850;     break;
     228               0 :           case 38: nCP = 866;     break;
     229               0 :           case 55: nCP = 850;     break;
     230               0 :           case 64: nCP = 852;     break;
     231               1 :           case 77: nCP = 936;     break;
     232               0 :           case 78: nCP = 949;     break;
     233               0 :           case 79: nCP = 950;     break;
     234               0 :           case 80: nCP = 874;     break;
     235            3637 :           case 87: return CPL_ENC_ISO8859_1;
     236               0 :           case 88: nCP = 1252;     break;
     237               0 :           case 89: nCP = 1252;     break;
     238               0 :           case 100: nCP = 852;     break;
     239               0 :           case 101: nCP = 866;     break;
     240               0 :           case 102: nCP = 865;     break;
     241               0 :           case 103: nCP = 861;     break;
     242               0 :           case 104: nCP = 895;     break;
     243               0 :           case 105: nCP = 620;     break;
     244               0 :           case 106: nCP = 737;     break;
     245               0 :           case 107: nCP = 857;     break;
     246               0 :           case 108: nCP = 863;     break;
     247               0 :           case 120: nCP = 950;     break;
     248               0 :           case 121: nCP = 949;     break;
     249               0 :           case 122: nCP = 936;     break;
     250               0 :           case 123: nCP = 932;     break;
     251               0 :           case 124: nCP = 874;     break;
     252               0 :           case 134: nCP = 737;     break;
     253               0 :           case 135: nCP = 852;     break;
     254               0 :           case 136: nCP = 857;     break;
     255               0 :           case 150: nCP = 10007;   break;
     256               0 :           case 151: nCP = 10029;   break;
     257               0 :           case 200: nCP = 1250;    break;
     258               0 :           case 201: nCP = 1251;    break;
     259               0 :           case 202: nCP = 1254;    break;
     260               0 :           case 203: nCP = 1253;    break;
     261               0 :           case 204: nCP = 1257;    break;
     262                 :           default: break;
     263                 :         }
     264                 : 
     265               1 :         if( nCP != -1 )
     266                 :         {
     267               1 :             osEncoding.Printf( "CP%d", nCP );
     268               1 :             return osEncoding;
     269                 :         }
     270                 :     }
     271                 : 
     272                 :     // From the CPG file
     273                 :     // http://resources.arcgis.com/fr/content/kbase?fa=articleShow&d=21106
     274                 :     
     275               1 :     if( (atoi(pszCodePage) >= 437 && atoi(pszCodePage) <= 950)
     276                 :         || (atoi(pszCodePage) >= 1250 && atoi(pszCodePage) <= 1258) )
     277                 :     {
     278               0 :         osEncoding.Printf( "CP%d", atoi(pszCodePage) );
     279               0 :         return osEncoding;
     280                 :     }
     281               1 :     if( EQUALN(pszCodePage,"8859",4) )
     282                 :     {
     283               0 :         if( pszCodePage[4] == '-' )
     284               0 :             osEncoding.Printf( "ISO-8859-%s", pszCodePage + 5 );
     285                 :         else
     286               0 :             osEncoding.Printf( "ISO-8859-%s", pszCodePage + 4 );
     287               0 :         return osEncoding;
     288                 :     }
     289               1 :     if( EQUALN(pszCodePage,"UTF-8",5) )
     290               0 :         return CPL_ENC_UTF8;
     291                 : 
     292                 :     // try just using the CPG value directly.  Works for stuff like Big5.
     293               1 :     return pszCodePage;
     294                 : }
     295                 : 
     296                 : /************************************************************************/
     297                 : /*                            CheckForQIX()                             */
     298                 : /************************************************************************/
     299                 : 
     300           29809 : int OGRShapeLayer::CheckForQIX()
     301                 : 
     302                 : {
     303                 :     const char *pszQIXFilename;
     304                 : 
     305           29809 :     if( bCheckedForQIX )
     306           28522 :         return hQIX != NULL;
     307                 : 
     308            1287 :     pszQIXFilename = CPLResetExtension( pszFullName, "qix" );
     309                 : 
     310            1287 :     hQIX = SHPOpenDiskTree( pszQIXFilename, NULL ); 
     311                 : 
     312            1287 :     bCheckedForQIX = TRUE;
     313                 : 
     314            1287 :     return hQIX != NULL;
     315                 : }
     316                 : 
     317                 : /************************************************************************/
     318                 : /*                            CheckForSBN()                             */
     319                 : /************************************************************************/
     320                 : 
     321           29756 : int OGRShapeLayer::CheckForSBN()
     322                 : 
     323                 : {
     324                 :     const char *pszSBNFilename;
     325                 : 
     326           29756 :     if( bCheckedForSBN )
     327           28501 :         return hSBN != NULL;
     328                 : 
     329            1255 :     pszSBNFilename = CPLResetExtension( pszFullName, "sbn" );
     330                 : 
     331            1255 :     hSBN = SBNOpenDiskTree( pszSBNFilename, NULL );
     332                 : 
     333            1255 :     bCheckedForSBN = TRUE;
     334                 : 
     335            1255 :     return hSBN != NULL;
     336                 : }
     337                 : 
     338                 : /************************************************************************/
     339                 : /*                            ScanIndices()                             */
     340                 : /*                                                                      */
     341                 : /*      Utilize optional spatial and attribute indices if they are      */
     342                 : /*      available.                                                      */
     343                 : /************************************************************************/
     344                 : 
     345           17931 : int OGRShapeLayer::ScanIndices()
     346                 : 
     347                 : {
     348           17931 :     iMatchingFID = 0;
     349                 : 
     350                 : /* -------------------------------------------------------------------- */
     351                 : /*      Utilize attribute index if appropriate.                         */
     352                 : /* -------------------------------------------------------------------- */
     353           17931 :     if( m_poAttrQuery != NULL )
     354                 :     {
     355             400 :         CPLAssert( panMatchingFIDs == NULL );
     356                 : 
     357             400 :         InitializeIndexSupport( pszFullName );
     358                 : 
     359                 :         panMatchingFIDs = m_poAttrQuery->EvaluateAgainstIndices( this,
     360             400 :                                                                  NULL );
     361                 :     }
     362                 : 
     363                 : /* -------------------------------------------------------------------- */
     364                 : /*      Check for spatial index if we have a spatial query.             */
     365                 : /* -------------------------------------------------------------------- */
     366                 : 
     367           17931 :     if( m_poFilterGeom == NULL || hSHP == NULL )
     368             398 :         return TRUE;
     369                 : 
     370           17533 :     OGREnvelope oSpatialFilterEnvelope;
     371           17533 :     int bTryQIXorSBN = TRUE;
     372                 : 
     373           17533 :     m_poFilterGeom->getEnvelope( &oSpatialFilterEnvelope );
     374                 : 
     375           17533 :     OGREnvelope oLayerExtent;
     376           17533 :     if (GetExtent(&oLayerExtent, TRUE) == OGRERR_NONE)
     377                 :     {
     378           17533 :         if (oSpatialFilterEnvelope.Contains(oLayerExtent))
     379                 :         {
     380                 :             // The spatial filter is larger than the layer extent. No use of .qix file for now
     381               5 :             return TRUE;
     382                 :         }
     383           17528 :         else if (!oSpatialFilterEnvelope.Intersects(oLayerExtent))
     384                 :         {
     385                 :             /* No intersection : no need to check for .qix or .sbn */
     386              11 :             bTryQIXorSBN = FALSE;
     387                 : 
     388                 :             /* Set an empty result for spatial FIDs */
     389              11 :             free(panSpatialFIDs);
     390              11 :             panSpatialFIDs = (int*) calloc(1, sizeof(int));
     391              11 :             nSpatialFIDCount = 0;
     392                 : 
     393              11 :             delete m_poFilterGeomLastValid;
     394              11 :             m_poFilterGeomLastValid = m_poFilterGeom->clone();
     395                 :         }
     396                 :     }
     397                 : 
     398           17528 :     if( bTryQIXorSBN )
     399                 :     {
     400           17517 :         if( !bCheckedForQIX )
     401              32 :             CheckForQIX();
     402           17517 :         if( hQIX == NULL && !bCheckedForSBN )
     403              24 :             CheckForSBN();
     404                 :     }
     405                 : 
     406                 : /* -------------------------------------------------------------------- */
     407                 : /*      Compute spatial index if appropriate.                           */
     408                 : /* -------------------------------------------------------------------- */
     409           17528 :     if( bTryQIXorSBN && (hQIX != NULL || hSBN != NULL) && panSpatialFIDs == NULL )
     410                 :     {
     411                 :         double adfBoundsMin[4], adfBoundsMax[4];
     412                 : 
     413           17480 :         adfBoundsMin[0] = oSpatialFilterEnvelope.MinX;
     414           17480 :         adfBoundsMin[1] = oSpatialFilterEnvelope.MinY;
     415           17480 :         adfBoundsMin[2] = 0.0;
     416           17480 :         adfBoundsMin[3] = 0.0;
     417           17480 :         adfBoundsMax[0] = oSpatialFilterEnvelope.MaxX;
     418           17480 :         adfBoundsMax[1] = oSpatialFilterEnvelope.MaxY;
     419           17480 :         adfBoundsMax[2] = 0.0;
     420           17480 :         adfBoundsMax[3] = 0.0;
     421                 : 
     422           17480 :         if( hQIX != NULL )
     423                 :             panSpatialFIDs = SHPSearchDiskTreeEx( hQIX,
     424                 :                                                   adfBoundsMin, adfBoundsMax,
     425           12316 :                                                   &nSpatialFIDCount );
     426                 :         else
     427                 :             panSpatialFIDs = SBNSearchDiskTree( hSBN,
     428                 :                                                 adfBoundsMin, adfBoundsMax,
     429            5164 :                                                 &nSpatialFIDCount );
     430                 : 
     431                 :         CPLDebug( "SHAPE", "Used spatial index, got %d matches.", 
     432           17480 :                   nSpatialFIDCount );
     433                 : 
     434           17480 :         delete m_poFilterGeomLastValid;
     435           17480 :         m_poFilterGeomLastValid = m_poFilterGeom->clone();
     436                 :     }
     437                 : 
     438                 : /* -------------------------------------------------------------------- */
     439                 : /*      Use spatial index if appropriate.                               */
     440                 : /* -------------------------------------------------------------------- */
     441           17528 :     if( panSpatialFIDs != NULL )
     442                 :     {
     443                 :         // Use resulting list as matching FID list (but reallocate and
     444                 :         // terminate with OGRNullFID).
     445                 : 
     446           17494 :         if( panMatchingFIDs == NULL )
     447                 :         {
     448                 :             int i;
     449                 : 
     450                 :             panMatchingFIDs = (long *)
     451           17492 :                 CPLMalloc(sizeof(long) * (nSpatialFIDCount+1) );
     452          274116 :             for( i = 0; i < nSpatialFIDCount; i++ )
     453          256624 :                 panMatchingFIDs[i] = (long) panSpatialFIDs[i];
     454           17492 :             panMatchingFIDs[nSpatialFIDCount] = OGRNullFID;
     455                 :         }
     456                 : 
     457                 :         // Cull attribute index matches based on those in the spatial index
     458                 :         // result set.  We assume that the attribute results are in sorted
     459                 :         // order.
     460                 :         else
     461                 :         {
     462               2 :             int iRead, iWrite=0, iSpatial=0;
     463                 : 
     464               4 :             for( iRead = 0; panMatchingFIDs[iRead] != OGRNullFID; iRead++ )
     465                 :             {
     466              23 :                 while( iSpatial < nSpatialFIDCount
     467              14 :                        && panSpatialFIDs[iSpatial] < panMatchingFIDs[iRead] )
     468               5 :                     iSpatial++;
     469                 : 
     470               2 :                 if( iSpatial == nSpatialFIDCount )
     471               0 :                     continue;
     472                 : 
     473               2 :                 if( panSpatialFIDs[iSpatial] == panMatchingFIDs[iRead] )
     474               2 :                     panMatchingFIDs[iWrite++] = panMatchingFIDs[iRead];
     475                 :             }
     476               2 :             panMatchingFIDs[iWrite] = OGRNullFID;
     477                 :         }
     478                 : 
     479           17494 :         if (nSpatialFIDCount > 100000)
     480                 :         {
     481               0 :             ClearSpatialFIDs();
     482                 :         }
     483                 :     }
     484                 : 
     485           17528 :     return TRUE;
     486                 : }
     487                 : 
     488                 : /************************************************************************/
     489                 : /*                            ResetReading()                            */
     490                 : /************************************************************************/
     491                 : 
     492           37723 : void OGRShapeLayer::ResetReading()
     493                 : 
     494                 : {
     495           37723 :     if (!TouchLayer())
     496               0 :         return;
     497                 : 
     498           37723 :     iMatchingFID = 0;
     499                 : 
     500           37723 :     iNextShapeId = 0;
     501                 : 
     502           37723 :     if( bHeaderDirty && bUpdateAccess )
     503              15 :         SyncToDisk();
     504                 : }
     505                 : 
     506                 : /************************************************************************/
     507                 : /*                        ClearMatchingFIDs()                           */
     508                 : /************************************************************************/
     509                 : 
     510           23044 : void OGRShapeLayer::ClearMatchingFIDs()
     511                 : {
     512                 : /* -------------------------------------------------------------------- */
     513                 : /*      Clear previous index search result, if any.                     */
     514                 : /* -------------------------------------------------------------------- */
     515           23044 :     CPLFree( panMatchingFIDs );
     516           23044 :     panMatchingFIDs = NULL;
     517           23044 : }
     518                 : 
     519                 : /************************************************************************/
     520                 : /*                        ClearSpatialFIDs()                           */
     521                 : /************************************************************************/
     522                 : 
     523           21375 : void OGRShapeLayer::ClearSpatialFIDs()
     524                 : {
     525           21375 :     if ( panSpatialFIDs != NULL )
     526                 :     {
     527           17488 :         CPLDebug("SHAPE", "Clear panSpatialFIDs");
     528           17488 :         free( panSpatialFIDs );
     529                 :     }
     530           21375 :     panSpatialFIDs = NULL;
     531           21375 :     nSpatialFIDCount = 0;
     532                 : 
     533           21375 :     delete m_poFilterGeomLastValid;
     534           21375 :     m_poFilterGeomLastValid = NULL;
     535           21375 : }
     536                 : 
     537                 : /************************************************************************/
     538                 : /*                         SetSpatialFilter()                           */
     539                 : /************************************************************************/
     540                 : 
     541           18197 : void OGRShapeLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
     542                 : {
     543           18197 :     ClearMatchingFIDs();
     544                 : 
     545           18197 :     if( poGeomIn == NULL )
     546                 :     {
     547                 :         /* Do nothing */
     548                 :     }
     549           34995 :     else if ( m_poFilterGeomLastValid != NULL &&
     550           17467 :               m_poFilterGeomLastValid->Equals(poGeomIn) )
     551                 :     {
     552                 :         /* Do nothing */
     553                 :     }
     554           17522 :     else if ( panSpatialFIDs != NULL )
     555                 :     {
     556                 :         /* We clear the spatialFIDs only if we have a new non-NULL */
     557                 :         /* spatial filter, otherwise we keep the previous result */
     558                 :         /* cached. This can be usefull when several SQL layers */
     559                 :         /* rely on the same table layer, and use the same spatial */
     560                 :         /* filters. But as there is in the destructor of OGRGenSQLResultsLayer */
     561                 :         /* a clearing of the spatial filter of the table layer, we */
     562                 :         /* need this trick. */
     563           17461 :         ClearSpatialFIDs();
     564                 :     }
     565                 : 
     566           18197 :     return OGRLayer::SetSpatialFilter(poGeomIn);
     567                 : }
     568                 : 
     569                 : /************************************************************************/
     570                 : /*                         SetAttributeFilter()                         */
     571                 : /************************************************************************/
     572                 : 
     573             939 : OGRErr OGRShapeLayer::SetAttributeFilter( const char * pszAttributeFilter )
     574                 : {
     575             939 :     ClearMatchingFIDs();
     576                 : 
     577             939 :     return OGRLayer::SetAttributeFilter(pszAttributeFilter);
     578                 : }
     579                 : 
     580                 : /************************************************************************/
     581                 : /*                           SetNextByIndex()                           */
     582                 : /*                                                                      */
     583                 : /*      If we already have an FID list, we can easily resposition       */
     584                 : /*      ourselves in it.                                                */
     585                 : /************************************************************************/
     586                 : 
     587              22 : OGRErr OGRShapeLayer::SetNextByIndex( long nIndex )
     588                 : 
     589                 : {
     590              22 :     if (!TouchLayer())
     591               0 :         return OGRERR_FAILURE;
     592                 : 
     593              22 :     if( nIndex < 0 )
     594               5 :         return OGRERR_FAILURE;
     595                 : 
     596                 :     // Eventually we should try to use panMatchingFIDs list 
     597                 :     // if available and appropriate. 
     598              17 :     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
     599               0 :         return OGRLayer::SetNextByIndex( nIndex );
     600                 : 
     601              17 :     iNextShapeId = nIndex;
     602                 : 
     603              17 :     return OGRERR_NONE;
     604                 : }
     605                 : 
     606                 : /************************************************************************/
     607                 : /*                             FetchShape()                             */
     608                 : /*                                                                      */
     609                 : /*      Take a shape id, a geometry, and a feature, and set the feature */
     610                 : /*      if the shapeid bbox intersects the geometry.                    */
     611                 : /************************************************************************/
     612                 : 
     613          169539 : OGRFeature *OGRShapeLayer::FetchShape(int iShapeId /*, OGREnvelope* psShapeExtent */)
     614                 : 
     615                 : {
     616                 :     OGRFeature *poFeature;
     617                 : 
     618          297738 :     if (m_poFilterGeom != NULL && hSHP != NULL ) 
     619                 :     {
     620                 :         SHPObject   *psShape;
     621                 :         
     622          128199 :         psShape = SHPReadObject( hSHP, iShapeId );
     623                 : 
     624                 :         // do not trust degenerate bounds on non-point geometries
     625                 :         // or bounds on null shapes.
     626          128238 :         if( psShape == NULL
     627                 :             || (psShape->nSHPType != SHPT_POINT
     628                 :                 && psShape->nSHPType != SHPT_POINTZ
     629                 :                 && psShape->nSHPType != SHPT_POINTM
     630                 :                 && (psShape->dfXMin == psShape->dfXMax
     631                 :                  || psShape->dfYMin == psShape->dfYMax))
     632                 :             || psShape->nSHPType == SHPT_NULL )
     633                 :         {
     634                 :             poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn,
     635              39 :                                            iShapeId, psShape, osEncoding );
     636                 :         }
     637          219098 :         else if( m_sFilterEnvelope.MaxX < psShape->dfXMin 
     638                 :                  || m_sFilterEnvelope.MaxY < psShape->dfYMin
     639                 :                  || psShape->dfXMax  < m_sFilterEnvelope.MinX
     640                 :                  || psShape->dfYMax < m_sFilterEnvelope.MinY ) 
     641                 :         {
     642           90938 :             SHPDestroyObject(psShape);
     643           90938 :             poFeature = NULL;
     644                 :         } 
     645                 :         else 
     646                 :         {
     647                 :             /*psShapeExtent->MinX = psShape->dfXMin;
     648                 :             psShapeExtent->MinY = psShape->dfYMin;
     649                 :             psShapeExtent->MaxX = psShape->dfXMax;
     650                 :             psShapeExtent->MaxY = psShape->dfYMax;*/
     651                 :             poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn,
     652           37222 :                                            iShapeId, psShape, osEncoding );
     653                 :         }                
     654                 :     } 
     655                 :     else 
     656                 :     {
     657                 :         poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn,
     658           41340 :                                        iShapeId, NULL, osEncoding );
     659                 :     }    
     660                 :     
     661          169539 :     return poFeature;
     662                 : }
     663                 : 
     664                 : /************************************************************************/
     665                 : /*                           GetNextFeature()                           */
     666                 : /************************************************************************/
     667                 : 
     668           74798 : OGRFeature *OGRShapeLayer::GetNextFeature()
     669                 : 
     670                 : {
     671           74798 :     if (!TouchLayer())
     672               0 :         return NULL;
     673                 : 
     674           74798 :     OGRFeature  *poFeature = NULL;
     675                 : 
     676                 : /* -------------------------------------------------------------------- */
     677                 : /*      Collect a matching list if we have attribute or spatial         */
     678                 : /*      indices.  Only do this on the first request for a given pass    */
     679                 : /*      of course.                                                      */
     680                 : /* -------------------------------------------------------------------- */
     681           74798 :     if( (m_poAttrQuery != NULL || m_poFilterGeom != NULL)
     682                 :         && iNextShapeId == 0 && panMatchingFIDs == NULL )
     683                 :     {
     684           17883 :         ScanIndices();
     685                 :     }
     686                 :     
     687                 : /* -------------------------------------------------------------------- */
     688                 : /*      Loop till we find a feature matching our criteria.              */
     689                 : /* -------------------------------------------------------------------- */
     690           95409 :     while( TRUE )
     691                 :     {
     692                 :         //OGREnvelope oShapeExtent;
     693                 : 
     694          170207 :         if( panMatchingFIDs != NULL )
     695                 :         {
     696          125042 :             if( panMatchingFIDs[iMatchingFID] == OGRNullFID )
     697                 :             {
     698              19 :                 return NULL;
     699                 :             }
     700                 :             
     701                 :             // Check the shape object's geometry, and if it matches
     702                 :             // any spatial filter, return it.  
     703          125023 :             poFeature = FetchShape(panMatchingFIDs[iMatchingFID] /*, &oShapeExtent*/);
     704                 :             
     705          125023 :             iMatchingFID++;
     706                 : 
     707                 :         }
     708                 :         else
     709                 :         {
     710           45165 :             if( iNextShapeId >= nTotalShapeCount )
     711                 :             {
     712             642 :                 return NULL;
     713                 :             }
     714                 : 
     715           44523 :             if( hDBF )
     716                 :             {
     717           44496 :                 if (DBFIsRecordDeleted( hDBF, iNextShapeId ))
     718               7 :                     poFeature = NULL;
     719           44489 :                 else if( VSIFEofL((VSILFILE*)hDBF->fp) )
     720               0 :                     return NULL; /* There's an I/O error */
     721                 :                 else
     722           44489 :                     poFeature = FetchShape(iNextShapeId /*, &oShapeExtent */);
     723                 :             }
     724                 :             else
     725              27 :                 poFeature = FetchShape(iNextShapeId /*, &oShapeExtent */);
     726                 : 
     727           44523 :             iNextShapeId++;
     728                 :         }
     729                 :         
     730          169546 :         if( poFeature != NULL )
     731                 :         {
     732           78601 :             OGRGeometry* poGeom = poFeature->GetGeometryRef();
     733           78601 :             if( poGeom != NULL )
     734                 :             {
     735           75296 :                 poGeom->assignSpatialReference( GetSpatialRef() );
     736                 :             }
     737                 : 
     738           78601 :             m_nFeaturesRead++;
     739                 : 
     740           78601 :             if( (m_poFilterGeom == NULL || FilterGeometry( poGeom /*, &oShapeExtent*/ ) )
     741                 :                 && (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) )
     742                 :             {
     743           74137 :                 return poFeature;
     744                 :             }
     745                 : 
     746            4464 :             delete poFeature;
     747                 :         }
     748                 :     }
     749                 : }
     750                 : 
     751                 : /************************************************************************/
     752                 : /*                             GetFeature()                             */
     753                 : /************************************************************************/
     754                 : 
     755              81 : OGRFeature *OGRShapeLayer::GetFeature( long nFeatureId )
     756                 : 
     757                 : {
     758              81 :     if (!TouchLayer())
     759               0 :         return NULL;
     760                 : 
     761              81 :     OGRFeature *poFeature = NULL;
     762                 :     poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn, nFeatureId, NULL,
     763              81 :                                    osEncoding );
     764                 : 
     765              81 :     if( poFeature != NULL )
     766                 :     {
     767              69 :         if( poFeature->GetGeometryRef() != NULL )
     768                 :         {
     769              64 :             poFeature->GetGeometryRef()->assignSpatialReference( GetSpatialRef() );
     770                 :         }
     771                 : 
     772              69 :         m_nFeaturesRead++;
     773                 :     
     774              69 :         return poFeature;
     775                 :     }
     776                 : 
     777                 :     /*
     778                 :      * Reading shape feature failed.
     779                 :      */
     780              12 :     return NULL;
     781                 : }
     782                 : 
     783                 : /************************************************************************/
     784                 : /*                             SetFeature()                             */
     785                 : /************************************************************************/
     786                 : 
     787              30 : OGRErr OGRShapeLayer::SetFeature( OGRFeature *poFeature )
     788                 : 
     789                 : {
     790              30 :     if (!TouchLayer())
     791               0 :         return OGRERR_FAILURE;
     792                 : 
     793              30 :     if( !bUpdateAccess )
     794                 :     {
     795                 :         CPLError( CE_Failure, CPLE_NotSupported,
     796                 :                   UNSUPPORTED_OP_READ_ONLY,
     797               1 :                   "SetFeature");
     798               1 :         return OGRERR_FAILURE;
     799                 :     }
     800                 : 
     801              29 :     long nFID = poFeature->GetFID();
     802              29 :     if( nFID < 0
     803                 :         || (hSHP != NULL && nFID >= hSHP->nRecords)
     804                 :         || (hDBF != NULL && nFID >= hDBF->nRecords) )
     805                 :     {
     806                 :         CPLError( CE_Failure, CPLE_AppDefined,
     807                 :                   "Attempt to set shape with feature id (%ld) which does "
     808               2 :                   "not exist.", nFID );
     809               2 :         return OGRERR_FAILURE;
     810                 :     }
     811                 : 
     812              27 :     bHeaderDirty = TRUE;
     813              27 :     if( CheckForQIX() || CheckForSBN() )
     814               1 :         DropSpatialIndex();
     815                 : 
     816                 :     return SHPWriteOGRFeature( hSHP, hDBF, poFeatureDefn, poFeature,
     817              27 :                                osEncoding, &bTruncationWarningEmitted );
     818                 : }
     819                 : 
     820                 : /************************************************************************/
     821                 : /*                           DeleteFeature()                            */
     822                 : /************************************************************************/
     823                 : 
     824              11 : OGRErr OGRShapeLayer::DeleteFeature( long nFID )
     825                 : 
     826                 : {
     827              11 :     if (!TouchLayer())
     828               0 :         return OGRERR_FAILURE;
     829                 : 
     830              11 :     if( !bUpdateAccess )
     831                 :     {
     832                 :         CPLError( CE_Failure, CPLE_NotSupported,
     833                 :                   UNSUPPORTED_OP_READ_ONLY,
     834               1 :                   "DeleteFeature");
     835               1 :         return OGRERR_FAILURE;
     836                 :     }
     837                 : 
     838              10 :     if( nFID < 0 
     839                 :         || (hSHP != NULL && nFID >= hSHP->nRecords)
     840                 :         || (hDBF != NULL && nFID >= hDBF->nRecords) )
     841                 :     {
     842                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     843                 :                   "Attempt to delete shape with feature id (%ld) which does "
     844               1 :                   "not exist.", nFID );
     845               1 :         return OGRERR_FAILURE;
     846                 :     }
     847                 : 
     848               9 :     if( !hDBF )
     849                 :     {
     850                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     851                 :                   "Attempt to delete shape in shapefile with no .dbf file.\n"
     852                 :                   "Deletion is done by marking record deleted in dbf\n"
     853               1 :                   "and is not supported without a .dbf file." );
     854               1 :         return OGRERR_FAILURE;
     855                 :     }
     856                 : 
     857               8 :     if( DBFIsRecordDeleted( hDBF, nFID ) )
     858                 :     {
     859                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     860                 :                   "Attempt to delete shape with feature id (%ld), but it is marked deleted already.",
     861               1 :                   nFID );
     862               1 :         return OGRERR_FAILURE;
     863                 :     }
     864                 : 
     865               7 :     if( !DBFMarkRecordDeleted( hDBF, nFID, TRUE ) )
     866               0 :         return OGRERR_FAILURE;
     867                 : 
     868               7 :     bHeaderDirty = TRUE;
     869               7 :     if( CheckForQIX() || CheckForSBN() )
     870               1 :         DropSpatialIndex();
     871                 : 
     872               7 :     return OGRERR_NONE;
     873                 : }
     874                 : 
     875                 : /************************************************************************/
     876                 : /*                           CreateFeature()                            */
     877                 : /************************************************************************/
     878                 : 
     879           29699 : OGRErr OGRShapeLayer::CreateFeature( OGRFeature *poFeature )
     880                 : 
     881                 : {
     882                 :     OGRErr eErr;
     883                 : 
     884           29699 :     if (!TouchLayer())
     885               0 :         return OGRERR_FAILURE;
     886                 : 
     887           29699 :     if( !bUpdateAccess )
     888                 :     {
     889                 :         CPLError( CE_Failure, CPLE_NotSupported,
     890                 :                   UNSUPPORTED_OP_READ_ONLY,
     891               1 :                   "CreateFeature");
     892               1 :         return OGRERR_FAILURE;
     893                 :     }
     894                 : 
     895           29698 :     bHeaderDirty = TRUE;
     896           29698 :     if( CheckForQIX() || CheckForSBN() )
     897               2 :         DropSpatialIndex();
     898                 : 
     899           29698 :     poFeature->SetFID( OGRNullFID );
     900                 : 
     901           29698 :     if( nTotalShapeCount == 0 
     902                 :         && eRequestedGeomType == wkbUnknown 
     903                 :         && poFeature->GetGeometryRef() != NULL )
     904                 :     {
     905             574 :         OGRGeometry     *poGeom = poFeature->GetGeometryRef();
     906                 :         int             nShapeType;
     907                 :         
     908             574 :         switch( poGeom->getGeometryType() )
     909                 :         {
     910                 :           case wkbPoint:
     911             520 :             nShapeType = SHPT_POINT;
     912             520 :             eRequestedGeomType = wkbPoint;
     913             520 :             break;
     914                 : 
     915                 :           case wkbPoint25D:
     916               3 :             nShapeType = SHPT_POINTZ;
     917               3 :             eRequestedGeomType = wkbPoint25D;
     918               3 :             break;
     919                 : 
     920                 :           case wkbMultiPoint:
     921               4 :             nShapeType = SHPT_MULTIPOINT;
     922               4 :             eRequestedGeomType = wkbMultiPoint;
     923               4 :             break;
     924                 : 
     925                 :           case wkbMultiPoint25D:
     926               2 :             nShapeType = SHPT_MULTIPOINTZ;
     927               2 :             eRequestedGeomType = wkbMultiPoint25D;
     928               2 :             break;
     929                 : 
     930                 :           case wkbLineString:
     931                 :           case wkbMultiLineString:
     932               8 :             nShapeType = SHPT_ARC;
     933               8 :             eRequestedGeomType = wkbLineString;
     934               8 :             break;
     935                 : 
     936                 :           case wkbLineString25D:
     937                 :           case wkbMultiLineString25D:
     938               5 :             nShapeType = SHPT_ARCZ;
     939               5 :             eRequestedGeomType = wkbLineString25D;
     940               5 :             break;
     941                 : 
     942                 :           case wkbPolygon:
     943                 :           case wkbMultiPolygon:
     944              28 :             nShapeType = SHPT_POLYGON;
     945              28 :             eRequestedGeomType = wkbPolygon;
     946              28 :             break;
     947                 : 
     948                 :           case wkbPolygon25D:
     949                 :           case wkbMultiPolygon25D:
     950               4 :             nShapeType = SHPT_POLYGONZ;
     951               4 :             eRequestedGeomType = wkbPolygon25D;
     952               4 :             break;
     953                 : 
     954                 :           default:
     955               0 :             nShapeType = -1;
     956                 :             break;
     957                 :         }
     958                 : 
     959             574 :         if( nShapeType != -1 )
     960                 :         {
     961             574 :             ResetGeomType( nShapeType );
     962                 :         }
     963                 :     }
     964                 :     
     965                 :     eErr = SHPWriteOGRFeature( hSHP, hDBF, poFeatureDefn, poFeature, 
     966           29698 :                                osEncoding, &bTruncationWarningEmitted );
     967                 : 
     968           29698 :     if( hSHP != NULL )
     969           29671 :         nTotalShapeCount = hSHP->nRecords;
     970                 :     else 
     971              27 :         nTotalShapeCount = hDBF->nRecords;
     972                 :     
     973           29698 :     return eErr;
     974                 : }
     975                 : 
     976                 : /************************************************************************/
     977                 : /*               GetFeatureCountWithSpatialFilterOnly()                 */
     978                 : /*                                                                      */
     979                 : /* Specialized implementation of GetFeatureCount() when there is *only* */
     980                 : /* a spatial filter and no attribute filter.                            */
     981                 : /************************************************************************/
     982                 : 
     983              48 : int OGRShapeLayer::GetFeatureCountWithSpatialFilterOnly()
     984                 : 
     985                 : {
     986                 : /* -------------------------------------------------------------------- */
     987                 : /*      Collect a matching list if we have attribute or spatial         */
     988                 : /*      indices.  Only do this on the first request for a given pass    */
     989                 : /*      of course.                                                      */
     990                 : /* -------------------------------------------------------------------- */
     991              48 :     if( panMatchingFIDs == NULL )
     992                 :     {
     993              48 :         ScanIndices();
     994                 :     }
     995                 : 
     996              48 :     int nFeatureCount = 0;
     997              48 :     int iLocalMatchingFID = 0;
     998              48 :     int iLocalNextShapeId = 0;
     999              48 :     int bExpectPoints = FALSE;
    1000                 : 
    1001              48 :     if (wkbFlatten(poFeatureDefn->GetGeomType()) == wkbPoint)
    1002              27 :         bExpectPoints = TRUE;
    1003                 : 
    1004                 : /* -------------------------------------------------------------------- */
    1005                 : /*      Loop till we find a feature matching our criteria.              */
    1006                 : /* -------------------------------------------------------------------- */
    1007                 : 
    1008                 :     SHPObject sShape;
    1009              48 :     memset(&sShape, 0, sizeof(sShape));
    1010                 : 
    1011              48 :     VSILFILE* fpSHP = (VSILFILE*) hSHP->fpSHP;
    1012                 : 
    1013           17622 :     while( TRUE )
    1014                 :     {
    1015           17670 :         SHPObject* psShape = NULL;
    1016           17670 :         int iShape = -1;
    1017                 : 
    1018           17670 :         if( panMatchingFIDs != NULL )
    1019                 :         {
    1020           17549 :             iShape = panMatchingFIDs[iLocalMatchingFID];
    1021           17549 :             if( iShape == OGRNullFID )
    1022              37 :                 break;
    1023           17512 :             iLocalMatchingFID++;
    1024                 :         }
    1025                 :         else
    1026                 :         {
    1027             121 :             if( iLocalNextShapeId >= nTotalShapeCount )
    1028              11 :                 break;
    1029             110 :             iShape = iLocalNextShapeId ++;
    1030                 : 
    1031             110 :             if( hDBF )
    1032                 :             {
    1033             110 :                 if (DBFIsRecordDeleted( hDBF, iShape ))
    1034               0 :                     continue;
    1035                 : 
    1036             110 :                 if (VSIFEofL((VSILFILE*)hDBF->fp))
    1037               0 :                     break;
    1038                 :             }
    1039                 :         }
    1040                 : 
    1041                 :         /* Read full shape for point layers */
    1042           17622 :         if (bExpectPoints)
    1043            1120 :             psShape = SHPReadObject( hSHP, iShape);
    1044                 : 
    1045                 : /* -------------------------------------------------------------------- */
    1046                 : /*      Only read feature type and bounding box for now. In case of     */
    1047                 : /*      inconclusive tests on bounding box only, we will read the full  */
    1048                 : /*      shape later.                                                    */
    1049                 : /* -------------------------------------------------------------------- */
    1050           33004 :         else if (iShape >= 0 && iShape < hSHP->nRecords &&
    1051           16502 :                     hSHP->panRecSize[iShape] > 4 + 8 * 4 )
    1052                 :         {
    1053                 :             GByte abyBuf[4 + 8 * 4];
    1054           16502 :             if( VSIFSeekL( fpSHP, hSHP->panRecOffset[iShape] + 8, 0 ) == 0 &&
    1055                 :                 VSIFReadL( abyBuf, sizeof(abyBuf), 1, fpSHP ) == 1 )
    1056                 :             {
    1057           16502 :                 memcpy(&(sShape.nSHPType), abyBuf, 4);
    1058                 :                 CPL_LSBPTR32(&(sShape.nSHPType));
    1059           16502 :                 if ( sShape.nSHPType != SHPT_NULL &&
    1060                 :                         sShape.nSHPType != SHPT_POINT &&
    1061                 :                         sShape.nSHPType != SHPT_POINTM &&
    1062                 :                         sShape.nSHPType != SHPT_POINTZ)
    1063                 :                 {
    1064           16502 :                     psShape = &sShape;
    1065           16502 :                     memcpy(&(sShape.dfXMin), abyBuf + 4, 8);
    1066           16502 :                     memcpy(&(sShape.dfYMin), abyBuf + 12, 8);
    1067           16502 :                     memcpy(&(sShape.dfXMax), abyBuf + 20, 8);
    1068           16502 :                     memcpy(&(sShape.dfYMax), abyBuf + 28, 8);
    1069                 :                     CPL_LSBPTR64(&(sShape.dfXMin));
    1070                 :                     CPL_LSBPTR64(&(sShape.dfYMin));
    1071                 :                     CPL_LSBPTR64(&(sShape.dfXMax));
    1072                 :                     CPL_LSBPTR64(&(sShape.dfYMax));
    1073                 :                 }
    1074                 :             }
    1075                 :             else
    1076                 :             {
    1077               0 :                 break;
    1078                 :             }
    1079                 :         }
    1080                 : 
    1081           35244 :         if( psShape != NULL && psShape->nSHPType != SHPT_NULL )
    1082                 :         {
    1083           17622 :             OGRGeometry* poGeometry = NULL;
    1084           17622 :             OGREnvelope sGeomEnv;
    1085                 :             /* Test if we have a degenerated bounding box */
    1086           17627 :             if (psShape->nSHPType != SHPT_POINT
    1087                 :                 && psShape->nSHPType != SHPT_POINTZ
    1088                 :                 && psShape->nSHPType != SHPT_POINTM
    1089                 :                 && (psShape->dfXMin == psShape->dfXMax
    1090                 :                     || psShape->dfYMin == psShape->dfYMax))
    1091                 :             {
    1092                 :                 /* We need to read the full geometry */
    1093                 :                 /* to compute the envelope */
    1094               5 :                 if (psShape == &sShape)
    1095               5 :                     psShape = SHPReadObject( hSHP, iShape);
    1096               5 :                 if (psShape)
    1097                 :                 {
    1098               5 :                     poGeometry = SHPReadOGRObject( hSHP, iShape, psShape );
    1099               5 :                     poGeometry->getEnvelope( &sGeomEnv );
    1100               5 :                     psShape = NULL;
    1101                 :                 }
    1102                 :             }
    1103                 :             else
    1104                 :             {
    1105                 :                 /* Trust the shape bounding box as the shape envelope */
    1106           17617 :                 sGeomEnv.MinX = psShape->dfXMin;
    1107           17617 :                 sGeomEnv.MinY = psShape->dfYMin;
    1108           17617 :                 sGeomEnv.MaxX = psShape->dfXMax;
    1109           17617 :                 sGeomEnv.MaxY = psShape->dfYMax;
    1110                 :             }
    1111                 : 
    1112                 : /* -------------------------------------------------------------------- */
    1113                 : /*      If there is no                                                  */
    1114                 : /*      intersection between the envelopes we are sure not to have      */
    1115                 : /*      any intersection.                                               */
    1116                 : /* -------------------------------------------------------------------- */
    1117           17622 :             if( sGeomEnv.MaxX < m_sFilterEnvelope.MinX
    1118                 :                 || sGeomEnv.MaxY < m_sFilterEnvelope.MinY
    1119                 :                 || m_sFilterEnvelope.MaxX < sGeomEnv.MinX
    1120                 :                 || m_sFilterEnvelope.MaxY < sGeomEnv.MinY )
    1121                 :             {
    1122                 :             }
    1123                 : /* -------------------------------------------------------------------- */
    1124                 : /*      If the filter geometry is its own envelope and if the           */
    1125                 : /*      envelope of the geometry is inside the filter geometry,         */
    1126                 : /*      the geometry itself is inside the filter geometry               */
    1127                 : /* -------------------------------------------------------------------- */
    1128           34457 :             else if( m_bFilterIsEnvelope &&
    1129                 :                 sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
    1130                 :                 sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
    1131                 :                 sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
    1132                 :                 sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
    1133                 :             {
    1134           16949 :                 nFeatureCount ++;
    1135                 :             }
    1136                 :             else
    1137                 :             {
    1138                 : /* -------------------------------------------------------------------- */
    1139                 : /*      Fallback to full intersect test (using GEOS) if we still        */
    1140                 : /*      don't know for sure.                                            */
    1141                 : /* -------------------------------------------------------------------- */
    1142             559 :                 if( OGRGeometryFactory::haveGEOS() )
    1143                 :                 {
    1144                 :                     /* We need to read the full geometry */
    1145             559 :                     if (poGeometry == NULL)
    1146                 :                     {
    1147             559 :                         if (psShape == &sShape)
    1148             559 :                             psShape = SHPReadObject( hSHP, iShape);
    1149             559 :                         if (psShape)
    1150                 :                         {
    1151                 :                             poGeometry =
    1152             559 :                                 SHPReadOGRObject( hSHP, iShape, psShape );
    1153             559 :                             psShape = NULL;
    1154                 :                         }
    1155                 :                     }
    1156             559 :                     if( poGeometry == NULL )
    1157               0 :                         nFeatureCount ++;
    1158             559 :                     else if ( m_pPreparedFilterGeom != NULL )
    1159                 :                     {
    1160             559 :                         if( OGRPreparedGeometryIntersects(m_pPreparedFilterGeom,
    1161                 :                                                           poGeometry) )
    1162                 :                         {
    1163             544 :                             nFeatureCount ++;
    1164                 :                         }
    1165                 :                     }
    1166               0 :                     else if( m_poFilterGeom->Intersects( poGeometry ) )
    1167               0 :                         nFeatureCount ++;
    1168                 :                 }
    1169                 :                 else
    1170               0 :                     nFeatureCount ++;
    1171                 :             }
    1172                 : 
    1173           17622 :             delete poGeometry;
    1174                 :         }
    1175                 :         else
    1176               0 :             nFeatureCount ++;
    1177                 : 
    1178           17622 :         if (psShape && psShape != &sShape)
    1179            1120 :             SHPDestroyObject( psShape );
    1180                 :     }
    1181                 : 
    1182              48 :     return nFeatureCount;
    1183                 : }
    1184                 : 
    1185                 : /************************************************************************/
    1186                 : /*                          GetFeatureCount()                           */
    1187                 : /************************************************************************/
    1188                 : 
    1189             426 : int OGRShapeLayer::GetFeatureCount( int bForce )
    1190                 : 
    1191                 : {
    1192                 :     /* Check if the spatial filter is non-trivial */
    1193                 :     int bHasTrivialSpatialFilter;
    1194             426 :     if (m_poFilterGeom != NULL)
    1195                 :     {
    1196              52 :         OGREnvelope oSpatialFilterEnvelope;
    1197              52 :         m_poFilterGeom->getEnvelope( &oSpatialFilterEnvelope );
    1198                 : 
    1199              52 :         OGREnvelope oLayerExtent;
    1200              52 :         if (GetExtent(&oLayerExtent, TRUE) == OGRERR_NONE)
    1201                 :         {
    1202              52 :             if (oSpatialFilterEnvelope.Contains(oLayerExtent))
    1203                 :             {
    1204               4 :                 bHasTrivialSpatialFilter = TRUE;
    1205                 :             }
    1206                 :             else
    1207              48 :                 bHasTrivialSpatialFilter = FALSE;
    1208                 :         }
    1209                 :         else
    1210               0 :             bHasTrivialSpatialFilter = FALSE;
    1211                 :     }
    1212                 :     else
    1213             374 :         bHasTrivialSpatialFilter = TRUE;
    1214                 : 
    1215                 : 
    1216             426 :     if( bHasTrivialSpatialFilter && m_poAttrQuery == NULL )
    1217             244 :         return nTotalShapeCount;
    1218                 : 
    1219             182 :     if (!TouchLayer())
    1220               0 :         return 0;
    1221                 : 
    1222                 :     /* Spatial filter only */
    1223             182 :     if( m_poAttrQuery == NULL && hSHP != NULL )
    1224                 :     {
    1225              48 :         return GetFeatureCountWithSpatialFilterOnly();
    1226                 :     }
    1227                 : 
    1228                 :     /* Attribute filter only */
    1229             134 :     if( m_poAttrQuery != NULL )
    1230                 :     {
    1231                 :         /* Let's see if we can ignore reading geometries */
    1232             134 :         int bSaveGeometryIgnored = poFeatureDefn->IsGeometryIgnored();
    1233             134 :         if (!AttributeFilterEvaluationNeedsGeometry())
    1234             134 :             poFeatureDefn->SetGeometryIgnored(TRUE);
    1235                 : 
    1236             134 :         int nRet = OGRLayer::GetFeatureCount( bForce );
    1237                 : 
    1238             134 :         poFeatureDefn->SetGeometryIgnored(bSaveGeometryIgnored);
    1239             134 :         return nRet;
    1240                 :     }
    1241                 : 
    1242               0 :     return OGRLayer::GetFeatureCount( bForce );
    1243                 : }
    1244                 : 
    1245                 : /************************************************************************/
    1246                 : /*                             GetExtent()                              */
    1247                 : /*                                                                      */
    1248                 : /*      Fetch extent of the data currently stored in the dataset.       */
    1249                 : /*      The bForce flag has no effect on SHP files since that value     */
    1250                 : /*      is always in the header.                                        */
    1251                 : /*                                                                      */
    1252                 : /*      Returns OGRERR_NONE/OGRRERR_FAILURE.                            */
    1253                 : /************************************************************************/
    1254                 : 
    1255           17658 : OGRErr OGRShapeLayer::GetExtent (OGREnvelope *psExtent, int bForce)
    1256                 : 
    1257                 : {
    1258                 :     UNREFERENCED_PARAM( bForce );
    1259                 : 
    1260           17658 :     if (!TouchLayer())
    1261               0 :         return OGRERR_FAILURE;
    1262                 : 
    1263                 :     double adMin[4], adMax[4];
    1264                 : 
    1265           17658 :     if( hSHP == NULL )
    1266               1 :         return OGRERR_FAILURE;
    1267                 : 
    1268           17657 :     SHPGetInfo(hSHP, NULL, NULL, adMin, adMax);
    1269                 : 
    1270           17657 :     psExtent->MinX = adMin[0];
    1271           17657 :     psExtent->MinY = adMin[1];
    1272           17657 :     psExtent->MaxX = adMax[0];
    1273           17657 :     psExtent->MaxY = adMax[1];
    1274                 : 
    1275           17657 :     return OGRERR_NONE;
    1276                 : }
    1277                 : 
    1278                 : /************************************************************************/
    1279                 : /*                           TestCapability()                           */
    1280                 : /************************************************************************/
    1281                 : 
    1282            4197 : int OGRShapeLayer::TestCapability( const char * pszCap )
    1283                 : 
    1284                 : {
    1285            4197 :     if (!TouchLayer())
    1286               0 :         return FALSE;
    1287                 : 
    1288            4197 :     if( EQUAL(pszCap,OLCRandomRead) )
    1289               9 :         return TRUE;
    1290                 : 
    1291            4188 :     else if( EQUAL(pszCap,OLCSequentialWrite) 
    1292                 :              || EQUAL(pszCap,OLCRandomWrite) )
    1293               9 :         return bUpdateAccess;
    1294                 : 
    1295            4179 :     else if( EQUAL(pszCap,OLCFastFeatureCount) )
    1296                 :     {
    1297             103 :         if( !(m_poFilterGeom == NULL || CheckForQIX() || CheckForSBN()) )
    1298               0 :             return FALSE;
    1299                 : 
    1300             103 :         if( m_poAttrQuery != NULL )
    1301                 :         {
    1302              67 :             InitializeIndexSupport( pszFullName );
    1303              67 :             return m_poAttrQuery->CanUseIndex(this);
    1304                 :         }
    1305              36 :         return TRUE;
    1306                 :     }
    1307                 : 
    1308            4076 :     else if( EQUAL(pszCap,OLCDeleteFeature) )
    1309               2 :         return bUpdateAccess;
    1310                 : 
    1311            4074 :     else if( EQUAL(pszCap,OLCFastSpatialFilter) )
    1312               6 :         return CheckForQIX() || CheckForSBN();
    1313                 : 
    1314            4068 :     else if( EQUAL(pszCap,OLCFastGetExtent) )
    1315               6 :         return TRUE;
    1316                 : 
    1317            4062 :     else if( EQUAL(pszCap,OLCFastSetNextByIndex) )
    1318              18 :         return m_poFilterGeom == NULL && m_poAttrQuery == NULL;
    1319                 : 
    1320            4044 :     else if( EQUAL(pszCap,OLCCreateField) )
    1321               1 :         return bUpdateAccess;
    1322                 : 
    1323            4043 :     else if( EQUAL(pszCap,OLCDeleteField) )
    1324               2 :         return bUpdateAccess;
    1325                 : 
    1326            4041 :     else if( EQUAL(pszCap,OLCReorderFields) )
    1327               2 :         return bUpdateAccess;
    1328                 : 
    1329            4039 :     else if( EQUAL(pszCap,OLCAlterFieldDefn) )
    1330               2 :         return bUpdateAccess;
    1331                 : 
    1332            4037 :     else if( EQUAL(pszCap,OLCIgnoreFields) )
    1333             380 :         return TRUE;
    1334                 : 
    1335            3657 :     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
    1336                 :     {
    1337                 :         /* No encoding defined : we don't know */
    1338            3654 :         if( osEncoding.size() == 0)
    1339               4 :             return FALSE;
    1340                 : 
    1341            3650 :         if( hDBF == NULL || DBFGetFieldCount( hDBF ) == 0 )
    1342            1224 :             return TRUE;
    1343                 : 
    1344            2426 :         CPLClearRecodeWarningFlags();
    1345                 : 
    1346                 :         /* Otherwise test that we can re-encode field names to UTF-8 */
    1347            2426 :         int nFieldCount = DBFGetFieldCount( hDBF );
    1348            5525 :         for(int i=0;i<nFieldCount;i++)
    1349                 :         {
    1350                 :             char            szFieldName[20];
    1351                 :             int             nWidth, nPrecision;
    1352                 : 
    1353                 :             DBFGetFieldInfo( hDBF, i, szFieldName,
    1354            3100 :                             &nWidth, &nPrecision );
    1355                 : 
    1356            3100 :             CPLErrorReset();
    1357            3100 :             CPLPushErrorHandler(CPLQuietErrorHandler);
    1358                 :             char *pszUTF8Field = CPLRecode( szFieldName,
    1359            3100 :                                             osEncoding, CPL_ENC_UTF8);
    1360            3100 :             CPLPopErrorHandler();
    1361            3100 :             CPLFree( pszUTF8Field );
    1362                 : 
    1363            3100 :             if (CPLGetLastErrorType() != 0)
    1364                 :             {
    1365               1 :                 return FALSE;
    1366                 :             }
    1367                 :         }
    1368                 : 
    1369            2425 :         return TRUE;
    1370                 :     }
    1371                 :     else 
    1372               3 :         return FALSE;
    1373                 : }
    1374                 : 
    1375                 : /************************************************************************/
    1376                 : /*                            CreateField()                             */
    1377                 : /************************************************************************/
    1378                 : 
    1379            4354 : OGRErr OGRShapeLayer::CreateField( OGRFieldDefn *poFieldDefn, int bApproxOK )
    1380                 : 
    1381                 : {
    1382            4354 :     if (!TouchLayer())
    1383               0 :         return OGRERR_FAILURE;
    1384                 : 
    1385            4354 :     CPLAssert( NULL != poFieldDefn );
    1386                 :     
    1387                 :     int         iNewField;
    1388                 : 
    1389            4354 :     if( !bUpdateAccess )
    1390                 :     {
    1391                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1392                 :                   UNSUPPORTED_OP_READ_ONLY,
    1393               1 :                   "CreateField");
    1394               1 :         return OGRERR_FAILURE;
    1395                 : 
    1396                 :     }
    1397                 : 
    1398            4353 :     int bDBFJustCreated = FALSE;
    1399            4353 :     if( hDBF == NULL )
    1400                 :     {
    1401               1 :         CPLString osFilename = CPLResetExtension( pszFullName, "dbf" );
    1402               1 :         hDBF = DBFCreate( osFilename );
    1403                 : 
    1404               1 :         if( hDBF == NULL )
    1405                 :         {
    1406                 :             CPLError( CE_Failure, CPLE_OpenFailed,
    1407                 :                       "Failed to create DBF file `%s'.\n",
    1408               0 :                       osFilename.c_str() );
    1409               0 :             return OGRERR_FAILURE;
    1410                 :         }
    1411                 : 
    1412               1 :         bDBFJustCreated = TRUE;
    1413                 :     }
    1414                 : 
    1415            4353 :     CPLErrorReset();
    1416                 : 
    1417            4353 :     if ( poFeatureDefn->GetFieldCount() == 255 )
    1418                 :     {
    1419                 :         CPLError( CE_Warning, CPLE_AppDefined,
    1420               2 :                   "Creating a 256th field, but some DBF readers might only support 255 fields" );
    1421                 :     }
    1422            4353 :     if ( hDBF->nHeaderLength + 32 > 65535 )
    1423                 :     {
    1424                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1425               1 :                   "Cannot add more fields in DBF file.");
    1426               1 :         return OGRERR_FAILURE;
    1427                 :     }
    1428                 : 
    1429                 : /* -------------------------------------------------------------------- */
    1430                 : /*      Normalize field name                                            */
    1431                 : /* -------------------------------------------------------------------- */
    1432                 :         
    1433                 :     char szNewFieldName[10 + 1];
    1434            4352 :     char * pszTmp = NULL;
    1435            4352 :     int nRenameNum = 1;
    1436                 : 
    1437            4352 :     CPLString osFieldName;
    1438            4352 :     if( osEncoding.size() )
    1439                 :     {
    1440            4351 :         CPLClearRecodeWarningFlags();
    1441            4351 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    1442            4351 :         CPLErr eLastErr = CPLGetLastErrorType();
    1443            4351 :         char* pszRecoded = CPLRecode( poFieldDefn->GetNameRef(), CPL_ENC_UTF8, osEncoding);
    1444            4351 :         CPLPopErrorHandler();
    1445            4351 :         osFieldName = pszRecoded;
    1446            4351 :         CPLFree(pszRecoded);
    1447            4351 :         if( CPLGetLastErrorType() != eLastErr )
    1448                 :         {
    1449                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1450                 :                      "Failed to create field name '%s' : cannot convert to %s",
    1451               1 :                      poFieldDefn->GetNameRef(), osEncoding.c_str());
    1452               1 :             return OGRERR_FAILURE;
    1453                 :         }
    1454                 :     }
    1455                 :     else
    1456               1 :         osFieldName = poFieldDefn->GetNameRef();
    1457                 : 
    1458            4351 :     size_t nNameSize = osFieldName.size();
    1459                 :     pszTmp = CPLScanString( osFieldName,
    1460            4351 :                             MIN( nNameSize, 10) , TRUE, TRUE);
    1461            4351 :     strncpy(szNewFieldName, pszTmp, 10);
    1462            4351 :     szNewFieldName[10] = '\0';
    1463                 : 
    1464            4351 :     if( !bApproxOK &&
    1465                 :         ( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 ||
    1466                 :           !EQUAL(osFieldName,szNewFieldName) ) )
    1467                 :     {
    1468                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1469                 :                   "Failed to add field named '%s'",
    1470               0 :                   poFieldDefn->GetNameRef() );
    1471                 :                   
    1472               0 :         CPLFree( pszTmp );
    1473               0 :         return OGRERR_FAILURE;
    1474                 :     }
    1475                 : 
    1476            8879 :     while( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 && nRenameNum < 10 )
    1477             177 :         sprintf( szNewFieldName, "%.8s_%.1d", pszTmp, nRenameNum++ );
    1478            8707 :     while( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 && nRenameNum < 100 )
    1479               5 :         sprintf( szNewFieldName, "%.8s%.2d", pszTmp, nRenameNum++ );
    1480                 : 
    1481            4351 :     CPLFree( pszTmp );
    1482            4351 :     pszTmp = NULL;
    1483                 :     
    1484            4351 :     if( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 )
    1485                 :     {
    1486                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1487                 :                   "Too many field names like '%s' when truncated to 10 letters "
    1488                 :                   "for Shapefile format.",
    1489               0 :                   poFieldDefn->GetNameRef() );//One hundred similar field names!!?
    1490                 :     }
    1491                 : 
    1492            4351 :     OGRFieldDefn oModFieldDefn(poFieldDefn);
    1493                 : 
    1494            4351 :     if( !EQUAL(osFieldName,szNewFieldName) )
    1495                 :     {
    1496                 :         CPLError( CE_Warning, CPLE_NotSupported,
    1497                 :                   "Normalized/laundered field name: '%s' to '%s'", 
    1498                 :                   poFieldDefn->GetNameRef(),
    1499              46 :                   szNewFieldName );
    1500                 : 
    1501                 :         // Set field name with normalized value
    1502              46 :         oModFieldDefn.SetName(szNewFieldName);
    1503                 :     }
    1504                 : 
    1505                 : /* -------------------------------------------------------------------- */
    1506                 : /*      Add field to layer                                              */
    1507                 : /* -------------------------------------------------------------------- */
    1508                 : 
    1509            4351 :     char chType = 'C';
    1510            4351 :     int nWidth = 0;
    1511            4351 :     int nDecimals = 0;
    1512                 : 
    1513            4351 :     switch( oModFieldDefn.GetType() )
    1514                 :     {
    1515                 :         case OFTInteger:
    1516            2093 :             chType = 'N';
    1517            2093 :             nWidth = oModFieldDefn.GetWidth();
    1518            2093 :             if (nWidth == 0) nWidth = 10;
    1519            2093 :             break;
    1520                 : 
    1521                 :         case OFTReal:
    1522             148 :             chType = 'N';
    1523             148 :             nWidth = oModFieldDefn.GetWidth();
    1524             148 :             nDecimals = oModFieldDefn.GetPrecision();
    1525             148 :             if (nWidth == 0)
    1526                 :             {
    1527               8 :                 nWidth = 24;
    1528               8 :                 nDecimals = 15;
    1529                 :             }
    1530             148 :             break;
    1531                 : 
    1532                 :         case OFTString:
    1533            2109 :             chType = 'C';
    1534            2109 :             nWidth = oModFieldDefn.GetWidth();
    1535            2109 :             if (nWidth == 0) nWidth = 80;
    1536              80 :             else if (nWidth > 255)
    1537                 :             {
    1538                 :                 CPLError( CE_Warning, CPLE_AppDefined,
    1539                 :                         "Field %s of width %d truncated to %d.",
    1540               1 :                         szNewFieldName, nWidth, 255 );
    1541               1 :                 nWidth = 255;
    1542                 :             }
    1543            2109 :             break;
    1544                 : 
    1545                 :         case OFTDate:
    1546               1 :             chType = 'D';
    1547               1 :             nWidth = 8;
    1548               1 :             break;
    1549                 : 
    1550                 :         case OFTDateTime:
    1551                 :             CPLError( CE_Warning, CPLE_NotSupported,
    1552                 :                     "Field %s create as date field, though DateTime requested.",
    1553               0 :                     szNewFieldName );
    1554               0 :             chType = 'D';
    1555               0 :             nWidth = 8;
    1556               0 :             oModFieldDefn.SetType( OFTDate );
    1557               0 :             break;
    1558                 : 
    1559                 :         default:
    1560                 :             CPLError( CE_Failure, CPLE_NotSupported,
    1561                 :                     "Can't create fields of type %s on shapefile layers.",
    1562               0 :                     OGRFieldDefn::GetFieldTypeName(oModFieldDefn.GetType()) );
    1563                 : 
    1564               0 :             return OGRERR_FAILURE;
    1565                 :             break;
    1566                 :     }
    1567                 : 
    1568            4351 :     oModFieldDefn.SetWidth( nWidth );
    1569            4351 :     oModFieldDefn.SetPrecision( nDecimals );
    1570                 : 
    1571            4351 :     if ( hDBF->nRecordLength + nWidth > 65535 )
    1572                 :     {
    1573                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1574                 :                   "Can't create field %s in Shape DBF file. "
    1575                 :                   "Maximum record length reached.",
    1576               1 :                   szNewFieldName );
    1577               1 :         return OGRERR_FAILURE;
    1578                 :     }
    1579                 : 
    1580                 :     iNewField =
    1581                 :         DBFAddNativeFieldType( hDBF, szNewFieldName,
    1582            4350 :                                chType, nWidth, nDecimals );
    1583                 : 
    1584            4350 :     if( iNewField != -1 )
    1585                 :     {
    1586            4350 :         poFeatureDefn->AddFieldDefn( &oModFieldDefn );
    1587                 : 
    1588            4350 :         if( bDBFJustCreated )
    1589                 :         {
    1590               2 :             for(int i=0;i<nTotalShapeCount;i++)
    1591                 :             {
    1592               1 :                 DBFWriteNULLAttribute( hDBF, i, 0 );
    1593                 :             }
    1594                 :         }
    1595                 : 
    1596            4350 :         return OGRERR_NONE;
    1597                 :     }
    1598                 :     else        
    1599                 :     {
    1600                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1601                 :                   "Can't create field %s in Shape DBF file, reason unknown.",
    1602               0 :                   szNewFieldName );
    1603                 : 
    1604               0 :         return OGRERR_FAILURE;
    1605               0 :     }
    1606                 : }
    1607                 : 
    1608                 : /************************************************************************/
    1609                 : /*                            DeleteField()                             */
    1610                 : /************************************************************************/
    1611                 : 
    1612              10 : OGRErr OGRShapeLayer::DeleteField( int iField )
    1613                 : {
    1614              10 :     if (!TouchLayer())
    1615               0 :         return OGRERR_FAILURE;
    1616                 : 
    1617              10 :     if( !bUpdateAccess )
    1618                 :     {
    1619                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1620                 :                   UNSUPPORTED_OP_READ_ONLY,
    1621               1 :                   "DeleteField");
    1622               1 :         return OGRERR_FAILURE;
    1623                 :     }
    1624                 : 
    1625               9 :     if (iField < 0 || iField >= poFeatureDefn->GetFieldCount())
    1626                 :     {
    1627                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1628               3 :                   "Invalid field index");
    1629               3 :         return OGRERR_FAILURE;
    1630                 :     }
    1631                 : 
    1632               6 :     if ( DBFDeleteField( hDBF, iField ) )
    1633                 :     {
    1634               6 :         TruncateDBF();
    1635                 : 
    1636               6 :         return poFeatureDefn->DeleteFieldDefn( iField );
    1637                 :     }
    1638                 :     else
    1639               0 :         return OGRERR_FAILURE;
    1640                 : }
    1641                 : 
    1642                 : /************************************************************************/
    1643                 : /*                           ReorderFields()                            */
    1644                 : /************************************************************************/
    1645                 : 
    1646              15 : OGRErr OGRShapeLayer::ReorderFields( int* panMap )
    1647                 : {
    1648              15 :     if (!TouchLayer())
    1649               0 :         return OGRERR_FAILURE;
    1650                 : 
    1651              15 :     if( !bUpdateAccess )
    1652                 :     {
    1653                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1654                 :                   UNSUPPORTED_OP_READ_ONLY,
    1655               1 :                   "ReorderFields");
    1656               1 :         return OGRERR_FAILURE;
    1657                 :     }
    1658                 : 
    1659              14 :     if (poFeatureDefn->GetFieldCount() == 0)
    1660               2 :         return OGRERR_NONE;
    1661                 : 
    1662              12 :     OGRErr eErr = OGRCheckPermutation(panMap, poFeatureDefn->GetFieldCount());
    1663              12 :     if (eErr != OGRERR_NONE)
    1664               2 :         return eErr;
    1665                 : 
    1666              10 :     if ( DBFReorderFields( hDBF, panMap ) )
    1667                 :     {
    1668              10 :         return poFeatureDefn->ReorderFieldDefns( panMap );
    1669                 :     }
    1670                 :     else
    1671               0 :         return OGRERR_FAILURE;
    1672                 : }
    1673                 : 
    1674                 : /************************************************************************/
    1675                 : /*                           AlterFieldDefn()                           */
    1676                 : /************************************************************************/
    1677                 : 
    1678              14 : OGRErr OGRShapeLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags )
    1679                 : {
    1680              14 :     if (!TouchLayer())
    1681               0 :         return OGRERR_FAILURE;
    1682                 : 
    1683              14 :     if( !bUpdateAccess )
    1684                 :     {
    1685                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1686                 :                   UNSUPPORTED_OP_READ_ONLY,
    1687               1 :                   "AlterFieldDefn");
    1688               1 :         return OGRERR_FAILURE;
    1689                 :     }
    1690                 : 
    1691              13 :     if (iField < 0 || iField >= poFeatureDefn->GetFieldCount())
    1692                 :     {
    1693                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1694               3 :                   "Invalid field index");
    1695               3 :         return OGRERR_FAILURE;
    1696                 :     }
    1697                 : 
    1698              10 :     OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
    1699                 : 
    1700                 :     char chNativeType;
    1701                 :     char            szFieldName[20];
    1702                 :     int             nWidth, nPrecision;
    1703              10 :     OGRFieldType    eType = poFieldDefn->GetType();
    1704                 :     DBFFieldType    eDBFType;
    1705                 : 
    1706              10 :     chNativeType = DBFGetNativeFieldType( hDBF, iField );
    1707                 :     eDBFType = DBFGetFieldInfo( hDBF, iField, szFieldName,
    1708              10 :                                 &nWidth, &nPrecision );
    1709                 : 
    1710              10 :     if ((nFlags & ALTER_TYPE_FLAG) &&
    1711                 :         poNewFieldDefn->GetType() != poFieldDefn->GetType())
    1712                 :     {
    1713               3 :         if (poNewFieldDefn->GetType() != OFTString)
    1714                 :         {
    1715                 :             CPLError( CE_Failure, CPLE_NotSupported,
    1716               1 :                       "Can only convert to OFTString");
    1717               1 :             return OGRERR_FAILURE;
    1718                 :         }
    1719                 :         else
    1720                 :         {
    1721               2 :             chNativeType = 'C';
    1722               2 :             eType = poNewFieldDefn->GetType();
    1723                 :         }
    1724                 :     }
    1725                 : 
    1726               9 :     if (nFlags & ALTER_NAME_FLAG)
    1727                 :     {
    1728               9 :         CPLString osFieldName;
    1729               9 :         if( osEncoding.size() )
    1730                 :         {
    1731               9 :             CPLClearRecodeWarningFlags();
    1732               9 :             CPLErrorReset();
    1733               9 :             CPLPushErrorHandler(CPLQuietErrorHandler);
    1734               9 :             char* pszRecoded = CPLRecode( poNewFieldDefn->GetNameRef(), CPL_ENC_UTF8, osEncoding);
    1735               9 :             CPLPopErrorHandler();
    1736               9 :             osFieldName = pszRecoded;
    1737               9 :             CPLFree(pszRecoded);
    1738               9 :             if( CPLGetLastErrorType() != 0 )
    1739                 :             {
    1740                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1741                 :                         "Failed to rename field name to '%s' : cannot convert to %s",
    1742               1 :                         poNewFieldDefn->GetNameRef(), osEncoding.c_str());
    1743               1 :                 return OGRERR_FAILURE;
    1744                 :             }
    1745                 :         }
    1746                 :         else
    1747               0 :             osFieldName = poNewFieldDefn->GetNameRef();
    1748                 : 
    1749               8 :         strncpy(szFieldName, osFieldName, 10);
    1750               8 :         szFieldName[10] = '\0';
    1751                 :     }
    1752               8 :     if (nFlags & ALTER_WIDTH_PRECISION_FLAG)
    1753                 :     {
    1754               7 :         nWidth = poNewFieldDefn->GetWidth();
    1755               7 :         nPrecision = poNewFieldDefn->GetPrecision();
    1756                 :     }
    1757                 : 
    1758               8 :     if ( DBFAlterFieldDefn( hDBF, iField, szFieldName,
    1759                 :                             chNativeType, nWidth, nPrecision) )
    1760                 :     {
    1761               8 :         if (nFlags & ALTER_TYPE_FLAG)
    1762               7 :             poFieldDefn->SetType(eType);
    1763               8 :         if (nFlags & ALTER_NAME_FLAG)
    1764               8 :             poFieldDefn->SetName(poNewFieldDefn->GetNameRef());
    1765               8 :         if (nFlags & ALTER_WIDTH_PRECISION_FLAG)
    1766                 :         {
    1767               7 :             poFieldDefn->SetWidth(nWidth);
    1768               7 :             poFieldDefn->SetPrecision(nPrecision);
    1769                 : 
    1770               7 :             TruncateDBF();
    1771                 :         }
    1772               8 :         return OGRERR_NONE;
    1773                 :     }
    1774                 :     else
    1775               0 :         return OGRERR_FAILURE;
    1776                 : }
    1777                 : 
    1778                 : /************************************************************************/
    1779                 : /*                           GetSpatialRef()                            */
    1780                 : /************************************************************************/
    1781                 : 
    1782           75845 : OGRSpatialReference *OGRShapeLayer::GetSpatialRef()
    1783                 : 
    1784                 : {
    1785           75845 :     if (bSRSSet)
    1786           74916 :         return poSRS;
    1787                 : 
    1788             929 :     bSRSSet = TRUE;
    1789                 : 
    1790                 : /* -------------------------------------------------------------------- */
    1791                 : /*      Is there an associated .prj file we can read?                   */
    1792                 : /* -------------------------------------------------------------------- */
    1793             929 :     const char  *pszPrjFile = CPLResetExtension( pszFullName, "prj" );
    1794                 :     char    **papszLines;
    1795                 : 
    1796             929 :     char* apszOptions[] = { (char*)"EMIT_ERROR_IF_CANNOT_OPEN_FILE=FALSE", NULL };
    1797             929 :     papszLines = CSLLoad2( pszPrjFile, -1, -1, apszOptions );
    1798             929 :     if (papszLines == NULL)
    1799                 :     {
    1800             779 :         pszPrjFile = CPLResetExtension( pszFullName, "PRJ" );
    1801             779 :         papszLines = CSLLoad2( pszPrjFile, -1, -1, apszOptions );
    1802                 :     }
    1803                 : 
    1804             929 :     if( papszLines != NULL )
    1805                 :     {
    1806             316 :         poSRS = new OGRSpatialReference();
    1807             316 :         if( poSRS->importFromESRI( papszLines ) != OGRERR_NONE )
    1808                 :         {
    1809               0 :             delete poSRS;
    1810               0 :             poSRS = NULL;
    1811                 :         }
    1812             316 :         CSLDestroy( papszLines );
    1813                 :     }
    1814                 : 
    1815             929 :     return poSRS;
    1816                 : }
    1817                 : 
    1818                 : /************************************************************************/
    1819                 : /*                           ResetGeomType()                            */
    1820                 : /*                                                                      */
    1821                 : /*      Modify the geometry type for this file.  Used to convert to     */
    1822                 : /*      a different geometry type when a layer was created with a       */
    1823                 : /*      type of unknown, and we get to the first feature to             */
    1824                 : /*      establish the type.                                             */
    1825                 : /************************************************************************/
    1826                 : 
    1827             574 : int OGRShapeLayer::ResetGeomType( int nNewGeomType )
    1828                 : 
    1829                 : {
    1830                 :     char        abyHeader[100];
    1831                 :     int         nStartPos;
    1832                 : 
    1833             574 :     if( nTotalShapeCount > 0 )
    1834               0 :         return FALSE;
    1835                 : 
    1836             574 :     if( hSHP->fpSHX == NULL)
    1837                 :     {
    1838                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    1839               0 :                   " OGRShapeLayer::ResetGeomType failed : SHX file is closed");
    1840               0 :         return FALSE;
    1841                 :     }
    1842                 : 
    1843                 : /* -------------------------------------------------------------------- */
    1844                 : /*      Update .shp header.                                             */
    1845                 : /* -------------------------------------------------------------------- */
    1846             574 :     nStartPos = (int)( hSHP->sHooks.FTell( hSHP->fpSHP ) );
    1847                 : 
    1848             574 :     if( hSHP->sHooks.FSeek( hSHP->fpSHP, 0, SEEK_SET ) != 0
    1849                 :         || hSHP->sHooks.FRead( abyHeader, 100, 1, hSHP->fpSHP ) != 1 )
    1850               0 :         return FALSE;
    1851                 : 
    1852             574 :     *((GInt32 *) (abyHeader + 32)) = CPL_LSBWORD32( nNewGeomType );
    1853                 : 
    1854             574 :     if( hSHP->sHooks.FSeek( hSHP->fpSHP, 0, SEEK_SET ) != 0
    1855                 :         || hSHP->sHooks.FWrite( abyHeader, 100, 1, hSHP->fpSHP ) != 1 )
    1856               0 :         return FALSE;
    1857                 : 
    1858             574 :     if( hSHP->sHooks.FSeek( hSHP->fpSHP, nStartPos, SEEK_SET ) != 0 )
    1859               0 :         return FALSE;
    1860                 : 
    1861                 : /* -------------------------------------------------------------------- */
    1862                 : /*      Update .shx header.                                             */
    1863                 : /* -------------------------------------------------------------------- */
    1864             574 :     nStartPos = (int)( hSHP->sHooks.FTell( hSHP->fpSHX ) );
    1865                 :     
    1866             574 :     if( hSHP->sHooks.FSeek( hSHP->fpSHX, 0, SEEK_SET ) != 0
    1867                 :         || hSHP->sHooks.FRead( abyHeader, 100, 1, hSHP->fpSHX ) != 1 )
    1868               0 :         return FALSE;
    1869                 : 
    1870             574 :     *((GInt32 *) (abyHeader + 32)) = CPL_LSBWORD32( nNewGeomType );
    1871                 : 
    1872             574 :     if( hSHP->sHooks.FSeek( hSHP->fpSHX, 0, SEEK_SET ) != 0
    1873                 :         || hSHP->sHooks.FWrite( abyHeader, 100, 1, hSHP->fpSHX ) != 1 )
    1874               0 :         return FALSE;
    1875                 : 
    1876             574 :     if( hSHP->sHooks.FSeek( hSHP->fpSHX, nStartPos, SEEK_SET ) != 0 )
    1877               0 :         return FALSE;
    1878                 : 
    1879                 : /* -------------------------------------------------------------------- */
    1880                 : /*      Update other information.                                       */
    1881                 : /* -------------------------------------------------------------------- */
    1882             574 :     hSHP->nShapeType = nNewGeomType;
    1883                 : 
    1884             574 :     return TRUE;
    1885                 : }
    1886                 : 
    1887                 : /************************************************************************/
    1888                 : /*                             SyncToDisk()                             */
    1889                 : /************************************************************************/
    1890                 : 
    1891              31 : OGRErr OGRShapeLayer::SyncToDisk()
    1892                 : 
    1893                 : {
    1894              31 :     if (!TouchLayer())
    1895               0 :         return OGRERR_FAILURE;
    1896                 : 
    1897              31 :     if( bHeaderDirty )
    1898                 :     {
    1899              24 :         if( hSHP != NULL )
    1900              23 :             SHPWriteHeader( hSHP );
    1901                 : 
    1902              24 :         if( hDBF != NULL )
    1903              24 :             DBFUpdateHeader( hDBF );
    1904                 : 
    1905              24 :         bHeaderDirty = FALSE;
    1906                 :     }
    1907                 : 
    1908              31 :     if( hSHP != NULL )
    1909                 :     {
    1910              29 :         hSHP->sHooks.FFlush( hSHP->fpSHP );
    1911              29 :         if( hSHP->fpSHX != NULL )
    1912              29 :             hSHP->sHooks.FFlush( hSHP->fpSHX );
    1913                 :     }
    1914                 : 
    1915              31 :     if( hDBF != NULL )
    1916              31 :         hDBF->sHooks.FFlush( hDBF->fp );
    1917                 : 
    1918              31 :     return OGRERR_NONE;
    1919                 : }
    1920                 : 
    1921                 : /************************************************************************/
    1922                 : /*                          DropSpatialIndex()                          */
    1923                 : /************************************************************************/
    1924                 : 
    1925               7 : OGRErr OGRShapeLayer::DropSpatialIndex()
    1926                 : 
    1927                 : {
    1928               7 :     if (!TouchLayer())
    1929               0 :         return OGRERR_FAILURE;
    1930                 : 
    1931               7 :     if( !CheckForQIX() && !CheckForSBN() )
    1932                 :     {
    1933                 :         CPLError( CE_Warning, CPLE_AppDefined, 
    1934                 :                   "Layer %s has no spatial index, DROP SPATIAL INDEX failed.",
    1935               1 :                   poFeatureDefn->GetName() );
    1936               1 :         return OGRERR_FAILURE;
    1937                 :     }
    1938                 : 
    1939               6 :     int bHadQIX = hQIX != NULL;
    1940                 : 
    1941               6 :     SHPCloseDiskTree( hQIX );
    1942               6 :     hQIX = NULL;
    1943               6 :     bCheckedForQIX = FALSE;
    1944                 : 
    1945               6 :     SBNCloseDiskTree( hSBN );
    1946               6 :     hSBN = NULL;
    1947               6 :     bCheckedForSBN = FALSE;
    1948                 : 
    1949               6 :     if( bHadQIX )
    1950                 :     {
    1951                 :         const char *pszQIXFilename;
    1952                 : 
    1953               6 :         pszQIXFilename = CPLResetExtension( pszFullName, "qix" );
    1954               6 :         CPLDebug( "SHAPE", "Unlinking index file %s", pszQIXFilename );
    1955                 : 
    1956               6 :         if( VSIUnlink( pszQIXFilename ) != 0 )
    1957                 :         {
    1958                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1959                 :                     "Failed to delete file %s.\n%s",
    1960               0 :                     pszQIXFilename, VSIStrerror( errno ) );
    1961               0 :             return OGRERR_FAILURE;
    1962                 :         }
    1963                 :     }
    1964                 : 
    1965               6 :     if( !bSbnSbxDeleted )
    1966                 :     {
    1967                 :         const char *pszIndexFilename;
    1968               5 :         const char papszExt[2][4] = { "sbn", "sbx" };
    1969                 :         int i;
    1970              15 :         for( i = 0; i < 2; i++ )
    1971                 :         {
    1972              10 :             pszIndexFilename = CPLResetExtension( pszFullName, papszExt[i] );
    1973              10 :             CPLDebug( "SHAPE", "Trying to unlink index file %s", pszIndexFilename );
    1974                 : 
    1975              10 :             if( VSIUnlink( pszIndexFilename ) != 0 )
    1976                 :             {
    1977                 :                 CPLDebug( "SHAPE",
    1978                 :                           "Failed to delete file %s.\n%s", 
    1979               4 :                           pszIndexFilename, VSIStrerror( errno ) );
    1980                 :             }
    1981                 :         }
    1982                 :     }
    1983               6 :     bSbnSbxDeleted = TRUE;
    1984                 : 
    1985               6 :     ClearSpatialFIDs();
    1986                 : 
    1987               6 :     return OGRERR_NONE;
    1988                 : }
    1989                 : 
    1990                 : /************************************************************************/
    1991                 : /*                         CreateSpatialIndex()                         */
    1992                 : /************************************************************************/
    1993                 : 
    1994              14 : OGRErr OGRShapeLayer::CreateSpatialIndex( int nMaxDepth )
    1995                 : 
    1996                 : {
    1997              14 :     if (!TouchLayer())
    1998               0 :         return OGRERR_FAILURE;
    1999                 : 
    2000                 : /* -------------------------------------------------------------------- */
    2001                 : /*      If we have an existing spatial index, blow it away first.       */
    2002                 : /* -------------------------------------------------------------------- */
    2003              14 :     if( CheckForQIX() )
    2004               1 :         DropSpatialIndex();
    2005                 : 
    2006              14 :     bCheckedForQIX = FALSE;
    2007                 : 
    2008                 : /* -------------------------------------------------------------------- */
    2009                 : /*      Build a quadtree structure for this file.                       */
    2010                 : /* -------------------------------------------------------------------- */
    2011                 :     SHPTree *psTree;
    2012                 : 
    2013              14 :     SyncToDisk();
    2014              14 :     psTree = SHPCreateTree( hSHP, 2, nMaxDepth, NULL, NULL );
    2015                 : 
    2016              14 :     if( NULL == psTree )
    2017                 :     {
    2018                 :         // TODO - mloskot: Is it better to return OGRERR_NOT_ENOUGH_MEMORY?
    2019                 : 
    2020                 :         CPLDebug( "SHAPE",
    2021               0 :                   "Index creation failure. Likely, memory allocation error." );
    2022                 : 
    2023               0 :         return OGRERR_FAILURE;
    2024                 :     }
    2025                 : 
    2026                 : /* -------------------------------------------------------------------- */
    2027                 : /*      Trim unused nodes from the tree.                                */
    2028                 : /* -------------------------------------------------------------------- */
    2029              14 :     SHPTreeTrimExtraNodes( psTree );
    2030                 : 
    2031                 : /* -------------------------------------------------------------------- */
    2032                 : /*      Dump tree to .qix file.                                         */
    2033                 : /* -------------------------------------------------------------------- */
    2034                 :     char *pszQIXFilename;
    2035                 : 
    2036              14 :     pszQIXFilename = CPLStrdup(CPLResetExtension( pszFullName, "qix" ));
    2037                 : 
    2038              14 :     CPLDebug( "SHAPE", "Creating index file %s", pszQIXFilename );
    2039                 : 
    2040              14 :     SHPWriteTree( psTree, pszQIXFilename );
    2041              14 :     CPLFree( pszQIXFilename );
    2042                 : 
    2043                 : 
    2044                 : /* -------------------------------------------------------------------- */
    2045                 : /*      cleanup                                                         */
    2046                 : /* -------------------------------------------------------------------- */
    2047              14 :     SHPDestroyTree( psTree );
    2048                 : 
    2049              14 :     CheckForQIX();
    2050                 : 
    2051              14 :     return OGRERR_NONE;
    2052                 : }
    2053                 : 
    2054                 : /************************************************************************/
    2055                 : /*                               Repack()                               */
    2056                 : /*                                                                      */
    2057                 : /*      Repack the shape and dbf file, dropping deleted records.        */
    2058                 : /*      FIDs may change.                                                */
    2059                 : /************************************************************************/
    2060                 : 
    2061               6 : OGRErr OGRShapeLayer::Repack()
    2062                 : 
    2063                 : {
    2064               6 :     if (!TouchLayer())
    2065               0 :         return OGRERR_FAILURE;
    2066                 : 
    2067               6 :     if( !bUpdateAccess )
    2068                 :     {
    2069                 :         CPLError( CE_Failure, CPLE_NotSupported,
    2070                 :                   UNSUPPORTED_OP_READ_ONLY,
    2071               1 :                   "Repack");
    2072               1 :         return OGRERR_FAILURE;
    2073                 :     }
    2074                 :     
    2075               5 :     if( hDBF == NULL )
    2076                 :     {
    2077                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    2078               1 :                   "Attempt to repack a shapefile with no .dbf file not supported.");
    2079               1 :         return OGRERR_FAILURE;
    2080                 :     }
    2081                 :     
    2082                 : /* -------------------------------------------------------------------- */
    2083                 : /*      Build a list of records to be dropped.                          */
    2084                 : /* -------------------------------------------------------------------- */
    2085                 :     int *panRecordsToDelete = (int *) 
    2086               4 :         CPLMalloc(sizeof(int)*(nTotalShapeCount+1));
    2087               4 :     int nDeleteCount = 0;
    2088               4 :     int iShape = 0;
    2089               4 :     OGRErr eErr = OGRERR_NONE;
    2090                 : 
    2091              35 :     for( iShape = 0; iShape < nTotalShapeCount; iShape++ )
    2092                 :     {
    2093              31 :         if( DBFIsRecordDeleted( hDBF, iShape ) )
    2094               3 :             panRecordsToDelete[nDeleteCount++] = iShape;
    2095                 :     }
    2096               4 :     panRecordsToDelete[nDeleteCount] = -1;
    2097                 : 
    2098                 : /* -------------------------------------------------------------------- */
    2099                 : /*      If there are no records marked for deletion, we take no         */
    2100                 : /*      action.                                                         */
    2101                 : /* -------------------------------------------------------------------- */
    2102               4 :     if( nDeleteCount == 0 )
    2103                 :     {
    2104               1 :         CPLFree( panRecordsToDelete );
    2105               1 :         return OGRERR_NONE;
    2106                 :     }
    2107                 : 
    2108                 : /* -------------------------------------------------------------------- */
    2109                 : /*      Find existing filenames with exact case (see #3293).            */
    2110                 : /* -------------------------------------------------------------------- */
    2111               3 :     CPLString osDirname(CPLGetPath(pszFullName));
    2112               3 :     CPLString osBasename(CPLGetBasename(pszFullName));
    2113                 :     
    2114               3 :     CPLString osDBFName, osSHPName, osSHXName;
    2115               3 :     char **papszCandidates = CPLReadDir( osDirname );
    2116               3 :     int i = 0;
    2117              25 :     while(papszCandidates != NULL && papszCandidates[i] != NULL)
    2118                 :     {
    2119              22 :         CPLString osCandidateBasename = CPLGetBasename(papszCandidates[i]);
    2120              22 :         CPLString osCandidateExtension = CPLGetExtension(papszCandidates[i]);
    2121              22 :         if (osCandidateBasename.compare(osBasename) == 0)
    2122                 :         {
    2123               9 :             if (EQUAL(osCandidateExtension, "dbf"))
    2124               3 :                 osDBFName = CPLFormFilename(osDirname, papszCandidates[i], NULL);
    2125               6 :             else if (EQUAL(osCandidateExtension, "shp"))
    2126               3 :                 osSHPName = CPLFormFilename(osDirname, papszCandidates[i], NULL);
    2127               3 :             else if (EQUAL(osCandidateExtension, "shx"))
    2128               3 :                 osSHXName = CPLFormFilename(osDirname, papszCandidates[i], NULL);
    2129                 :         }
    2130                 :         
    2131              22 :         i++;
    2132                 :     }
    2133               3 :     CSLDestroy(papszCandidates);
    2134               3 :     papszCandidates = NULL;
    2135                 :     
    2136               3 :     if (osDBFName.size() == 0)
    2137                 :     {
    2138                 :         /* Should not happen, really */
    2139               0 :         CPLFree( panRecordsToDelete );
    2140               0 :         return OGRERR_FAILURE;
    2141                 :     }
    2142                 :     
    2143                 : /* -------------------------------------------------------------------- */
    2144                 : /*      Cleanup any existing spatial index.  It will become             */
    2145                 : /*      meaningless when the fids change.                               */
    2146                 : /* -------------------------------------------------------------------- */
    2147               3 :     if( CheckForQIX() || CheckForSBN() )
    2148               0 :         DropSpatialIndex();
    2149                 : 
    2150                 : /* -------------------------------------------------------------------- */
    2151                 : /*      Create a new dbf file, matching the old.                        */
    2152                 : /* -------------------------------------------------------------------- */
    2153               3 :     DBFHandle hNewDBF = NULL;
    2154                 :     
    2155               3 :     CPLString oTempFile(CPLFormFilename(osDirname, osBasename, NULL));
    2156               3 :     oTempFile += "_packed.dbf";
    2157                 : 
    2158               3 :     hNewDBF = DBFCloneEmpty( hDBF, oTempFile );
    2159               3 :     if( hNewDBF == NULL )
    2160                 :     {
    2161               0 :         CPLFree( panRecordsToDelete );
    2162                 : 
    2163                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
    2164                 :                   "Failed to create temp file %s.", 
    2165               0 :                   oTempFile.c_str() );
    2166               0 :         return OGRERR_FAILURE;
    2167                 :     }
    2168                 : 
    2169                 : /* -------------------------------------------------------------------- */
    2170                 : /*      Copy over all records that are not deleted.                     */
    2171                 : /* -------------------------------------------------------------------- */
    2172               3 :     int iDestShape = 0;
    2173               3 :     int iNextDeletedShape = 0;
    2174                 : 
    2175              34 :     for( iShape = 0; 
    2176                 :          iShape < nTotalShapeCount && eErr == OGRERR_NONE; 
    2177                 :          iShape++ )
    2178                 :     {
    2179              31 :         if( panRecordsToDelete[iNextDeletedShape] == iShape )
    2180               3 :             iNextDeletedShape++;
    2181                 :         else
    2182                 :         {
    2183              28 :             void *pTuple = (void *) DBFReadTuple( hDBF, iShape );
    2184              28 :             if( pTuple == NULL )
    2185               0 :                 eErr = OGRERR_FAILURE;
    2186              28 :             else if( !DBFWriteTuple( hNewDBF, iDestShape++, pTuple ) )
    2187               0 :                 eErr = OGRERR_FAILURE;
    2188                 :         }                           
    2189                 :     }
    2190                 : 
    2191               3 :     if( eErr != OGRERR_NONE )
    2192                 :     {
    2193               0 :         CPLFree( panRecordsToDelete );
    2194               0 :         VSIUnlink( oTempFile );
    2195               0 :         return eErr;
    2196                 :     }
    2197                 : 
    2198                 : /* -------------------------------------------------------------------- */
    2199                 : /*      Cleanup the old .dbf and rename the new one.                    */
    2200                 : /* -------------------------------------------------------------------- */
    2201               3 :     DBFClose( hDBF );
    2202               3 :     DBFClose( hNewDBF );
    2203               3 :     hDBF = hNewDBF = NULL;
    2204                 :     
    2205               3 :     VSIUnlink( osDBFName );
    2206                 :         
    2207               3 :     if( VSIRename( oTempFile, osDBFName ) != 0 )
    2208                 :     {
    2209               0 :         CPLDebug( "Shape", "Can not rename DBF file: %s", VSIStrerror( errno ) );
    2210               0 :         CPLFree( panRecordsToDelete );
    2211               0 :         return OGRERR_FAILURE;
    2212                 :     }
    2213                 :     
    2214                 : /* -------------------------------------------------------------------- */
    2215                 : /*      Now create a shapefile matching the old one.                    */
    2216                 : /* -------------------------------------------------------------------- */
    2217               3 :     if( hSHP != NULL )
    2218                 :     {
    2219               3 :         SHPHandle hNewSHP = NULL;
    2220                 :         
    2221               3 :         if (osSHPName.size() == 0 || osSHXName.size() == 0)
    2222                 :         {
    2223                 :             /* Should not happen, really */
    2224               0 :             CPLFree( panRecordsToDelete );
    2225               0 :             return OGRERR_FAILURE;
    2226                 :         }
    2227                 : 
    2228               3 :         oTempFile = CPLFormFilename(osDirname, osBasename, NULL);
    2229               3 :         oTempFile += "_packed.shp";
    2230                 : 
    2231               3 :         hNewSHP = SHPCreate( oTempFile, hSHP->nShapeType );
    2232               3 :         if( hNewSHP == NULL )
    2233                 :         {
    2234               0 :             CPLFree( panRecordsToDelete );
    2235               0 :             return OGRERR_FAILURE;
    2236                 :         }
    2237                 : 
    2238                 : /* -------------------------------------------------------------------- */
    2239                 : /*      Copy over all records that are not deleted.                     */
    2240                 : /* -------------------------------------------------------------------- */
    2241               3 :         iNextDeletedShape = 0;
    2242                 : 
    2243              34 :         for( iShape = 0; 
    2244                 :              iShape < nTotalShapeCount && eErr == OGRERR_NONE; 
    2245                 :              iShape++ )
    2246                 :         {
    2247              31 :             if( panRecordsToDelete[iNextDeletedShape] == iShape )
    2248               3 :                 iNextDeletedShape++;
    2249                 :             else
    2250                 :             {
    2251                 :                 SHPObject *hObject;
    2252                 : 
    2253              28 :                 hObject = SHPReadObject( hSHP, iShape );
    2254              28 :                 if( hObject == NULL )
    2255               0 :                     eErr = OGRERR_FAILURE;
    2256              28 :                 else if( SHPWriteObject( hNewSHP, -1, hObject ) == -1 )
    2257               0 :                     eErr = OGRERR_FAILURE;
    2258                 : 
    2259              28 :                 if( hObject )
    2260              28 :                     SHPDestroyObject( hObject );
    2261                 :             }
    2262                 :         }
    2263                 : 
    2264               3 :         if( eErr != OGRERR_NONE )
    2265                 :         {
    2266               0 :             CPLFree( panRecordsToDelete );
    2267               0 :             VSIUnlink( CPLResetExtension( oTempFile, "shp" ) );
    2268               0 :             VSIUnlink( CPLResetExtension( oTempFile, "shx" ) );
    2269               0 :             return eErr;
    2270                 :         }
    2271                 : 
    2272                 : /* -------------------------------------------------------------------- */
    2273                 : /*      Cleanup the old .shp/.shx and rename the new one.               */
    2274                 : /* -------------------------------------------------------------------- */
    2275               3 :         SHPClose( hSHP );
    2276               3 :         SHPClose( hNewSHP );
    2277               3 :         hSHP = hNewSHP = NULL;
    2278                 : 
    2279               3 :         VSIUnlink( osSHPName );
    2280               3 :         VSIUnlink( osSHXName );
    2281                 : 
    2282               3 :         oTempFile = CPLResetExtension( oTempFile, "shp" );
    2283               3 :         if( VSIRename( oTempFile, osSHPName ) != 0 )
    2284                 :         {
    2285               0 :             CPLDebug( "Shape", "Can not rename SHP file: %s", VSIStrerror( errno ) );
    2286               0 :             CPLFree( panRecordsToDelete );
    2287               0 :             return OGRERR_FAILURE;
    2288                 :         }
    2289                 :     
    2290               3 :         oTempFile = CPLResetExtension( oTempFile, "shx" );
    2291               3 :         if( VSIRename( oTempFile, osSHXName ) != 0 )
    2292                 :         {
    2293               0 :             CPLDebug( "Shape", "Can not rename SHX file: %s", VSIStrerror( errno ) );
    2294               0 :             CPLFree( panRecordsToDelete );
    2295               0 :             return OGRERR_FAILURE;
    2296                 :         }
    2297                 :     }
    2298                 :     
    2299               3 :     CPLFree( panRecordsToDelete );
    2300               3 :     panRecordsToDelete = NULL;
    2301                 : 
    2302                 : /* -------------------------------------------------------------------- */
    2303                 : /*      Reopen the shapefile                                            */
    2304                 : /*                                                                      */
    2305                 : /* We do not need to reimplement OGRShapeDataSource::OpenFile() here    */  
    2306                 : /* with the fully featured error checking.                              */
    2307                 : /* If all operations above succeeded, then all necessery files are      */
    2308                 : /* in the right place and accessible.                                   */
    2309                 : /* -------------------------------------------------------------------- */
    2310               3 :     CPLAssert( NULL == hSHP );
    2311               3 :     CPLAssert( NULL == hDBF && NULL == hNewDBF );
    2312                 :     
    2313               3 :     CPLPushErrorHandler( CPLQuietErrorHandler );
    2314                 :     
    2315               3 :     const char* pszAccess = NULL;
    2316               3 :     if( bUpdateAccess )
    2317               3 :         pszAccess = "r+";
    2318                 :     else
    2319               0 :         pszAccess = "r";
    2320                 :     
    2321               3 :     hSHP = SHPOpen ( CPLResetExtension( pszFullName, "shp" ) , pszAccess );
    2322               3 :     hDBF = DBFOpen ( CPLResetExtension( pszFullName, "dbf" ) , pszAccess );
    2323                 :     
    2324               3 :     CPLPopErrorHandler();
    2325                 :     
    2326               3 :     if( NULL == hSHP || NULL == hDBF )
    2327                 :     {
    2328               0 :         CPLString osMsg(CPLGetLastErrorMsg());
    2329               0 :         CPLError( CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str() );
    2330                 : 
    2331               0 :         return OGRERR_FAILURE;
    2332                 :     }
    2333                 : 
    2334                 : /* -------------------------------------------------------------------- */
    2335                 : /*      Update total shape count.                                       */
    2336                 : /* -------------------------------------------------------------------- */
    2337               3 :     nTotalShapeCount = hDBF->nRecords;
    2338                 : 
    2339               3 :     return OGRERR_NONE;
    2340                 : }
    2341                 : 
    2342                 : /************************************************************************/
    2343                 : /*                               ResizeDBF()                            */
    2344                 : /*                                                                      */
    2345                 : /*      Autoshrink columns of the DBF file to their minimum             */
    2346                 : /*      size, according to the existing data.                           */
    2347                 : /************************************************************************/
    2348                 : 
    2349               2 : OGRErr OGRShapeLayer::ResizeDBF()
    2350                 : 
    2351                 : {
    2352               2 :     if (!TouchLayer())
    2353               0 :         return OGRERR_FAILURE;
    2354                 : 
    2355               2 :     if( !bUpdateAccess )
    2356                 :     {
    2357                 :         CPLError( CE_Failure, CPLE_NotSupported,
    2358                 :                   UNSUPPORTED_OP_READ_ONLY,
    2359               0 :                   "ResizeDBF");
    2360               0 :         return OGRERR_FAILURE;
    2361                 :     }
    2362                 : 
    2363               2 :     if( hDBF == NULL )
    2364                 :     {
    2365                 :         CPLError( CE_Failure, CPLE_NotSupported,
    2366               0 :                   "Attempt to RESIZE a shapefile with no .dbf file not supported.");
    2367               0 :         return OGRERR_FAILURE;
    2368                 :     }
    2369                 : 
    2370                 :     int i, j;
    2371                 : 
    2372                 :     /* Look which columns must be examined */
    2373               2 :     int* panColMap = (int*) CPLMalloc(poFeatureDefn->GetFieldCount() * sizeof(int));
    2374               2 :     int* panBestWidth = (int*) CPLMalloc(poFeatureDefn->GetFieldCount() * sizeof(int));
    2375               2 :     int nStringCols = 0;
    2376               8 :     for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
    2377                 :     {
    2378               6 :         if( poFeatureDefn->GetFieldDefn(i)->GetType() == OFTString ||
    2379                 :             poFeatureDefn->GetFieldDefn(i)->GetType() == OFTInteger )
    2380                 :         {
    2381               6 :             panColMap[nStringCols] = i;
    2382               6 :             panBestWidth[nStringCols] = 1;
    2383               6 :             nStringCols ++;
    2384                 :         }
    2385                 :     }
    2386                 : 
    2387               2 :     if (nStringCols == 0)
    2388                 :     {
    2389                 :         /* Nothing to do */
    2390               0 :         CPLFree(panColMap);
    2391               0 :         CPLFree(panBestWidth);
    2392               0 :         return OGRERR_NONE;
    2393                 :     }
    2394                 : 
    2395               2 :     CPLDebug("SHAPE", "Computing optimal column size...");
    2396                 : 
    2397               2 :     int bAlreadyWarned = FALSE;
    2398              10 :     for( i = 0; i < hDBF->nRecords; i++ )
    2399                 :     {
    2400               8 :         if( !DBFIsRecordDeleted( hDBF, i ) )
    2401                 :         {
    2402              24 :             for( j = 0; j < nStringCols; j ++)
    2403                 :             {
    2404              18 :                 if (DBFIsAttributeNULL(hDBF, i, panColMap[j]))
    2405               6 :                     continue;
    2406                 : 
    2407              12 :                 const char* pszVal = DBFReadStringAttribute(hDBF, i, panColMap[j]);
    2408              12 :                 int nLen = strlen(pszVal);
    2409              12 :                 if (nLen > panBestWidth[j])
    2410               6 :                     panBestWidth[j] = nLen;
    2411                 :             }
    2412                 :         }
    2413               2 :         else if (!bAlreadyWarned)
    2414                 :         {
    2415               2 :             bAlreadyWarned = TRUE;
    2416                 :             CPLDebug("SHAPE",
    2417               2 :                      "DBF file would also need a REPACK due to deleted records");
    2418                 :         }
    2419                 :     }
    2420                 : 
    2421               8 :     for( j = 0; j < nStringCols; j ++)
    2422                 :     {
    2423               6 :         int             iField = panColMap[j];
    2424               6 :         OGRFieldDefn*   poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
    2425                 : 
    2426                 :         char            szFieldName[20];
    2427                 :         int             nOriWidth, nPrecision;
    2428                 :         char            chNativeType;
    2429                 :         DBFFieldType    eDBFType;
    2430                 : 
    2431               6 :         chNativeType = DBFGetNativeFieldType( hDBF, iField );
    2432                 :         eDBFType = DBFGetFieldInfo( hDBF, iField, szFieldName,
    2433               6 :                                     &nOriWidth, &nPrecision );
    2434                 : 
    2435               6 :         if (panBestWidth[j] < nOriWidth)
    2436                 :         {
    2437                 :             CPLDebug("SHAPE", "Shrinking field %d (%s) from %d to %d characters",
    2438               3 :                         iField, poFieldDefn->GetNameRef(), nOriWidth, panBestWidth[j]);
    2439                 : 
    2440               3 :             if (!DBFAlterFieldDefn( hDBF, iField, szFieldName,
    2441                 :                                     chNativeType, panBestWidth[j], nPrecision ))
    2442                 :             {
    2443                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2444                 :                         "Shrinking field %d (%s) from %d to %d characters failed",
    2445               0 :                         iField, poFieldDefn->GetNameRef(), nOriWidth, panBestWidth[j]);
    2446                 : 
    2447               0 :                 CPLFree(panColMap);
    2448               0 :                 CPLFree(panBestWidth);
    2449                 : 
    2450               0 :                 return OGRERR_FAILURE;
    2451                 :             }
    2452                 :             else
    2453                 :             {
    2454               3 :                 poFieldDefn->SetWidth(panBestWidth[j]);
    2455                 :             }
    2456                 :         }
    2457                 :     }
    2458                 : 
    2459               2 :     TruncateDBF();
    2460                 : 
    2461               2 :     CPLFree(panColMap);
    2462               2 :     CPLFree(panBestWidth);
    2463                 : 
    2464               2 :     return OGRERR_NONE;
    2465                 : }
    2466                 : 
    2467                 : /************************************************************************/
    2468                 : /*                          TruncateDBF()                               */
    2469                 : /************************************************************************/
    2470                 : 
    2471              15 : void OGRShapeLayer::TruncateDBF()
    2472                 : {
    2473              15 :     if (hDBF == NULL)
    2474               0 :         return;
    2475                 : 
    2476              15 :     VSILFILE* fp = (VSILFILE*)(hDBF->fp);
    2477              15 :     VSIFSeekL(fp, 0, SEEK_END);
    2478              15 :     vsi_l_offset nOldSize = VSIFTellL(fp);
    2479                 :     vsi_l_offset nNewSize = hDBF->nRecordLength * (SAOffset) hDBF->nRecords
    2480              15 :                             + hDBF->nHeaderLength;
    2481              15 :     if (nNewSize < nOldSize)
    2482                 :     {
    2483                 :         CPLDebug("SHAPE",
    2484                 :                  "Truncating DBF file from " CPL_FRMT_GUIB " to " CPL_FRMT_GUIB " bytes",
    2485              11 :                  nOldSize, nNewSize);
    2486              11 :         VSIFTruncateL(fp, nNewSize);
    2487                 :     }
    2488              15 :     VSIFSeekL(fp, 0, SEEK_SET);
    2489                 : }
    2490                 : 
    2491                 : /************************************************************************/
    2492                 : /*                        RecomputeExtent()                             */
    2493                 : /*                                                                      */
    2494                 : /*      Force recomputation of the extent of the .SHP file              */
    2495                 : /************************************************************************/
    2496                 : 
    2497               2 : OGRErr OGRShapeLayer::RecomputeExtent()
    2498                 : {
    2499               2 :     if (!TouchLayer())
    2500               0 :         return OGRERR_FAILURE;
    2501                 : 
    2502               2 :     if( !bUpdateAccess )
    2503                 :     {
    2504                 :         CPLError( CE_Failure, CPLE_NotSupported,
    2505                 :                   UNSUPPORTED_OP_READ_ONLY,
    2506               1 :                   "RecomputeExtent");
    2507               1 :         return OGRERR_FAILURE;
    2508                 :     }
    2509                 :     
    2510               1 :     if( hSHP == NULL )
    2511                 :     {
    2512                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    2513               0 :                   "The RECOMPUTE EXTENT operation is not permitted on a layer without .SHP file." );
    2514               0 :         return OGRERR_FAILURE;
    2515                 :     }
    2516                 :     
    2517               1 :     double adBoundsMin[4] = { 0.0, 0.0, 0.0, 0.0 };
    2518               1 :     double adBoundsMax[4] = { 0.0, 0.0, 0.0, 0.0 };
    2519                 : 
    2520               1 :     int bHasBeenInit = FALSE;
    2521                 : 
    2522               2 :     for( int iShape = 0; 
    2523                 :          iShape < nTotalShapeCount; 
    2524                 :          iShape++ )
    2525                 :     {
    2526               1 :         if( hDBF == NULL || !DBFIsRecordDeleted( hDBF, iShape ) )
    2527                 :         {
    2528               1 :             SHPObject *psObject = SHPReadObject( hSHP, iShape );
    2529               1 :             if ( psObject != NULL &&
    2530                 :                  psObject->nSHPType != SHPT_NULL &&
    2531                 :                  psObject->nVertices != 0 )
    2532                 :             {
    2533               1 :                 if( !bHasBeenInit )
    2534                 :                 {
    2535               1 :                     bHasBeenInit = TRUE;
    2536               1 :                     adBoundsMin[0] = adBoundsMax[0] = psObject->padfX[0];
    2537               1 :                     adBoundsMin[1] = adBoundsMax[1] = psObject->padfY[0];
    2538               1 :                     adBoundsMin[2] = adBoundsMax[2] = psObject->padfZ[0];
    2539               1 :                     adBoundsMin[3] = adBoundsMax[3] = psObject->padfM[0];
    2540                 :                 }
    2541                 : 
    2542               2 :                 for( int i = 0; i < psObject->nVertices; i++ )
    2543                 :                 {
    2544               1 :                     adBoundsMin[0] = MIN(adBoundsMin[0],psObject->padfX[i]);
    2545               1 :                     adBoundsMin[1] = MIN(adBoundsMin[1],psObject->padfY[i]);
    2546               1 :                     adBoundsMin[2] = MIN(adBoundsMin[2],psObject->padfZ[i]);
    2547               1 :                     adBoundsMin[3] = MIN(adBoundsMin[3],psObject->padfM[i]);
    2548               1 :                     adBoundsMax[0] = MAX(adBoundsMax[0],psObject->padfX[i]);
    2549               1 :                     adBoundsMax[1] = MAX(adBoundsMax[1],psObject->padfY[i]);
    2550               1 :                     adBoundsMax[2] = MAX(adBoundsMax[2],psObject->padfZ[i]);
    2551               1 :                     adBoundsMax[3] = MAX(adBoundsMax[3],psObject->padfM[i]);
    2552                 :                 }
    2553                 :             }
    2554               1 :             SHPDestroyObject(psObject);
    2555                 :         }
    2556                 :     }
    2557                 : 
    2558               1 :     if( memcmp(hSHP->adBoundsMin, adBoundsMin, 4*sizeof(double)) != 0 ||
    2559                 :         memcmp(hSHP->adBoundsMax, adBoundsMax, 4*sizeof(double)) != 0 )
    2560                 :     {
    2561               1 :         bHeaderDirty = TRUE;
    2562               1 :         hSHP->bUpdated = TRUE;
    2563               1 :         memcpy(hSHP->adBoundsMin, adBoundsMin, 4*sizeof(double));
    2564               1 :         memcpy(hSHP->adBoundsMax, adBoundsMax, 4*sizeof(double));
    2565                 :     }
    2566                 :     
    2567               1 :     return OGRERR_NONE;
    2568                 : }
    2569                 : 
    2570                 : 
    2571                 : /************************************************************************/
    2572                 : /*                              TouchLayer()                            */
    2573                 : /************************************************************************/
    2574                 : 
    2575          172764 : int OGRShapeLayer::TouchLayer()
    2576                 : {
    2577          172764 :     poDS->SetLastUsedLayer(this);
    2578                 : 
    2579          172764 :     if (eFileDescriptorsState == FD_OPENED)
    2580          172759 :         return TRUE;
    2581               5 :     else if (eFileDescriptorsState == FD_CANNOT_REOPEN)
    2582               0 :         return FALSE;
    2583                 :     else
    2584               5 :         return ReopenFileDescriptors();
    2585                 : }
    2586                 : 
    2587                 : /************************************************************************/
    2588                 : /*                        ReopenFileDescriptors()                       */
    2589                 : /************************************************************************/
    2590                 : 
    2591               5 : int OGRShapeLayer::ReopenFileDescriptors()
    2592                 : {
    2593               5 :     CPLDebug("SHAPE", "ReopenFileDescriptors(%s)", pszFullName);
    2594                 : 
    2595               5 :     if( bHSHPWasNonNULL )
    2596                 :     {
    2597               5 :         if( bUpdateAccess )
    2598               1 :             hSHP = SHPOpen( pszFullName, "r+" );
    2599                 :         else
    2600               4 :             hSHP = SHPOpen( pszFullName, "r" );
    2601                 : 
    2602               5 :         if (hSHP == NULL)
    2603                 :         {
    2604               0 :             eFileDescriptorsState = FD_CANNOT_REOPEN;
    2605               0 :             return FALSE;
    2606                 :         }
    2607                 :     }
    2608                 : 
    2609               5 :     if( bHDBFWasNonNULL )
    2610                 :     {
    2611               5 :         if( bUpdateAccess )
    2612               1 :             hDBF = DBFOpen( pszFullName, "r+" );
    2613                 :         else
    2614               4 :             hDBF = DBFOpen( pszFullName, "r" );
    2615                 : 
    2616               5 :         if (hDBF == NULL)
    2617                 :         {
    2618                 :             CPLError(CE_Failure, CPLE_OpenFailed,
    2619               0 :                      "Cannot reopen %s", CPLResetExtension(pszFullName, "dbf"));
    2620               0 :             eFileDescriptorsState = FD_CANNOT_REOPEN;
    2621               0 :             return FALSE;
    2622                 :         }
    2623                 :     }
    2624                 : 
    2625               5 :     eFileDescriptorsState = FD_OPENED;
    2626                 : 
    2627               5 :     return TRUE;
    2628                 : }
    2629                 : 
    2630                 : /************************************************************************/
    2631                 : /*                        CloseUnderlyingLayer()                        */
    2632                 : /************************************************************************/
    2633                 : 
    2634            2006 : void OGRShapeLayer::CloseUnderlyingLayer()
    2635                 : {
    2636            2006 :     CPLDebug("SHAPE", "CloseUnderlyingLayer(%s)", pszFullName);
    2637                 : 
    2638            2006 :     if( hDBF != NULL )
    2639            2006 :         DBFClose( hDBF );
    2640            2006 :     hDBF = NULL;
    2641                 : 
    2642            2006 :     if( hSHP != NULL )
    2643            2006 :         SHPClose( hSHP );
    2644            2006 :     hSHP = NULL;
    2645                 : 
    2646                 :     /* We close QIX and reset the check flag, so that CheckForQIX() */
    2647                 :     /* will retry opening it if necessary when the layer is active again */
    2648            2006 :     if( hQIX != NULL )
    2649               0 :         SHPCloseDiskTree( hQIX ); 
    2650            2006 :     hQIX = NULL;
    2651            2006 :     bCheckedForQIX = FALSE;
    2652                 : 
    2653            2006 :     if( hSBN != NULL )
    2654               0 :         SBNCloseDiskTree( hSBN );
    2655            2006 :     hSBN = NULL;
    2656            2006 :     bCheckedForSBN = FALSE;
    2657                 : 
    2658            2006 :     eFileDescriptorsState = FD_CLOSED;
    2659            2006 : }

Generated by: LCOV version 1.7