1 : /******************************************************************************
2 : * $Id: ogrshapedatasource.cpp 17806 2009-10-13 17:27:54Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRShapeDataSource 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 : CPL_CVSID("$Id: ogrshapedatasource.cpp 17806 2009-10-13 17:27:54Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRShapeDataSource() */
38 : /************************************************************************/
39 :
40 420 : OGRShapeDataSource::OGRShapeDataSource()
41 :
42 : {
43 420 : pszName = NULL;
44 420 : papoLayers = NULL;
45 420 : nLayers = 0;
46 420 : bSingleNewFile = FALSE;
47 420 : }
48 :
49 : /************************************************************************/
50 : /* ~OGRShapeDataSource() */
51 : /************************************************************************/
52 :
53 840 : OGRShapeDataSource::~OGRShapeDataSource()
54 :
55 : {
56 420 : CPLFree( pszName );
57 :
58 1333 : for( int i = 0; i < nLayers; i++ )
59 : {
60 : CPLAssert( NULL != papoLayers[i] );
61 :
62 913 : delete papoLayers[i];
63 : }
64 :
65 420 : CPLFree( papoLayers );
66 840 : }
67 :
68 : /************************************************************************/
69 : /* Open() */
70 : /************************************************************************/
71 :
72 420 : int OGRShapeDataSource::Open( const char * pszNewName, int bUpdate,
73 : int bTestOpen, int bSingleNewFileIn )
74 :
75 : {
76 : VSIStatBufL stat;
77 :
78 : CPLAssert( nLayers == 0 );
79 :
80 420 : pszName = CPLStrdup( pszNewName );
81 :
82 420 : bDSUpdate = bUpdate;
83 :
84 420 : bSingleNewFile = bSingleNewFileIn;
85 :
86 : /* -------------------------------------------------------------------- */
87 : /* If bSingleNewFile is TRUE we don't try to do anything else. */
88 : /* This is only utilized when the OGRShapeDriver::Create() */
89 : /* method wants to create a stub OGRShapeDataSource for a */
90 : /* single shapefile. The driver will take care of creating the */
91 : /* file by calling CreateLayer(). */
92 : /* -------------------------------------------------------------------- */
93 420 : if( bSingleNewFile )
94 29 : return TRUE;
95 :
96 : /* -------------------------------------------------------------------- */
97 : /* Is the given path a directory or a regular file? */
98 : /* -------------------------------------------------------------------- */
99 391 : if( VSIStatL( pszNewName, &stat ) != 0
100 : || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) )
101 : {
102 71 : if( !bTestOpen )
103 : CPLError( CE_Failure, CPLE_AppDefined,
104 : "%s is neither a file or directory, Shape access failed.\n",
105 0 : pszNewName );
106 :
107 71 : return FALSE;
108 : }
109 :
110 : /* -------------------------------------------------------------------- */
111 : /* Build a list of filenames we figure are Shape files. */
112 : /* -------------------------------------------------------------------- */
113 320 : if( VSI_ISREG(stat.st_mode) )
114 : {
115 251 : if( !OpenFile( pszNewName, bUpdate, bTestOpen ) )
116 : {
117 124 : if( !bTestOpen )
118 : CPLError( CE_Failure, CPLE_OpenFailed,
119 : "Failed to open shapefile %s.\n"
120 : "It may be corrupt or read-only file accessed in update mode.\n",
121 0 : pszNewName );
122 :
123 124 : return FALSE;
124 : }
125 :
126 127 : return TRUE;
127 : }
128 : else
129 : {
130 69 : char **papszCandidates = CPLReadDir( pszNewName );
131 69 : int iCan, nCandidateCount = CSLCount( papszCandidates );
132 69 : int bMightBeOldCoverage = FALSE;
133 :
134 2645 : for( iCan = 0; iCan < nCandidateCount; iCan++ )
135 : {
136 : char *pszFilename;
137 2576 : const char *pszCandidate = papszCandidates[iCan];
138 :
139 2576 : if( EQUAL(pszCandidate,"ARC") )
140 0 : bMightBeOldCoverage = TRUE;
141 :
142 2576 : if( strlen(pszCandidate) < 4
143 : || !EQUAL(pszCandidate+strlen(pszCandidate)-4,".shp") )
144 1887 : continue;
145 :
146 : pszFilename =
147 689 : CPLStrdup(CPLFormFilename(pszNewName, pszCandidate, NULL));
148 :
149 689 : if( !OpenFile( pszFilename, bUpdate, bTestOpen )
150 : && !bTestOpen )
151 : {
152 : CPLError( CE_Failure, CPLE_OpenFailed,
153 : "Failed to open shapefile %s.\n"
154 : "It may be corrupt or read-only file accessed in update mode.\n",
155 0 : pszFilename );
156 0 : CPLFree( pszFilename );
157 0 : return FALSE;
158 : }
159 :
160 689 : CPLFree( pszFilename );
161 : }
162 :
163 : // Try and .dbf files without apparent associated shapefiles.
164 2645 : for( iCan = 0; iCan < nCandidateCount; iCan++ )
165 : {
166 : char *pszFilename;
167 2576 : const char *pszCandidate = papszCandidates[iCan];
168 : const char *pszLayerName;
169 2576 : int iLayer, bGotAlready = FALSE;
170 :
171 : // We don't consume .dbf files in a directory that looks like
172 : // an old style Arc/Info (for PC?) that unless we found at least
173 : // some shapefiles. See Bug 493.
174 2576 : if( bMightBeOldCoverage && nLayers == 0 )
175 0 : continue;
176 :
177 2576 : if( strlen(pszCandidate) < 4
178 : || !EQUAL(pszCandidate+strlen(pszCandidate)-4,".dbf") )
179 1891 : continue;
180 :
181 685 : pszLayerName = CPLGetBasename(pszCandidate);
182 12716 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
183 : {
184 12031 : if( EQUAL(pszLayerName,
185 : GetLayer(iLayer)->GetLayerDefn()->GetName()) )
186 677 : bGotAlready = TRUE;
187 : }
188 :
189 685 : if( bGotAlready )
190 677 : continue;
191 :
192 : // We don't want to access .dbf files with an associated .tab
193 : // file, or it will never get recognised as a mapinfo dataset.
194 8 : int iCan2, bFoundTAB = FALSE;
195 1072 : for( iCan2 = 0; iCan2 < nCandidateCount; iCan2++ )
196 : {
197 1064 : const char *pszCandidate2 = papszCandidates[iCan2];
198 :
199 1064 : if( EQUALN(pszCandidate2,pszLayerName,strlen(pszLayerName))
200 : && EQUAL(pszCandidate2 + strlen(pszLayerName), ".tab") )
201 0 : bFoundTAB = TRUE;
202 : }
203 :
204 8 : if( bFoundTAB )
205 0 : continue;
206 :
207 : pszFilename =
208 8 : CPLStrdup(CPLFormFilename(pszNewName, pszCandidate, NULL));
209 :
210 8 : if( !OpenFile( pszFilename, bUpdate, bTestOpen )
211 : && !bTestOpen )
212 : {
213 : CPLError( CE_Failure, CPLE_OpenFailed,
214 : "Failed to open dbf file %s.\n"
215 : "It may be corrupt or read-only file accessed in update mode.\n",
216 0 : pszFilename );
217 0 : CPLFree( pszFilename );
218 0 : return FALSE;
219 : }
220 :
221 8 : CPLFree( pszFilename );
222 : }
223 :
224 69 : CSLDestroy( papszCandidates );
225 :
226 69 : if( !bTestOpen && nLayers == 0 && !bUpdate )
227 : {
228 : CPLError( CE_Failure, CPLE_OpenFailed,
229 : "No Shapefiles found in directory %s\n",
230 0 : pszNewName );
231 : }
232 : }
233 :
234 69 : return nLayers > 0 || bUpdate;
235 : }
236 :
237 : /************************************************************************/
238 : /* OpenFile() */
239 : /************************************************************************/
240 :
241 948 : int OGRShapeDataSource::OpenFile( const char *pszNewName, int bUpdate,
242 : int bTestOpen )
243 :
244 : {
245 : SHPHandle hSHP;
246 : DBFHandle hDBF;
247 948 : const char *pszExtension = CPLGetExtension( pszNewName );
248 :
249 : (void) bTestOpen;
250 :
251 948 : if( !EQUAL(pszExtension,"shp") && !EQUAL(pszExtension,"shx")
252 : && !EQUAL(pszExtension,"dbf") )
253 124 : return FALSE;
254 :
255 : /* -------------------------------------------------------------------- */
256 : /* SHPOpen() should include better (CPL based) error reporting, */
257 : /* and we should be trying to distinquish at this point whether */
258 : /* failure is a result of trying to open a non-shapefile, or */
259 : /* whether it was a shapefile and we want to report the error */
260 : /* up. */
261 : /* */
262 : /* Care is taken to suppress the error and only reissue it if */
263 : /* we think it is appropriate. */
264 : /* -------------------------------------------------------------------- */
265 824 : CPLPushErrorHandler( CPLQuietErrorHandler );
266 824 : if( bUpdate )
267 666 : hSHP = SHPOpen( pszNewName, "r+" );
268 : else
269 158 : hSHP = SHPOpen( pszNewName, "r" );
270 824 : CPLPopErrorHandler();
271 :
272 824 : if( hSHP == NULL
273 : && (!EQUAL(CPLGetExtension(pszNewName),"dbf")
274 : || strstr(CPLGetLastErrorMsg(),".shp") == NULL) )
275 : {
276 0 : CPLString osMsg = CPLGetLastErrorMsg();
277 :
278 0 : CPLError( CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str() );
279 :
280 0 : return FALSE;
281 : }
282 824 : CPLErrorReset();
283 :
284 : /* -------------------------------------------------------------------- */
285 : /* Open the .dbf file, if it exists. To open a dbf file, the */
286 : /* filename has to either refer to a successfully opened shp */
287 : /* file or has to refer to the actual .dbf file. */
288 : /* -------------------------------------------------------------------- */
289 824 : if( hSHP != NULL || EQUAL(CPLGetExtension(pszNewName),"dbf") )
290 : {
291 824 : if( bUpdate )
292 666 : hDBF = DBFOpen( pszNewName, "r+" );
293 : else
294 158 : hDBF = DBFOpen( pszNewName, "r" );
295 : }
296 : else
297 0 : hDBF = NULL;
298 :
299 824 : if( hDBF == NULL && hSHP == NULL )
300 0 : return FALSE;
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Is there an associated .prj file we can read? */
304 : /* -------------------------------------------------------------------- */
305 824 : OGRSpatialReference *poSRS = NULL;
306 824 : const char *pszPrjFile = CPLResetExtension( pszNewName, "prj" );
307 824 : FILE *fp = NULL;
308 :
309 824 : fp = VSIFOpen( pszPrjFile, "r" );
310 :
311 : #ifndef WIN32
312 824 : if( NULL == fp )
313 : {
314 783 : pszPrjFile = CPLResetExtension( pszNewName, "PRJ" );
315 783 : fp = VSIFOpen( pszPrjFile, "r" );
316 : }
317 : #endif
318 :
319 824 : if( fp != NULL )
320 : {
321 : char **papszLines;
322 :
323 91 : VSIFClose( fp );
324 :
325 91 : papszLines = CSLLoad( pszPrjFile );
326 :
327 91 : poSRS = new OGRSpatialReference();
328 91 : if( poSRS->importFromESRI( papszLines ) != OGRERR_NONE )
329 : {
330 0 : delete poSRS;
331 0 : poSRS = NULL;
332 : }
333 91 : CSLDestroy( papszLines );
334 : }
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Create the layer object. */
338 : /* -------------------------------------------------------------------- */
339 : OGRShapeLayer *poLayer;
340 :
341 : poLayer = new OGRShapeLayer( pszNewName, hSHP, hDBF, poSRS, bUpdate,
342 824 : wkbNone );
343 :
344 :
345 824 : poLayer->InitializeIndexSupport( pszNewName );
346 :
347 : /* -------------------------------------------------------------------- */
348 : /* Add layer to data source layer list. */
349 : /* -------------------------------------------------------------------- */
350 : papoLayers = (OGRShapeLayer **)
351 824 : CPLRealloc( papoLayers, sizeof(OGRShapeLayer *) * (nLayers+1) );
352 824 : papoLayers[nLayers++] = poLayer;
353 :
354 824 : return TRUE;
355 : }
356 :
357 : /************************************************************************/
358 : /* CreateLayer() */
359 : /************************************************************************/
360 :
361 : OGRLayer *
362 90 : OGRShapeDataSource::CreateLayer( const char * pszLayerName,
363 : OGRSpatialReference *poSRS,
364 : OGRwkbGeometryType eType,
365 : char ** papszOptions )
366 :
367 : {
368 : SHPHandle hSHP;
369 : DBFHandle hDBF;
370 : int nShapeType;
371 :
372 : /* -------------------------------------------------------------------- */
373 : /* Verify we are in update mode. */
374 : /* -------------------------------------------------------------------- */
375 90 : if( !bDSUpdate )
376 : {
377 : CPLError( CE_Failure, CPLE_NoWriteAccess,
378 : "Data source %s opened read-only.\n"
379 : "New layer %s cannot be created.\n",
380 0 : pszName, pszLayerName );
381 :
382 0 : return NULL;
383 : }
384 :
385 : /* -------------------------------------------------------------------- */
386 : /* Figure out what type of layer we need. */
387 : /* -------------------------------------------------------------------- */
388 140 : if( eType == wkbUnknown || eType == wkbLineString )
389 50 : nShapeType = SHPT_ARC;
390 40 : else if( eType == wkbPoint )
391 2 : nShapeType = SHPT_POINT;
392 38 : else if( eType == wkbPolygon )
393 21 : nShapeType = SHPT_POLYGON;
394 17 : else if( eType == wkbMultiPoint )
395 2 : nShapeType = SHPT_MULTIPOINT;
396 15 : else if( eType == wkbPoint25D )
397 1 : nShapeType = SHPT_POINTZ;
398 14 : else if( eType == wkbLineString25D )
399 2 : nShapeType = SHPT_ARCZ;
400 12 : else if( eType == wkbMultiLineString )
401 2 : nShapeType = SHPT_ARC;
402 10 : else if( eType == wkbMultiLineString25D )
403 1 : nShapeType = SHPT_ARCZ;
404 9 : else if( eType == wkbPolygon25D )
405 2 : nShapeType = SHPT_POLYGONZ;
406 7 : else if( eType == wkbMultiPolygon )
407 3 : nShapeType = SHPT_POLYGON;
408 4 : else if( eType == wkbMultiPolygon25D )
409 1 : nShapeType = SHPT_POLYGONZ;
410 3 : else if( eType == wkbMultiPoint25D )
411 1 : nShapeType = SHPT_MULTIPOINTZ;
412 2 : else if( eType == wkbNone )
413 2 : nShapeType = SHPT_NULL;
414 : else
415 0 : nShapeType = -1;
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Has the application overridden this with a special creation */
419 : /* option? */
420 : /* -------------------------------------------------------------------- */
421 90 : const char *pszOverride = CSLFetchNameValue( papszOptions, "SHPT" );
422 :
423 90 : if( pszOverride == NULL )
424 : /* ignore */;
425 1 : else if( EQUAL(pszOverride,"POINT") )
426 : {
427 0 : nShapeType = SHPT_POINT;
428 0 : eType = wkbPoint;
429 : }
430 1 : else if( EQUAL(pszOverride,"ARC") )
431 : {
432 0 : nShapeType = SHPT_ARC;
433 0 : eType = wkbLineString;
434 : }
435 1 : else if( EQUAL(pszOverride,"POLYGON") )
436 : {
437 0 : nShapeType = SHPT_POLYGON;
438 0 : eType = wkbPolygon;
439 : }
440 1 : else if( EQUAL(pszOverride,"MULTIPOINT") )
441 : {
442 0 : nShapeType = SHPT_MULTIPOINT;
443 0 : eType = wkbMultiPoint;
444 : }
445 1 : else if( EQUAL(pszOverride,"POINTZ") )
446 : {
447 0 : nShapeType = SHPT_POINTZ;
448 0 : eType = wkbPoint25D;
449 : }
450 1 : else if( EQUAL(pszOverride,"ARCZ") )
451 : {
452 0 : nShapeType = SHPT_ARCZ;
453 0 : eType = wkbLineString25D;
454 : }
455 1 : else if( EQUAL(pszOverride,"POLYGONZ") )
456 : {
457 1 : nShapeType = SHPT_POLYGONZ;
458 1 : eType = wkbPolygon25D;
459 : }
460 0 : else if( EQUAL(pszOverride,"MULTIPOINTZ") )
461 : {
462 0 : nShapeType = SHPT_MULTIPOINTZ;
463 0 : eType = wkbMultiPoint25D;
464 : }
465 0 : else if( EQUAL(pszOverride,"NONE") )
466 : {
467 0 : nShapeType = SHPT_NULL;
468 : }
469 : else
470 : {
471 : CPLError( CE_Failure, CPLE_NotSupported,
472 : "Unknown SHPT value of `%s' passed to Shapefile layer\n"
473 : "creation. Creation aborted.\n",
474 0 : pszOverride );
475 :
476 0 : return NULL;
477 : }
478 :
479 90 : if( nShapeType == -1 )
480 : {
481 : CPLError( CE_Failure, CPLE_NotSupported,
482 : "Geometry type of `%s' not supported in shapefiles.\n"
483 : "Type can be overridden with a layer creation option\n"
484 : "of SHPT=POINT/ARC/POLYGON/MULTIPOINT/POINTZ/ARCZ/POLYGONZ/MULTIPOINTZ.\n",
485 0 : OGRGeometryTypeToName(eType) );
486 0 : return NULL;
487 : }
488 :
489 : /* -------------------------------------------------------------------- */
490 : /* What filename do we use, excluding the extension? */
491 : /* -------------------------------------------------------------------- */
492 : char *pszBasename;
493 :
494 119 : if( bSingleNewFile && nLayers == 0 )
495 : {
496 29 : char *pszPath = CPLStrdup(CPLGetPath(pszName));
497 29 : char *pszFBasename = CPLStrdup(CPLGetBasename(pszName));
498 :
499 29 : pszBasename = CPLStrdup(CPLFormFilename(pszPath, pszFBasename, NULL));
500 :
501 29 : CPLFree( pszFBasename );
502 29 : CPLFree( pszPath );
503 : }
504 61 : else if( bSingleNewFile )
505 : {
506 0 : char *pszPath = CPLStrdup(CPLGetPath(pszName));
507 0 : pszBasename = CPLStrdup(CPLFormFilename(pszPath,pszLayerName,NULL));
508 0 : CPLFree( pszPath );
509 : }
510 : else
511 61 : pszBasename = CPLStrdup(CPLFormFilename(pszName,pszLayerName,NULL));
512 :
513 : /* -------------------------------------------------------------------- */
514 : /* Create the shapefile. */
515 : /* -------------------------------------------------------------------- */
516 : char *pszFilename;
517 :
518 90 : if( nShapeType != SHPT_NULL )
519 : {
520 88 : pszFilename = CPLStrdup(CPLFormFilename( NULL, pszBasename, "shp" ));
521 :
522 88 : hSHP = SHPCreate( pszFilename, nShapeType );
523 :
524 88 : if( hSHP == NULL )
525 : {
526 : CPLError( CE_Failure, CPLE_OpenFailed,
527 : "Failed to open Shapefile `%s'.\n",
528 0 : pszFilename );
529 0 : CPLFree( pszFilename );
530 0 : CPLFree( pszBasename );
531 0 : return NULL;
532 : }
533 88 : CPLFree( pszFilename );
534 : }
535 : else
536 2 : hSHP = NULL;
537 :
538 : /* -------------------------------------------------------------------- */
539 : /* Create a DBF file. */
540 : /* -------------------------------------------------------------------- */
541 90 : pszFilename = CPLStrdup(CPLFormFilename( NULL, pszBasename, "dbf" ));
542 :
543 90 : hDBF = DBFCreate( pszFilename );
544 :
545 90 : if( hDBF == NULL )
546 : {
547 : CPLError( CE_Failure, CPLE_OpenFailed,
548 : "Failed to open Shape DBF file `%s'.\n",
549 0 : pszFilename );
550 0 : CPLFree( pszFilename );
551 0 : CPLFree( pszBasename );
552 0 : return NULL;
553 : }
554 :
555 90 : CPLFree( pszFilename );
556 :
557 : /* -------------------------------------------------------------------- */
558 : /* Create the .prj file, if required. */
559 : /* -------------------------------------------------------------------- */
560 90 : if( poSRS != NULL )
561 : {
562 30 : char *pszWKT = NULL;
563 30 : CPLString osPrjFile = CPLFormFilename( NULL, pszBasename, "prj");
564 : FILE *fp;
565 :
566 : /* the shape layer needs it's own copy */
567 30 : poSRS = poSRS->Clone();
568 30 : poSRS->morphToESRI();
569 :
570 30 : if( poSRS->exportToWkt( &pszWKT ) == OGRERR_NONE
571 : && (fp = VSIFOpen( osPrjFile, "wt" )) != NULL )
572 : {
573 30 : VSIFWrite( pszWKT, strlen(pszWKT), 1, fp );
574 30 : VSIFClose( fp );
575 : }
576 :
577 30 : CPLFree( pszWKT );
578 :
579 30 : poSRS->morphFromESRI();
580 : }
581 :
582 : /* -------------------------------------------------------------------- */
583 : /* Create the layer object. */
584 : /* -------------------------------------------------------------------- */
585 : OGRShapeLayer *poLayer;
586 :
587 : poLayer = new OGRShapeLayer( pszBasename, hSHP, hDBF, poSRS, TRUE,
588 90 : eType );
589 :
590 90 : poLayer->InitializeIndexSupport( pszBasename );
591 :
592 90 : CPLFree( pszBasename );
593 :
594 : /* -------------------------------------------------------------------- */
595 : /* Add layer to data source layer list. */
596 : /* -------------------------------------------------------------------- */
597 : papoLayers = (OGRShapeLayer **)
598 90 : CPLRealloc( papoLayers, sizeof(OGRShapeLayer *) * (nLayers+1) );
599 :
600 90 : papoLayers[nLayers++] = poLayer;
601 :
602 90 : return poLayer;
603 : }
604 :
605 : /************************************************************************/
606 : /* TestCapability() */
607 : /************************************************************************/
608 :
609 19 : int OGRShapeDataSource::TestCapability( const char * pszCap )
610 :
611 : {
612 19 : if( EQUAL(pszCap,ODsCCreateLayer) )
613 19 : return bDSUpdate;
614 0 : else if( EQUAL(pszCap,ODsCDeleteLayer) )
615 0 : return bDSUpdate;
616 : else
617 0 : return FALSE;
618 : }
619 :
620 : /************************************************************************/
621 : /* GetLayer() */
622 : /************************************************************************/
623 :
624 13856 : OGRLayer *OGRShapeDataSource::GetLayer( int iLayer )
625 :
626 : {
627 13856 : if( iLayer < 0 || iLayer >= nLayers )
628 0 : return NULL;
629 : else
630 13856 : return papoLayers[iLayer];
631 : }
632 :
633 : /************************************************************************/
634 : /* ExecuteSQL() */
635 : /* */
636 : /* We override this to provide special handling of CREATE */
637 : /* SPATIAL INDEX commands. Support forms are: */
638 : /* */
639 : /* CREATE SPATIAL INDEX ON layer_name [DEPTH n] */
640 : /* DROP SPATIAL INDEX ON layer_name */
641 : /* REPACK layer_name */
642 : /************************************************************************/
643 :
644 45 : OGRLayer * OGRShapeDataSource::ExecuteSQL( const char *pszStatement,
645 : OGRGeometry *poSpatialFilter,
646 : const char *pszDialect )
647 :
648 : {
649 : /* ==================================================================== */
650 : /* Handle command to drop a spatial index. */
651 : /* ==================================================================== */
652 45 : if( EQUALN(pszStatement, "REPACK ", 7) )
653 : {
654 : OGRShapeLayer *poLayer = (OGRShapeLayer *)
655 3 : GetLayerByName( pszStatement + 7 );
656 :
657 3 : if( poLayer != NULL )
658 3 : poLayer->Repack();
659 : else
660 : {
661 : CPLError( CE_Failure, CPLE_AppDefined,
662 : "No such layer as '%s' in REPACK.",
663 0 : pszStatement + 7 );
664 : }
665 3 : return NULL;
666 : }
667 :
668 : /* ==================================================================== */
669 : /* Handle command to drop a spatial index. */
670 : /* ==================================================================== */
671 42 : if( EQUALN(pszStatement, "DROP SPATIAL INDEX ON ", 22) )
672 : {
673 : OGRShapeLayer *poLayer = (OGRShapeLayer *)
674 1 : GetLayerByName( pszStatement + 22 );
675 :
676 1 : if( poLayer != NULL )
677 1 : poLayer->DropSpatialIndex();
678 : else
679 : {
680 : CPLError( CE_Failure, CPLE_AppDefined,
681 : "No such layer as '%s' in DROP SPATIAL INDEX.",
682 0 : pszStatement + 19 );
683 : }
684 1 : return NULL;
685 : }
686 :
687 : /* ==================================================================== */
688 : /* Handle all comands except spatial index creation generically. */
689 : /* ==================================================================== */
690 41 : if( !EQUALN(pszStatement,"CREATE SPATIAL INDEX ON ",24) )
691 : return OGRDataSource::ExecuteSQL( pszStatement, poSpatialFilter,
692 38 : pszDialect );
693 :
694 : /* -------------------------------------------------------------------- */
695 : /* Parse into keywords. */
696 : /* -------------------------------------------------------------------- */
697 3 : char **papszTokens = CSLTokenizeString( pszStatement );
698 :
699 15 : if( CSLCount(papszTokens) < 5
700 3 : || !EQUAL(papszTokens[0],"CREATE")
701 3 : || !EQUAL(papszTokens[1],"SPATIAL")
702 3 : || !EQUAL(papszTokens[2],"INDEX")
703 3 : || !EQUAL(papszTokens[3],"ON")
704 : || CSLCount(papszTokens) > 7
705 0 : || (CSLCount(papszTokens) == 7 && !EQUAL(papszTokens[5],"DEPTH")) )
706 : {
707 0 : CSLDestroy( papszTokens );
708 : CPLError( CE_Failure, CPLE_AppDefined,
709 : "Syntax error in CREATE SPATIAL INDEX command.\n"
710 : "Was '%s'\n"
711 : "Should be of form 'CREATE SPATIAL INDEX ON <table> [DEPTH <n>]'",
712 0 : pszStatement );
713 0 : return NULL;
714 : }
715 :
716 : /* -------------------------------------------------------------------- */
717 : /* Get depth if provided. */
718 : /* -------------------------------------------------------------------- */
719 3 : int nDepth = 0;
720 3 : if( CSLCount(papszTokens) == 7 )
721 0 : nDepth = atoi(papszTokens[6]);
722 :
723 : /* -------------------------------------------------------------------- */
724 : /* What layer are we operating on. */
725 : /* -------------------------------------------------------------------- */
726 3 : OGRShapeLayer *poLayer = (OGRShapeLayer *) GetLayerByName(papszTokens[4]);
727 3 : CSLDestroy( papszTokens );
728 :
729 3 : if( poLayer == NULL )
730 : {
731 : CPLError( CE_Failure, CPLE_AppDefined,
732 : "Layer %s not recognised.",
733 0 : papszTokens[4] );
734 0 : return NULL;
735 : }
736 :
737 3 : poLayer->CreateSpatialIndex( nDepth );
738 3 : return NULL;
739 : }
740 :
741 :
742 : /************************************************************************/
743 : /* DeleteLayer() */
744 : /************************************************************************/
745 :
746 1 : OGRErr OGRShapeDataSource::DeleteLayer( int iLayer )
747 :
748 : {
749 : char *pszFilename;
750 :
751 : /* -------------------------------------------------------------------- */
752 : /* Verify we are in update mode. */
753 : /* -------------------------------------------------------------------- */
754 1 : if( !bDSUpdate )
755 : {
756 : CPLError( CE_Failure, CPLE_NoWriteAccess,
757 : "Data source %s opened read-only.\n"
758 : "Layer %d cannot be deleted.\n",
759 0 : pszName, iLayer );
760 :
761 0 : return OGRERR_FAILURE;
762 : }
763 :
764 1 : if( iLayer < 0 || iLayer >= nLayers )
765 : {
766 : CPLError( CE_Failure, CPLE_AppDefined,
767 : "Layer %d not in legal range of 0 to %d.",
768 0 : iLayer, nLayers-1 );
769 0 : return OGRERR_FAILURE;
770 : }
771 :
772 1 : pszFilename = CPLStrdup(((OGRShapeLayer*) papoLayers[iLayer])->GetFullName());
773 :
774 1 : delete papoLayers[iLayer];
775 :
776 2 : while( iLayer < nLayers - 1 )
777 : {
778 0 : papoLayers[iLayer] = papoLayers[iLayer+1];
779 0 : iLayer++;
780 : }
781 :
782 1 : nLayers--;
783 :
784 1 : VSIUnlink( CPLResetExtension(pszFilename, "shp") );
785 1 : VSIUnlink( CPLResetExtension(pszFilename, "shx") );
786 1 : VSIUnlink( CPLResetExtension(pszFilename, "dbf") );
787 1 : VSIUnlink( CPLResetExtension(pszFilename, "prj") );
788 1 : VSIUnlink( CPLResetExtension(pszFilename, "qix") );
789 :
790 1 : CPLFree( pszFilename );
791 :
792 1 : return OGRERR_NONE;
793 : }
|