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