1 : /******************************************************************************
2 : * $Id: ogrshapelayer.cpp 19940 2010-06-27 21:16:19Z 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 :
34 : #if defined(_WIN32_WCE)
35 : # include <wce_errno.h>
36 : #endif
37 :
38 : #if defined(WIN32) || defined(WIN32CE)
39 : #define SEP_CHAR '\\'
40 : #else
41 : #define SEP_CHAR '/'
42 : #endif
43 :
44 :
45 :
46 : CPL_CVSID("$Id: ogrshapelayer.cpp 19940 2010-06-27 21:16:19Z rouault $");
47 :
48 : /************************************************************************/
49 : /* OGRShapeLayer() */
50 : /************************************************************************/
51 :
52 : OGRShapeLayer::OGRShapeLayer( const char * pszName,
53 : SHPHandle hSHPIn, DBFHandle hDBFIn,
54 : OGRSpatialReference *poSRSIn, int bUpdate,
55 1023 : OGRwkbGeometryType eReqType )
56 :
57 : {
58 1023 : poSRS = poSRSIn;
59 :
60 1023 : pszFullName = CPLStrdup(pszName);
61 :
62 1023 : hSHP = hSHPIn;
63 1023 : hDBF = hDBFIn;
64 1023 : bUpdateAccess = bUpdate;
65 :
66 1023 : iNextShapeId = 0;
67 1023 : panMatchingFIDs = NULL;
68 :
69 1023 : bCheckedForQIX = FALSE;
70 1023 : fpQIX = NULL;
71 :
72 1023 : bHeaderDirty = FALSE;
73 :
74 1023 : if( hSHP != NULL )
75 1000 : nTotalShapeCount = hSHP->nRecords;
76 : else
77 23 : nTotalShapeCount = hDBF->nRecords;
78 :
79 : poFeatureDefn = SHPReadOGRFeatureDefn( CPLGetBasename(pszName),
80 1023 : hSHP, hDBF );
81 :
82 1023 : eRequestedGeomType = eReqType;
83 1023 : }
84 :
85 : /************************************************************************/
86 : /* ~OGRShapeLayer() */
87 : /************************************************************************/
88 :
89 1023 : OGRShapeLayer::~OGRShapeLayer()
90 :
91 : {
92 1023 : if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
93 : {
94 : CPLDebug( "Shape", "%d features read on layer '%s'.",
95 : (int) m_nFeaturesRead,
96 217 : poFeatureDefn->GetName() );
97 : }
98 :
99 1023 : CPLFree( panMatchingFIDs );
100 1023 : panMatchingFIDs = NULL;
101 :
102 1023 : CPLFree( pszFullName );
103 :
104 1023 : if( poFeatureDefn != NULL )
105 1023 : poFeatureDefn->Release();
106 :
107 1023 : if( poSRS != NULL )
108 233 : poSRS->Release();
109 :
110 1023 : if( hDBF != NULL )
111 1005 : DBFClose( hDBF );
112 :
113 1023 : if( hSHP != NULL )
114 1000 : SHPClose( hSHP );
115 :
116 1023 : if( fpQIX != NULL )
117 4 : VSIFClose( fpQIX );
118 1023 : }
119 :
120 : /************************************************************************/
121 : /* CheckForQIX() */
122 : /************************************************************************/
123 :
124 25 : int OGRShapeLayer::CheckForQIX()
125 :
126 : {
127 : const char *pszQIXFilename;
128 :
129 25 : if( bCheckedForQIX )
130 2 : return fpQIX != NULL;
131 :
132 23 : pszQIXFilename = CPLResetExtension( pszFullName, "qix" );
133 :
134 23 : fpQIX = VSIFOpen( pszQIXFilename, "rb" );
135 :
136 23 : bCheckedForQIX = TRUE;
137 :
138 23 : return fpQIX != NULL;
139 : }
140 :
141 : /************************************************************************/
142 : /* ScanIndices() */
143 : /* */
144 : /* Utilize optional spatial and attribute indices if they are */
145 : /* available. */
146 : /************************************************************************/
147 :
148 130 : int OGRShapeLayer::ScanIndices()
149 :
150 : {
151 130 : iMatchingFID = 0;
152 :
153 : /* -------------------------------------------------------------------- */
154 : /* Utilize attribute index if appropriate. */
155 : /* -------------------------------------------------------------------- */
156 130 : if( m_poAttrQuery != NULL )
157 : {
158 106 : CPLAssert( panMatchingFIDs == NULL );
159 : panMatchingFIDs = m_poAttrQuery->EvaluateAgainstIndices( this,
160 106 : NULL );
161 : }
162 :
163 : /* -------------------------------------------------------------------- */
164 : /* Check for spatial index if we have a spatial query. */
165 : /* -------------------------------------------------------------------- */
166 130 : if( m_poFilterGeom != NULL && !bCheckedForQIX )
167 14 : CheckForQIX();
168 :
169 : /* -------------------------------------------------------------------- */
170 : /* Utilize spatial index if appropriate. */
171 : /* -------------------------------------------------------------------- */
172 130 : if( m_poFilterGeom && fpQIX )
173 : {
174 : int nSpatialFIDCount, *panSpatialFIDs;
175 : double adfBoundsMin[4], adfBoundsMax[4];
176 10 : OGREnvelope oEnvelope;
177 :
178 10 : m_poFilterGeom->getEnvelope( &oEnvelope );
179 :
180 10 : adfBoundsMin[0] = oEnvelope.MinX;
181 10 : adfBoundsMin[1] = oEnvelope.MinY;
182 10 : adfBoundsMin[2] = 0.0;
183 10 : adfBoundsMin[3] = 0.0;
184 10 : adfBoundsMax[0] = oEnvelope.MaxX;
185 10 : adfBoundsMax[1] = oEnvelope.MaxY;
186 10 : adfBoundsMax[2] = 0.0;
187 10 : adfBoundsMax[3] = 0.0;
188 :
189 : panSpatialFIDs = SHPSearchDiskTree( fpQIX,
190 : adfBoundsMin, adfBoundsMax,
191 10 : &nSpatialFIDCount );
192 : CPLDebug( "SHAPE", "Used spatial index, got %d matches.",
193 10 : nSpatialFIDCount );
194 :
195 : // Use resulting list as matching FID list (but reallocate and
196 : // terminate with OGRNullFID).
197 :
198 10 : if( panMatchingFIDs == NULL )
199 : {
200 : int i;
201 :
202 : panMatchingFIDs = (long *)
203 8 : CPLMalloc(sizeof(long) * (nSpatialFIDCount+1) );
204 42 : for( i = 0; i < nSpatialFIDCount; i++ )
205 34 : panMatchingFIDs[i] = (long) panSpatialFIDs[i];
206 8 : panMatchingFIDs[nSpatialFIDCount] = OGRNullFID;
207 : }
208 :
209 : // Cull attribute index matches based on those in the spatial index
210 : // result set. We assume that the attribute results are in sorted
211 : // order.
212 : else
213 : {
214 2 : int iRead, iWrite=0, iSpatial=0;
215 :
216 4 : for( iRead = 0; panMatchingFIDs[iRead] != OGRNullFID; iRead++ )
217 : {
218 9 : while( iSpatial < nSpatialFIDCount
219 : && panSpatialFIDs[iSpatial] < panMatchingFIDs[iRead] )
220 5 : iSpatial++;
221 :
222 2 : if( iSpatial == nSpatialFIDCount )
223 0 : continue;
224 :
225 2 : if( panSpatialFIDs[iSpatial] == panMatchingFIDs[iRead] )
226 2 : panMatchingFIDs[iWrite++] = panMatchingFIDs[iRead];
227 : }
228 2 : panMatchingFIDs[iWrite] = OGRNullFID;
229 : }
230 :
231 10 : if ( panSpatialFIDs )
232 9 : free( panSpatialFIDs );
233 : }
234 :
235 130 : return TRUE;
236 : }
237 :
238 : /************************************************************************/
239 : /* ResetReading() */
240 : /************************************************************************/
241 :
242 406 : void OGRShapeLayer::ResetReading()
243 :
244 : {
245 : /* -------------------------------------------------------------------- */
246 : /* Clear previous index search result, if any. */
247 : /* -------------------------------------------------------------------- */
248 406 : CPLFree( panMatchingFIDs );
249 406 : panMatchingFIDs = NULL;
250 406 : iMatchingFID = 0;
251 :
252 406 : iNextShapeId = 0;
253 :
254 406 : if( bHeaderDirty && bUpdateAccess )
255 5 : SyncToDisk();
256 406 : }
257 :
258 : /************************************************************************/
259 : /* SetNextByIndex() */
260 : /* */
261 : /* If we already have an FID list, we can easily resposition */
262 : /* ourselves in it. */
263 : /************************************************************************/
264 :
265 0 : OGRErr OGRShapeLayer::SetNextByIndex( long nIndex )
266 :
267 : {
268 : // Eventually we should try to use panMatchingFIDs list
269 : // if available and appropriate.
270 0 : if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
271 0 : return OGRLayer::SetNextByIndex( nIndex );
272 :
273 0 : iNextShapeId = nIndex;
274 :
275 0 : return OGRERR_NONE;
276 : }
277 :
278 : /************************************************************************/
279 : /* FetchShape() */
280 : /* */
281 : /* Take a shape id, a geometry, and a feature, and set the feature */
282 : /* if the shapeid bbox intersects the geometry. */
283 : /************************************************************************/
284 :
285 17838 : OGRFeature *OGRShapeLayer::FetchShape(int iShapeId)
286 :
287 : {
288 : OGRFeature *poFeature;
289 :
290 17989 : if (m_poFilterGeom != NULL && hSHP != NULL )
291 : {
292 : SHPObject *psShape;
293 :
294 151 : psShape = SHPReadObject( hSHP, iShapeId );
295 :
296 : // do not trust degenerate bounds or bounds on null shapes.
297 173 : if( psShape == NULL || psShape->dfXMin == psShape->dfXMax
298 : || psShape->dfYMin == psShape->dfYMax
299 : || psShape->nSHPType == SHPT_NULL )
300 : {
301 : poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn,
302 22 : iShapeId, psShape );
303 : }
304 209 : else if( m_sFilterEnvelope.MaxX < psShape->dfXMin
305 : || m_sFilterEnvelope.MaxY < psShape->dfYMin
306 : || psShape->dfXMax < m_sFilterEnvelope.MinX
307 : || psShape->dfYMax < m_sFilterEnvelope.MinY )
308 : {
309 80 : SHPDestroyObject(psShape);
310 80 : poFeature = NULL;
311 : }
312 : else
313 : {
314 : poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn,
315 49 : iShapeId, psShape );
316 : }
317 : }
318 : else
319 : {
320 : poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn,
321 17687 : iShapeId, NULL );
322 : }
323 :
324 17838 : return poFeature;
325 : }
326 :
327 : /************************************************************************/
328 : /* GetNextFeature() */
329 : /************************************************************************/
330 :
331 17390 : OGRFeature *OGRShapeLayer::GetNextFeature()
332 :
333 : {
334 17390 : OGRFeature *poFeature = NULL;
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Collect a matching list if we have attribute or spatial */
338 : /* indices. Only do this on the first request for a given pass */
339 : /* of course. */
340 : /* -------------------------------------------------------------------- */
341 17390 : if( (m_poAttrQuery != NULL || m_poFilterGeom != NULL)
342 : && iNextShapeId == 0 && panMatchingFIDs == NULL )
343 : {
344 130 : ScanIndices();
345 : }
346 :
347 : /* -------------------------------------------------------------------- */
348 : /* Loop till we find a feature matching our criteria. */
349 : /* -------------------------------------------------------------------- */
350 645 : while( TRUE )
351 : {
352 18035 : if( panMatchingFIDs != NULL )
353 : {
354 54 : if( panMatchingFIDs[iMatchingFID] == OGRNullFID )
355 : {
356 11 : return NULL;
357 : }
358 :
359 : // Check the shape object's geometry, and if it matches
360 : // any spatial filter, return it.
361 43 : poFeature = FetchShape(panMatchingFIDs[iMatchingFID]);
362 :
363 43 : iMatchingFID++;
364 :
365 : }
366 : else
367 : {
368 17981 : if( iNextShapeId >= nTotalShapeCount )
369 : {
370 185 : return NULL;
371 : }
372 :
373 17796 : if ( hDBF && DBFIsRecordDeleted( hDBF, iNextShapeId ) ) {
374 1 : poFeature = NULL;
375 : } else {
376 : // Check the shape object's geometry, and if it matches
377 : // any spatial filter, return it.
378 17795 : poFeature = FetchShape(iNextShapeId);
379 : }
380 17796 : iNextShapeId++;
381 : }
382 :
383 17839 : if( poFeature != NULL )
384 : {
385 17758 : if( poFeature->GetGeometryRef() != NULL )
386 : {
387 17239 : poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
388 : }
389 :
390 17758 : m_nFeaturesRead++;
391 :
392 17758 : if( (m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) )
393 : && (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) )
394 : {
395 17194 : return poFeature;
396 : }
397 :
398 564 : delete poFeature;
399 : }
400 : }
401 :
402 : /*
403 : * NEVER SHOULD GET HERE
404 : */
405 : CPLAssert(!"OGRShapeLayer::GetNextFeature(): Execution never should get here!");
406 : }
407 :
408 : /************************************************************************/
409 : /* GetFeature() */
410 : /************************************************************************/
411 :
412 51 : OGRFeature *OGRShapeLayer::GetFeature( long nFeatureId )
413 :
414 : {
415 51 : OGRFeature *poFeature = NULL;
416 51 : poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn, nFeatureId, NULL);
417 :
418 51 : if( poFeature != NULL )
419 : {
420 51 : if( poFeature->GetGeometryRef() != NULL )
421 48 : poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
422 :
423 51 : m_nFeaturesRead++;
424 :
425 51 : return poFeature;
426 : }
427 :
428 : /*
429 : * Reading shape feature failed.
430 : */
431 0 : return NULL;
432 : }
433 :
434 : /************************************************************************/
435 : /* SetFeature() */
436 : /************************************************************************/
437 :
438 16 : OGRErr OGRShapeLayer::SetFeature( OGRFeature *poFeature )
439 :
440 : {
441 16 : if( !bUpdateAccess )
442 : {
443 : CPLError( CE_Failure, CPLE_AppDefined,
444 0 : "The SetFeature() operation is not permitted on a read-only shapefile." );
445 0 : return OGRERR_FAILURE;
446 : }
447 :
448 16 : bHeaderDirty = TRUE;
449 :
450 16 : return SHPWriteOGRFeature( hSHP, hDBF, poFeatureDefn, poFeature );
451 : }
452 :
453 : /************************************************************************/
454 : /* DeleteFeature() */
455 : /************************************************************************/
456 :
457 3 : OGRErr OGRShapeLayer::DeleteFeature( long nFID )
458 :
459 : {
460 3 : if( !bUpdateAccess )
461 : {
462 : CPLError( CE_Failure, CPLE_AppDefined,
463 0 : "The DeleteFeature() operation is not permitted on a read-only shapefile." );
464 0 : return OGRERR_FAILURE;
465 : }
466 :
467 3 : if( nFID < 0
468 : || (hSHP != NULL && nFID >= hSHP->nRecords)
469 : || (hDBF != NULL && nFID >= hDBF->nRecords) )
470 : {
471 : CPLError( CE_Failure, CPLE_AppDefined,
472 : "Attempt to delete shape with feature id (%ld) which does "
473 0 : "not exist.", nFID );
474 0 : return OGRERR_FAILURE;
475 : }
476 :
477 3 : if( !hDBF )
478 : {
479 : CPLError( CE_Failure, CPLE_AppDefined,
480 : "Attempt to delete shape in shapefile with no .dbf file.\n"
481 : "Deletion is done by marking record deleted in dbf\n"
482 0 : "and is not supported without a .dbf file." );
483 0 : return OGRERR_FAILURE;
484 : }
485 :
486 3 : if( DBFIsRecordDeleted( hDBF, nFID ) )
487 : {
488 : CPLError( CE_Failure, CPLE_AppDefined,
489 : "Attempt to delete shape with feature id (%ld), but it is marked deleted already.",
490 0 : nFID );
491 0 : return OGRERR_FAILURE;
492 : }
493 :
494 3 : if( !DBFMarkRecordDeleted( hDBF, nFID, TRUE ) )
495 0 : return OGRERR_FAILURE;
496 :
497 3 : bHeaderDirty = TRUE;
498 :
499 3 : return OGRERR_NONE;
500 : }
501 :
502 : /************************************************************************/
503 : /* CreateFeature() */
504 : /************************************************************************/
505 :
506 15905 : OGRErr OGRShapeLayer::CreateFeature( OGRFeature *poFeature )
507 :
508 : {
509 : OGRErr eErr;
510 :
511 15905 : if( !bUpdateAccess )
512 : {
513 : CPLError( CE_Failure, CPLE_AppDefined,
514 0 : "The CreateFeature() operation is not permitted on a read-only shapefile." );
515 0 : return OGRERR_FAILURE;
516 : }
517 :
518 15905 : bHeaderDirty = TRUE;
519 :
520 15905 : poFeature->SetFID( OGRNullFID );
521 :
522 15905 : if( nTotalShapeCount == 0
523 : && eRequestedGeomType == wkbUnknown
524 : && poFeature->GetGeometryRef() != NULL )
525 : {
526 48 : OGRGeometry *poGeom = poFeature->GetGeometryRef();
527 : int nShapeType;
528 :
529 48 : switch( poGeom->getGeometryType() )
530 : {
531 : case wkbPoint:
532 12 : nShapeType = SHPT_POINT;
533 12 : eRequestedGeomType = wkbPoint;
534 12 : break;
535 :
536 : case wkbPoint25D:
537 2 : nShapeType = SHPT_POINTZ;
538 2 : eRequestedGeomType = wkbPoint25D;
539 2 : break;
540 :
541 : case wkbMultiPoint:
542 3 : nShapeType = SHPT_MULTIPOINT;
543 3 : eRequestedGeomType = wkbMultiPoint;
544 3 : break;
545 :
546 : case wkbMultiPoint25D:
547 1 : nShapeType = SHPT_MULTIPOINTZ;
548 1 : eRequestedGeomType = wkbMultiPoint25D;
549 1 : break;
550 :
551 : case wkbLineString:
552 : case wkbMultiLineString:
553 6 : nShapeType = SHPT_ARC;
554 6 : eRequestedGeomType = wkbLineString;
555 6 : break;
556 :
557 : case wkbLineString25D:
558 : case wkbMultiLineString25D:
559 3 : nShapeType = SHPT_ARCZ;
560 3 : eRequestedGeomType = wkbLineString25D;
561 3 : break;
562 :
563 : case wkbPolygon:
564 : case wkbMultiPolygon:
565 19 : nShapeType = SHPT_POLYGON;
566 19 : eRequestedGeomType = wkbPolygon;
567 19 : break;
568 :
569 : case wkbPolygon25D:
570 : case wkbMultiPolygon25D:
571 2 : nShapeType = SHPT_POLYGONZ;
572 2 : eRequestedGeomType = wkbPolygon25D;
573 2 : break;
574 :
575 : default:
576 0 : nShapeType = -1;
577 : break;
578 : }
579 :
580 48 : if( nShapeType != -1 )
581 : {
582 48 : ResetGeomType( nShapeType );
583 : }
584 : }
585 :
586 15905 : eErr = SHPWriteOGRFeature( hSHP, hDBF, poFeatureDefn, poFeature );
587 :
588 15905 : if( hSHP != NULL )
589 15884 : nTotalShapeCount = hSHP->nRecords;
590 : else
591 21 : nTotalShapeCount = hDBF->nRecords;
592 :
593 15905 : return eErr;
594 : }
595 :
596 : /************************************************************************/
597 : /* GetFeatureCount() */
598 : /* */
599 : /* If a spatial filter is in effect, we turn control over to */
600 : /* the generic counter. Otherwise we return the total count. */
601 : /* Eventually we should consider implementing a more efficient */
602 : /* way of counting features matching a spatial query. */
603 : /************************************************************************/
604 :
605 142 : int OGRShapeLayer::GetFeatureCount( int bForce )
606 :
607 : {
608 142 : if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
609 15 : return OGRLayer::GetFeatureCount( bForce );
610 : else
611 127 : return nTotalShapeCount;
612 : }
613 :
614 : /************************************************************************/
615 : /* GetExtent() */
616 : /* */
617 : /* Fetch extent of the data currently stored in the dataset. */
618 : /* The bForce flag has no effect on SHO files since that value */
619 : /* is always in the header. */
620 : /* */
621 : /* Returns OGRERR_NONE/OGRRERR_FAILURE. */
622 : /************************************************************************/
623 :
624 39 : OGRErr OGRShapeLayer::GetExtent (OGREnvelope *psExtent, int bForce)
625 :
626 : {
627 : UNREFERENCED_PARAM( bForce );
628 :
629 : double adMin[4], adMax[4];
630 :
631 39 : if( hSHP == NULL )
632 0 : return OGRERR_FAILURE;
633 :
634 39 : SHPGetInfo(hSHP, NULL, NULL, adMin, adMax);
635 :
636 39 : psExtent->MinX = adMin[0];
637 39 : psExtent->MinY = adMin[1];
638 39 : psExtent->MaxX = adMax[0];
639 39 : psExtent->MaxY = adMax[1];
640 :
641 39 : return OGRERR_NONE;
642 : }
643 :
644 : /************************************************************************/
645 : /* TestCapability() */
646 : /************************************************************************/
647 :
648 11 : int OGRShapeLayer::TestCapability( const char * pszCap )
649 :
650 : {
651 11 : if( EQUAL(pszCap,OLCRandomRead) )
652 2 : return TRUE;
653 :
654 9 : else if( EQUAL(pszCap,OLCSequentialWrite)
655 : || EQUAL(pszCap,OLCRandomWrite) )
656 2 : return bUpdateAccess;
657 :
658 7 : else if( EQUAL(pszCap,OLCFastFeatureCount) )
659 4 : return m_poFilterGeom == NULL || CheckForQIX();
660 :
661 3 : else if( EQUAL(pszCap,OLCDeleteFeature) )
662 0 : return bUpdateAccess;
663 :
664 3 : else if( EQUAL(pszCap,OLCFastSpatialFilter) )
665 1 : return CheckForQIX();
666 :
667 2 : else if( EQUAL(pszCap,OLCFastGetExtent) )
668 2 : return TRUE;
669 :
670 0 : else if( EQUAL(pszCap,OLCFastSetNextByIndex) )
671 0 : return m_poFilterGeom == NULL && m_poAttrQuery == NULL;
672 :
673 0 : else if( EQUAL(pszCap,OLCCreateField) )
674 0 : return bUpdateAccess;
675 :
676 : else
677 0 : return FALSE;
678 : }
679 :
680 : /************************************************************************/
681 : /* CreateField() */
682 : /************************************************************************/
683 :
684 190 : OGRErr OGRShapeLayer::CreateField( OGRFieldDefn *poFieldDefn, int bApproxOK )
685 :
686 : {
687 190 : CPLAssert( NULL != poFieldDefn );
688 :
689 : int iNewField;
690 :
691 190 : if( !bUpdateAccess )
692 : {
693 : CPLError( CE_Failure, CPLE_NotSupported,
694 0 : "Can't create fields on a read-only shapefile layer.\n");
695 0 : return OGRERR_FAILURE;
696 :
697 : }
698 :
699 : /* -------------------------------------------------------------------- */
700 : /* Normalize field name */
701 : /* -------------------------------------------------------------------- */
702 :
703 : char szNewFieldName[10 + 1];
704 190 : char * pszTmp = NULL;
705 190 : int nRenameNum = 1;
706 :
707 190 : size_t nNameSize = strlen( poFieldDefn->GetNameRef() );
708 : pszTmp = CPLScanString( poFieldDefn->GetNameRef(),
709 190 : MIN( nNameSize, 10) , TRUE, TRUE);
710 190 : strncpy(szNewFieldName, pszTmp, 10);
711 190 : szNewFieldName[10] = '\0';
712 :
713 190 : if( !bApproxOK &&
714 : ( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 ||
715 : !EQUAL(poFieldDefn->GetNameRef(),szNewFieldName) ) )
716 : {
717 : CPLError( CE_Failure, CPLE_NotSupported,
718 : "Failed to add field named '%s'",
719 0 : poFieldDefn->GetNameRef() );
720 :
721 0 : CPLFree( pszTmp );
722 0 : return OGRERR_FAILURE;
723 : }
724 :
725 503 : while( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 && nRenameNum < 10 )
726 123 : sprintf( szNewFieldName, "%.8s_%.1d", pszTmp, nRenameNum++ );
727 384 : while( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 && nRenameNum < 100 )
728 4 : sprintf( szNewFieldName, "%.8s%.2d", pszTmp, nRenameNum++ );
729 :
730 190 : CPLFree( pszTmp );
731 190 : pszTmp = NULL;
732 :
733 190 : if( DBFGetFieldIndex( hDBF, szNewFieldName ) >= 0 )
734 : {
735 : CPLError( CE_Failure, CPLE_NotSupported,
736 : "Too many field names like '%s' when truncated to 10 letters "
737 : "for Shapefile format.",
738 0 : poFieldDefn->GetNameRef() );//One hundred similar field names!!?
739 : }
740 :
741 190 : if( !EQUAL(poFieldDefn->GetNameRef(),szNewFieldName) )
742 : CPLError( CE_Warning, CPLE_NotSupported,
743 : "Normalized/laundered field name: '%s' to '%s'",
744 : poFieldDefn->GetNameRef(),
745 30 : szNewFieldName );
746 :
747 : // Set field name with normalized value
748 190 : OGRFieldDefn oModFieldDefn(poFieldDefn);
749 190 : oModFieldDefn.SetName(szNewFieldName);
750 :
751 : /* -------------------------------------------------------------------- */
752 : /* Add field to layer */
753 : /* -------------------------------------------------------------------- */
754 :
755 190 : if( oModFieldDefn.GetType() == OFTInteger )
756 : {
757 31 : if( oModFieldDefn.GetWidth() == 0 )
758 : iNewField =
759 25 : DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTInteger, 11, 0 );
760 : else
761 : iNewField = DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTInteger,
762 6 : oModFieldDefn.GetWidth(), 0 );
763 :
764 31 : if( iNewField != -1 )
765 31 : poFeatureDefn->AddFieldDefn( &oModFieldDefn );
766 : }
767 159 : else if( oModFieldDefn.GetType() == OFTReal )
768 : {
769 94 : if( oModFieldDefn.GetWidth() == 0 )
770 : iNewField =
771 5 : DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTDouble, 24, 15 );
772 : else
773 : iNewField =
774 : DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTDouble,
775 89 : oModFieldDefn.GetWidth(), oModFieldDefn.GetPrecision() );
776 :
777 94 : if( iNewField != -1 )
778 94 : poFeatureDefn->AddFieldDefn( &oModFieldDefn );
779 : }
780 65 : else if( oModFieldDefn.GetType() == OFTString )
781 : {
782 64 : if( oModFieldDefn.GetWidth() < 1 )
783 : iNewField =
784 18 : DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTString, 80, 0 );
785 : else
786 : iNewField = DBFAddField( hDBF, oModFieldDefn.GetNameRef(), FTString,
787 46 : oModFieldDefn.GetWidth(), 0 );
788 :
789 64 : if( iNewField != -1 )
790 64 : poFeatureDefn->AddFieldDefn( &oModFieldDefn );
791 : }
792 1 : else if( oModFieldDefn.GetType() == OFTDate )
793 : {
794 : iNewField =
795 1 : DBFAddNativeFieldType( hDBF, oModFieldDefn.GetNameRef(), 'D', 8, 0 );
796 :
797 1 : if( iNewField != -1 )
798 1 : poFeatureDefn->AddFieldDefn( &oModFieldDefn );
799 : }
800 0 : else if( oModFieldDefn.GetType() == OFTDateTime )
801 : {
802 : CPLError( CE_Warning, CPLE_NotSupported,
803 : "Field %s create as date field, though DateTime requested.\n",
804 0 : oModFieldDefn.GetNameRef() );
805 :
806 : iNewField =
807 0 : DBFAddNativeFieldType( hDBF, oModFieldDefn.GetNameRef(), 'D', 8, 0 );
808 :
809 0 : if( iNewField != -1 )
810 : {
811 0 : oModFieldDefn.SetType( OFTDate );
812 0 : poFeatureDefn->AddFieldDefn( &oModFieldDefn );
813 : }
814 : }
815 : else
816 : {
817 : CPLError( CE_Failure, CPLE_NotSupported,
818 : "Can't create fields of type %s on shapefile layers.\n",
819 0 : OGRFieldDefn::GetFieldTypeName(oModFieldDefn.GetType()) );
820 :
821 190 : return OGRERR_FAILURE;
822 : }
823 :
824 190 : if( iNewField != -1 )
825 : {
826 190 : return OGRERR_NONE;
827 : }
828 : else
829 : {
830 : CPLError( CE_Failure, CPLE_AppDefined,
831 : "Can't create field %s in Shape DBF file, reason unknown.\n",
832 0 : oModFieldDefn.GetNameRef() );
833 :
834 0 : return OGRERR_FAILURE;
835 0 : }
836 : }
837 :
838 : /************************************************************************/
839 : /* GetSpatialRef() */
840 : /************************************************************************/
841 :
842 124 : OGRSpatialReference *OGRShapeLayer::GetSpatialRef()
843 :
844 : {
845 124 : return poSRS;
846 : }
847 :
848 : /************************************************************************/
849 : /* ResetGeomType() */
850 : /* */
851 : /* Modify the geometry type for this file. Used to convert to */
852 : /* a different geometry type when a layer was created with a */
853 : /* type of unknown, and we get to the first feature to */
854 : /* establish the type. */
855 : /************************************************************************/
856 :
857 48 : int OGRShapeLayer::ResetGeomType( int nNewGeomType )
858 :
859 : {
860 : char abyHeader[100];
861 : int nStartPos;
862 :
863 48 : if( nTotalShapeCount > 0 )
864 0 : return FALSE;
865 :
866 48 : if( hSHP->fpSHX == NULL)
867 : {
868 : CPLError( CE_Failure, CPLE_NotSupported,
869 0 : " OGRShapeLayer::ResetGeomType failed : SHX file is closed");
870 0 : return FALSE;
871 : }
872 :
873 : /* -------------------------------------------------------------------- */
874 : /* Update .shp header. */
875 : /* -------------------------------------------------------------------- */
876 48 : nStartPos = (int)( hSHP->sHooks.FTell( hSHP->fpSHP ) );
877 :
878 48 : if( hSHP->sHooks.FSeek( hSHP->fpSHP, 0, SEEK_SET ) != 0
879 : || hSHP->sHooks.FRead( abyHeader, 100, 1, hSHP->fpSHP ) != 1 )
880 0 : return FALSE;
881 :
882 48 : *((GInt32 *) (abyHeader + 32)) = CPL_LSBWORD32( nNewGeomType );
883 :
884 48 : if( hSHP->sHooks.FSeek( hSHP->fpSHP, 0, SEEK_SET ) != 0
885 : || hSHP->sHooks.FWrite( abyHeader, 100, 1, hSHP->fpSHP ) != 1 )
886 0 : return FALSE;
887 :
888 48 : if( hSHP->sHooks.FSeek( hSHP->fpSHP, nStartPos, SEEK_SET ) != 0 )
889 0 : return FALSE;
890 :
891 : /* -------------------------------------------------------------------- */
892 : /* Update .shx header. */
893 : /* -------------------------------------------------------------------- */
894 48 : nStartPos = (int)( hSHP->sHooks.FTell( hSHP->fpSHX ) );
895 :
896 48 : if( hSHP->sHooks.FSeek( hSHP->fpSHX, 0, SEEK_SET ) != 0
897 : || hSHP->sHooks.FRead( abyHeader, 100, 1, hSHP->fpSHX ) != 1 )
898 0 : return FALSE;
899 :
900 48 : *((GInt32 *) (abyHeader + 32)) = CPL_LSBWORD32( nNewGeomType );
901 :
902 48 : if( hSHP->sHooks.FSeek( hSHP->fpSHX, 0, SEEK_SET ) != 0
903 : || hSHP->sHooks.FWrite( abyHeader, 100, 1, hSHP->fpSHX ) != 1 )
904 0 : return FALSE;
905 :
906 48 : if( hSHP->sHooks.FSeek( hSHP->fpSHX, nStartPos, SEEK_SET ) != 0 )
907 0 : return FALSE;
908 :
909 : /* -------------------------------------------------------------------- */
910 : /* Update other information. */
911 : /* -------------------------------------------------------------------- */
912 48 : hSHP->nShapeType = nNewGeomType;
913 :
914 48 : return TRUE;
915 : }
916 :
917 : /************************************************************************/
918 : /* SyncToDisk() */
919 : /************************************************************************/
920 :
921 8 : OGRErr OGRShapeLayer::SyncToDisk()
922 :
923 : {
924 8 : if( bHeaderDirty )
925 : {
926 7 : if( hSHP != NULL )
927 7 : SHPWriteHeader( hSHP );
928 :
929 7 : if( hDBF != NULL )
930 7 : DBFUpdateHeader( hDBF );
931 :
932 7 : bHeaderDirty = FALSE;
933 : }
934 :
935 8 : if( hSHP != NULL )
936 : {
937 8 : hSHP->sHooks.FFlush( hSHP->fpSHP );
938 8 : if( hSHP->fpSHX != NULL )
939 8 : hSHP->sHooks.FFlush( hSHP->fpSHX );
940 : }
941 :
942 8 : if( hDBF != NULL )
943 8 : hDBF->sHooks.FFlush( hDBF->fp );
944 :
945 8 : return OGRERR_NONE;
946 : }
947 :
948 : /************************************************************************/
949 : /* DropSpatialIndex() */
950 : /************************************************************************/
951 :
952 1 : OGRErr OGRShapeLayer::DropSpatialIndex()
953 :
954 : {
955 1 : if( !CheckForQIX() )
956 : {
957 : CPLError( CE_Warning, CPLE_AppDefined,
958 : "Layer %s has no spatial index, DROP SPATIAL INDEX failed.",
959 0 : poFeatureDefn->GetName() );
960 0 : return OGRERR_FAILURE;
961 : }
962 :
963 1 : VSIFClose( fpQIX );
964 1 : fpQIX = NULL;
965 1 : bCheckedForQIX = FALSE;
966 :
967 : const char *pszQIXFilename;
968 :
969 1 : pszQIXFilename = CPLResetExtension( pszFullName, "qix" );
970 1 : CPLDebug( "SHAPE", "Unlinking index file %s", pszQIXFilename );
971 :
972 1 : if( VSIUnlink( pszQIXFilename ) != 0 )
973 : {
974 : CPLError( CE_Failure, CPLE_AppDefined,
975 : "Failed to delete file %s.\n%s",
976 0 : pszQIXFilename, VSIStrerror( errno ) );
977 0 : return OGRERR_FAILURE;
978 : }
979 : else
980 1 : return OGRERR_NONE;
981 : }
982 :
983 : /************************************************************************/
984 : /* CreateSpatialIndex() */
985 : /************************************************************************/
986 :
987 3 : OGRErr OGRShapeLayer::CreateSpatialIndex( int nMaxDepth )
988 :
989 : {
990 : /* -------------------------------------------------------------------- */
991 : /* If we have an existing spatial index, blow it away first. */
992 : /* -------------------------------------------------------------------- */
993 3 : if( CheckForQIX() )
994 0 : DropSpatialIndex();
995 :
996 3 : bCheckedForQIX = FALSE;
997 :
998 : /* -------------------------------------------------------------------- */
999 : /* Build a quadtree structure for this file. */
1000 : /* -------------------------------------------------------------------- */
1001 : SHPTree *psTree;
1002 :
1003 3 : SyncToDisk();
1004 3 : psTree = SHPCreateTree( hSHP, 2, nMaxDepth, NULL, NULL );
1005 :
1006 3 : if( NULL == psTree )
1007 : {
1008 : // TODO - mloskot: Is it better to return OGRERR_NOT_ENOUGH_MEMORY?
1009 :
1010 : CPLDebug( "SHAPE",
1011 0 : "Index creation failure. Likely, memory allocation error." );
1012 :
1013 0 : return OGRERR_FAILURE;
1014 : }
1015 :
1016 : /* -------------------------------------------------------------------- */
1017 : /* Trim unused nodes from the tree. */
1018 : /* -------------------------------------------------------------------- */
1019 3 : SHPTreeTrimExtraNodes( psTree );
1020 :
1021 : /* -------------------------------------------------------------------- */
1022 : /* Dump tree to .qix file. */
1023 : /* -------------------------------------------------------------------- */
1024 : char *pszQIXFilename;
1025 :
1026 3 : pszQIXFilename = CPLStrdup(CPLResetExtension( pszFullName, "qix" ));
1027 :
1028 3 : CPLDebug( "SHAPE", "Creating index file %s", pszQIXFilename );
1029 :
1030 3 : SHPWriteTree( psTree, pszQIXFilename );
1031 3 : CPLFree( pszQIXFilename );
1032 :
1033 :
1034 : /* -------------------------------------------------------------------- */
1035 : /* cleanup */
1036 : /* -------------------------------------------------------------------- */
1037 3 : SHPDestroyTree( psTree );
1038 :
1039 3 : CheckForQIX();
1040 :
1041 3 : return OGRERR_NONE;
1042 : }
1043 :
1044 : /************************************************************************/
1045 : /* Repack() */
1046 : /* */
1047 : /* Repack the shape and dbf file, dropping deleted records. */
1048 : /* FIDs may change. */
1049 : /************************************************************************/
1050 :
1051 3 : OGRErr OGRShapeLayer::Repack()
1052 :
1053 : {
1054 3 : if( !bUpdateAccess )
1055 : {
1056 : CPLError( CE_Failure, CPLE_AppDefined,
1057 0 : "The REPACK operation is not permitted on a read-only shapefile." );
1058 0 : return OGRERR_FAILURE;
1059 : }
1060 :
1061 3 : if( hDBF == NULL )
1062 : {
1063 : CPLError( CE_Failure, CPLE_NotSupported,
1064 0 : "Attempt to repack a shapefile with no .dbf file not supported.");
1065 0 : return OGRERR_FAILURE;
1066 : }
1067 :
1068 : /* -------------------------------------------------------------------- */
1069 : /* Build a list of records to be dropped. */
1070 : /* -------------------------------------------------------------------- */
1071 : int *panRecordsToDelete = (int *)
1072 3 : CPLMalloc(sizeof(int)*(nTotalShapeCount+1));
1073 3 : int nDeleteCount = 0;
1074 3 : int iShape = 0;
1075 3 : OGRErr eErr = OGRERR_NONE;
1076 :
1077 34 : for( iShape = 0; iShape < nTotalShapeCount; iShape++ )
1078 : {
1079 31 : if( DBFIsRecordDeleted( hDBF, iShape ) )
1080 3 : panRecordsToDelete[nDeleteCount++] = iShape;
1081 : }
1082 3 : panRecordsToDelete[nDeleteCount] = -1;
1083 :
1084 : /* -------------------------------------------------------------------- */
1085 : /* If there are no records marked for deletion, we take no */
1086 : /* action. */
1087 : /* -------------------------------------------------------------------- */
1088 3 : if( nDeleteCount == 0 )
1089 : {
1090 0 : CPLFree( panRecordsToDelete );
1091 0 : return OGRERR_NONE;
1092 : }
1093 :
1094 : /* -------------------------------------------------------------------- */
1095 : /* Find existing filenames with exact case (see #3293). */
1096 : /* -------------------------------------------------------------------- */
1097 3 : CPLString osDirname(CPLGetPath(pszFullName));
1098 3 : CPLString osBasename(CPLGetBasename(pszFullName));
1099 :
1100 3 : CPLString osDBFName, osSHPName, osSHXName;
1101 3 : char **papszCandidates = CPLReadDir( osDirname );
1102 3 : int i = 0;
1103 21 : while(papszCandidates != NULL && papszCandidates[i] != NULL)
1104 : {
1105 18 : CPLString osCandidateBasename = CPLGetBasename(papszCandidates[i]);
1106 18 : CPLString osCandidateExtension = CPLGetExtension(papszCandidates[i]);
1107 18 : if (osCandidateBasename.compare(osBasename) == 0)
1108 : {
1109 9 : if (EQUAL(osCandidateExtension, "dbf"))
1110 3 : osDBFName = CPLFormFilename(osDirname, papszCandidates[i], NULL);
1111 6 : else if (EQUAL(osCandidateExtension, "shp"))
1112 3 : osSHPName = CPLFormFilename(osDirname, papszCandidates[i], NULL);
1113 3 : else if (EQUAL(osCandidateExtension, "shx"))
1114 3 : osSHXName = CPLFormFilename(osDirname, papszCandidates[i], NULL);
1115 : }
1116 :
1117 18 : i++;
1118 : }
1119 3 : CSLDestroy(papszCandidates);
1120 3 : papszCandidates = NULL;
1121 :
1122 3 : if (osDBFName.size() == 0)
1123 : {
1124 : /* Should not happen, really */
1125 0 : CPLFree( panRecordsToDelete );
1126 3 : return OGRERR_FAILURE;
1127 : }
1128 :
1129 : /* -------------------------------------------------------------------- */
1130 : /* Cleanup any existing spatial index. It will become */
1131 : /* meaningless when the fids change. */
1132 : /* -------------------------------------------------------------------- */
1133 3 : if( CheckForQIX() )
1134 0 : DropSpatialIndex();
1135 :
1136 : /* -------------------------------------------------------------------- */
1137 : /* Create a new dbf file, matching the old. */
1138 : /* -------------------------------------------------------------------- */
1139 3 : DBFHandle hNewDBF = NULL;
1140 :
1141 3 : CPLString oTempFile(osDirname);
1142 3 : oTempFile += SEP_CHAR;
1143 3 : oTempFile += osBasename;
1144 3 : oTempFile += "_packed.dbf";
1145 :
1146 3 : hNewDBF = DBFCloneEmpty( hDBF, oTempFile );
1147 3 : if( hNewDBF == NULL )
1148 : {
1149 0 : CPLFree( panRecordsToDelete );
1150 :
1151 : CPLError( CE_Failure, CPLE_OpenFailed,
1152 : "Failed to create temp file %s.",
1153 0 : oTempFile.c_str() );
1154 0 : return OGRERR_FAILURE;
1155 : }
1156 :
1157 : /* -------------------------------------------------------------------- */
1158 : /* Copy over all records that are not deleted. */
1159 : /* -------------------------------------------------------------------- */
1160 3 : int iDestShape = 0;
1161 3 : int iNextDeletedShape = 0;
1162 :
1163 34 : for( iShape = 0;
1164 : iShape < nTotalShapeCount && eErr == OGRERR_NONE;
1165 : iShape++ )
1166 : {
1167 31 : if( panRecordsToDelete[iNextDeletedShape] == iShape )
1168 3 : iNextDeletedShape++;
1169 : else
1170 : {
1171 28 : void *pTuple = (void *) DBFReadTuple( hDBF, iShape );
1172 28 : if( pTuple == NULL )
1173 0 : eErr = OGRERR_FAILURE;
1174 28 : else if( !DBFWriteTuple( hNewDBF, iDestShape++, pTuple ) )
1175 0 : eErr = OGRERR_FAILURE;
1176 : }
1177 : }
1178 :
1179 3 : if( eErr != OGRERR_NONE )
1180 : {
1181 0 : CPLFree( panRecordsToDelete );
1182 0 : VSIUnlink( oTempFile );
1183 0 : return eErr;
1184 : }
1185 :
1186 : /* -------------------------------------------------------------------- */
1187 : /* Cleanup the old .dbf and rename the new one. */
1188 : /* -------------------------------------------------------------------- */
1189 3 : DBFClose( hDBF );
1190 3 : DBFClose( hNewDBF );
1191 3 : hDBF = hNewDBF = NULL;
1192 :
1193 3 : VSIUnlink( osDBFName );
1194 :
1195 3 : if( VSIRename( oTempFile, osDBFName ) != 0 )
1196 : {
1197 0 : CPLDebug( "Shape", "Can not rename DBF file: %s", VSIStrerror( errno ) );
1198 0 : CPLFree( panRecordsToDelete );
1199 0 : return OGRERR_FAILURE;
1200 : }
1201 :
1202 : /* -------------------------------------------------------------------- */
1203 : /* Now create a shapefile matching the old one. */
1204 : /* -------------------------------------------------------------------- */
1205 3 : if( hSHP != NULL )
1206 : {
1207 3 : SHPHandle hNewSHP = NULL;
1208 :
1209 3 : if (osSHPName.size() == 0 || osSHXName.size() == 0)
1210 : {
1211 : /* Should not happen, really */
1212 0 : CPLFree( panRecordsToDelete );
1213 0 : return OGRERR_FAILURE;
1214 : }
1215 :
1216 3 : oTempFile = osDirname;
1217 3 : oTempFile += SEP_CHAR;
1218 3 : oTempFile += osBasename;
1219 3 : oTempFile += "_packed.shp";
1220 :
1221 3 : hNewSHP = SHPCreate( oTempFile, hSHP->nShapeType );
1222 3 : if( hNewSHP == NULL )
1223 : {
1224 0 : CPLFree( panRecordsToDelete );
1225 0 : return OGRERR_FAILURE;
1226 : }
1227 :
1228 : /* -------------------------------------------------------------------- */
1229 : /* Copy over all records that are not deleted. */
1230 : /* -------------------------------------------------------------------- */
1231 3 : iNextDeletedShape = 0;
1232 :
1233 34 : for( iShape = 0;
1234 : iShape < nTotalShapeCount && eErr == OGRERR_NONE;
1235 : iShape++ )
1236 : {
1237 31 : if( panRecordsToDelete[iNextDeletedShape] == iShape )
1238 3 : iNextDeletedShape++;
1239 : else
1240 : {
1241 : SHPObject *hObject;
1242 :
1243 28 : hObject = SHPReadObject( hSHP, iShape );
1244 28 : if( hObject == NULL )
1245 0 : eErr = OGRERR_FAILURE;
1246 28 : else if( SHPWriteObject( hNewSHP, -1, hObject ) == -1 )
1247 0 : eErr = OGRERR_FAILURE;
1248 :
1249 28 : if( hObject )
1250 28 : SHPDestroyObject( hObject );
1251 : }
1252 : }
1253 :
1254 3 : if( eErr != OGRERR_NONE )
1255 : {
1256 0 : CPLFree( panRecordsToDelete );
1257 0 : VSIUnlink( CPLResetExtension( oTempFile, "shp" ) );
1258 0 : VSIUnlink( CPLResetExtension( oTempFile, "shx" ) );
1259 0 : return eErr;
1260 : }
1261 :
1262 : /* -------------------------------------------------------------------- */
1263 : /* Cleanup the old .shp/.shx and rename the new one. */
1264 : /* -------------------------------------------------------------------- */
1265 3 : SHPClose( hSHP );
1266 3 : SHPClose( hNewSHP );
1267 3 : hSHP = hNewSHP = NULL;
1268 :
1269 3 : VSIUnlink( osSHPName );
1270 3 : VSIUnlink( osSHXName );
1271 :
1272 3 : oTempFile = CPLResetExtension( oTempFile, "shp" );
1273 3 : if( VSIRename( oTempFile, osSHPName ) != 0 )
1274 : {
1275 0 : CPLDebug( "Shape", "Can not rename SHP file: %s", VSIStrerror( errno ) );
1276 0 : CPLFree( panRecordsToDelete );
1277 0 : return OGRERR_FAILURE;
1278 : }
1279 :
1280 3 : oTempFile = CPLResetExtension( oTempFile, "shx" );
1281 3 : if( VSIRename( oTempFile, osSHXName ) != 0 )
1282 : {
1283 0 : CPLDebug( "Shape", "Can not rename SHX file: %s", VSIStrerror( errno ) );
1284 0 : CPLFree( panRecordsToDelete );
1285 0 : return OGRERR_FAILURE;
1286 : }
1287 : }
1288 :
1289 3 : CPLFree( panRecordsToDelete );
1290 3 : panRecordsToDelete = NULL;
1291 :
1292 : /* -------------------------------------------------------------------- */
1293 : /* Reopen the shapefile */
1294 : /* */
1295 : /* We do not need to reimplement OGRShapeDataSource::OpenFile() here */
1296 : /* with the fully featured error checking. */
1297 : /* If all operations above succeeded, then all necessery files are */
1298 : /* in the right place and accessible. */
1299 : /* -------------------------------------------------------------------- */
1300 3 : CPLAssert( NULL == hSHP );
1301 3 : CPLAssert( NULL == hDBF && NULL == hNewDBF );
1302 :
1303 3 : CPLPushErrorHandler( CPLQuietErrorHandler );
1304 :
1305 3 : const char* pszAccess = NULL;
1306 3 : if( bUpdateAccess )
1307 3 : pszAccess = "r+";
1308 : else
1309 0 : pszAccess = "r";
1310 :
1311 3 : hSHP = SHPOpen ( CPLResetExtension( pszFullName, "shp" ) , pszAccess );
1312 3 : hDBF = DBFOpen ( CPLResetExtension( pszFullName, "dbf" ) , pszAccess );
1313 :
1314 3 : CPLPopErrorHandler();
1315 :
1316 3 : if( NULL == hSHP || NULL == hDBF )
1317 : {
1318 0 : CPLString osMsg(CPLGetLastErrorMsg());
1319 0 : CPLError( CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str() );
1320 :
1321 0 : return OGRERR_FAILURE;
1322 : }
1323 :
1324 : /* -------------------------------------------------------------------- */
1325 : /* Update total shape count. */
1326 : /* -------------------------------------------------------------------- */
1327 3 : nTotalShapeCount = hDBF->nRecords;
1328 :
1329 3 : return OGRERR_NONE;
1330 : }
|