1 : /******************************************************************************
2 : * $Id: ogrgeoconceptdatasource.cpp
3 : *
4 : * Name: ogrgeoconceptdatasource.h
5 : * Project: OpenGIS Simple Features Reference Implementation
6 : * Purpose: Implements OGRGeoconceptDataSource class.
7 : * Language: C++
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2007, Geoconcept and IGN
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "ogrgeoconceptlayer.h"
32 : #include "ogrgeoconceptdatasource.h"
33 : #include "cpl_conv.h"
34 : #include "cpl_string.h"
35 :
36 : CPL_CVSID("$Id: ogrgeoconceptdatasource.cpp 00000 2007-11-03 11:49:22Z drichard $");
37 :
38 : /************************************************************************/
39 : /* OGRGeoconceptDataSource() */
40 : /************************************************************************/
41 :
42 284 : OGRGeoconceptDataSource::OGRGeoconceptDataSource()
43 :
44 : {
45 284 : _papoLayers = NULL;
46 284 : _nLayers = 0;
47 :
48 284 : _pszGCT = NULL;
49 284 : _pszName = NULL;
50 284 : _pszDirectory = NULL;
51 284 : _pszExt = NULL;
52 284 : _papszOptions = NULL;
53 :
54 284 : _bSingleNewFile = FALSE;
55 284 : _bUpdate = FALSE;
56 284 : _hGXT = NULL;
57 284 : }
58 :
59 : /************************************************************************/
60 : /* ~OGRGeoconceptDataSource() */
61 : /************************************************************************/
62 :
63 284 : OGRGeoconceptDataSource::~OGRGeoconceptDataSource()
64 :
65 : {
66 284 : if ( _pszGCT )
67 : {
68 0 : CPLFree( _pszGCT );
69 : }
70 284 : if ( _pszName )
71 : {
72 14 : CPLFree( _pszName );
73 : }
74 284 : if ( _pszDirectory )
75 : {
76 14 : CPLFree( _pszDirectory );
77 : }
78 284 : if ( _pszExt )
79 : {
80 14 : CPLFree( _pszExt );
81 : }
82 :
83 284 : if ( _papoLayers )
84 : {
85 20 : for( int i = 0; i < _nLayers; i++ )
86 : {
87 10 : delete _papoLayers[i];
88 : }
89 :
90 10 : CPLFree( _papoLayers );
91 : }
92 :
93 284 : if( _hGXT )
94 : {
95 10 : Close_GCIO(&_hGXT);
96 : }
97 :
98 284 : if ( _papszOptions )
99 : {
100 0 : CSLDestroy( _papszOptions );
101 : }
102 284 : }
103 :
104 : /************************************************************************/
105 : /* Open() */
106 : /* */
107 : /* Open an existing file. */
108 : /************************************************************************/
109 :
110 282 : int OGRGeoconceptDataSource::Open( const char* pszName, int bTestOpen, int bUpdate )
111 :
112 : {
113 : /* -------------------------------------------------------------------- */
114 : /* We will only consider .gxt and .txt files. */
115 : /* -------------------------------------------------------------------- */
116 282 : const char* pszExtension = CPLGetExtension(pszName);
117 282 : if( !EQUAL(pszExtension,"gxt") && !EQUAL(pszExtension,"txt") )
118 : {
119 268 : return FALSE;
120 : }
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* Is the given path a directory or a regular file? */
124 : /* -------------------------------------------------------------------- */
125 : VSIStatBuf stat;
126 :
127 14 : if( CPLStat( pszName, &stat ) != 0
128 : || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) )
129 : {
130 2 : if( !bTestOpen )
131 : {
132 : CPLError( CE_Failure, CPLE_AppDefined,
133 : "%s is neither a file or directory, Geoconcept access failed.",
134 0 : pszName );
135 : }
136 :
137 2 : return FALSE;
138 : }
139 :
140 12 : if( VSI_ISDIR(stat.st_mode) )
141 : {
142 : CPLDebug( "GEOCONCEPT",
143 : "%s is a directory, Geoconcept access is not yet supported.",
144 0 : pszName );
145 :
146 0 : return FALSE;
147 : }
148 :
149 12 : if( VSI_ISREG(stat.st_mode) )
150 : {
151 12 : _bSingleNewFile= FALSE;
152 12 : _bUpdate= bUpdate;
153 12 : _pszName= CPLStrdup( pszName );
154 12 : if( !LoadFile( _bUpdate? "a+t":"rt" ) )
155 : {
156 : CPLDebug( "GEOCONCEPT",
157 : "Failed to open Geoconcept %s."
158 : " It may be corrupt.",
159 4 : pszName );
160 :
161 4 : return FALSE;
162 : }
163 :
164 8 : return TRUE;
165 : }
166 :
167 0 : return _nLayers > 0;
168 : }
169 :
170 : /************************************************************************/
171 : /* LoadFile() */
172 : /************************************************************************/
173 :
174 14 : int OGRGeoconceptDataSource::LoadFile( const char *pszMode )
175 :
176 : {
177 : OGRGeoconceptLayer *poFile;
178 :
179 14 : if( _pszExt == NULL)
180 : {
181 12 : const char* pszExtension = CPLGetExtension(_pszName);
182 12 : _pszExt = CPLStrdup(pszExtension);
183 : }
184 14 : CPLStrlwr( _pszExt );
185 :
186 14 : if( !_pszDirectory )
187 12 : _pszDirectory = CPLStrdup( CPLGetPath(_pszName) );
188 :
189 14 : if( (_hGXT= Open_GCIO(_pszName,_pszExt,pszMode,_pszGCT))==NULL )
190 : {
191 4 : return FALSE;
192 : }
193 :
194 : /* Collect layers : */
195 10 : GCExportFileMetadata* Meta= GetGCMeta_GCIO(_hGXT);
196 10 : if( Meta )
197 : {
198 : int nC, iC, nS, iS;
199 :
200 8 : if( (nC= CountMetaTypes_GCIO(Meta))>0 )
201 : {
202 : GCType* aClass;
203 : GCSubType* aSubclass;
204 :
205 16 : for( iC= 0; iC<nC; iC++ )
206 : {
207 8 : if( (aClass= GetMetaType_GCIO(Meta,iC)) )
208 : {
209 8 : if( (nS= CountTypeSubtypes_GCIO(aClass)) )
210 : {
211 16 : for( iS= 0; iS<nS; iS++ )
212 : {
213 8 : if( (aSubclass= GetTypeSubtype_GCIO(aClass,iS)) )
214 : {
215 8 : poFile = new OGRGeoconceptLayer;
216 8 : if( poFile->Open(aSubclass) != OGRERR_NONE )
217 : {
218 0 : delete poFile;
219 0 : return FALSE;
220 : }
221 :
222 : /* Add layer to data source layers list */
223 : _papoLayers = (OGRGeoconceptLayer **)
224 8 : CPLRealloc( _papoLayers, sizeof(OGRGeoconceptLayer *) * (_nLayers+1) );
225 8 : _papoLayers[_nLayers++] = poFile;
226 :
227 : CPLDebug("GEOCONCEPT",
228 : "nLayers=%d - last=[%s]",
229 8 : _nLayers, poFile->GetLayerDefn()->GetName());
230 : }
231 : }
232 : }
233 : }
234 : }
235 : }
236 : }
237 :
238 10 : return TRUE;
239 : }
240 :
241 : /************************************************************************/
242 : /* Create() */
243 : /* */
244 : /* Create a new dataset. */
245 : /* */
246 : /* Options (-dsco) : */
247 : /* EXTENSION : gxt|txt */
248 : /* CONFIG : path to GCT file */
249 : /************************************************************************/
250 :
251 2 : int OGRGeoconceptDataSource::Create( const char *pszName, char** papszOptions )
252 :
253 : {
254 : const char *pszConf;
255 : const char *pszExtension;
256 :
257 2 : if( _pszName ) CPLFree(_pszName);
258 2 : _papszOptions = CSLDuplicate( papszOptions );
259 :
260 2 : pszConf= CSLFetchNameValue(papszOptions,"CONFIG");
261 2 : if( pszConf != NULL )
262 : {
263 0 : _pszGCT = CPLStrdup(pszConf);
264 : }
265 :
266 2 : _pszExt = (char *)CSLFetchNameValue(papszOptions,"EXTENSION");
267 2 : pszExtension = CSLFetchNameValue(papszOptions,"EXTENSION");
268 2 : if( pszExtension == NULL )
269 : {
270 2 : _pszExt = CPLStrdup(CPLGetExtension(pszName));
271 : }
272 : else
273 : {
274 0 : _pszExt = CPLStrdup(pszExtension);
275 : }
276 :
277 2 : if( strlen(_pszExt) == 0 )
278 : {
279 0 : if( VSIMkdir( pszName, 0755 ) != 0 )
280 : {
281 : CPLError( CE_Failure, CPLE_AppDefined,
282 : "Directory %s already exists"
283 : " as geoconcept datastore or"
284 : " is made up of a non existing list of directories.",
285 0 : pszName );
286 :
287 0 : return FALSE;
288 : }
289 0 : _pszDirectory = CPLStrdup( pszName );
290 0 : CPLFree(_pszExt);
291 0 : _pszExt = CPLStrdup("gxt");
292 0 : char *pszbName = CPLStrdup(CPLGetBasename( pszName ));
293 0 : if (strlen(pszbName)==0) {/* pszName ends with '/' */
294 0 : CPLFree(pszbName);
295 0 : char *pszNameDup= CPLStrdup(pszName);
296 0 : pszNameDup[strlen(pszName)-2] = '\0';
297 0 : pszbName = CPLStrdup(CPLGetBasename( pszNameDup ));
298 0 : CPLFree(pszNameDup);
299 : }
300 0 : _pszName = CPLStrdup((char *)CPLFormFilename( _pszDirectory, pszbName, NULL ));
301 0 : CPLFree(pszbName);
302 : }
303 : else
304 : {
305 2 : _pszDirectory = CPLStrdup( CPLGetPath(pszName) );
306 2 : _pszName = CPLStrdup( pszName );
307 : }
308 :
309 : /* -------------------------------------------------------------------- */
310 : /* Create a new single file. */
311 : /* OGRGeoconceptDriver::CreateLayer() will do the job. */
312 : /* -------------------------------------------------------------------- */
313 2 : _bSingleNewFile = TRUE;
314 :
315 2 : if( !LoadFile( "wt" ) )
316 : {
317 : CPLDebug( "GEOCONCEPT",
318 : "Failed to create Geoconcept %s.",
319 0 : pszName );
320 :
321 0 : return FALSE;
322 : }
323 :
324 2 : return TRUE;
325 : }
326 :
327 : /************************************************************************/
328 : /* CreateLayer() */
329 : /* */
330 : /* Options (-lco) : */
331 : /* FEATURETYPE : TYPE.SUBTYPE */
332 : /************************************************************************/
333 :
334 2 : OGRLayer *OGRGeoconceptDataSource::CreateLayer( const char * pszLayerName,
335 : OGRSpatialReference *poSRS /* = NULL */,
336 : OGRwkbGeometryType eType /* = wkbUnknown */,
337 : char ** papszOptions /* = NULL */ )
338 :
339 : {
340 : GCTypeKind gcioFeaType;
341 : GCDim gcioDim;
342 2 : OGRGeoconceptLayer *poFile= NULL;
343 : const char *pszFeatureType;
344 : char **ft;
345 : int iLayer;
346 : char pszln[512];
347 :
348 2 : if( _hGXT == NULL )
349 : {
350 : CPLError( CE_Failure, CPLE_NotSupported,
351 : "Internal Error : null datasource handler."
352 0 : );
353 0 : return NULL;
354 : }
355 :
356 2 : if( poSRS == NULL && !_bUpdate)
357 : {
358 : CPLError( CE_Failure, CPLE_NotSupported,
359 : "SRS is mandatory of creating a Geoconcept Layer."
360 0 : );
361 0 : return NULL;
362 : }
363 :
364 : /*
365 : * pszLayerName Class.Subclass if -nln option used, otherwise file name
366 : */
367 2 : if( !(pszFeatureType = CSLFetchNameValue(papszOptions,"FEATURETYPE")) )
368 : {
369 4 : if( !pszLayerName || !strchr(pszLayerName,'.') )
370 : {
371 : snprintf(pszln,511,"%s.%s", pszLayerName? pszLayerName:"ANONCLASS",
372 2 : pszLayerName? pszLayerName:"ANONSUBCLASS");
373 2 : pszln[511]= '\0';
374 2 : pszFeatureType= pszln;
375 : }
376 : else
377 0 : pszFeatureType= pszLayerName;
378 : }
379 :
380 2 : if( !(ft= CSLTokenizeString2(pszFeatureType,".",0)) ||
381 : CSLCount(ft)!=2 )
382 : {
383 0 : CSLDestroy(ft);
384 : CPLError( CE_Failure, CPLE_AppDefined,
385 : "Feature type name '%s' is incorrect."
386 : "Correct syntax is : Class.Subclass.",
387 0 : pszFeatureType );
388 0 : return NULL;
389 : }
390 :
391 : /* -------------------------------------------------------------------- */
392 : /* Figure out what type of layer we need. */
393 : /* -------------------------------------------------------------------- */
394 2 : gcioDim= v2D_GCIO;
395 2 : if( eType == wkbUnknown )
396 0 : gcioFeaType = vUnknownItemType_GCIO;
397 2 : else if( eType == wkbPoint )
398 2 : gcioFeaType = vPoint_GCIO;
399 0 : else if( eType == wkbLineString )
400 0 : gcioFeaType = vLine_GCIO;
401 0 : else if( eType == wkbPolygon )
402 0 : gcioFeaType = vPoly_GCIO;
403 0 : else if( eType == wkbMultiPoint )
404 0 : gcioFeaType = vPoint_GCIO;
405 0 : else if( eType == wkbMultiLineString )
406 0 : gcioFeaType = vLine_GCIO;
407 0 : else if( eType == wkbMultiPolygon )
408 0 : gcioFeaType = vPoly_GCIO;
409 0 : else if( eType == wkbPoint25D )
410 : {
411 0 : gcioFeaType = vPoint_GCIO;
412 0 : gcioDim= v3DM_GCIO;
413 : }
414 0 : else if( eType == wkbLineString25D )
415 : {
416 0 : gcioFeaType = vLine_GCIO;
417 0 : gcioDim= v3DM_GCIO;
418 : }
419 0 : else if( eType == wkbPolygon25D )
420 : {
421 0 : gcioFeaType = vPoly_GCIO;
422 0 : gcioDim= v3DM_GCIO;
423 : }
424 0 : else if( eType == wkbMultiPoint25D )
425 : {
426 0 : gcioFeaType = vPoint_GCIO;
427 0 : gcioDim= v3DM_GCIO;
428 : }
429 0 : else if( eType == wkbMultiLineString25D )
430 : {
431 0 : gcioFeaType = vLine_GCIO;
432 0 : gcioDim= v3DM_GCIO;
433 : }
434 0 : else if( eType == wkbMultiPolygon25D )
435 : {
436 0 : gcioFeaType = vPoly_GCIO;
437 0 : gcioDim= v3DM_GCIO;
438 : }
439 : else
440 : {
441 0 : CSLDestroy(ft);
442 : CPLError( CE_Failure, CPLE_NotSupported,
443 : "Geometry type of '%s' not supported in Geoconcept files.",
444 0 : OGRGeometryTypeToName(eType) );
445 0 : return NULL;
446 : }
447 :
448 : /*
449 : * As long as we use the CONFIG, creating a layer implies the
450 : * layer name to exist in the CONFIG as "Class.Subclass".
451 : * Removing the CONFIG, implies on-the-fly-creation of layers...
452 : */
453 2 : if( _nLayers > 0 )
454 0 : for( iLayer= 0; iLayer<_nLayers; iLayer++)
455 : {
456 0 : poFile= (OGRGeoconceptLayer*)GetLayer(iLayer);
457 0 : if( EQUAL(poFile->GetLayerDefn()->GetName(),pszFeatureType) )
458 : {
459 0 : break;
460 : }
461 0 : poFile= NULL;
462 : }
463 2 : if( !poFile )
464 : {
465 2 : GCSubType* aSubclass= NULL;
466 : GCExportFileMetadata* m;
467 :
468 2 : if( !(m= GetGCMeta_GCIO(_hGXT)) )
469 : {
470 2 : if( !(m= CreateHeader_GCIO()) )
471 : {
472 0 : CSLDestroy(ft);
473 0 : return NULL;
474 : }
475 2 : SetMetaExtent_GCIO(m, CreateExtent_GCIO(HUGE_VAL,HUGE_VAL,-HUGE_VAL,-HUGE_VAL));
476 2 : SetGCMeta_GCIO(_hGXT, m);
477 : }
478 2 : if( FindFeature_GCIO(_hGXT, pszFeatureType) )
479 : {
480 0 : CSLDestroy(ft);
481 : CPLError( CE_Failure, CPLE_AppDefined,
482 : "Layer '%s' already exists.",
483 0 : pszFeatureType );
484 0 : return NULL;
485 : }
486 2 : if( !AddType_GCIO(_hGXT, ft[0], -1L) )
487 : {
488 0 : CSLDestroy(ft);
489 : CPLError( CE_Failure, CPLE_AppDefined,
490 : "Failed to add layer '%s'.",
491 0 : pszFeatureType );
492 0 : return NULL;
493 : }
494 2 : if( !(aSubclass= AddSubType_GCIO(_hGXT, ft[0], ft[1], -1L, gcioFeaType, gcioDim)) )
495 : {
496 0 : CSLDestroy(ft);
497 : CPLError( CE_Failure, CPLE_AppDefined,
498 : "Failed to add layer '%s'.",
499 0 : pszFeatureType );
500 0 : return NULL;
501 : }
502 : /* complete feature type with private fields : */
503 2 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kIdentifier_GCIO, -100, vIntFld_GCIO, NULL, NULL);
504 2 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kClass_GCIO, -101, vMemoFld_GCIO, NULL, NULL);
505 2 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kSubclass_GCIO, -102, vMemoFld_GCIO, NULL, NULL);
506 2 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kName_GCIO, -103, vMemoFld_GCIO, NULL, NULL);
507 2 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kNbFields_GCIO, -104, vIntFld_GCIO, NULL, NULL);
508 2 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kX_GCIO, -105, vRealFld_GCIO, NULL, NULL);
509 2 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kY_GCIO, -106, vRealFld_GCIO, NULL, NULL);
510 : /* user's fields will be added with Layer->CreateField() method ... */
511 2 : switch( gcioFeaType )
512 : {
513 : case vPoint_GCIO :
514 2 : break;
515 : case vLine_GCIO :
516 0 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kXP_GCIO, -107, vRealFld_GCIO, NULL, NULL);
517 0 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kYP_GCIO, -108, vRealFld_GCIO, NULL, NULL);
518 0 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kGraphics_GCIO, -109, vUnknownItemType_GCIO, NULL, NULL);
519 0 : break;
520 : default :
521 0 : AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kGraphics_GCIO, -109, vUnknownItemType_GCIO, NULL, NULL);
522 : break;
523 : }
524 2 : SetSubTypeGCHandle_GCIO(aSubclass,_hGXT);
525 :
526 : /* Add layer to data source layers list */
527 2 : poFile = new OGRGeoconceptLayer;
528 2 : if( poFile->Open(aSubclass) != OGRERR_NONE )
529 : {
530 0 : CSLDestroy(ft);
531 0 : delete poFile;
532 0 : return NULL;
533 : }
534 :
535 : _papoLayers = (OGRGeoconceptLayer **)
536 2 : CPLRealloc( _papoLayers, sizeof(OGRGeoconceptLayer *) * (_nLayers+1) );
537 2 : _papoLayers[_nLayers++] = poFile;
538 :
539 : CPLDebug("GEOCONCEPT",
540 : "nLayers=%d - last=[%s]",
541 2 : _nLayers, poFile->GetLayerDefn()->GetName());
542 : }
543 2 : CSLDestroy(ft);
544 :
545 : /* -------------------------------------------------------------------- */
546 : /* Assign the coordinate system (if provided) */
547 : /* -------------------------------------------------------------------- */
548 2 : if( poSRS != NULL )
549 2 : poFile->SetSpatialRef( poSRS );
550 :
551 2 : return poFile;
552 : }
553 :
554 : /************************************************************************/
555 : /* TestCapability() */
556 : /************************************************************************/
557 :
558 0 : int OGRGeoconceptDataSource::TestCapability( const char * pszCap )
559 :
560 : {
561 0 : if( EQUAL(pszCap,ODsCCreateLayer) )
562 0 : return TRUE;
563 : else
564 0 : return FALSE;
565 : }
566 :
567 : /************************************************************************/
568 : /* GetLayer() */
569 : /************************************************************************/
570 :
571 8 : OGRLayer *OGRGeoconceptDataSource::GetLayer( int iLayer )
572 :
573 : {
574 : OGRLayer *poFile;
575 8 : if( iLayer < 0 || iLayer >= GetLayerCount() )
576 0 : poFile= NULL;
577 : else
578 8 : poFile= _papoLayers[iLayer];
579 8 : return poFile;
580 : }
|