1 : /******************************************************************************
2 : * $Id: ogrshapedatasource.cpp 19753 2010-05-22 15:37:08Z 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 19753 2010-05-22 15:37:08Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRShapeDataSource() */
38 : /************************************************************************/
39 :
40 658 : OGRShapeDataSource::OGRShapeDataSource()
41 :
42 : {
43 658 : pszName = NULL;
44 658 : papoLayers = NULL;
45 658 : nLayers = 0;
46 658 : bSingleNewFile = FALSE;
47 658 : }
48 :
49 : /************************************************************************/
50 : /* ~OGRShapeDataSource() */
51 : /************************************************************************/
52 :
53 658 : OGRShapeDataSource::~OGRShapeDataSource()
54 :
55 : {
56 658 : CPLFree( pszName );
57 :
58 1679 : for( int i = 0; i < nLayers; i++ )
59 : {
60 1021 : CPLAssert( NULL != papoLayers[i] );
61 :
62 1021 : delete papoLayers[i];
63 : }
64 :
65 658 : CPLFree( papoLayers );
66 658 : }
67 :
68 : /************************************************************************/
69 : /* Open() */
70 : /************************************************************************/
71 :
72 : int OGRShapeDataSource::Open( const char * pszNewName, int bUpdate,
73 658 : int bTestOpen, int bSingleNewFileIn )
74 :
75 : {
76 : VSIStatBufL stat;
77 :
78 658 : CPLAssert( nLayers == 0 );
79 :
80 658 : pszName = CPLStrdup( pszNewName );
81 :
82 658 : bDSUpdate = bUpdate;
83 :
84 658 : 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 658 : if( bSingleNewFile )
94 65 : return TRUE;
95 :
96 : /* -------------------------------------------------------------------- */
97 : /* Is the given path a directory or a regular file? */
98 : /* -------------------------------------------------------------------- */
99 593 : if( VSIStatL( pszNewName, &stat ) != 0
100 : || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) )
101 : {
102 80 : 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 80 : return FALSE;
108 : }
109 :
110 : /* -------------------------------------------------------------------- */
111 : /* Build a list of filenames we figure are Shape files. */
112 : /* -------------------------------------------------------------------- */
113 513 : if( VSI_ISREG(stat.st_mode) )
114 : {
115 436 : if( !OpenFile( pszNewName, bUpdate, bTestOpen ) )
116 : {
117 220 : 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 220 : return FALSE;
124 : }
125 :
126 216 : return TRUE;
127 : }
128 : else
129 : {
130 77 : char **papszCandidates = CPLReadDir( pszNewName );
131 77 : int iCan, nCandidateCount = CSLCount( papszCandidates );
132 77 : int bMightBeOldCoverage = FALSE;
133 :
134 2658 : for( iCan = 0; iCan < nCandidateCount; iCan++ )
135 : {
136 : char *pszFilename;
137 2581 : const char *pszCandidate = papszCandidates[iCan];
138 :
139 2581 : if( EQUAL(pszCandidate,"ARC") )
140 0 : bMightBeOldCoverage = TRUE;
141 :
142 2581 : if( strlen(pszCandidate) < 4
143 : || !EQUAL(pszCandidate+strlen(pszCandidate)-4,".shp") )
144 1909 : continue;
145 :
146 : pszFilename =
147 672 : CPLStrdup(CPLFormFilename(pszNewName, pszCandidate, NULL));
148 :
149 672 : 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 672 : CPLFree( pszFilename );
161 : }
162 :
163 : // Try and .dbf files without apparent associated shapefiles.
164 2658 : for( iCan = 0; iCan < nCandidateCount; iCan++ )
165 : {
166 : char *pszFilename;
167 2581 : const char *pszCandidate = papszCandidates[iCan];
168 : const char *pszLayerName;
169 2581 : 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 2581 : if( bMightBeOldCoverage && nLayers == 0 )
175 0 : continue;
176 :
177 2581 : if( strlen(pszCandidate) < 4
178 : || !EQUAL(pszCandidate+strlen(pszCandidate)-4,".dbf") )
179 1913 : continue;
180 :
181 668 : pszLayerName = CPLGetBasename(pszCandidate);
182 12296 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
183 : {
184 11628 : if( EQUAL(pszLayerName,
185 : GetLayer(iLayer)->GetLayerDefn()->GetName()) )
186 660 : bGotAlready = TRUE;
187 : }
188 :
189 668 : if( bGotAlready )
190 660 : 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 1296 : for( iCan2 = 0; iCan2 < nCandidateCount; iCan2++ )
196 : {
197 1288 : const char *pszCandidate2 = papszCandidates[iCan2];
198 :
199 1288 : 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 77 : CSLDestroy( papszCandidates );
225 :
226 77 : 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 77 : return nLayers > 0 || bUpdate;
235 : }
236 :
237 : /************************************************************************/
238 : /* OpenFile() */
239 : /************************************************************************/
240 :
241 : int OGRShapeDataSource::OpenFile( const char *pszNewName, int bUpdate,
242 1116 : int bTestOpen )
243 :
244 : {
245 : SHPHandle hSHP;
246 : DBFHandle hDBF;
247 1116 : const char *pszExtension = CPLGetExtension( pszNewName );
248 :
249 : (void) bTestOpen;
250 :
251 1116 : if( !EQUAL(pszExtension,"shp") && !EQUAL(pszExtension,"shx")
252 : && !EQUAL(pszExtension,"dbf") )
253 220 : 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 896 : CPLPushErrorHandler( CPLQuietErrorHandler );
266 896 : if( bUpdate )
267 656 : hSHP = SHPOpen( pszNewName, "r+" );
268 : else
269 240 : hSHP = SHPOpen( pszNewName, "r" );
270 896 : CPLPopErrorHandler();
271 :
272 896 : 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 896 : 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 896 : if( hSHP != NULL || EQUAL(CPLGetExtension(pszNewName),"dbf") )
290 : {
291 896 : if( bUpdate )
292 656 : hDBF = DBFOpen( pszNewName, "r+" );
293 : else
294 240 : hDBF = DBFOpen( pszNewName, "r" );
295 : }
296 : else
297 0 : hDBF = NULL;
298 :
299 896 : if( hDBF == NULL && hSHP == NULL )
300 0 : return FALSE;
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Is there an associated .prj file we can read? */
304 : /* -------------------------------------------------------------------- */
305 896 : OGRSpatialReference *poSRS = NULL;
306 896 : const char *pszPrjFile = CPLResetExtension( pszNewName, "prj" );
307 896 : FILE *fp = NULL;
308 :
309 896 : fp = VSIFOpenL( pszPrjFile, "r" );
310 :
311 896 : if( NULL == fp )
312 : {
313 819 : pszPrjFile = CPLResetExtension( pszNewName, "PRJ" );
314 819 : fp = VSIFOpenL( pszPrjFile, "r" );
315 : }
316 :
317 896 : if( fp != NULL )
318 : {
319 : char **papszLines;
320 :
321 171 : VSIFCloseL( fp );
322 :
323 171 : papszLines = CSLLoad( pszPrjFile );
324 :
325 171 : poSRS = new OGRSpatialReference();
326 171 : if( poSRS->importFromESRI( papszLines ) != OGRERR_NONE )
327 : {
328 0 : delete poSRS;
329 0 : poSRS = NULL;
330 : }
331 171 : CSLDestroy( papszLines );
332 : }
333 :
334 : /* -------------------------------------------------------------------- */
335 : /* Create the layer object. */
336 : /* -------------------------------------------------------------------- */
337 : OGRShapeLayer *poLayer;
338 :
339 : poLayer = new OGRShapeLayer( pszNewName, hSHP, hDBF, poSRS, bUpdate,
340 896 : wkbNone );
341 :
342 :
343 896 : poLayer->InitializeIndexSupport( pszNewName );
344 :
345 : /* -------------------------------------------------------------------- */
346 : /* Add layer to data source layer list. */
347 : /* -------------------------------------------------------------------- */
348 : papoLayers = (OGRShapeLayer **)
349 896 : CPLRealloc( papoLayers, sizeof(OGRShapeLayer *) * (nLayers+1) );
350 896 : papoLayers[nLayers++] = poLayer;
351 :
352 896 : return TRUE;
353 : }
354 :
355 : /************************************************************************/
356 : /* CreateLayer() */
357 : /************************************************************************/
358 :
359 : OGRLayer *
360 : OGRShapeDataSource::CreateLayer( const char * pszLayerName,
361 : OGRSpatialReference *poSRS,
362 : OGRwkbGeometryType eType,
363 128 : char ** papszOptions )
364 :
365 : {
366 : SHPHandle hSHP;
367 : DBFHandle hDBF;
368 : int nShapeType;
369 : int iLayer;
370 :
371 : /* -------------------------------------------------------------------- */
372 : /* Check that the layer doesn't already exist. */
373 : /* -------------------------------------------------------------------- */
374 736 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
375 : {
376 609 : OGRLayer *poLayer = papoLayers[iLayer];
377 :
378 609 : if( poLayer != NULL
379 : && EQUAL(poLayer->GetLayerDefn()->GetName(),pszLayerName) )
380 : {
381 : CPLError( CE_Failure, CPLE_AppDefined, "Layer '%s' already exists",
382 1 : pszLayerName);
383 1 : return NULL;
384 : }
385 : }
386 :
387 : /* -------------------------------------------------------------------- */
388 : /* Verify we are in update mode. */
389 : /* -------------------------------------------------------------------- */
390 127 : if( !bDSUpdate )
391 : {
392 : CPLError( CE_Failure, CPLE_NoWriteAccess,
393 : "Data source %s opened read-only.\n"
394 : "New layer %s cannot be created.\n",
395 0 : pszName, pszLayerName );
396 :
397 0 : return NULL;
398 : }
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Figure out what type of layer we need. */
402 : /* -------------------------------------------------------------------- */
403 185 : if( eType == wkbUnknown || eType == wkbLineString )
404 58 : nShapeType = SHPT_ARC;
405 69 : else if( eType == wkbPoint )
406 2 : nShapeType = SHPT_POINT;
407 67 : else if( eType == wkbPolygon )
408 45 : nShapeType = SHPT_POLYGON;
409 22 : else if( eType == wkbMultiPoint )
410 2 : nShapeType = SHPT_MULTIPOINT;
411 20 : else if( eType == wkbPoint25D )
412 1 : nShapeType = SHPT_POINTZ;
413 19 : else if( eType == wkbLineString25D )
414 4 : nShapeType = SHPT_ARCZ;
415 15 : else if( eType == wkbMultiLineString )
416 2 : nShapeType = SHPT_ARC;
417 13 : else if( eType == wkbMultiLineString25D )
418 1 : nShapeType = SHPT_ARCZ;
419 12 : else if( eType == wkbPolygon25D )
420 3 : nShapeType = SHPT_POLYGONZ;
421 9 : else if( eType == wkbMultiPolygon )
422 5 : nShapeType = SHPT_POLYGON;
423 4 : else if( eType == wkbMultiPolygon25D )
424 1 : nShapeType = SHPT_POLYGONZ;
425 3 : else if( eType == wkbMultiPoint25D )
426 1 : nShapeType = SHPT_MULTIPOINTZ;
427 2 : else if( eType == wkbNone )
428 2 : nShapeType = SHPT_NULL;
429 : else
430 0 : nShapeType = -1;
431 :
432 : /* -------------------------------------------------------------------- */
433 : /* Has the application overridden this with a special creation */
434 : /* option? */
435 : /* -------------------------------------------------------------------- */
436 127 : const char *pszOverride = CSLFetchNameValue( papszOptions, "SHPT" );
437 :
438 127 : if( pszOverride == NULL )
439 : /* ignore */;
440 2 : else if( EQUAL(pszOverride,"POINT") )
441 : {
442 0 : nShapeType = SHPT_POINT;
443 0 : eType = wkbPoint;
444 : }
445 2 : else if( EQUAL(pszOverride,"ARC") )
446 : {
447 0 : nShapeType = SHPT_ARC;
448 0 : eType = wkbLineString;
449 : }
450 2 : else if( EQUAL(pszOverride,"POLYGON") )
451 : {
452 0 : nShapeType = SHPT_POLYGON;
453 0 : eType = wkbPolygon;
454 : }
455 2 : else if( EQUAL(pszOverride,"MULTIPOINT") )
456 : {
457 0 : nShapeType = SHPT_MULTIPOINT;
458 0 : eType = wkbMultiPoint;
459 : }
460 2 : else if( EQUAL(pszOverride,"POINTZ") )
461 : {
462 0 : nShapeType = SHPT_POINTZ;
463 0 : eType = wkbPoint25D;
464 : }
465 2 : else if( EQUAL(pszOverride,"ARCZ") )
466 : {
467 0 : nShapeType = SHPT_ARCZ;
468 0 : eType = wkbLineString25D;
469 : }
470 2 : else if( EQUAL(pszOverride,"POLYGONZ") )
471 : {
472 2 : nShapeType = SHPT_POLYGONZ;
473 2 : eType = wkbPolygon25D;
474 : }
475 0 : else if( EQUAL(pszOverride,"MULTIPOINTZ") )
476 : {
477 0 : nShapeType = SHPT_MULTIPOINTZ;
478 0 : eType = wkbMultiPoint25D;
479 : }
480 0 : else if( EQUAL(pszOverride,"NONE") )
481 : {
482 0 : nShapeType = SHPT_NULL;
483 : }
484 : else
485 : {
486 : CPLError( CE_Failure, CPLE_NotSupported,
487 : "Unknown SHPT value of `%s' passed to Shapefile layer\n"
488 : "creation. Creation aborted.\n",
489 0 : pszOverride );
490 :
491 0 : return NULL;
492 : }
493 :
494 127 : if( nShapeType == -1 )
495 : {
496 : CPLError( CE_Failure, CPLE_NotSupported,
497 : "Geometry type of `%s' not supported in shapefiles.\n"
498 : "Type can be overridden with a layer creation option\n"
499 : "of SHPT=POINT/ARC/POLYGON/MULTIPOINT/POINTZ/ARCZ/POLYGONZ/MULTIPOINTZ.\n",
500 0 : OGRGeometryTypeToName(eType) );
501 0 : return NULL;
502 : }
503 :
504 : /* -------------------------------------------------------------------- */
505 : /* What filename do we use, excluding the extension? */
506 : /* -------------------------------------------------------------------- */
507 : char *pszBasename;
508 :
509 192 : if( bSingleNewFile && nLayers == 0 )
510 : {
511 65 : char *pszPath = CPLStrdup(CPLGetPath(pszName));
512 65 : char *pszFBasename = CPLStrdup(CPLGetBasename(pszName));
513 :
514 65 : pszBasename = CPLStrdup(CPLFormFilename(pszPath, pszFBasename, NULL));
515 :
516 65 : CPLFree( pszFBasename );
517 65 : CPLFree( pszPath );
518 : }
519 62 : else if( bSingleNewFile )
520 : {
521 0 : char *pszPath = CPLStrdup(CPLGetPath(pszName));
522 0 : pszBasename = CPLStrdup(CPLFormFilename(pszPath,pszLayerName,NULL));
523 0 : CPLFree( pszPath );
524 : }
525 : else
526 62 : pszBasename = CPLStrdup(CPLFormFilename(pszName,pszLayerName,NULL));
527 :
528 : /* -------------------------------------------------------------------- */
529 : /* Create the shapefile. */
530 : /* -------------------------------------------------------------------- */
531 : char *pszFilename;
532 :
533 127 : if( nShapeType != SHPT_NULL )
534 : {
535 125 : pszFilename = CPLStrdup(CPLFormFilename( NULL, pszBasename, "shp" ));
536 :
537 125 : hSHP = SHPCreate( pszFilename, nShapeType );
538 :
539 125 : if( hSHP == NULL )
540 : {
541 : CPLError( CE_Failure, CPLE_OpenFailed,
542 : "Failed to open Shapefile `%s'.\n",
543 0 : pszFilename );
544 0 : CPLFree( pszFilename );
545 0 : CPLFree( pszBasename );
546 0 : return NULL;
547 : }
548 125 : CPLFree( pszFilename );
549 : }
550 : else
551 2 : hSHP = NULL;
552 :
553 : /* -------------------------------------------------------------------- */
554 : /* Create a DBF file. */
555 : /* -------------------------------------------------------------------- */
556 127 : pszFilename = CPLStrdup(CPLFormFilename( NULL, pszBasename, "dbf" ));
557 :
558 127 : hDBF = DBFCreate( pszFilename );
559 :
560 127 : if( hDBF == NULL )
561 : {
562 : CPLError( CE_Failure, CPLE_OpenFailed,
563 : "Failed to open Shape DBF file `%s'.\n",
564 0 : pszFilename );
565 0 : CPLFree( pszFilename );
566 0 : CPLFree( pszBasename );
567 0 : SHPClose(hSHP);
568 0 : return NULL;
569 : }
570 :
571 127 : CPLFree( pszFilename );
572 :
573 : /* -------------------------------------------------------------------- */
574 : /* Create the .prj file, if required. */
575 : /* -------------------------------------------------------------------- */
576 127 : if( poSRS != NULL )
577 : {
578 62 : char *pszWKT = NULL;
579 62 : CPLString osPrjFile = CPLFormFilename( NULL, pszBasename, "prj");
580 : FILE *fp;
581 :
582 : /* the shape layer needs it's own copy */
583 62 : poSRS = poSRS->Clone();
584 62 : poSRS->morphToESRI();
585 :
586 62 : if( poSRS->exportToWkt( &pszWKT ) == OGRERR_NONE
587 : && (fp = VSIFOpenL( osPrjFile, "wt" )) != NULL )
588 : {
589 62 : VSIFWriteL( pszWKT, strlen(pszWKT), 1, fp );
590 62 : VSIFCloseL( fp );
591 : }
592 :
593 62 : CPLFree( pszWKT );
594 :
595 62 : poSRS->morphFromESRI();
596 : }
597 :
598 : /* -------------------------------------------------------------------- */
599 : /* Create the layer object. */
600 : /* -------------------------------------------------------------------- */
601 : OGRShapeLayer *poLayer;
602 :
603 : poLayer = new OGRShapeLayer( pszBasename, hSHP, hDBF, poSRS, TRUE,
604 127 : eType );
605 :
606 127 : poLayer->InitializeIndexSupport( pszBasename );
607 :
608 127 : CPLFree( pszBasename );
609 :
610 : /* -------------------------------------------------------------------- */
611 : /* Add layer to data source layer list. */
612 : /* -------------------------------------------------------------------- */
613 : papoLayers = (OGRShapeLayer **)
614 127 : CPLRealloc( papoLayers, sizeof(OGRShapeLayer *) * (nLayers+1) );
615 :
616 127 : papoLayers[nLayers++] = poLayer;
617 :
618 127 : return poLayer;
619 : }
620 :
621 : /************************************************************************/
622 : /* TestCapability() */
623 : /************************************************************************/
624 :
625 46 : int OGRShapeDataSource::TestCapability( const char * pszCap )
626 :
627 : {
628 46 : if( EQUAL(pszCap,ODsCCreateLayer) )
629 46 : return bDSUpdate;
630 0 : else if( EQUAL(pszCap,ODsCDeleteLayer) )
631 0 : return bDSUpdate;
632 : else
633 0 : return FALSE;
634 : }
635 :
636 : /************************************************************************/
637 : /* GetLayer() */
638 : /************************************************************************/
639 :
640 14207 : OGRLayer *OGRShapeDataSource::GetLayer( int iLayer )
641 :
642 : {
643 14207 : if( iLayer < 0 || iLayer >= nLayers )
644 0 : return NULL;
645 : else
646 14207 : return papoLayers[iLayer];
647 : }
648 :
649 : /************************************************************************/
650 : /* ExecuteSQL() */
651 : /* */
652 : /* We override this to provide special handling of CREATE */
653 : /* SPATIAL INDEX commands. Support forms are: */
654 : /* */
655 : /* CREATE SPATIAL INDEX ON layer_name [DEPTH n] */
656 : /* DROP SPATIAL INDEX ON layer_name */
657 : /* REPACK layer_name */
658 : /************************************************************************/
659 :
660 : OGRLayer * OGRShapeDataSource::ExecuteSQL( const char *pszStatement,
661 : OGRGeometry *poSpatialFilter,
662 53 : const char *pszDialect )
663 :
664 : {
665 : /* ==================================================================== */
666 : /* Handle command to drop a spatial index. */
667 : /* ==================================================================== */
668 53 : if( EQUALN(pszStatement, "REPACK ", 7) )
669 : {
670 : OGRShapeLayer *poLayer = (OGRShapeLayer *)
671 3 : GetLayerByName( pszStatement + 7 );
672 :
673 3 : if( poLayer != NULL )
674 3 : poLayer->Repack();
675 : else
676 : {
677 : CPLError( CE_Failure, CPLE_AppDefined,
678 : "No such layer as '%s' in REPACK.",
679 0 : pszStatement + 7 );
680 : }
681 3 : return NULL;
682 : }
683 :
684 : /* ==================================================================== */
685 : /* Handle command to drop a spatial index. */
686 : /* ==================================================================== */
687 50 : if( EQUALN(pszStatement, "DROP SPATIAL INDEX ON ", 22) )
688 : {
689 : OGRShapeLayer *poLayer = (OGRShapeLayer *)
690 1 : GetLayerByName( pszStatement + 22 );
691 :
692 1 : if( poLayer != NULL )
693 1 : poLayer->DropSpatialIndex();
694 : else
695 : {
696 : CPLError( CE_Failure, CPLE_AppDefined,
697 : "No such layer as '%s' in DROP SPATIAL INDEX.",
698 0 : pszStatement + 19 );
699 : }
700 1 : return NULL;
701 : }
702 :
703 : /* ==================================================================== */
704 : /* Handle all comands except spatial index creation generically. */
705 : /* ==================================================================== */
706 49 : if( !EQUALN(pszStatement,"CREATE SPATIAL INDEX ON ",24) )
707 : return OGRDataSource::ExecuteSQL( pszStatement, poSpatialFilter,
708 46 : pszDialect );
709 :
710 : /* -------------------------------------------------------------------- */
711 : /* Parse into keywords. */
712 : /* -------------------------------------------------------------------- */
713 3 : char **papszTokens = CSLTokenizeString( pszStatement );
714 :
715 3 : if( CSLCount(papszTokens) < 5
716 : || !EQUAL(papszTokens[0],"CREATE")
717 : || !EQUAL(papszTokens[1],"SPATIAL")
718 : || !EQUAL(papszTokens[2],"INDEX")
719 : || !EQUAL(papszTokens[3],"ON")
720 : || CSLCount(papszTokens) > 7
721 : || (CSLCount(papszTokens) == 7 && !EQUAL(papszTokens[5],"DEPTH")) )
722 : {
723 0 : CSLDestroy( papszTokens );
724 : CPLError( CE_Failure, CPLE_AppDefined,
725 : "Syntax error in CREATE SPATIAL INDEX command.\n"
726 : "Was '%s'\n"
727 : "Should be of form 'CREATE SPATIAL INDEX ON <table> [DEPTH <n>]'",
728 0 : pszStatement );
729 0 : return NULL;
730 : }
731 :
732 : /* -------------------------------------------------------------------- */
733 : /* Get depth if provided. */
734 : /* -------------------------------------------------------------------- */
735 3 : int nDepth = 0;
736 3 : if( CSLCount(papszTokens) == 7 )
737 0 : nDepth = atoi(papszTokens[6]);
738 :
739 : /* -------------------------------------------------------------------- */
740 : /* What layer are we operating on. */
741 : /* -------------------------------------------------------------------- */
742 3 : OGRShapeLayer *poLayer = (OGRShapeLayer *) GetLayerByName(papszTokens[4]);
743 3 : CSLDestroy( papszTokens );
744 :
745 3 : if( poLayer == NULL )
746 : {
747 : CPLError( CE_Failure, CPLE_AppDefined,
748 : "Layer %s not recognised.",
749 0 : papszTokens[4] );
750 0 : return NULL;
751 : }
752 :
753 3 : poLayer->CreateSpatialIndex( nDepth );
754 3 : return NULL;
755 : }
756 :
757 :
758 : /************************************************************************/
759 : /* DeleteLayer() */
760 : /************************************************************************/
761 :
762 2 : OGRErr OGRShapeDataSource::DeleteLayer( int iLayer )
763 :
764 : {
765 : char *pszFilename;
766 :
767 : /* -------------------------------------------------------------------- */
768 : /* Verify we are in update mode. */
769 : /* -------------------------------------------------------------------- */
770 2 : if( !bDSUpdate )
771 : {
772 : CPLError( CE_Failure, CPLE_NoWriteAccess,
773 : "Data source %s opened read-only.\n"
774 : "Layer %d cannot be deleted.\n",
775 0 : pszName, iLayer );
776 :
777 0 : return OGRERR_FAILURE;
778 : }
779 :
780 2 : if( iLayer < 0 || iLayer >= nLayers )
781 : {
782 : CPLError( CE_Failure, CPLE_AppDefined,
783 : "Layer %d not in legal range of 0 to %d.",
784 0 : iLayer, nLayers-1 );
785 0 : return OGRERR_FAILURE;
786 : }
787 :
788 2 : pszFilename = CPLStrdup(((OGRShapeLayer*) papoLayers[iLayer])->GetFullName());
789 :
790 2 : delete papoLayers[iLayer];
791 :
792 4 : while( iLayer < nLayers - 1 )
793 : {
794 0 : papoLayers[iLayer] = papoLayers[iLayer+1];
795 0 : iLayer++;
796 : }
797 :
798 2 : nLayers--;
799 :
800 2 : VSIUnlink( CPLResetExtension(pszFilename, "shp") );
801 2 : VSIUnlink( CPLResetExtension(pszFilename, "shx") );
802 2 : VSIUnlink( CPLResetExtension(pszFilename, "dbf") );
803 2 : VSIUnlink( CPLResetExtension(pszFilename, "prj") );
804 2 : VSIUnlink( CPLResetExtension(pszFilename, "qix") );
805 :
806 2 : CPLFree( pszFilename );
807 :
808 2 : return OGRERR_NONE;
809 : }
|