LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - ogrshapelayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 932 751 80.6 %
Date: 2011-12-18 Functions: 34 31 91.2 %

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

Generated by: LCOV version 1.7