source: trunk/gdal/ogr/ogrsf_frmts/shape/ogrshapelayer.cpp

Last change on this file was 35467, checked in by rouault, 11 days ago

Shape: increase verbosity of file deletion/renaming errors in packing function (related to http://hub.qgis.org/issues/15570)

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