1 : /******************************************************************************
2 : * $Id: ogrs57datasource.cpp 20996 2010-10-28 18:38:15Z rouault $
3 : *
4 : * Project: S-57 Translator
5 : * Purpose: Implements OGRS57DataSource class
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
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 "ogr_s57.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: ogrs57datasource.cpp 20996 2010-10-28 18:38:15Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRS57DataSource() */
38 : /************************************************************************/
39 :
40 1482 : OGRS57DataSource::OGRS57DataSource()
41 :
42 : {
43 1482 : nLayers = 0;
44 1482 : papoLayers = NULL;
45 :
46 1482 : nModules = 0;
47 1482 : papoModules = NULL;
48 1482 : poWriter = NULL;
49 :
50 1482 : pszName = NULL;
51 :
52 1482 : poSpatialRef = new OGRSpatialReference();
53 1482 : poSpatialRef->SetWellKnownGeogCS( "WGS84" );
54 :
55 1482 : bExtentsSet = FALSE;
56 :
57 :
58 : /* -------------------------------------------------------------------- */
59 : /* Allow initialization of options from the environment. */
60 : /* -------------------------------------------------------------------- */
61 1482 : const char *pszOptString = CPLGetConfigOption( "OGR_S57_OPTIONS", NULL );
62 1482 : papszOptions = NULL;
63 :
64 1482 : if ( pszOptString )
65 : {
66 : char **papszCurOption;
67 :
68 : papszOptions =
69 0 : CSLTokenizeStringComplex( pszOptString, ",", FALSE, FALSE );
70 :
71 0 : if ( papszOptions && *papszOptions )
72 : {
73 0 : CPLDebug( "S57", "The following S57 options are being set:" );
74 0 : papszCurOption = papszOptions;
75 0 : while( *papszCurOption )
76 0 : CPLDebug( "S57", " %s", *papszCurOption++ );
77 : }
78 : }
79 1482 : }
80 :
81 : /************************************************************************/
82 : /* ~OGRS57DataSource() */
83 : /************************************************************************/
84 :
85 1482 : OGRS57DataSource::~OGRS57DataSource()
86 :
87 : {
88 : int i;
89 :
90 1838 : for( i = 0; i < nLayers; i++ )
91 356 : delete papoLayers[i];
92 :
93 1482 : CPLFree( papoLayers );
94 :
95 1494 : for( i = 0; i < nModules; i++ )
96 12 : delete papoModules[i];
97 1482 : CPLFree( papoModules );
98 :
99 1482 : CPLFree( pszName );
100 :
101 1482 : CSLDestroy( papszOptions );
102 :
103 1482 : poSpatialRef->Release();
104 :
105 1482 : if( poWriter != NULL )
106 : {
107 0 : poWriter->Close();
108 0 : delete poWriter;
109 : }
110 1482 : }
111 :
112 : /************************************************************************/
113 : /* SetOptionList() */
114 : /************************************************************************/
115 :
116 0 : void OGRS57DataSource::SetOptionList( char ** papszNewOptions )
117 :
118 : {
119 0 : CSLDestroy( papszOptions );
120 0 : papszOptions = CSLDuplicate( papszNewOptions );
121 0 : }
122 :
123 : /************************************************************************/
124 : /* GetOption() */
125 : /************************************************************************/
126 :
127 108 : const char *OGRS57DataSource::GetOption( const char * pszOption )
128 :
129 : {
130 108 : return CSLFetchNameValue( papszOptions, pszOption );
131 : }
132 :
133 : /************************************************************************/
134 : /* TestCapability() */
135 : /************************************************************************/
136 :
137 0 : int OGRS57DataSource::TestCapability( const char * )
138 :
139 : {
140 0 : return FALSE;
141 : }
142 :
143 : /************************************************************************/
144 : /* Open() */
145 : /************************************************************************/
146 :
147 1482 : int OGRS57DataSource::Open( const char * pszFilename, int bTestOpen )
148 :
149 : {
150 : int iModule;
151 :
152 1482 : pszName = CPLStrdup( pszFilename );
153 :
154 : /* -------------------------------------------------------------------- */
155 : /* Check a few bits of the header to see if it looks like an */
156 : /* S57 file (really, if it looks like an ISO8211 file). */
157 : /* -------------------------------------------------------------------- */
158 1482 : if( bTestOpen )
159 : {
160 : VSILFILE *fp;
161 : char pachLeader[10];
162 :
163 : VSIStatBufL sStatBuf;
164 1482 : if (VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) != 0 ||
165 : VSI_ISDIR(sStatBuf.st_mode))
166 414 : return FALSE;
167 :
168 1068 : fp = VSIFOpenL( pszFilename, "rb" );
169 1068 : if( fp == NULL )
170 0 : return FALSE;
171 :
172 4280 : if( VSIFReadL( pachLeader, 1, 10, fp ) != 10
173 2122 : || (pachLeader[5] != '1' && pachLeader[5] != '2'
174 1054 : && pachLeader[5] != '3' )
175 24 : || pachLeader[6] != 'L'
176 12 : || (pachLeader[8] != '1' && pachLeader[8] != ' ') )
177 : {
178 1056 : VSIFCloseL( fp );
179 1056 : return FALSE;
180 : }
181 :
182 12 : VSIFCloseL( fp );
183 : }
184 :
185 : /* -------------------------------------------------------------------- */
186 : /* Setup reader options. */
187 : /* -------------------------------------------------------------------- */
188 12 : char **papszReaderOptions = NULL;
189 : S57Reader *poModule;
190 :
191 12 : poModule = new S57Reader( pszFilename );
192 :
193 : papszReaderOptions = CSLSetNameValue(papszReaderOptions,
194 12 : S57O_LNAM_REFS, "ON" );
195 12 : if( GetOption(S57O_UPDATES) != NULL )
196 : papszReaderOptions =
197 : CSLSetNameValue( papszReaderOptions, S57O_UPDATES,
198 0 : GetOption(S57O_UPDATES));
199 :
200 12 : if( GetOption(S57O_SPLIT_MULTIPOINT) != NULL )
201 : papszReaderOptions =
202 : CSLSetNameValue( papszReaderOptions, S57O_SPLIT_MULTIPOINT,
203 0 : GetOption(S57O_SPLIT_MULTIPOINT) );
204 :
205 12 : if( GetOption(S57O_ADD_SOUNDG_DEPTH) != NULL )
206 : papszReaderOptions =
207 : CSLSetNameValue( papszReaderOptions, S57O_ADD_SOUNDG_DEPTH,
208 0 : GetOption(S57O_ADD_SOUNDG_DEPTH));
209 :
210 12 : if( GetOption(S57O_PRESERVE_EMPTY_NUMBERS) != NULL )
211 : papszReaderOptions =
212 : CSLSetNameValue( papszReaderOptions, S57O_PRESERVE_EMPTY_NUMBERS,
213 0 : GetOption(S57O_PRESERVE_EMPTY_NUMBERS) );
214 :
215 12 : if( GetOption(S57O_RETURN_PRIMITIVES) != NULL )
216 : papszReaderOptions =
217 : CSLSetNameValue( papszReaderOptions, S57O_RETURN_PRIMITIVES,
218 0 : GetOption(S57O_RETURN_PRIMITIVES) );
219 :
220 12 : if( GetOption(S57O_RETURN_LINKAGES) != NULL )
221 : papszReaderOptions =
222 : CSLSetNameValue( papszReaderOptions, S57O_RETURN_LINKAGES,
223 0 : GetOption(S57O_RETURN_LINKAGES) );
224 :
225 12 : if( GetOption(S57O_RETURN_DSID) != NULL )
226 : papszReaderOptions =
227 : CSLSetNameValue( papszReaderOptions, S57O_RETURN_DSID,
228 0 : GetOption(S57O_RETURN_DSID) );
229 :
230 12 : poModule->SetOptions( papszReaderOptions );
231 12 : CSLDestroy( papszReaderOptions );
232 :
233 : /* -------------------------------------------------------------------- */
234 : /* Try opening. */
235 : /* */
236 : /* Eventually this should check for catalogs, and if found */
237 : /* instantiate a whole series of modules. */
238 : /* -------------------------------------------------------------------- */
239 12 : if( !poModule->Open( bTestOpen ) )
240 : {
241 0 : delete poModule;
242 :
243 0 : return FALSE;
244 : }
245 :
246 12 : int bSuccess = TRUE;
247 :
248 12 : nModules = 1;
249 12 : papoModules = (S57Reader **) CPLMalloc(sizeof(void*));
250 12 : papoModules[0] = poModule;
251 :
252 : /* -------------------------------------------------------------------- */
253 : /* Add the header layers if they are called for. */
254 : /* -------------------------------------------------------------------- */
255 12 : if( GetOption( S57O_RETURN_DSID ) == NULL
256 : || CSLTestBoolean(GetOption( S57O_RETURN_DSID )) )
257 : {
258 : OGRFeatureDefn *poDefn;
259 :
260 12 : poDefn = S57GenerateDSIDFeatureDefn();
261 12 : AddLayer( new OGRS57Layer( this, poDefn ) );
262 : }
263 :
264 : /* -------------------------------------------------------------------- */
265 : /* Add the primitive layers if they are called for. */
266 : /* -------------------------------------------------------------------- */
267 12 : if( GetOption( S57O_RETURN_PRIMITIVES ) != NULL )
268 : {
269 : OGRFeatureDefn *poDefn;
270 :
271 0 : poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VI, poModule->GetOptionFlags());
272 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
273 :
274 0 : poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VC, poModule->GetOptionFlags());
275 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
276 :
277 0 : poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VE, poModule->GetOptionFlags());
278 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
279 :
280 0 : poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VF, poModule->GetOptionFlags());
281 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
282 : }
283 :
284 : /* -------------------------------------------------------------------- */
285 : /* Initialize a layer for each type of geometry. Eventually */
286 : /* we will do this by object class. */
287 : /* -------------------------------------------------------------------- */
288 12 : if( OGRS57Driver::GetS57Registrar() == NULL )
289 : {
290 : OGRFeatureDefn *poDefn;
291 :
292 : poDefn = S57GenerateGeomFeatureDefn( wkbPoint,
293 0 : poModule->GetOptionFlags() );
294 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
295 :
296 : poDefn = S57GenerateGeomFeatureDefn( wkbLineString,
297 0 : poModule->GetOptionFlags() );
298 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
299 :
300 : poDefn = S57GenerateGeomFeatureDefn( wkbPolygon,
301 0 : poModule->GetOptionFlags() );
302 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
303 :
304 : poDefn = S57GenerateGeomFeatureDefn( wkbNone,
305 0 : poModule->GetOptionFlags() );
306 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
307 : }
308 :
309 : /* -------------------------------------------------------------------- */
310 : /* Initialize a feature definition for each class that actually */
311 : /* occurs in the dataset. */
312 : /* -------------------------------------------------------------------- */
313 : else
314 : {
315 : OGRFeatureDefn *poDefn;
316 : int *panClassCount;
317 12 : int iClass, bGeneric = FALSE;
318 :
319 24 : for( iModule = 0; iModule < nModules; iModule++ )
320 12 : papoModules[iModule]->SetClassBased( OGRS57Driver::GetS57Registrar() );
321 :
322 12 : panClassCount = (int *) CPLCalloc(sizeof(int),MAX_CLASSES);
323 :
324 24 : for( iModule = 0; iModule < nModules; iModule++ )
325 : {
326 : bSuccess &=
327 12 : papoModules[iModule]->CollectClassList(panClassCount,
328 24 : MAX_CLASSES);
329 : }
330 :
331 276012 : for( iClass = 0; iClass < MAX_CLASSES; iClass++ )
332 : {
333 276000 : if( panClassCount[iClass] > 0 )
334 : {
335 : poDefn =
336 : S57GenerateObjectClassDefn( OGRS57Driver::GetS57Registrar(),
337 : iClass,
338 366 : poModule->GetOptionFlags() );
339 :
340 366 : if( poDefn != NULL )
341 : AddLayer( new OGRS57Layer( this, poDefn,
342 340 : panClassCount[iClass] ) );
343 : else
344 : {
345 26 : bGeneric = TRUE;
346 : CPLDebug( "S57",
347 : "Unable to find definition for OBJL=%d\n",
348 26 : iClass );
349 : }
350 : }
351 : }
352 :
353 12 : if( bGeneric )
354 : {
355 : poDefn = S57GenerateGeomFeatureDefn( wkbUnknown,
356 4 : poModule->GetOptionFlags() );
357 4 : AddLayer( new OGRS57Layer( this, poDefn ) );
358 : }
359 :
360 12 : CPLFree( panClassCount );
361 : }
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* Attach the layer definitions to each of the readers. */
365 : /* -------------------------------------------------------------------- */
366 24 : for( iModule = 0; iModule < nModules; iModule++ )
367 : {
368 368 : for( int iLayer = 0; iLayer < nLayers; iLayer++ )
369 : {
370 356 : papoModules[iModule]->AddFeatureDefn(
371 712 : papoLayers[iLayer]->GetLayerDefn() );
372 : }
373 : }
374 :
375 12 : return bSuccess;
376 : }
377 :
378 : /************************************************************************/
379 : /* GetLayer() */
380 : /************************************************************************/
381 :
382 278 : OGRLayer *OGRS57DataSource::GetLayer( int iLayer )
383 :
384 : {
385 278 : if( iLayer < 0 || iLayer >= nLayers )
386 0 : return NULL;
387 : else
388 278 : return papoLayers[iLayer];
389 : }
390 :
391 : /************************************************************************/
392 : /* AddLayer() */
393 : /************************************************************************/
394 :
395 356 : void OGRS57DataSource::AddLayer( OGRS57Layer * poNewLayer )
396 :
397 : {
398 : papoLayers = (OGRS57Layer **)
399 356 : CPLRealloc( papoLayers, sizeof(void*) * ++nLayers );
400 :
401 356 : papoLayers[nLayers-1] = poNewLayer;
402 356 : }
403 :
404 : /************************************************************************/
405 : /* GetModule() */
406 : /************************************************************************/
407 :
408 58 : S57Reader * OGRS57DataSource::GetModule( int i )
409 :
410 : {
411 58 : if( i < 0 || i >= nModules )
412 16 : return NULL;
413 : else
414 42 : return papoModules[i];
415 : }
416 :
417 : /************************************************************************/
418 : /* GetDSExtent() */
419 : /************************************************************************/
420 :
421 0 : OGRErr OGRS57DataSource::GetDSExtent( OGREnvelope *psExtent, int bForce )
422 :
423 : {
424 : /* -------------------------------------------------------------------- */
425 : /* If we have it, return it immediately. */
426 : /* -------------------------------------------------------------------- */
427 0 : if( bExtentsSet )
428 : {
429 0 : *psExtent = oExtents;
430 0 : return OGRERR_NONE;
431 : }
432 :
433 0 : if( nModules == 0 )
434 0 : return OGRERR_FAILURE;
435 :
436 : /* -------------------------------------------------------------------- */
437 : /* Otherwise try asking each of the readers for it. */
438 : /* -------------------------------------------------------------------- */
439 0 : for( int iModule=0; iModule < nModules; iModule++ )
440 : {
441 0 : OGREnvelope oModuleEnvelope;
442 : OGRErr eErr;
443 :
444 0 : eErr = papoModules[iModule]->GetExtent( &oModuleEnvelope, bForce );
445 0 : if( eErr != OGRERR_NONE )
446 0 : return eErr;
447 :
448 0 : if( iModule == 0 )
449 0 : oExtents = oModuleEnvelope;
450 : else
451 : {
452 0 : oExtents.MinX = MIN(oExtents.MinX,oModuleEnvelope.MinX);
453 0 : oExtents.MaxX = MAX(oExtents.MaxX,oModuleEnvelope.MaxX);
454 0 : oExtents.MinY = MIN(oExtents.MinY,oModuleEnvelope.MinY);
455 0 : oExtents.MaxX = MAX(oExtents.MaxY,oModuleEnvelope.MaxY);
456 : }
457 : }
458 :
459 0 : *psExtent = oExtents;
460 0 : bExtentsSet = TRUE;
461 :
462 0 : return OGRERR_NONE;
463 : }
464 :
465 : /************************************************************************/
466 : /* Create() */
467 : /* */
468 : /* Create a new S57 file, and represent it as a datasource. */
469 : /************************************************************************/
470 :
471 0 : int OGRS57DataSource::Create( const char *pszFilename, char **papszOptions )
472 :
473 : {
474 : /* -------------------------------------------------------------------- */
475 : /* Instantiate the class registrar if possible. */
476 : /* -------------------------------------------------------------------- */
477 0 : if( OGRS57Driver::GetS57Registrar() == NULL )
478 : {
479 : CPLError( CE_Failure, CPLE_AppDefined,
480 0 : "Unable to load s57objectclasses.csv, unable to continue." );
481 0 : return FALSE;
482 : }
483 :
484 : /* -------------------------------------------------------------------- */
485 : /* Create the S-57 file with definition record. */
486 : /* -------------------------------------------------------------------- */
487 0 : poWriter = new S57Writer();
488 :
489 0 : if( !poWriter->CreateS57File( pszFilename ) )
490 0 : return FALSE;
491 :
492 0 : poWriter->SetClassBased( OGRS57Driver::GetS57Registrar() );
493 0 : pszName = CPLStrdup( pszFilename );
494 :
495 : /* -------------------------------------------------------------------- */
496 : /* Add the primitive layers if they are called for. */
497 : /* -------------------------------------------------------------------- */
498 : OGRFeatureDefn *poDefn;
499 0 : int nOptionFlags = S57M_RETURN_LINKAGES | S57M_LNAM_REFS;
500 :
501 0 : poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VI, nOptionFlags );
502 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
503 :
504 0 : poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VC, nOptionFlags );
505 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
506 :
507 0 : poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VE, nOptionFlags );
508 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
509 :
510 0 : poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VF, nOptionFlags );
511 0 : AddLayer( new OGRS57Layer( this, poDefn ) );
512 :
513 : /* -------------------------------------------------------------------- */
514 : /* Initialize a feature definition for each object class. */
515 : /* -------------------------------------------------------------------- */
516 0 : for( int iClass = 0; iClass < MAX_CLASSES; iClass++ )
517 : {
518 : poDefn =
519 : S57GenerateObjectClassDefn( OGRS57Driver::GetS57Registrar(),
520 0 : iClass, nOptionFlags );
521 :
522 0 : if( poDefn == NULL )
523 0 : continue;
524 :
525 0 : AddLayer( new OGRS57Layer( this, poDefn, 0, iClass ) );
526 : }
527 :
528 : /* -------------------------------------------------------------------- */
529 : /* Write out "header" records. */
530 : /* -------------------------------------------------------------------- */
531 0 : poWriter->WriteDSID( pszFilename, "20010409", "03.1", 540, "" );
532 :
533 0 : poWriter->WriteDSPM();
534 :
535 :
536 0 : return TRUE;
537 : }
|