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