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