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