LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - ogrshapelayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1025 823 80.3 %
Date: 2012-04-28 Functions: 40 37 92.5 %

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

Generated by: LCOV version 1.7