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

Last change on this file was 34100, checked in by rouault, 5 weeks ago

Shape: when reading a .prj with a EPSG code, retrieve from the EPSG database the TOWGS84 node when it exists (#6485)

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