1 : /******************************************************************************
2 : * $Id: ogrshapedatasource.cpp 23526 2011-12-11 12:16:27Z 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 : #define MAX_SIMULTANEOUSLY_OPENED_LAYERS 100
35 :
36 : CPL_CVSID("$Id: ogrshapedatasource.cpp 23526 2011-12-11 12:16:27Z rouault $");
37 :
38 : /************************************************************************/
39 : /* OGRShapeDataSource() */
40 : /************************************************************************/
41 :
42 1202 : OGRShapeDataSource::OGRShapeDataSource()
43 :
44 : {
45 1202 : pszName = NULL;
46 1202 : papoLayers = NULL;
47 1202 : nLayers = 0;
48 1202 : bSingleFileDataSource = FALSE;
49 :
50 1202 : poMRULayer = NULL;
51 1202 : poLRULayer = NULL;
52 1202 : nMRUListSize = 0;
53 1202 : }
54 :
55 : /************************************************************************/
56 : /* ~OGRShapeDataSource() */
57 : /************************************************************************/
58 :
59 1202 : OGRShapeDataSource::~OGRShapeDataSource()
60 :
61 : {
62 1202 : CPLFree( pszName );
63 :
64 5452 : for( int i = 0; i < nLayers; i++ )
65 : {
66 4250 : CPLAssert( NULL != papoLayers[i] );
67 :
68 4250 : delete papoLayers[i];
69 : }
70 :
71 1202 : CPLAssert( poMRULayer == NULL );
72 1202 : CPLAssert( poLRULayer == NULL );
73 1202 : CPLAssert( nMRUListSize == 0 );
74 :
75 1202 : CPLFree( papoLayers );
76 1202 : }
77 :
78 : /************************************************************************/
79 : /* Open() */
80 : /************************************************************************/
81 :
82 1202 : int OGRShapeDataSource::Open( const char * pszNewName, int bUpdate,
83 : int bTestOpen, int bForceSingleFileDataSource )
84 :
85 : {
86 : VSIStatBufL stat;
87 :
88 1202 : CPLAssert( nLayers == 0 );
89 :
90 1202 : pszName = CPLStrdup( pszNewName );
91 :
92 1202 : bDSUpdate = bUpdate;
93 :
94 1202 : bSingleFileDataSource = bForceSingleFileDataSource;
95 :
96 : /* -------------------------------------------------------------------- */
97 : /* If bSingleFileDataSource is TRUE we don't try to do anything else. */
98 : /* This is only utilized when the OGRShapeDriver::Create() */
99 : /* method wants to create a stub OGRShapeDataSource for a */
100 : /* single shapefile. The driver will take care of creating the */
101 : /* file by calling CreateLayer(). */
102 : /* -------------------------------------------------------------------- */
103 1202 : if( bSingleFileDataSource )
104 88 : return TRUE;
105 :
106 : /* -------------------------------------------------------------------- */
107 : /* Is the given path a directory or a regular file? */
108 : /* -------------------------------------------------------------------- */
109 1114 : if( VSIStatExL( pszNewName, &stat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) != 0
110 : || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) )
111 : {
112 172 : if( !bTestOpen )
113 : CPLError( CE_Failure, CPLE_AppDefined,
114 : "%s is neither a file or directory, Shape access failed.\n",
115 0 : pszNewName );
116 :
117 172 : return FALSE;
118 : }
119 :
120 : /* -------------------------------------------------------------------- */
121 : /* Build a list of filenames we figure are Shape files. */
122 : /* -------------------------------------------------------------------- */
123 942 : if( VSI_ISREG(stat.st_mode) )
124 : {
125 812 : if( !OpenFile( pszNewName, bUpdate, bTestOpen ) )
126 : {
127 489 : if( !bTestOpen )
128 : CPLError( CE_Failure, CPLE_OpenFailed,
129 : "Failed to open shapefile %s.\n"
130 : "It may be corrupt or read-only file accessed in update mode.\n",
131 0 : pszNewName );
132 :
133 489 : return FALSE;
134 : }
135 :
136 323 : bSingleFileDataSource = TRUE;
137 :
138 323 : return TRUE;
139 : }
140 : else
141 : {
142 130 : char **papszCandidates = CPLReadDir( pszNewName );
143 130 : int iCan, nCandidateCount = CSLCount( papszCandidates );
144 130 : int bMightBeOldCoverage = FALSE;
145 :
146 11492 : for( iCan = 0; iCan < nCandidateCount; iCan++ )
147 : {
148 : char *pszFilename;
149 11362 : const char *pszCandidate = papszCandidates[iCan];
150 :
151 11362 : if( EQUAL(pszCandidate,"ARC") )
152 0 : bMightBeOldCoverage = TRUE;
153 :
154 11362 : if( strlen(pszCandidate) < 4
155 : || !EQUAL(pszCandidate+strlen(pszCandidate)-4,".shp") )
156 8125 : continue;
157 :
158 : pszFilename =
159 3237 : CPLStrdup(CPLFormFilename(pszNewName, pszCandidate, NULL));
160 :
161 3237 : if( !OpenFile( pszFilename, bUpdate, bTestOpen )
162 : && !bTestOpen )
163 : {
164 : CPLError( CE_Failure, CPLE_OpenFailed,
165 : "Failed to open shapefile %s.\n"
166 : "It may be corrupt or read-only file accessed in update mode.\n",
167 0 : pszFilename );
168 0 : CPLFree( pszFilename );
169 0 : return FALSE;
170 : }
171 :
172 3237 : CPLFree( pszFilename );
173 : }
174 :
175 : // Try and .dbf files without apparent associated shapefiles.
176 11492 : for( iCan = 0; iCan < nCandidateCount; iCan++ )
177 : {
178 : char *pszFilename;
179 11362 : const char *pszCandidate = papszCandidates[iCan];
180 : const char *pszLayerName;
181 11362 : int iLayer, bGotAlready = FALSE;
182 :
183 : // We don't consume .dbf files in a directory that looks like
184 : // an old style Arc/Info (for PC?) that unless we found at least
185 : // some shapefiles. See Bug 493.
186 11362 : if( bMightBeOldCoverage && nLayers == 0 )
187 0 : continue;
188 :
189 11362 : if( strlen(pszCandidate) < 4
190 : || !EQUAL(pszCandidate+strlen(pszCandidate)-4,".dbf") )
191 8131 : continue;
192 :
193 3231 : pszLayerName = CPLGetBasename(pszCandidate);
194 1267703 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
195 : {
196 1264472 : if( EQUAL(pszLayerName,
197 : GetLayer(iLayer)->GetLayerDefn()->GetName()) )
198 3216 : bGotAlready = TRUE;
199 : }
200 :
201 3231 : if( bGotAlready )
202 3216 : continue;
203 :
204 : // We don't want to access .dbf files with an associated .tab
205 : // file, or it will never get recognised as a mapinfo dataset.
206 15 : int iCan2, bFoundTAB = FALSE;
207 3420 : for( iCan2 = 0; iCan2 < nCandidateCount; iCan2++ )
208 : {
209 3405 : const char *pszCandidate2 = papszCandidates[iCan2];
210 :
211 3405 : if( EQUALN(pszCandidate2,pszLayerName,strlen(pszLayerName))
212 : && EQUAL(pszCandidate2 + strlen(pszLayerName), ".tab") )
213 0 : bFoundTAB = TRUE;
214 : }
215 :
216 15 : if( bFoundTAB )
217 0 : continue;
218 :
219 : pszFilename =
220 15 : CPLStrdup(CPLFormFilename(pszNewName, pszCandidate, NULL));
221 :
222 15 : if( !OpenFile( pszFilename, bUpdate, bTestOpen )
223 : && !bTestOpen )
224 : {
225 : CPLError( CE_Failure, CPLE_OpenFailed,
226 : "Failed to open dbf file %s.\n"
227 : "It may be corrupt or read-only file accessed in update mode.\n",
228 0 : pszFilename );
229 0 : CPLFree( pszFilename );
230 0 : return FALSE;
231 : }
232 :
233 15 : CPLFree( pszFilename );
234 : }
235 :
236 130 : CSLDestroy( papszCandidates );
237 :
238 130 : if( !bTestOpen && nLayers == 0 && !bUpdate )
239 : {
240 : CPLError( CE_Failure, CPLE_OpenFailed,
241 : "No Shapefiles found in directory %s\n",
242 0 : pszNewName );
243 : }
244 : }
245 :
246 130 : return nLayers > 0 || bUpdate;
247 : }
248 :
249 : /************************************************************************/
250 : /* OpenFile() */
251 : /************************************************************************/
252 :
253 4064 : int OGRShapeDataSource::OpenFile( const char *pszNewName, int bUpdate,
254 : int bTestOpen )
255 :
256 : {
257 : SHPHandle hSHP;
258 : DBFHandle hDBF;
259 4064 : const char *pszExtension = CPLGetExtension( pszNewName );
260 :
261 : (void) bTestOpen;
262 :
263 4064 : if( !EQUAL(pszExtension,"shp") && !EQUAL(pszExtension,"shx")
264 : && !EQUAL(pszExtension,"dbf") )
265 489 : return FALSE;
266 :
267 : /* -------------------------------------------------------------------- */
268 : /* SHPOpen() should include better (CPL based) error reporting, */
269 : /* and we should be trying to distinquish at this point whether */
270 : /* failure is a result of trying to open a non-shapefile, or */
271 : /* whether it was a shapefile and we want to report the error */
272 : /* up. */
273 : /* */
274 : /* Care is taken to suppress the error and only reissue it if */
275 : /* we think it is appropriate. */
276 : /* -------------------------------------------------------------------- */
277 3575 : CPLPushErrorHandler( CPLQuietErrorHandler );
278 3575 : if( bUpdate )
279 1693 : hSHP = SHPOpen( pszNewName, "r+" );
280 : else
281 1882 : hSHP = SHPOpen( pszNewName, "r" );
282 3575 : CPLPopErrorHandler();
283 :
284 3575 : if( hSHP == NULL
285 : && (!EQUAL(CPLGetExtension(pszNewName),"dbf")
286 : || strstr(CPLGetLastErrorMsg(),".shp") == NULL) )
287 : {
288 0 : CPLString osMsg = CPLGetLastErrorMsg();
289 :
290 0 : CPLError( CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str() );
291 :
292 0 : return FALSE;
293 : }
294 3575 : CPLErrorReset();
295 :
296 : /* -------------------------------------------------------------------- */
297 : /* Open the .dbf file, if it exists. To open a dbf file, the */
298 : /* filename has to either refer to a successfully opened shp */
299 : /* file or has to refer to the actual .dbf file. */
300 : /* -------------------------------------------------------------------- */
301 3575 : if( hSHP != NULL || EQUAL(CPLGetExtension(pszNewName),"dbf") )
302 : {
303 3575 : if( bUpdate )
304 : {
305 1693 : hDBF = DBFOpen( pszNewName, "r+" );
306 1693 : if( hSHP != NULL && hDBF == NULL )
307 : {
308 : VSIStatBufL sStat;
309 3 : const char* pszDBFName = CPLResetExtension(pszNewName, "dbf");
310 3 : VSILFILE* fp = NULL;
311 3 : if( VSIStatExL( pszDBFName, &sStat, VSI_STAT_EXISTS_FLAG) == 0 )
312 : {
313 0 : fp = VSIFOpenL(pszDBFName, "r+");
314 0 : if (fp == NULL)
315 : {
316 : CPLError( CE_Failure, CPLE_OpenFailed,
317 : "%s exists, but cannot be opened in update mode",
318 0 : pszDBFName );
319 0 : return FALSE;
320 : }
321 : }
322 : else
323 : {
324 3 : pszDBFName = CPLResetExtension(pszNewName, "DBF");
325 3 : if( VSIStatExL( pszDBFName, &sStat, VSI_STAT_EXISTS_FLAG) == 0 )
326 : {
327 0 : fp = VSIFOpenL(pszDBFName, "r+");
328 0 : if (fp == NULL)
329 : {
330 : CPLError( CE_Failure, CPLE_OpenFailed,
331 : "%s exists, but cannot be opened in update mode",
332 0 : pszDBFName );
333 0 : return FALSE;
334 : }
335 : }
336 : }
337 3 : if (fp != NULL)
338 0 : VSIFCloseL(fp);
339 : }
340 : }
341 : else
342 1882 : hDBF = DBFOpen( pszNewName, "r" );
343 : }
344 : else
345 0 : hDBF = NULL;
346 :
347 3575 : if( hDBF == NULL && hSHP == NULL )
348 0 : return FALSE;
349 :
350 : /* -------------------------------------------------------------------- */
351 : /* Create the layer object. */
352 : /* -------------------------------------------------------------------- */
353 : OGRShapeLayer *poLayer;
354 :
355 : poLayer = new OGRShapeLayer( this, pszNewName, hSHP, hDBF, NULL, FALSE, bUpdate,
356 3575 : wkbNone );
357 :
358 : /* -------------------------------------------------------------------- */
359 : /* Add layer to data source layer list. */
360 : /* -------------------------------------------------------------------- */
361 3575 : AddLayer(poLayer);
362 :
363 3575 : return TRUE;
364 : }
365 :
366 :
367 : /************************************************************************/
368 : /* AddLayer() */
369 : /************************************************************************/
370 :
371 4758 : void OGRShapeDataSource::AddLayer(OGRShapeLayer* poLayer)
372 : {
373 : papoLayers = (OGRShapeLayer **)
374 4758 : CPLRealloc( papoLayers, sizeof(OGRShapeLayer *) * (nLayers+1) );
375 4758 : papoLayers[nLayers++] = poLayer;
376 :
377 : /* If we reach the limit, then register all the already opened layers */
378 : /* Technically this code would not be necessary if there was not the */
379 : /* following initial test in SetLastUsedLayer() : */
380 : /* if (nLayers < MAX_SIMULTANEOUSLY_OPENED_LAYERS) */
381 : /* return; */
382 4758 : if (nLayers == MAX_SIMULTANEOUSLY_OPENED_LAYERS && nMRUListSize == 0)
383 : {
384 707 : for(int i=0;i<nLayers;i++)
385 700 : SetLastUsedLayer(papoLayers[i]);
386 : }
387 4758 : }
388 :
389 : /************************************************************************/
390 : /* CreateLayer() */
391 : /************************************************************************/
392 :
393 : OGRLayer *
394 1184 : OGRShapeDataSource::CreateLayer( const char * pszLayerName,
395 : OGRSpatialReference *poSRS,
396 : OGRwkbGeometryType eType,
397 : char ** papszOptions )
398 :
399 : {
400 : SHPHandle hSHP;
401 : DBFHandle hDBF;
402 : int nShapeType;
403 : int iLayer;
404 :
405 : /* -------------------------------------------------------------------- */
406 : /* Check that the layer doesn't already exist. */
407 : /* -------------------------------------------------------------------- */
408 252263 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
409 : {
410 251080 : OGRLayer *poLayer = papoLayers[iLayer];
411 :
412 502160 : if( poLayer != NULL
413 251080 : && EQUAL(poLayer->GetLayerDefn()->GetName(),pszLayerName) )
414 : {
415 : CPLError( CE_Failure, CPLE_AppDefined, "Layer '%s' already exists",
416 1 : pszLayerName);
417 1 : return NULL;
418 : }
419 : }
420 :
421 : /* -------------------------------------------------------------------- */
422 : /* Verify we are in update mode. */
423 : /* -------------------------------------------------------------------- */
424 1183 : if( !bDSUpdate )
425 : {
426 : CPLError( CE_Failure, CPLE_NoWriteAccess,
427 : "Data source %s opened read-only.\n"
428 : "New layer %s cannot be created.\n",
429 0 : pszName, pszLayerName );
430 :
431 0 : return NULL;
432 : }
433 :
434 : /* -------------------------------------------------------------------- */
435 : /* Figure out what type of layer we need. */
436 : /* -------------------------------------------------------------------- */
437 2272 : if( eType == wkbUnknown || eType == wkbLineString )
438 1089 : nShapeType = SHPT_ARC;
439 94 : else if( eType == wkbPoint )
440 2 : nShapeType = SHPT_POINT;
441 92 : else if( eType == wkbPolygon )
442 67 : nShapeType = SHPT_POLYGON;
443 25 : else if( eType == wkbMultiPoint )
444 2 : nShapeType = SHPT_MULTIPOINT;
445 23 : else if( eType == wkbPoint25D )
446 1 : nShapeType = SHPT_POINTZ;
447 22 : else if( eType == wkbLineString25D )
448 4 : nShapeType = SHPT_ARCZ;
449 18 : else if( eType == wkbMultiLineString )
450 2 : nShapeType = SHPT_ARC;
451 16 : else if( eType == wkbMultiLineString25D )
452 1 : nShapeType = SHPT_ARCZ;
453 15 : else if( eType == wkbPolygon25D )
454 5 : nShapeType = SHPT_POLYGONZ;
455 10 : else if( eType == wkbMultiPolygon )
456 5 : nShapeType = SHPT_POLYGON;
457 5 : else if( eType == wkbMultiPolygon25D )
458 1 : nShapeType = SHPT_POLYGONZ;
459 4 : else if( eType == wkbMultiPoint25D )
460 1 : nShapeType = SHPT_MULTIPOINTZ;
461 3 : else if( eType == wkbNone )
462 3 : nShapeType = SHPT_NULL;
463 : else
464 0 : nShapeType = -1;
465 :
466 : /* -------------------------------------------------------------------- */
467 : /* Has the application overridden this with a special creation */
468 : /* option? */
469 : /* -------------------------------------------------------------------- */
470 1183 : const char *pszOverride = CSLFetchNameValue( papszOptions, "SHPT" );
471 :
472 1183 : if( pszOverride == NULL )
473 : /* ignore */;
474 2 : else if( EQUAL(pszOverride,"POINT") )
475 : {
476 0 : nShapeType = SHPT_POINT;
477 0 : eType = wkbPoint;
478 : }
479 2 : else if( EQUAL(pszOverride,"ARC") )
480 : {
481 0 : nShapeType = SHPT_ARC;
482 0 : eType = wkbLineString;
483 : }
484 2 : else if( EQUAL(pszOverride,"POLYGON") )
485 : {
486 0 : nShapeType = SHPT_POLYGON;
487 0 : eType = wkbPolygon;
488 : }
489 2 : else if( EQUAL(pszOverride,"MULTIPOINT") )
490 : {
491 0 : nShapeType = SHPT_MULTIPOINT;
492 0 : eType = wkbMultiPoint;
493 : }
494 2 : else if( EQUAL(pszOverride,"POINTZ") )
495 : {
496 0 : nShapeType = SHPT_POINTZ;
497 0 : eType = wkbPoint25D;
498 : }
499 2 : else if( EQUAL(pszOverride,"ARCZ") )
500 : {
501 0 : nShapeType = SHPT_ARCZ;
502 0 : eType = wkbLineString25D;
503 : }
504 2 : else if( EQUAL(pszOverride,"POLYGONZ") )
505 : {
506 2 : nShapeType = SHPT_POLYGONZ;
507 2 : eType = wkbPolygon25D;
508 : }
509 0 : else if( EQUAL(pszOverride,"MULTIPOINTZ") )
510 : {
511 0 : nShapeType = SHPT_MULTIPOINTZ;
512 0 : eType = wkbMultiPoint25D;
513 : }
514 0 : else if( EQUAL(pszOverride,"NONE") || EQUAL(pszOverride,"NULL") )
515 : {
516 0 : nShapeType = SHPT_NULL;
517 0 : eType = wkbNone;
518 : }
519 : else
520 : {
521 : CPLError( CE_Failure, CPLE_NotSupported,
522 : "Unknown SHPT value of `%s' passed to Shapefile layer\n"
523 : "creation. Creation aborted.\n",
524 0 : pszOverride );
525 :
526 0 : return NULL;
527 : }
528 :
529 1183 : if( nShapeType == -1 )
530 : {
531 : CPLError( CE_Failure, CPLE_NotSupported,
532 : "Geometry type of `%s' not supported in shapefiles.\n"
533 : "Type can be overridden with a layer creation option\n"
534 : "of SHPT=POINT/ARC/POLYGON/MULTIPOINT/POINTZ/ARCZ/POLYGONZ/MULTIPOINTZ.\n",
535 0 : OGRGeometryTypeToName(eType) );
536 0 : return NULL;
537 : }
538 :
539 : /* -------------------------------------------------------------------- */
540 : /* What filename do we use, excluding the extension? */
541 : /* -------------------------------------------------------------------- */
542 : char *pszBasename;
543 :
544 1273 : if( bSingleFileDataSource && nLayers == 0 )
545 : {
546 90 : char *pszPath = CPLStrdup(CPLGetPath(pszName));
547 90 : char *pszFBasename = CPLStrdup(CPLGetBasename(pszName));
548 :
549 90 : pszBasename = CPLStrdup(CPLFormFilename(pszPath, pszFBasename, NULL));
550 :
551 90 : CPLFree( pszFBasename );
552 90 : CPLFree( pszPath );
553 : }
554 1093 : else if( bSingleFileDataSource )
555 : {
556 : /* This is a very weird use case : the user creates/open a datasource */
557 : /* made of a single shapefile 'foo.shp' and wants to add a new layer */
558 : /* to it, 'bar'. So we create a new shapefile 'bar.shp' in the same */
559 : /* directory as 'foo.shp' */
560 : /* So technically, we will not be any longer a single file */
561 : /* datasource ... Ahem ahem */
562 1 : char *pszPath = CPLStrdup(CPLGetPath(pszName));
563 1 : pszBasename = CPLStrdup(CPLFormFilename(pszPath,pszLayerName,NULL));
564 1 : CPLFree( pszPath );
565 : }
566 : else
567 1092 : pszBasename = CPLStrdup(CPLFormFilename(pszName,pszLayerName,NULL));
568 :
569 : /* -------------------------------------------------------------------- */
570 : /* Create the shapefile. */
571 : /* -------------------------------------------------------------------- */
572 : char *pszFilename;
573 :
574 1183 : if( nShapeType != SHPT_NULL )
575 : {
576 1180 : pszFilename = CPLStrdup(CPLFormFilename( NULL, pszBasename, "shp" ));
577 :
578 1180 : hSHP = SHPCreate( pszFilename, nShapeType );
579 :
580 1180 : if( hSHP == NULL )
581 : {
582 : CPLError( CE_Failure, CPLE_OpenFailed,
583 : "Failed to open Shapefile `%s'.\n",
584 0 : pszFilename );
585 0 : CPLFree( pszFilename );
586 0 : CPLFree( pszBasename );
587 0 : return NULL;
588 : }
589 1180 : CPLFree( pszFilename );
590 : }
591 : else
592 3 : hSHP = NULL;
593 :
594 : /* -------------------------------------------------------------------- */
595 : /* Has a specific LDID been specified by the caller? */
596 : /* -------------------------------------------------------------------- */
597 1183 : const char *pszLDID = CSLFetchNameValue( papszOptions, "ENCODING" );
598 :
599 : /* -------------------------------------------------------------------- */
600 : /* Create a DBF file. */
601 : /* -------------------------------------------------------------------- */
602 1183 : pszFilename = CPLStrdup(CPLFormFilename( NULL, pszBasename, "dbf" ));
603 :
604 1183 : if( pszLDID != NULL )
605 0 : hDBF = DBFCreateEx( pszFilename, pszLDID );
606 : else
607 1183 : hDBF = DBFCreate( pszFilename );
608 :
609 1183 : if( hDBF == NULL )
610 : {
611 : CPLError( CE_Failure, CPLE_OpenFailed,
612 : "Failed to open Shape DBF file `%s'.\n",
613 0 : pszFilename );
614 0 : CPLFree( pszFilename );
615 0 : CPLFree( pszBasename );
616 0 : SHPClose(hSHP);
617 0 : return NULL;
618 : }
619 :
620 1183 : CPLFree( pszFilename );
621 :
622 : /* -------------------------------------------------------------------- */
623 : /* Create the .prj file, if required. */
624 : /* -------------------------------------------------------------------- */
625 1183 : if( poSRS != NULL )
626 : {
627 80 : char *pszWKT = NULL;
628 80 : CPLString osPrjFile = CPLFormFilename( NULL, pszBasename, "prj");
629 : VSILFILE *fp;
630 :
631 : /* the shape layer needs it's own copy */
632 80 : poSRS = poSRS->Clone();
633 80 : poSRS->morphToESRI();
634 :
635 80 : if( poSRS->exportToWkt( &pszWKT ) == OGRERR_NONE
636 : && (fp = VSIFOpenL( osPrjFile, "wt" )) != NULL )
637 : {
638 80 : VSIFWriteL( pszWKT, strlen(pszWKT), 1, fp );
639 80 : VSIFCloseL( fp );
640 : }
641 :
642 80 : CPLFree( pszWKT );
643 :
644 80 : poSRS->morphFromESRI();
645 : }
646 :
647 : /* -------------------------------------------------------------------- */
648 : /* Create the layer object. */
649 : /* -------------------------------------------------------------------- */
650 : OGRShapeLayer *poLayer;
651 :
652 : poLayer = new OGRShapeLayer( this, pszBasename, hSHP, hDBF, poSRS, TRUE, TRUE,
653 1183 : eType );
654 :
655 1183 : CPLFree( pszBasename );
656 :
657 : /* -------------------------------------------------------------------- */
658 : /* Add layer to data source layer list. */
659 : /* -------------------------------------------------------------------- */
660 1183 : AddLayer(poLayer);
661 :
662 1183 : return poLayer;
663 : }
664 :
665 : /************************************************************************/
666 : /* TestCapability() */
667 : /************************************************************************/
668 :
669 74 : int OGRShapeDataSource::TestCapability( const char * pszCap )
670 :
671 : {
672 74 : if( EQUAL(pszCap,ODsCCreateLayer) )
673 74 : return bDSUpdate;
674 0 : else if( EQUAL(pszCap,ODsCDeleteLayer) )
675 0 : return bDSUpdate;
676 : else
677 0 : return FALSE;
678 : }
679 :
680 : /************************************************************************/
681 : /* GetLayer() */
682 : /************************************************************************/
683 :
684 1560695 : OGRLayer *OGRShapeDataSource::GetLayer( int iLayer )
685 :
686 : {
687 1560695 : if( iLayer < 0 || iLayer >= nLayers )
688 0 : return NULL;
689 : else
690 1560695 : return papoLayers[iLayer];
691 : }
692 :
693 : /************************************************************************/
694 : /* ExecuteSQL() */
695 : /* */
696 : /* We override this to provide special handling of CREATE */
697 : /* SPATIAL INDEX commands. Support forms are: */
698 : /* */
699 : /* CREATE SPATIAL INDEX ON layer_name [DEPTH n] */
700 : /* DROP SPATIAL INDEX ON layer_name */
701 : /* REPACK layer_name */
702 : /* RECOMPUTE EXTENT ON layer_name */
703 : /************************************************************************/
704 :
705 597 : OGRLayer * OGRShapeDataSource::ExecuteSQL( const char *pszStatement,
706 : OGRGeometry *poSpatialFilter,
707 : const char *pszDialect )
708 :
709 : {
710 : /* ==================================================================== */
711 : /* Handle command to drop a spatial index. */
712 : /* ==================================================================== */
713 597 : if( EQUALN(pszStatement, "REPACK ", 7) )
714 : {
715 : OGRShapeLayer *poLayer = (OGRShapeLayer *)
716 6 : GetLayerByName( pszStatement + 7 );
717 :
718 6 : if( poLayer != NULL )
719 6 : poLayer->Repack();
720 : else
721 : {
722 : CPLError( CE_Failure, CPLE_AppDefined,
723 : "No such layer as '%s' in REPACK.",
724 0 : pszStatement + 7 );
725 : }
726 6 : return NULL;
727 : }
728 :
729 : /* ==================================================================== */
730 : /* Handle command to recompute extent */
731 : /* ==================================================================== */
732 591 : if( EQUALN(pszStatement, "RECOMPUTE EXTENT ON ", 20) )
733 : {
734 : OGRShapeLayer *poLayer = (OGRShapeLayer *)
735 3 : GetLayerByName( pszStatement + 20 );
736 :
737 3 : if( poLayer != NULL )
738 2 : poLayer->RecomputeExtent();
739 : else
740 : {
741 : CPLError( CE_Failure, CPLE_AppDefined,
742 : "No such layer as '%s' in RECOMPUTE EXTENT.",
743 1 : pszStatement + 20 );
744 : }
745 3 : return NULL;
746 : }
747 :
748 : /* ==================================================================== */
749 : /* Handle command to drop a spatial index. */
750 : /* ==================================================================== */
751 588 : if( EQUALN(pszStatement, "DROP SPATIAL INDEX ON ", 22) )
752 : {
753 : OGRShapeLayer *poLayer = (OGRShapeLayer *)
754 2 : GetLayerByName( pszStatement + 22 );
755 :
756 2 : if( poLayer != NULL )
757 2 : poLayer->DropSpatialIndex();
758 : else
759 : {
760 : CPLError( CE_Failure, CPLE_AppDefined,
761 : "No such layer as '%s' in DROP SPATIAL INDEX.",
762 0 : pszStatement + 19 );
763 : }
764 2 : return NULL;
765 : }
766 :
767 : /* ==================================================================== */
768 : /* Handle all comands except spatial index creation generically. */
769 : /* ==================================================================== */
770 586 : if( !EQUALN(pszStatement,"CREATE SPATIAL INDEX ON ",24) )
771 : {
772 578 : char **papszTokens = CSLTokenizeString( pszStatement );
773 742 : if( CSLCount(papszTokens) >=4
774 148 : && (EQUAL(papszTokens[0],"CREATE") || EQUAL(papszTokens[0],"DROP"))
775 8 : && EQUAL(papszTokens[1],"INDEX")
776 8 : && EQUAL(papszTokens[2],"ON") )
777 : {
778 8 : OGRShapeLayer *poLayer = (OGRShapeLayer *) GetLayerByName(papszTokens[3]);
779 8 : if (poLayer != NULL)
780 8 : poLayer->InitializeIndexSupport( poLayer->GetFullName() );
781 : }
782 578 : CSLDestroy( papszTokens );
783 :
784 : return OGRDataSource::ExecuteSQL( pszStatement, poSpatialFilter,
785 578 : pszDialect );
786 : }
787 :
788 : /* -------------------------------------------------------------------- */
789 : /* Parse into keywords. */
790 : /* -------------------------------------------------------------------- */
791 8 : char **papszTokens = CSLTokenizeString( pszStatement );
792 :
793 40 : if( CSLCount(papszTokens) < 5
794 8 : || !EQUAL(papszTokens[0],"CREATE")
795 8 : || !EQUAL(papszTokens[1],"SPATIAL")
796 8 : || !EQUAL(papszTokens[2],"INDEX")
797 8 : || !EQUAL(papszTokens[3],"ON")
798 : || CSLCount(papszTokens) > 7
799 0 : || (CSLCount(papszTokens) == 7 && !EQUAL(papszTokens[5],"DEPTH")) )
800 : {
801 0 : CSLDestroy( papszTokens );
802 : CPLError( CE_Failure, CPLE_AppDefined,
803 : "Syntax error in CREATE SPATIAL INDEX command.\n"
804 : "Was '%s'\n"
805 : "Should be of form 'CREATE SPATIAL INDEX ON <table> [DEPTH <n>]'",
806 0 : pszStatement );
807 0 : return NULL;
808 : }
809 :
810 : /* -------------------------------------------------------------------- */
811 : /* Get depth if provided. */
812 : /* -------------------------------------------------------------------- */
813 8 : int nDepth = 0;
814 8 : if( CSLCount(papszTokens) == 7 )
815 0 : nDepth = atoi(papszTokens[6]);
816 :
817 : /* -------------------------------------------------------------------- */
818 : /* What layer are we operating on. */
819 : /* -------------------------------------------------------------------- */
820 8 : OGRShapeLayer *poLayer = (OGRShapeLayer *) GetLayerByName(papszTokens[4]);
821 :
822 8 : if( poLayer == NULL )
823 : {
824 : CPLError( CE_Failure, CPLE_AppDefined,
825 : "Layer %s not recognised.",
826 0 : papszTokens[4] );
827 0 : CSLDestroy( papszTokens );
828 0 : return NULL;
829 : }
830 :
831 8 : CSLDestroy( papszTokens );
832 :
833 8 : poLayer->CreateSpatialIndex( nDepth );
834 8 : return NULL;
835 : }
836 :
837 :
838 : /************************************************************************/
839 : /* DeleteLayer() */
840 : /************************************************************************/
841 :
842 508 : OGRErr OGRShapeDataSource::DeleteLayer( int iLayer )
843 :
844 : {
845 : char *pszFilename;
846 :
847 : /* -------------------------------------------------------------------- */
848 : /* Verify we are in update mode. */
849 : /* -------------------------------------------------------------------- */
850 508 : if( !bDSUpdate )
851 : {
852 : CPLError( CE_Failure, CPLE_NoWriteAccess,
853 : "Data source %s opened read-only.\n"
854 : "Layer %d cannot be deleted.\n",
855 0 : pszName, iLayer );
856 :
857 0 : return OGRERR_FAILURE;
858 : }
859 :
860 508 : if( iLayer < 0 || iLayer >= nLayers )
861 : {
862 : CPLError( CE_Failure, CPLE_AppDefined,
863 : "Layer %d not in legal range of 0 to %d.",
864 0 : iLayer, nLayers-1 );
865 0 : return OGRERR_FAILURE;
866 : }
867 :
868 508 : OGRShapeLayer* poLayerToDelete = (OGRShapeLayer*) papoLayers[iLayer];
869 :
870 508 : pszFilename = CPLStrdup(poLayerToDelete->GetFullName());
871 :
872 508 : delete poLayerToDelete;
873 :
874 86968 : while( iLayer < nLayers - 1 )
875 : {
876 85952 : papoLayers[iLayer] = papoLayers[iLayer+1];
877 85952 : iLayer++;
878 : }
879 :
880 508 : nLayers--;
881 :
882 508 : VSIUnlink( CPLResetExtension(pszFilename, "shp") );
883 508 : VSIUnlink( CPLResetExtension(pszFilename, "shx") );
884 508 : VSIUnlink( CPLResetExtension(pszFilename, "dbf") );
885 508 : VSIUnlink( CPLResetExtension(pszFilename, "prj") );
886 508 : VSIUnlink( CPLResetExtension(pszFilename, "qix") );
887 :
888 508 : CPLFree( pszFilename );
889 :
890 508 : return OGRERR_NONE;
891 : }
892 :
893 : /************************************************************************/
894 : /* SetLastUsedLayer() */
895 : /************************************************************************/
896 :
897 48486 : void OGRShapeDataSource::SetLastUsedLayer( OGRShapeLayer* poLayer )
898 : {
899 : /* We could remove that check and things would still work in */
900 : /* 99.99% cases */
901 : /* The only rationale for that test is to avoid breaking applications */
902 : /* that would deal with layers of the same datasource in different */
903 : /* threads. In GDAL < 1.9.0, this would work in most cases I can */
904 : /* imagine as shapefile layers are pretty much independant from each */
905 : /* others (although it has never been guaranteed to be a valid use case, */
906 : /* and the shape driver is likely more the exception than the rule in */
907 : /* permitting accessing layers from different threads !) */
908 : /* Anyway the LRU list mechanism leaves the door open to concurrent accesses to it */
909 : /* so when the datasource has not many layers, we don't try to build the */
910 : /* LRU list to avoid concurrency issues. I haven't bothered making the analysis */
911 : /* of how a mutex could be used to protect that (my intuition is that it would */
912 : /* need to be placed at the beginning of OGRShapeLayer::TouchLayer() ) */
913 48486 : if (nLayers < MAX_SIMULTANEOUSLY_OPENED_LAYERS)
914 41352 : return;
915 :
916 : /* If we are already the MRU layer, nothing to do */
917 7134 : if (poLayer == poMRULayer)
918 2622 : return;
919 :
920 : //CPLDebug("SHAPE", "SetLastUsedLayer(%s)", poLayer->GetName());
921 :
922 4514 : if (poLayer->poPrevLayer != NULL || poLayer->poNextLayer != NULL)
923 : {
924 : /* Remove current layer from its current place in the list */
925 2 : UnchainLayer(poLayer);
926 : }
927 4510 : else if (nMRUListSize == MAX_SIMULTANEOUSLY_OPENED_LAYERS)
928 : {
929 : /* If we have reached the maximum allowed number of layers */
930 : /* simultaneously opened, then close the LRU one that */
931 : /* was still active until now */
932 3809 : CPLAssert(poLRULayer != NULL);
933 :
934 3809 : poLRULayer->CloseFileDescriptors();
935 3809 : UnchainLayer(poLRULayer);
936 : }
937 :
938 : /* Put current layer on top of MRU list */
939 4512 : CPLAssert(poLayer->poPrevLayer == NULL);
940 4512 : CPLAssert(poLayer->poNextLayer == NULL);
941 4512 : poLayer->poNextLayer = poMRULayer;
942 4512 : if (poMRULayer != NULL)
943 : {
944 4505 : CPLAssert(poMRULayer->poPrevLayer == NULL);
945 4505 : poMRULayer->poPrevLayer = poLayer;
946 : }
947 4512 : poMRULayer = poLayer;
948 4512 : if (poLRULayer == NULL)
949 7 : poLRULayer = poLayer;
950 4512 : nMRUListSize ++;
951 : }
952 :
953 :
954 : /************************************************************************/
955 : /* UnchainLayer() */
956 : /* */
957 : /* Remove the layer from the MRU list */
958 : /************************************************************************/
959 :
960 8569 : void OGRShapeDataSource::UnchainLayer( OGRShapeLayer* poLayer )
961 : {
962 : //CPLDebug("SHAPE", "UnchainLayer(%s)", poLayer->GetName());
963 :
964 8569 : OGRShapeLayer* poPrevLayer = poLayer->poPrevLayer;
965 8569 : OGRShapeLayer* poNextLayer = poLayer->poNextLayer;
966 :
967 8569 : if (poPrevLayer != NULL)
968 4500 : CPLAssert(poPrevLayer->poNextLayer == poLayer);
969 8569 : if (poNextLayer != NULL)
970 109 : CPLAssert(poNextLayer->poPrevLayer == poLayer);
971 :
972 8569 : if (poPrevLayer != NULL || poNextLayer != NULL || poLayer == poMRULayer)
973 4512 : nMRUListSize --;
974 :
975 8569 : if (poLayer == poMRULayer)
976 12 : poMRULayer = poNextLayer;
977 8569 : if (poLayer == poLRULayer)
978 4403 : poLRULayer = poPrevLayer;
979 8569 : if (poPrevLayer != NULL)
980 4500 : poPrevLayer->poNextLayer = poNextLayer;
981 8569 : if (poNextLayer != NULL)
982 109 : poNextLayer->poPrevLayer = poPrevLayer;
983 8569 : poLayer->poPrevLayer = NULL;
984 8569 : poLayer->poNextLayer = NULL;
985 8569 : }
|