1 /******************************************************************************
2 *
3 * Project: S-57 Translator
4 * Purpose: Implements S57Reader class.
5 * Author: Frank Warmerdam, warmerdam@pobox.com
6 *
7 ******************************************************************************
8 * Copyright (c) 1999, 2001, Frank Warmerdam
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ******************************************************************************
28 *
29 * *
30 */
31
32 #include <assert.h>
33 #include "s57.h"
34 #include "gdal/ogr_api.h"
35 #include "gdal/cpl_conv.h"
36 #include "gdal/cpl_string.h"
37 #include "ogr_s57.h"
38
39 /************************************************************************/
40 /* S57Reader() */
41 /************************************************************************/
42
S57Reader(const char * pszFilename)43 S57Reader::S57Reader( const char * pszFilename )
44
45 {
46 pszModuleName = CPLStrdup( pszFilename );
47 pszDSNM = NULL;
48
49 poModule = NULL;
50
51 nFDefnCount = 0;
52 papoFDefnList = NULL;
53
54 nCOMF = 1000000;
55 nSOMF = 10;
56
57 poRegistrar = NULL;
58 bFileIngested = FALSE;
59
60 nNextFEIndex = 0;
61 nNextVIIndex = 0;
62 nNextVCIndex = 0;
63 nNextVEIndex = 0;
64 nNextVFIndex = 0;
65
66 iPointOffset = 0;
67 poMultiPoint = NULL;
68
69 papszOptions = NULL;
70
71 nOptionFlags = S57M_UPDATES;
72
73 bMissingWarningIssued = FALSE;
74 bAttrWarningIssued = FALSE;
75
76 Nall = 0;
77 Aall = 0;
78 }
79
80 /************************************************************************/
81 /* ~S57Reader() */
82 /************************************************************************/
83
~S57Reader()84 S57Reader::~S57Reader()
85
86 {
87 Close();
88
89 CPLFree( pszModuleName );
90 CSLDestroy( papszOptions );
91
92 CPLFree( papoFDefnList );
93 }
94
95 /************************************************************************/
96 /* Open() */
97 /************************************************************************/
98
Open(int bTestOpen)99 int S57Reader::Open( int bTestOpen )
100
101 {
102 if( poModule != NULL )
103 {
104 Rewind();
105 return TRUE;
106 }
107
108 poModule = new DDFModule();
109 if( !poModule->Open( pszModuleName ) )
110 {
111 // notdef: test bTestOpen.
112 delete poModule;
113 poModule = NULL;
114 return FALSE;
115 }
116
117 // note that the following won't work for catalogs.
118 if( poModule->FindFieldDefn("DSID") == NULL )
119 {
120 if( !bTestOpen )
121 {
122 CPLError( CE_Failure, CPLE_AppDefined,
123 "%s is an ISO8211 file, but not an S-57 data file.\n",
124 pszModuleName );
125 }
126 delete poModule;
127 poModule = NULL;
128 return FALSE;
129 }
130
131 // Make sure the FSPT field is marked as repeating.
132 DDFFieldDefn *poFSPT = poModule->FindFieldDefn( "FSPT" );
133 if( poFSPT != NULL && !poFSPT->IsRepeating() )
134 {
135 CPLDebug( "S57", "Forcing FSPT field to be repeating." );
136 poFSPT->SetRepeatingFlag( TRUE );
137 }
138
139 nNextFEIndex = 0;
140 nNextVIIndex = 0;
141 nNextVCIndex = 0;
142 nNextVEIndex = 0;
143 nNextVFIndex = 0;
144
145 return TRUE;
146 }
147
148 /************************************************************************/
149 /* Close() */
150 /************************************************************************/
151
Close()152 void S57Reader::Close()
153
154 {
155 if( poModule != NULL )
156 {
157 oVI_Index.Clear();
158 oVC_Index.Clear();
159 oVE_Index.Clear();
160 oVF_Index.Clear();
161 oFE_Index.Clear();
162
163 ClearPendingMultiPoint();
164
165 delete poModule;
166 poModule = NULL;
167
168 bFileIngested = FALSE;
169
170 CPLFreeConfig();
171
172 CPLFree( pszDSNM );
173 pszDSNM = NULL;
174 }
175 }
176
177 /************************************************************************/
178 /* ClearPendingMultiPoint() */
179 /************************************************************************/
180
ClearPendingMultiPoint()181 void S57Reader::ClearPendingMultiPoint()
182
183 {
184 if( poMultiPoint != NULL )
185 {
186 delete poMultiPoint;
187 poMultiPoint = NULL;
188 }
189 }
190
191 /************************************************************************/
192 /* NextPendingMultiPoint() */
193 /************************************************************************/
194
NextPendingMultiPoint()195 OGRFeature *S57Reader::NextPendingMultiPoint()
196
197 {
198 CPLAssert( poMultiPoint != NULL );
199 CPLAssert( wkbFlatten(poMultiPoint->GetGeometryRef()->getGeometryType())
200 == wkbMultiPoint );
201
202 OGRFeatureDefn *poDefn = poMultiPoint->GetDefnRef();
203 OGRFeature *poPoint = new OGRFeature( poDefn );
204 OGRMultiPoint *poMPGeom = (OGRMultiPoint *) poMultiPoint->GetGeometryRef();
205 OGRPoint *poSrcPoint;
206
207 poPoint->SetFID( poMultiPoint->GetFID() );
208
209 for( int i = 0; i < poDefn->GetFieldCount(); i++ )
210 {
211 poPoint->SetField( i, poMultiPoint->GetRawFieldRef(i) );
212 }
213
214 poSrcPoint = (OGRPoint *) poMPGeom->getGeometryRef( iPointOffset++ );
215 poPoint->SetGeometry( poSrcPoint );
216
217 poPoint->SetField( "DEPTH", poSrcPoint->getZ() );
218
219 if( iPointOffset >= poMPGeom->getNumGeometries() )
220 ClearPendingMultiPoint();
221
222 return poPoint;
223 }
224
225 /************************************************************************/
226 /* SetOptions() */
227 /************************************************************************/
228
SetOptions(char ** papszOptionsIn)229 void S57Reader::SetOptions( char ** papszOptionsIn )
230
231 {
232 const char * pszOptionValue;
233
234 CSLDestroy( papszOptions );
235 papszOptions = CSLDuplicate( papszOptionsIn );
236
237 pszOptionValue = CSLFetchNameValue( papszOptions, S57O_SPLIT_MULTIPOINT );
238 if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
239 nOptionFlags |= S57M_SPLIT_MULTIPOINT;
240 else
241 nOptionFlags &= ~S57M_SPLIT_MULTIPOINT;
242
243 pszOptionValue = CSLFetchNameValue( papszOptions, S57O_ADD_SOUNDG_DEPTH );
244 if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
245 nOptionFlags |= S57M_ADD_SOUNDG_DEPTH;
246 else
247 nOptionFlags &= ~S57M_ADD_SOUNDG_DEPTH;
248
249 CPLAssert( ! (nOptionFlags & S57M_ADD_SOUNDG_DEPTH)
250 || (nOptionFlags & S57M_SPLIT_MULTIPOINT) );
251
252 pszOptionValue = CSLFetchNameValue( papszOptions, S57O_LNAM_REFS );
253 if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
254 nOptionFlags |= S57M_LNAM_REFS;
255 else
256 nOptionFlags &= ~S57M_LNAM_REFS;
257
258 pszOptionValue = CSLFetchNameValue( papszOptions, S57O_UPDATES );
259 if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
260 nOptionFlags |= S57M_UPDATES;
261 else
262 nOptionFlags &= ~S57M_UPDATES;
263
264 pszOptionValue = CSLFetchNameValue(papszOptions,
265 S57O_PRESERVE_EMPTY_NUMBERS);
266 if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
267 nOptionFlags |= S57M_PRESERVE_EMPTY_NUMBERS;
268 else
269 nOptionFlags &= ~S57M_PRESERVE_EMPTY_NUMBERS;
270
271 pszOptionValue = CSLFetchNameValue( papszOptions, S57O_RETURN_PRIMITIVES );
272 if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
273 nOptionFlags |= S57M_RETURN_PRIMITIVES;
274 else
275 nOptionFlags &= ~S57M_RETURN_PRIMITIVES;
276
277 pszOptionValue = CSLFetchNameValue( papszOptions, S57O_RETURN_LINKAGES );
278 if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
279 nOptionFlags |= S57M_RETURN_LINKAGES;
280 else
281 nOptionFlags &= ~S57M_RETURN_LINKAGES;
282 }
283
284 /************************************************************************/
285 /* SetClassBased() */
286 /************************************************************************/
287
SetClassBased(S57ClassRegistrar * poReg)288 void S57Reader::SetClassBased( S57ClassRegistrar * poReg )
289
290 {
291 poRegistrar = poReg;
292 }
293
294 /************************************************************************/
295 /* Rewind() */
296 /************************************************************************/
297
Rewind()298 void S57Reader::Rewind()
299
300 {
301 ClearPendingMultiPoint();
302 nNextFEIndex = 0;
303 nNextVIIndex = 0;
304 nNextVCIndex = 0;
305 nNextVEIndex = 0;
306 nNextVFIndex = 0;
307 }
308
309 /************************************************************************/
310 /* Ingest() */
311 /* */
312 /* Read all the records into memory, adding to the appropriate */
313 /* indexes. */
314 /************************************************************************/
315
Ingest(CallBackFunction pcallback)316 int S57Reader::Ingest(CallBackFunction pcallback)
317 {
318 DDFRecord *poRecord;
319
320 CPLSetConfigOption( "CPL_DEBUG", "S57" );
321
322 if( poModule == NULL || bFileIngested )
323 return 0;
324
325 /* -------------------------------------------------------------------- */
326 /* Read all the records in the module, and place them in */
327 /* appropriate indexes. */
328 /* -------------------------------------------------------------------- */
329 while( (poRecord = poModule->ReadRecord()) != NULL )
330 {
331 if(pcallback)
332 {
333 if (!(*pcallback)())
334 return 0;
335 }
336
337 DDFField *poKeyField = poRecord->GetField(1);
338 const char *pszname = poKeyField->GetFieldDefn()->GetName();
339
340 if( EQUAL(pszname,"VRID") )
341 {
342 #if 0
343 int nRCNM = poRecord->GetIntSubfield( "VRID",0, "RCNM",0);
344 int nRCID = poRecord->GetIntSubfield( "VRID",0, "RCID",0);
345 #else
346 int nRCNM = 0, nRCID = 0;
347 DDFField *poField = poRecord->FindField( "VRID", 0 );
348 if( poField ) {
349 int nBytesRemaining;
350 DDFSubfieldDefn *poSFDefn;
351 poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( "RCNM" );
352 if( poSFDefn ) {
353 const char *pachData = poField->GetSubfieldData(poSFDefn, &nBytesRemaining, 0);
354 nRCNM = poSFDefn->ExtractIntData( pachData, nBytesRemaining, NULL );
355 }
356
357 poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( "RCID" );
358 if( poSFDefn ) {
359 const char *pachData = poField->GetSubfieldData(poSFDefn, &nBytesRemaining, 0);
360 nRCID = poSFDefn->ExtractIntData( pachData, nBytesRemaining, NULL );
361 }
362 }
363 #endif
364
365 switch( nRCNM )
366 {
367 case RCNM_VI:
368 oVI_Index.AddRecord( nRCID, poRecord->Copy() );
369 break;
370
371 case RCNM_VC:
372 oVC_Index.AddRecord( nRCID, poRecord->Copy() );
373 break;
374
375 case RCNM_VE:
376 oVE_Index.AddRecord( nRCID, poRecord->Copy() );
377 break;
378
379 case RCNM_VF:
380 oVF_Index.AddRecord( nRCID, poRecord->Copy() );
381 break;
382
383 default:
384 CPLAssert( FALSE );
385 break;
386 }
387
388 }
389
390 // Feature records
391 else if( EQUAL(pszname,"FRID") )
392 {
393
394 // poRecord->Dump(stderr); // for debugging, try ./opencpn &>test.dbg
395
396 int nRCID = poRecord->GetIntSubfield( "FRID",0, "RCID",0);
397 oFE_Index.AddRecord( nRCID, poRecord->Copy() );
398
399 }
400
401
402 // Convenience values
403 else if( EQUAL(pszname,"DSPM") )
404 {
405 nCOMF = MAX(1,poRecord->GetIntSubfield( "DSPM",0, "COMF",0));
406 nSOMF = MAX(1,poRecord->GetIntSubfield( "DSPM",0, "SOMF",0));
407 nCSCL = MAX(1,poRecord->GetIntSubfield( "DSPM",0, "CSCL",0));
408
409 }
410
411 else if( EQUAL(pszname,"DSID") )
412 {
413 CPLFree( pszDSNM );
414 pszDSNM = CPLStrdup(poRecord->GetStringSubfield( "DSID", 0, "DSNM", 0 ));
415 Nall = poRecord->GetIntSubfield( "DSSI", 0, "NALL", 0 );
416 Aall = poRecord->GetIntSubfield( "DSSI", 0, "AALL", 0 );
417 }
418
419 else
420 {
421 CPLDebug( "S57",
422 "Skipping %s record in S57Reader::Ingest().\n",
423 poKeyField->GetFieldDefn()->GetName() );
424 }
425
426 }
427
428 bFileIngested = TRUE;
429
430
431 /* -------------------------------------------------------------------- */
432 /* If update support is enabled, read and apply them. */
433 /* -------------------------------------------------------------------- */
434 int update_return = 0;
435 if( nOptionFlags & S57M_UPDATES )
436 update_return = FindAndApplyUpdates();
437
438 return update_return;
439 }
440
441 /************************************************************************/
442 /* SetNextFEIndex() */
443 /************************************************************************/
444
SetNextFEIndex(int nNewIndex,int nRCNM)445 void S57Reader::SetNextFEIndex( int nNewIndex, int nRCNM )
446
447 {
448 if( nRCNM == RCNM_VI )
449 nNextVIIndex = nNewIndex;
450 else if( nRCNM == RCNM_VC )
451 nNextVCIndex = nNewIndex;
452 else if( nRCNM == RCNM_VE )
453 nNextVEIndex = nNewIndex;
454 else if( nRCNM == RCNM_VF )
455 nNextVFIndex = nNewIndex;
456 else
457 {
458 if( nNextFEIndex != nNewIndex )
459 ClearPendingMultiPoint();
460
461 nNextFEIndex = nNewIndex;
462 }
463 }
464
465 /************************************************************************/
466 /* GetNextFEIndex() */
467 /************************************************************************/
468
GetNextFEIndex(int nRCNM)469 int S57Reader::GetNextFEIndex( int nRCNM )
470
471 {
472 if( nRCNM == RCNM_VI )
473 return nNextVIIndex;
474 else if( nRCNM == RCNM_VC )
475 return nNextVCIndex;
476 else if( nRCNM == RCNM_VE )
477 return nNextVEIndex;
478 else if( nRCNM == RCNM_VF )
479 return nNextVFIndex;
480 else
481 return nNextFEIndex;
482 }
483
484 /************************************************************************/
485 /* ReadNextFeature() */
486 /************************************************************************/
487
ReadNextFeature(OGRFeatureDefn * poTarget)488 OGRFeature * S57Reader::ReadNextFeature( OGRFeatureDefn * poTarget )
489
490 {
491 if( !bFileIngested )
492 Ingest();
493
494 /* -------------------------------------------------------------------- */
495 /* Special case for "in progress" multipoints being split up. */
496 /* -------------------------------------------------------------------- */
497 if( poMultiPoint != NULL )
498 {
499 if( poTarget == NULL || poTarget == poMultiPoint->GetDefnRef() )
500 {
501 return NextPendingMultiPoint();
502 }
503 else
504 {
505 ClearPendingMultiPoint();
506 }
507 }
508
509 /* -------------------------------------------------------------------- */
510 /* Next vector feature? */
511 /* -------------------------------------------------------------------- */
512 if( nOptionFlags & S57M_RETURN_PRIMITIVES )
513 {
514 int nRCNM = 0;
515 int *pnCounter = NULL;
516
517 if( poTarget == NULL )
518 {
519 if( nNextVIIndex < oVI_Index.GetCount() )
520 {
521 nRCNM = RCNM_VI;
522 pnCounter = &nNextVIIndex;
523 }
524 else if( nNextVCIndex < oVC_Index.GetCount() )
525 {
526 nRCNM = RCNM_VC;
527 pnCounter = &nNextVCIndex;
528 }
529 else if( nNextVEIndex < oVE_Index.GetCount() )
530 {
531 nRCNM = RCNM_VE;
532 pnCounter = &nNextVEIndex;
533 }
534 else if( nNextVFIndex < oVF_Index.GetCount() )
535 {
536 nRCNM = RCNM_VF;
537 pnCounter = &nNextVFIndex;
538 }
539 }
540 else
541 {
542 if( EQUAL(poTarget->GetName(),OGRN_VI) )
543 {
544 nRCNM = RCNM_VI;
545 pnCounter = &nNextVIIndex;
546 }
547 else if( EQUAL(poTarget->GetName(),OGRN_VC) )
548 {
549 nRCNM = RCNM_VC;
550 pnCounter = &nNextVCIndex;
551 }
552 else if( EQUAL(poTarget->GetName(),OGRN_VE) )
553 {
554 nRCNM = RCNM_VE;
555 pnCounter = &nNextVEIndex;
556 }
557 else if( EQUAL(poTarget->GetName(),OGRN_VF) )
558 {
559 nRCNM = RCNM_VF;
560 pnCounter = &nNextVFIndex;
561 }
562 }
563
564 if( nRCNM != 0 )
565 {
566 OGRFeature *poFeature = ReadVector( *pnCounter, nRCNM );
567 if( poFeature != NULL )
568 {
569 *pnCounter += 1;
570 return poFeature;
571 }
572 }
573 }
574
575 /* -------------------------------------------------------------------- */
576 /* Next feature. */
577 /* -------------------------------------------------------------------- */
578 while( nNextFEIndex < oFE_Index.GetCount() )
579 {
580 OGRFeature *poFeature;
581
582 poFeature = ReadFeature( nNextFEIndex++, poTarget );
583 if( poFeature != NULL )
584 {
585 if( (nOptionFlags & S57M_SPLIT_MULTIPOINT)
586 && poFeature->GetGeometryRef() != NULL
587 && wkbFlatten(poFeature->GetGeometryRef()->getGeometryType())
588 == wkbMultiPoint)
589 {
590 poMultiPoint = poFeature;
591 iPointOffset = 0;
592 return NextPendingMultiPoint();
593 }
594
595 return poFeature;
596 }
597 }
598
599 return NULL;
600 }
601
602
603 /************************************************************************/
604 /* ReadFeature() */
605 /* */
606 /* Read the features who's id is provided. */
607 /************************************************************************/
608 /*
609 OGRFeature *S57Reader::ReadFeature( int nFeatureId, OGRFeatureDefn *poTarget )
610
611 {
612 OGRFeature *poFeature;
613
614 if( nFeatureId < 0 || nFeatureId >= oFE_Index.GetCount() )
615 return NULL;
616
617
618 poFeature = AssembleFeature( oFE_Index.GetByIndex(nFeatureId),
619 poTarget );
620 if( poFeature != NULL )
621 poFeature->SetFID( nFeatureId );
622
623 return poFeature;
624 }
625
626 */
627 /************************************************************************/
628 /* ReadFeature() */
629 /* */
630 /* Read the features who's id is provided. */
631 /************************************************************************/
632
ReadFeature(int nFeatureId,OGRFeatureDefn * poTarget)633 OGRFeature *S57Reader::ReadFeature( int nFeatureId, OGRFeatureDefn *poTarget )
634
635 {
636 OGRFeature *poFeature;
637
638 if( nFeatureId < 0 || nFeatureId >= oFE_Index.GetCount() )
639 return NULL;
640
641 DDFRecord *poRecord = oFE_Index.GetByIndex(nFeatureId);
642
643 if(poTarget)
644 {
645 int nRecord_OBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
646 int nOBJL = poTarget->GetOBJL();
647
648 if(nRecord_OBJL == nOBJL) // tentative match
649 {
650 poFeature = AssembleFeature( oFE_Index.GetByIndex(nFeatureId),
651 poTarget );
652
653 if( poFeature != NULL )
654 poFeature->SetFID( nFeatureId );
655
656 return poFeature;
657 }
658 else
659 return NULL;
660 }
661 else
662 {
663 poFeature = AssembleFeature( oFE_Index.GetByIndex(nFeatureId),
664 poTarget );
665 if( poFeature != NULL )
666 poFeature->SetFID( nFeatureId );
667
668 return poFeature;
669 }
670
671 }
672
673
674 /************************************************************************/
675 /* AssembleFeature() */
676 /* */
677 /* Assemble an OGR feature based on a feature record. */
678 /************************************************************************/
679
AssembleFeature(DDFRecord * poRecord,OGRFeatureDefn * poTarget)680 OGRFeature *S57Reader::AssembleFeature( DDFRecord * poRecord,
681 OGRFeatureDefn * poTarget )
682
683 {
684 int nPRIM, nOBJL;
685 OGRFeatureDefn *poFDefn;
686
687 /* -------------------------------------------------------------------- */
688 /* Find the feature definition to use. Currently this is based */
689 /* on the primitive, but eventually this should be based on the */
690 /* object class (FRID.OBJL) in some cases, and the primitive in */
691 /* others. */
692 /* -------------------------------------------------------------------- */
693 poFDefn = FindFDefn( poRecord );
694 if( poFDefn == NULL ){
695
696 // It is possible that a Feature was added by update, whose Class
697 // was not already present in the module before updates.
698 // So, if necessary, try to create and add an OGRFeatureDefn for this Feature.
699 int nOBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
700 poFDefn = S57GenerateObjectClassDefn( poRegistrar, nOBJL,
701 this->GetOptionFlags() );
702 if(poFDefn)
703 AddFeatureDefn( poFDefn );
704 else
705 return NULL;
706 }
707
708 /* -------------------------------------------------------------------- */
709 /* Does this match our target feature definition? If not skip */
710 /* this feature. */
711 /* -------------------------------------------------------------------- */
712 if( poTarget != NULL && poFDefn != poTarget )
713 return NULL;
714
715 /* -------------------------------------------------------------------- */
716 /* Create the new feature object. */
717 /* -------------------------------------------------------------------- */
718 OGRFeature *poFeature;
719
720 poFeature = new OGRFeature( poFDefn );
721
722 /* -------------------------------------------------------------------- */
723 /* Assign a few standard feature attribues. */
724 /* -------------------------------------------------------------------- */
725 nOBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
726 poFeature->SetField( "OBJL", nOBJL );
727
728 poFeature->SetField( "RCID",
729 poRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ));
730 poFeature->SetField( "PRIM",
731 poRecord->GetIntSubfield( "FRID", 0, "PRIM", 0 ));
732 poFeature->SetField( "GRUP",
733 poRecord->GetIntSubfield( "FRID", 0, "GRUP", 0 ));
734 poFeature->SetField( "RVER",
735 poRecord->GetIntSubfield( "FRID", 0, "RVER", 0 ));
736 poFeature->SetField( "AGEN",
737 poRecord->GetIntSubfield( "FOID", 0, "AGEN", 0 ));
738 poFeature->SetField( "FIDN",
739 poRecord->GetIntSubfield( "FOID", 0, "FIDN", 0 ));
740 poFeature->SetField( "FIDS",
741 poRecord->GetIntSubfield( "FOID", 0, "FIDS", 0 ));
742
743 /* -------------------------------------------------------------------- */
744 /* Generate long name, if requested. */
745 /* -------------------------------------------------------------------- */
746 if( nOptionFlags & S57M_LNAM_REFS )
747 {
748 GenerateLNAMAndRefs( poRecord, poFeature );
749 }
750
751 /* -------------------------------------------------------------------- */
752 /* Generate primitive references if requested. */
753 /* -------------------------------------------------------------------- */
754 if( nOptionFlags & S57M_RETURN_LINKAGES )
755 GenerateFSPTAttributes( poRecord, poFeature );
756
757 /* -------------------------------------------------------------------- */
758 /* Apply object class specific attributes, if supported. */
759 /* -------------------------------------------------------------------- */
760 if( poRegistrar != NULL )
761 ApplyObjectClassAttributes( poRecord, poFeature );
762
763 /* -------------------------------------------------------------------- */
764 /* Find and assign spatial component. */
765 /* -------------------------------------------------------------------- */
766 nPRIM = poRecord->GetIntSubfield( "FRID", 0, "PRIM", 0 );
767
768 if( nPRIM == PRIM_P )
769 {
770 if( nOBJL == 129 ) /* SOUNDG */
771 AssembleSoundingGeometry( poRecord, poFeature );
772 else
773 AssemblePointGeometry( poRecord, poFeature );
774 }
775 else if( nPRIM == PRIM_L )
776 {
777 AssembleLineGeometry( poRecord, poFeature );
778 }
779 else if( nPRIM == PRIM_A )
780 {
781 AssembleAreaGeometry( poRecord, poFeature );
782 }
783
784 return poFeature;
785 }
786
787 /************************************************************************/
788 /* ApplyObjectClassAttributes() */
789 /************************************************************************/
790
ApplyObjectClassAttributes(DDFRecord * poRecord,OGRFeature * poFeature)791 void S57Reader::ApplyObjectClassAttributes( DDFRecord * poRecord,
792 OGRFeature * poFeature )
793
794 {
795 /* -------------------------------------------------------------------- */
796 /* ATTF Attributes */
797 /* -------------------------------------------------------------------- */
798 DDFField *poATTF = poRecord->FindField( "ATTF" );
799 int nAttrCount, iAttr;
800
801 if( poATTF == NULL )
802 return;
803
804 DDFFieldDefn *poDefn = poATTF->GetFieldDefn();
805
806 nAttrCount = poATTF->GetRepeatCount();
807 for( iAttr = 0; iAttr < nAttrCount; iAttr++ )
808 {
809 int nAttrId = poRecord->GetIntSubfield("ATTF",0,"ATTL",iAttr);
810 const char *pszAcronym;
811
812 if( nAttrId < 1 || nAttrId > poRegistrar->GetMaxAttrIndex()
813 || (pszAcronym = poRegistrar->GetAttrAcronym(nAttrId)) == NULL )
814 {
815 if( !bAttrWarningIssued )
816 {
817 bAttrWarningIssued = TRUE;
818 CPLError( CE_Warning, CPLE_AppDefined,
819 "Illegal feature attribute id (ATTF:ATTL[%d]) of %d\n"
820 "on feature FIDN=%d, FIDS=%d.\n"
821 "Skipping attribute, no more warnings will be issued.",
822 iAttr, nAttrId,
823 poFeature->GetFieldAsInteger( "FIDN" ),
824 poFeature->GetFieldAsInteger( "FIDS" ) );
825 }
826
827 continue;
828 }
829
830 /* Fetch the attribute value */
831 const char *pszValue;
832 pszValue = poRecord->GetStringSubfield("ATTF",0,"ATVL",iAttr);
833
834 /* Apply to feature in an appropriate way */
835 int iField;
836 OGRFieldDefn *poFldDefn;
837
838 iField = poFeature->GetDefnRef()->GetFieldIndex(pszAcronym);
839 if( iField < 0 )
840 {
841 if( !bMissingWarningIssued )
842 {
843 bMissingWarningIssued = TRUE;
844 CPLError( CE_Warning, CPLE_AppDefined,
845 "For feature \"%s\", attribute \"%s\" ignored, not in expected schema.\n",
846 poFeature->GetDefnRef()->GetName(), pszAcronym );
847 }
848 continue;
849 }
850
851 // Handle deleted attributes
852 // If the first char of the attribute is 0x7f, then unset this field.
853 // Any later requests for the attribute value will retrun an empty string.
854 if(pszValue[0] == 0x7f)
855 {
856 poFeature->UnsetField( iField );
857 continue;
858 }
859
860 poFldDefn = poFeature->GetDefnRef()->GetFieldDefn( iField );
861 if( poFldDefn->GetType() == OFTInteger
862 || poFldDefn->GetType() == OFTReal )
863 {
864 if( strlen(pszValue) == 0 )
865 {
866 if( nOptionFlags & S57M_PRESERVE_EMPTY_NUMBERS )
867 {
868 poFeature->SetField( iField, EMPTY_NUMBER_MARKER );
869 }
870 else
871 {
872 /* leave as null if value was empty string */;
873 }
874 }
875 else
876 {
877 poFeature->SetField( iField, pszValue );
878 }
879 }
880 else
881 {
882 poFeature->SetField( iField, pszValue );
883 }
884 }
885
886 /* -------------------------------------------------------------------- */
887 /* NATF (national) attributes */
888 /* -------------------------------------------------------------------- */
889 DDFField *poNATF = poRecord->FindField( "NATF" );
890
891 if( poNATF == NULL )
892 return;
893
894 nAttrCount = poNATF->GetRepeatCount();
895 for( iAttr = 0; iAttr < nAttrCount; iAttr++ )
896 {
897 int nAttrId = poRecord->GetIntSubfield("NATF",0,"ATTL",iAttr);
898 const char *pszAcronym;
899
900 if( nAttrId < 1 || nAttrId >= poRegistrar->GetMaxAttrIndex()
901 || (pszAcronym = poRegistrar->GetAttrAcronym(nAttrId)) == NULL )
902 {
903 // poRecord->Dump(stdout);
904 // int xnAttrId = poRecord->GetIntSubfield("NATF",0,"ATTL",iAttr);
905 static int bAttrWarningIssued = FALSE;
906
907 if( !bAttrWarningIssued )
908 {
909 bAttrWarningIssued = TRUE;
910 CPLError( CE_Warning, CPLE_AppDefined,
911 "Illegal feature attribute id (NATF:ATTL[%d]) of %d\n"
912 "on feature FIDN=%d, FIDS=%d.\n"
913 "Skipping attribute, no more warnings will be issued.",
914 iAttr, nAttrId,
915 poFeature->GetFieldAsInteger( "FIDN" ),
916 poFeature->GetFieldAsInteger( "FIDS" ) );
917 }
918
919 continue;
920 }
921
922 const char *pszValue = poRecord->GetStringSubfield("NATF",0,"ATVL",iAttr);
923 if( pszValue != NULL )
924 {
925
926 // If National Language strings are encoded as UCS-2 (a.k.a UTF-16)
927 // then we capture and duplicate the attribute string directly,
928 // in order to avoid truncation that would happen if it were considered a simple char *
929
930 if(Nall==2) { //national string encoded in UCS-2, determined from DSID record
931
932 // Compute the data size
933 DDFField *poField;
934 int nLength = 0;
935 poField = poRecord->FindField( "NATF", 0 );
936 if( poField ) {
937 DDFSubfieldDefn *poSFDefn;
938
939 poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( "ATVL" );
940 if( poSFDefn ) {
941 int max_length = 0;
942 const char *pachData = poField->GetSubfieldData(poSFDefn, &max_length, iAttr);
943 nLength = poSFDefn->GetDataLength( pachData, max_length, NULL);
944 }
945 }
946
947 if( nLength ) {
948 // Make the new length a multiple of 2, so that
949 // later stages will count chars correctly
950 // Also, be sure that the string ends with 00 00
951 int new_len = ((nLength / 2) + 2)*2;
952 char *aa = (char *)calloc(new_len, 1);
953 memcpy(aa, pszValue, nLength);
954
955 int index = poFeature->GetFieldIndex(pszAcronym);
956 OGRField *field = poFeature->GetRawFieldRef( index );
957 field->String = aa;
958 }
959 }
960 else { // encoded as ISO8859_1, pass it along
961 poFeature->SetField(pszAcronym,pszValue);
962 }
963 }
964
965 }
966 }
967
968 /************************************************************************/
969 /* generatelnamandrefs() */
970 /************************************************************************/
971
GenerateLNAMAndRefs(DDFRecord * poRecord,OGRFeature * poFeature)972 void S57Reader::GenerateLNAMAndRefs( DDFRecord * poRecord,
973 OGRFeature * poFeature )
974
975 {
976 char szLNAM[32];
977
978 /* -------------------------------------------------------------------- */
979 /* Apply the LNAM to the object. */
980 /* -------------------------------------------------------------------- */
981 sprintf( szLNAM, "%04X%08X%04X",
982 poFeature->GetFieldAsInteger( "AGEN" ),
983 poFeature->GetFieldAsInteger( "FIDN" ),
984 poFeature->GetFieldAsInteger( "FIDS" ) );
985 poFeature->SetField( "LNAM", szLNAM );
986
987 /* -------------------------------------------------------------------- */
988 /* Do we have references to other features. */
989 /* -------------------------------------------------------------------- */
990 DDFField *poFFPT;
991
992 poFFPT = poRecord->FindField( "FFPT" );
993
994 if( poFFPT == NULL )
995 return;
996
997 /* -------------------------------------------------------------------- */
998 /* Apply references. */
999 /* -------------------------------------------------------------------- */
1000 int nRefCount = poFFPT->GetRepeatCount();
1001 DDFSubfieldDefn *poLNAM;
1002 char **papszRefs = NULL;
1003 int *panRIND = (int *) CPLMalloc(sizeof(int) * nRefCount);
1004
1005 poLNAM = poFFPT->GetFieldDefn()->FindSubfieldDefn( "LNAM" );
1006 if( poLNAM == NULL )
1007 return;
1008
1009 for( int iRef = 0; iRef < nRefCount; iRef++ )
1010 {
1011 unsigned char *pabyData;
1012
1013 pabyData = (unsigned char *)
1014 poFFPT->GetSubfieldData( poLNAM, NULL, iRef );
1015
1016 sprintf( szLNAM, "%02X%02X%02X%02X%02X%02X%02X%02X",
1017 pabyData[1], pabyData[0], /* AGEN */
1018 pabyData[5], pabyData[4], pabyData[3], pabyData[2], /* FIDN */
1019 pabyData[7], pabyData[6] );
1020
1021 papszRefs = CSLAddString( papszRefs, szLNAM );
1022
1023 panRIND[iRef] = pabyData[8];
1024 }
1025
1026 poFeature->SetField( "LNAM_REFS", papszRefs );
1027 CSLDestroy( papszRefs );
1028
1029 poFeature->SetField( "FFPT_RIND", nRefCount, panRIND );
1030 CPLFree( panRIND );
1031 }
1032
1033 /************************************************************************/
1034 /* GenerateFSPTAttributes() */
1035 /************************************************************************/
1036
GenerateFSPTAttributes(DDFRecord * poRecord,OGRFeature * poFeature)1037 void S57Reader::GenerateFSPTAttributes( DDFRecord * poRecord,
1038 OGRFeature * poFeature )
1039
1040 {
1041 /* -------------------------------------------------------------------- */
1042 /* Feature the spatial record containing the point. */
1043 /* -------------------------------------------------------------------- */
1044 DDFField *poFSPT;
1045 int nCount, i;
1046
1047 poFSPT = poRecord->FindField( "FSPT" );
1048 if( poFSPT == NULL )
1049 return;
1050
1051 nCount = poFSPT->GetRepeatCount();
1052
1053 /* -------------------------------------------------------------------- */
1054 /* Allocate working lists of the attributes. */
1055 /* -------------------------------------------------------------------- */
1056 int *panORNT, *panUSAG, *panMASK, *panRCNM, *panRCID;
1057
1058 panORNT = (int *) CPLMalloc( sizeof(int) * nCount );
1059 panUSAG = (int *) CPLMalloc( sizeof(int) * nCount );
1060 panMASK = (int *) CPLMalloc( sizeof(int) * nCount );
1061 panRCNM = (int *) CPLMalloc( sizeof(int) * nCount );
1062 panRCID = (int *) CPLMalloc( sizeof(int) * nCount );
1063
1064 /* -------------------------------------------------------------------- */
1065 /* loop over all entries, decoding them. */
1066 /* -------------------------------------------------------------------- */
1067 for( i = 0; i < nCount; i++ )
1068 {
1069 panRCID[i] = ParseName( poFSPT, i, panRCNM + i );
1070 panORNT[i] = poRecord->GetIntSubfield( "FSPT", 0, "ORNT",i);
1071 panUSAG[i] = poRecord->GetIntSubfield( "FSPT", 0, "USAG",i);
1072 panMASK[i] = poRecord->GetIntSubfield( "FSPT", 0, "MASK",i);
1073 }
1074
1075 /* -------------------------------------------------------------------- */
1076 /* Assign to feature. */
1077 /* -------------------------------------------------------------------- */
1078 poFeature->SetField( "NAME_RCNM", nCount, panRCNM );
1079 poFeature->SetField( "NAME_RCID", nCount, panRCID );
1080 poFeature->SetField( "ORNT", nCount, panORNT );
1081 poFeature->SetField( "USAG", nCount, panUSAG );
1082 poFeature->SetField( "MASK", nCount, panMASK );
1083
1084 /* -------------------------------------------------------------------- */
1085 /* Cleanup. */
1086 /* -------------------------------------------------------------------- */
1087 CPLFree( panRCNM );
1088 CPLFree( panRCID );
1089 CPLFree( panORNT );
1090 CPLFree( panUSAG );
1091 CPLFree( panMASK );
1092 }
1093
1094 /************************************************************************/
1095 /* ReadVector() */
1096 /* */
1097 /* Read a vector primitive objects based on the type (RCNM_) */
1098 /* and index within the related index. */
1099 /************************************************************************/
1100
ReadVector(int nFeatureId,int nRCNM)1101 OGRFeature *S57Reader::ReadVector( int nFeatureId, int nRCNM )
1102
1103 {
1104 DDFRecordIndex *poIndex;
1105 const char *pszFDName = NULL;
1106
1107 /* -------------------------------------------------------------------- */
1108 /* What type of vector are we fetching. */
1109 /* -------------------------------------------------------------------- */
1110 switch( nRCNM )
1111 {
1112 case RCNM_VI:
1113 poIndex = &oVI_Index;
1114 pszFDName = OGRN_VI;
1115 break;
1116
1117 case RCNM_VC:
1118 poIndex = &oVC_Index;
1119 pszFDName = OGRN_VC;
1120 break;
1121
1122 case RCNM_VE:
1123 poIndex = &oVE_Index;
1124 pszFDName = OGRN_VE;
1125 break;
1126
1127 case RCNM_VF:
1128 poIndex = &oVF_Index;
1129 pszFDName = OGRN_VF;
1130 break;
1131
1132 default:
1133 CPLAssert( FALSE );
1134 return NULL;
1135 }
1136
1137 if( nFeatureId < 0 || nFeatureId >= poIndex->GetCount() )
1138 return NULL;
1139
1140 DDFRecord *poRecord = poIndex->GetByIndex( nFeatureId );
1141
1142 /* -------------------------------------------------------------------- */
1143 /* Find the feature definition to use. */
1144 /* -------------------------------------------------------------------- */
1145 OGRFeatureDefn *poFDefn = NULL;
1146
1147 for( int i = 0; i < nFDefnCount; i++ )
1148 {
1149 if( EQUAL(papoFDefnList[i]->GetName(),pszFDName) )
1150 {
1151 poFDefn = papoFDefnList[i];
1152 break;
1153 }
1154 }
1155
1156 if( poFDefn == NULL )
1157 {
1158 CPLAssert( FALSE );
1159 return NULL;
1160 }
1161
1162 /* -------------------------------------------------------------------- */
1163 /* Create feature, and assign standard fields. */
1164 /* -------------------------------------------------------------------- */
1165 OGRFeature *poFeature = new OGRFeature( poFDefn );
1166
1167 poFeature->SetFID( nFeatureId );
1168
1169 poFeature->SetField( "RCNM",
1170 poRecord->GetIntSubfield( "VRID", 0, "RCNM",0) );
1171 poFeature->SetField( "RCID",
1172 poRecord->GetIntSubfield( "VRID", 0, "RCID",0) );
1173 poFeature->SetField( "RVER",
1174 poRecord->GetIntSubfield( "VRID", 0, "RVER",0) );
1175 poFeature->SetField( "RUIN",
1176 poRecord->GetIntSubfield( "VRID", 0, "RUIN",0) );
1177
1178 /* -------------------------------------------------------------------- */
1179 /* Collect point geometries. */
1180 /* -------------------------------------------------------------------- */
1181 if( nRCNM == RCNM_VI || nRCNM == RCNM_VC )
1182 {
1183 double dfX=0.0, dfY=0.0, dfZ=0.0;
1184
1185 if( poRecord->FindField( "SG2D" ) != NULL )
1186 {
1187 dfX = poRecord->GetIntSubfield("SG2D",0,"XCOO",0) / (double)nCOMF;
1188 dfY = poRecord->GetIntSubfield("SG2D",0,"YCOO",0) / (double)nCOMF;
1189 poFeature->SetGeometryDirectly( new OGRPoint( dfX, dfY ) );
1190 }
1191
1192 else if( poRecord->FindField( "SG3D" ) != NULL ) /* presume sounding*/
1193 {
1194 int i, nVCount = poRecord->FindField("SG3D")->GetRepeatCount();
1195 if( nVCount == 1 )
1196 {
1197 dfX =poRecord->GetIntSubfield("SG3D",0,"XCOO",0)/(double)nCOMF;
1198 dfY =poRecord->GetIntSubfield("SG3D",0,"YCOO",0)/(double)nCOMF;
1199 dfZ =poRecord->GetIntSubfield("SG3D",0,"VE3D",0)/(double)nSOMF;
1200 poFeature->SetGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ));
1201 }
1202 else
1203 {
1204 OGRMultiPoint *poMP = new OGRMultiPoint();
1205
1206 for( i = 0; i < nVCount; i++ )
1207 {
1208 dfX = poRecord->GetIntSubfield("SG3D",0,"XCOO",i)
1209 / (double)nCOMF;
1210 dfY = poRecord->GetIntSubfield("SG3D",0,"YCOO",i)
1211 / (double)nCOMF;
1212 dfZ = poRecord->GetIntSubfield("SG3D",0,"VE3D",i)
1213 / (double)nSOMF;
1214
1215 poMP->addGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ) );
1216 }
1217
1218 poFeature->SetGeometryDirectly( poMP );
1219 }
1220 }
1221
1222 }
1223
1224 /* -------------------------------------------------------------------- */
1225 /* Collect an edge geometry. */
1226 /* -------------------------------------------------------------------- */
1227 else if( nRCNM == RCNM_VE && poRecord->FindField( "SG2D" ) != NULL )
1228 {
1229 int i, nVCount = poRecord->FindField("SG2D")->GetRepeatCount();
1230
1231 if(nVCount == 1)
1232 {
1233 // poRecord->Dump(stdout);
1234 OGRLineString *poLine = new OGRLineString();
1235
1236 int jpt = 0;
1237 while(poRecord->FindField( "SG2D", jpt ) != NULL)
1238 {
1239 poLine->setPoint(
1240 jpt,
1241 poRecord->GetIntSubfield("SG2D",jpt,"XCOO",0) / (double)nCOMF,
1242 poRecord->GetIntSubfield("SG2D",jpt,"YCOO",0) / (double)nCOMF );
1243 jpt++;
1244 }
1245
1246 poLine->setNumPoints( jpt );
1247
1248 poFeature->SetGeometryDirectly( poLine );
1249
1250 }
1251 else
1252 {
1253
1254 OGRLineString *poLine = new OGRLineString();
1255
1256 // if(nVCount != 1)
1257 // {
1258 // poRecord->Dump(stdout);
1259 // nVCount = poRecord->FindField("SG2D")->GetRepeatCount();
1260 // }
1261
1262 poLine->setNumPoints( nVCount );
1263
1264 for( i = 0; i < nVCount; i++ )
1265 {
1266 poLine->setPoint(
1267 i,
1268 poRecord->GetIntSubfield("SG2D",0,"XCOO",i) / (double)nCOMF,
1269 poRecord->GetIntSubfield("SG2D",0,"YCOO",i) / (double)nCOMF );
1270 }
1271 poFeature->SetGeometryDirectly( poLine );
1272 }
1273 }
1274
1275 /* -------------------------------------------------------------------- */
1276 /* Special edge fields. */
1277 /* -------------------------------------------------------------------- */
1278 DDFField *poVRPT;
1279
1280 if( nRCNM == RCNM_VE
1281 && (poVRPT = poRecord->FindField( "VRPT" )) != NULL )
1282 {
1283 poFeature->SetField( "NAME_RCNM_0", RCNM_VC );
1284 poFeature->SetField( "NAME_RCID_0", ParseName( poVRPT, 0 ) );
1285 poFeature->SetField( "ORNT_0",
1286 poRecord->GetIntSubfield("VRPT",0,"ORNT",0) );
1287 poFeature->SetField( "USAG_0",
1288 poRecord->GetIntSubfield("VRPT",0,"USAG",0) );
1289 poFeature->SetField( "TOPI_0",
1290 poRecord->GetIntSubfield("VRPT",0,"TOPI",0) );
1291 poFeature->SetField( "MASK_0",
1292 poRecord->GetIntSubfield("VRPT",0,"MASK",0) );
1293
1294
1295 if(poVRPT->GetRepeatCount() > 1)
1296 {
1297 poFeature->SetField( "NAME_RCNM_1", RCNM_VC );
1298 poFeature->SetField( "NAME_RCID_1", ParseName( poVRPT, 1 ) );
1299 poFeature->SetField( "ORNT_1",
1300 poRecord->GetIntSubfield("VRPT",0,"ORNT",1) );
1301 poFeature->SetField( "USAG_1",
1302 poRecord->GetIntSubfield("VRPT",0,"USAG",1) );
1303 poFeature->SetField( "TOPI_1",
1304 poRecord->GetIntSubfield("VRPT",0,"TOPI",1) );
1305 poFeature->SetField( "MASK_1",
1306 poRecord->GetIntSubfield("VRPT",0,"MASK",1) );
1307 }
1308 else
1309 {
1310 DDFField *poVRPTEnd = poRecord->FindField( "VRPT", 1 );
1311
1312 if(poVRPTEnd)
1313 {
1314
1315 poFeature->SetField( "NAME_RCNM_1", RCNM_VC );
1316 poFeature->SetField( "NAME_RCID_1", ParseName( poVRPTEnd, 0 ) );
1317 poFeature->SetField( "ORNT_1",
1318 poRecord->GetIntSubfield("VRPT",1,"ORNT",0) );
1319 poFeature->SetField( "USAG_1",
1320 poRecord->GetIntSubfield("VRPT",1,"USAG",0) );
1321 poFeature->SetField( "TOPI_1",
1322 poRecord->GetIntSubfield("VRPT",1,"TOPI",0) );
1323 poFeature->SetField( "MASK_1",
1324 poRecord->GetIntSubfield("VRPT",1,"MASK",0) );
1325 }
1326 else
1327 CPLDebug( "S57","Vector End Point not found, edge omitted." );
1328 }
1329 }
1330
1331 return poFeature;
1332 }
1333
1334 /************************************************************************/
1335 /* FetchPoint() */
1336 /* */
1337 /* Fetch the location and quality of a spatial point object. */
1338 /************************************************************************/
1339
FetchPoint(int nRCNM,int nRCID,double * pdfX,double * pdfY,double * pdfZ,int * pnquality)1340 int S57Reader::FetchPoint( int nRCNM, int nRCID,
1341 double * pdfX, double * pdfY, double * pdfZ, int * pnquality )
1342
1343 {
1344 DDFRecord *poSRecord;
1345
1346 if( nRCNM == RCNM_VI )
1347 poSRecord = oVI_Index.FindRecord( nRCID );
1348 else
1349 poSRecord = oVC_Index.FindRecord( nRCID );
1350
1351 if( poSRecord == NULL )
1352 return FALSE;
1353
1354 // Fetch the quality information
1355 if(NULL != pnquality)
1356 {
1357 DDFField *f;
1358 if( (f = poSRecord->FindField( "ATTV" )) != NULL )
1359 {
1360 DDFSubfieldDefn *sfd = (f->GetFieldDefn())->FindSubfieldDefn( "ATVL");
1361 if(NULL != sfd)
1362 {
1363 int nSuccess;
1364 char *s = (char *)poSRecord->GetStringSubfield("ATTV",0,"ATVL",0, &nSuccess) ;
1365 if(nSuccess)
1366 {
1367 *pnquality = atoi(s);
1368 }
1369 }
1370 }
1371 }
1372
1373 double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
1374
1375 if( poSRecord->FindField( "SG2D" ) != NULL )
1376 {
1377 dfX = poSRecord->GetIntSubfield("SG2D",0,"XCOO",0) / (double)nCOMF;
1378 dfY = poSRecord->GetIntSubfield("SG2D",0,"YCOO",0) / (double)nCOMF;
1379 }
1380 else if( poSRecord->FindField( "SG3D" ) != NULL )
1381 {
1382 dfX = poSRecord->GetIntSubfield("SG3D",0,"XCOO",0) / (double)nCOMF;
1383 dfY = poSRecord->GetIntSubfield("SG3D",0,"YCOO",0) / (double)nCOMF;
1384 dfZ = poSRecord->GetIntSubfield("SG3D",0,"VE3D",0) / (double)nSOMF;
1385 }
1386 else
1387 return FALSE;
1388
1389 if( pdfX != NULL )
1390 *pdfX = dfX;
1391 if( pdfY != NULL )
1392 *pdfY = dfY;
1393 if( pdfZ != NULL )
1394 *pdfZ = dfZ;
1395
1396 return TRUE;
1397 }
1398
1399 /************************************************************************/
1400 /* AssemblePointGeometry() */
1401 /************************************************************************/
1402
AssemblePointGeometry(DDFRecord * poFRecord,OGRFeature * poFeature)1403 void S57Reader::AssemblePointGeometry( DDFRecord * poFRecord,
1404 OGRFeature * poFeature )
1405
1406 {
1407 DDFField *poFSPT;
1408 int nRCNM, nRCID;
1409
1410 /* -------------------------------------------------------------------- */
1411 /* Feature the spatial record containing the point. */
1412 /* -------------------------------------------------------------------- */
1413 poFSPT = poFRecord->FindField( "FSPT" );
1414 if( poFSPT == NULL )
1415 return;
1416
1417 if( poFSPT->GetRepeatCount() != 1 )
1418 {
1419 #ifdef DEBUG
1420 fprintf( stderr,
1421 "Point features with other than one spatial linkage.\n" );
1422 poFRecord->Dump( stderr );
1423 #endif
1424 CPLDebug( "S57",
1425 "Point feature encountered with other than one spatial linkage." );
1426 }
1427
1428 nRCID = ParseName( poFSPT, 0, &nRCNM );
1429
1430 double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
1431
1432 int nquality = 10; // default is "precisely known"
1433 if( !FetchPoint( nRCNM, nRCID, &dfX, &dfY, &dfZ, &nquality ) )
1434 {
1435 CPLAssert( FALSE );
1436 return;
1437 }
1438
1439 poFeature->SetGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ) );
1440 OGRPoint * pp = (OGRPoint *)poFeature->GetGeometryRef();
1441 pp->setnQual(nquality);
1442 }
1443
1444 /************************************************************************/
1445 /* AssembleSoundingGeometry() */
1446 /************************************************************************/
1447
AssembleSoundingGeometry(DDFRecord * poFRecord,OGRFeature * poFeature)1448 void S57Reader::AssembleSoundingGeometry( DDFRecord * poFRecord,
1449 OGRFeature * poFeature )
1450
1451 {
1452 DDFField *poFSPT;
1453 int nRCNM, nRCID;
1454 DDFRecord *poSRecord;
1455
1456
1457 /* -------------------------------------------------------------------- */
1458 /* Feature the spatial record containing the point. */
1459 /* -------------------------------------------------------------------- */
1460 poFSPT = poFRecord->FindField( "FSPT" );
1461 if( poFSPT == NULL )
1462 return;
1463
1464 CPLAssert( poFSPT->GetRepeatCount() == 1 );
1465
1466 nRCID = ParseName( poFSPT, 0, &nRCNM );
1467
1468 if( nRCNM == RCNM_VI )
1469 poSRecord = oVI_Index.FindRecord( nRCID );
1470 else
1471 poSRecord = oVC_Index.FindRecord( nRCID );
1472
1473 if( poSRecord == NULL )
1474 return;
1475
1476 /* -------------------------------------------------------------------- */
1477 /* Extract vertices. */
1478 /* -------------------------------------------------------------------- */
1479 OGRMultiPoint *poMP = new OGRMultiPoint();
1480 DDFField *poField;
1481 int nPointCount, i, nBytesLeft;
1482 DDFSubfieldDefn *poXCOO, *poYCOO, *poVE3D;
1483 const char *pachData;
1484
1485 poField = poSRecord->FindField( "SG2D" );
1486 if( poField == NULL )
1487 poField = poSRecord->FindField( "SG3D" );
1488 if( poField == NULL )
1489 return;
1490
1491 poXCOO = poField->GetFieldDefn()->FindSubfieldDefn( "XCOO" );
1492 poYCOO = poField->GetFieldDefn()->FindSubfieldDefn( "YCOO" );
1493 poVE3D = poField->GetFieldDefn()->FindSubfieldDefn( "VE3D" );
1494
1495 nPointCount = poField->GetRepeatCount();
1496
1497 pachData = poField->GetData();
1498 nBytesLeft = poField->GetDataSize();
1499
1500 for( i = 0; i < nPointCount; i++ )
1501 {
1502 double dfX, dfY, dfZ = 0.0;
1503 int nBytesConsumed;
1504
1505 dfY = poYCOO->ExtractIntData( pachData, nBytesLeft,
1506 &nBytesConsumed ) / (double) nCOMF;
1507 nBytesLeft -= nBytesConsumed;
1508 pachData += nBytesConsumed;
1509
1510 dfX = poXCOO->ExtractIntData( pachData, nBytesLeft,
1511 &nBytesConsumed ) / (double) nCOMF;
1512 nBytesLeft -= nBytesConsumed;
1513 pachData += nBytesConsumed;
1514
1515 if( poVE3D != NULL )
1516 {
1517 dfZ = poYCOO->ExtractIntData( pachData, nBytesLeft,
1518 &nBytesConsumed ) / (double) nSOMF;
1519 nBytesLeft -= nBytesConsumed;
1520 pachData += nBytesConsumed;
1521 }
1522
1523 poMP->addGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ) );
1524 }
1525
1526 poFeature->SetGeometryDirectly( poMP );
1527 }
1528
1529 /************************************************************************/
1530 /* AssembleLineGeometry() */
1531 /************************************************************************/
1532
AssembleLineGeometry(DDFRecord * poFRecord,OGRFeature * poFeature)1533 void S57Reader::AssembleLineGeometry( DDFRecord * poFRecord,
1534 OGRFeature * poFeature )
1535
1536 {
1537 DDFField *poFSPT;
1538 int nEdgeCount;
1539 OGRLineString *poLine = new OGRLineString();
1540
1541 /* -------------------------------------------------------------------- */
1542 /* Find the FSPT field. */
1543 /* -------------------------------------------------------------------- */
1544 poFSPT = poFRecord->FindField( "FSPT" );
1545 if( poFSPT == NULL )
1546 return;
1547
1548 nEdgeCount = poFSPT->GetRepeatCount();
1549
1550 /* ==================================================================== */
1551 /* Loop collecting edges. */
1552 /* ==================================================================== */
1553 for( int iEdge = 0; iEdge < nEdgeCount; iEdge++ )
1554 {
1555 DDFRecord *poSRecord;
1556 int nRCID;
1557
1558 /* -------------------------------------------------------------------- */
1559 /* Find the spatial record for this edge. */
1560 /* -------------------------------------------------------------------- */
1561 nRCID = ParseName( poFSPT, iEdge );
1562
1563 poSRecord = oVE_Index.FindRecord( nRCID );
1564 if( poSRecord == NULL )
1565 {
1566 CPLError( CE_Warning, CPLE_AppDefined,
1567 "Couldn't find spatial record %d.\n"
1568 "Feature OBJL=%s, RCID=%d may have corrupt or"
1569 "missing geometry.",
1570 nRCID,
1571 poFeature->GetDefnRef()->GetName(),
1572 poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
1573 continue;
1574 }
1575
1576 /* -------------------------------------------------------------------- */
1577 /* Establish the number of vertices, and whether we need to */
1578 /* reverse or not. */
1579 /* -------------------------------------------------------------------- */
1580 int nVCount;
1581 int nStart, nEnd, nInc;
1582 DDFField *poSG2D = poSRecord->FindField( "SG2D" );
1583 DDFSubfieldDefn *poXCOO=NULL, *poYCOO=NULL;
1584
1585 if( poSG2D != NULL )
1586 {
1587 poXCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("XCOO");
1588 poYCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("YCOO");
1589
1590 nVCount = poSG2D->GetRepeatCount();
1591 }
1592 else
1593 nVCount = 0;
1594
1595 DDFField * poField = poSRecord->FindField( "VRPT" );
1596 int nVC_RCID0 = 0;
1597 int nVC_RCID1 = 0;
1598 int nVC_RCIDStart, nVC_RCIDEnd;
1599
1600 if( poField == NULL )
1601 {
1602 CPLError( CE_Warning, CPLE_AppDefined,
1603 "Couldn't find field VRPT in spatial record %d.\n"
1604 "Feature OBJL=%s, RCID=%d may have corrupt or"
1605 "missing geometry.",
1606 nRCID,
1607 poFeature->GetDefnRef()->GetName(),
1608 poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
1609 continue;
1610 }
1611
1612 if(poField->GetRepeatCount() > 1)
1613 {
1614 nVC_RCID0 = ParseName( poField, 0 );
1615 nVC_RCID1 = ParseName( poField, 1 );
1616 }
1617 else
1618 {
1619 nVC_RCID0 = ParseName( poField, 0 );
1620 DDFField * poFieldEnd = poSRecord->FindField( "VRPT", 1 );
1621 if(poFieldEnd)
1622 nVC_RCID1 = ParseName( poFieldEnd, 0 );
1623 }
1624
1625
1626 if( poFRecord->GetIntSubfield( "FSPT", 0, "ORNT", iEdge ) == 2 )
1627 {
1628 nStart = nVCount-1;
1629 nEnd = 0;
1630 nInc = -1;
1631 nVC_RCIDStart = nVC_RCID1; // reversed
1632 nVC_RCIDEnd = nVC_RCID0;
1633 }
1634 else
1635 {
1636 nStart = 0;
1637 nEnd = nVCount-1;
1638 nInc = 1;
1639 nVC_RCIDStart = nVC_RCID0;
1640 nVC_RCIDEnd = nVC_RCID1;
1641 }
1642
1643 /* -------------------------------------------------------------------- */
1644 /* Add the start node, if this is the first edge. */
1645 /* -------------------------------------------------------------------- */
1646 if( iEdge == 0 )
1647 {
1648 int nVC_RCID = 0;
1649 double dfX, dfY;
1650 /*
1651 if(poField)
1652 {
1653 if( nInc == 1 )
1654 nVC_RCID = ParseName( poField, 0 );
1655 else
1656 nVC_RCID = ParseName( poField, 1 );
1657 }
1658 */
1659
1660 if( FetchPoint( RCNM_VC, nVC_RCIDStart, &dfX, &dfY ) )
1661 poLine->addPoint( dfX, dfY );
1662 else
1663 CPLError( CE_Warning, CPLE_AppDefined,
1664 "Unable to fetch start node RCID%d.\n"
1665 "Feature OBJL=%s, RCID=%d may have corrupt or"
1666 " missing geometry.",
1667 nVC_RCID,
1668 poFeature->GetDefnRef()->GetName(),
1669 poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
1670 }
1671
1672 /* -------------------------------------------------------------------- */
1673 /* Collect the vertices. */
1674 /* -------------------------------------------------------------------- */
1675 int nVBase = poLine->getNumPoints();
1676
1677 if(nVCount == 1)
1678 {
1679 int jpt = 0;
1680 while(poSRecord->FindField( "SG2D", jpt ))
1681 {
1682 poLine->addPoint(
1683 poSRecord->GetIntSubfield("SG2D",jpt,"XCOO",0) / (double)nCOMF,
1684 poSRecord->GetIntSubfield("SG2D",jpt,"YCOO",0) / (double)nCOMF );
1685 jpt++;
1686
1687 }
1688 }
1689 else
1690 {
1691
1692 poLine->setNumPoints( nVCount+nVBase );
1693
1694 for( int i = nStart; i != nEnd+nInc; i += nInc )
1695 {
1696 double dfX, dfY;
1697 const char *pachData;
1698 int nBytesRemaining;
1699
1700 pachData = poSG2D->GetSubfieldData(poXCOO,&nBytesRemaining,i);
1701
1702 dfX = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
1703 / (double) nCOMF;
1704
1705 pachData = poSG2D->GetSubfieldData(poYCOO,&nBytesRemaining,i);
1706
1707 dfY = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
1708 / (double) nCOMF;
1709
1710 poLine->setPoint( nVBase++, dfX, dfY );
1711 }
1712 }
1713
1714 /* -------------------------------------------------------------------- */
1715 /* Add the end node. */
1716 /* -------------------------------------------------------------------- */
1717 {
1718 int nVC_RCID = 0;
1719 double dfX, dfY;
1720 /*
1721 if(poField)
1722 {
1723 if( nInc == 1 )
1724 nVC_RCID = ParseName( poField, 1 );
1725 else
1726 nVC_RCID = ParseName( poField, 0 );
1727 }
1728 */
1729 if( FetchPoint( RCNM_VC, nVC_RCIDEnd, &dfX, &dfY ) )
1730 poLine->addPoint( dfX, dfY );
1731 else
1732 CPLError( CE_Warning, CPLE_AppDefined,
1733 "Unable to fetch end node RCID=%d.\n"
1734 "Feature OBJL=%s, RCID=%d may have corrupt or"
1735 " missing geometry.",
1736 nVC_RCID,
1737 poFeature->GetDefnRef()->GetName(),
1738 poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
1739 }
1740 }
1741
1742 if( poLine->getNumPoints() >= 2 )
1743 poFeature->SetGeometryDirectly( poLine );
1744 else
1745 delete poLine;
1746 }
1747
1748 /************************************************************************/
1749 /* AssembleAreaGeometry() */
1750 /************************************************************************/
1751
AssembleAreaGeometry(DDFRecord * poFRecord,OGRFeature * poFeature)1752 void S57Reader::AssembleAreaGeometry( DDFRecord * poFRecord,
1753 OGRFeature * poFeature )
1754
1755 {
1756 DDFField *poFSPT;
1757 OGRGeometryCollection * poLines = new OGRGeometryCollection();
1758 // poFRecord->Dump(stdout);
1759 /* -------------------------------------------------------------------- */
1760 /* Find the FSPT fields. */
1761 /* -------------------------------------------------------------------- */
1762 for( int iFSPT = 0;
1763 (poFSPT = poFRecord->FindField( "FSPT", iFSPT )) != NULL;
1764 iFSPT++ )
1765 {
1766 int nEdgeCount;
1767
1768 nEdgeCount = poFSPT->GetRepeatCount();
1769
1770 /* ==================================================================== */
1771 /* Loop collecting edges. */
1772 /* ==================================================================== */
1773 for( int iEdge = 0; iEdge < nEdgeCount; iEdge++ )
1774 {
1775 DDFRecord *poSRecord;
1776 int nRCID;
1777
1778 /* -------------------------------------------------------------------- */
1779 /* Find the spatial record for this edge. */
1780 /* -------------------------------------------------------------------- */
1781 nRCID = ParseName( poFSPT, iEdge );
1782
1783 poSRecord = oVE_Index.FindRecord( nRCID );
1784 if( poSRecord == NULL )
1785 {
1786 CPLError( CE_Warning, CPLE_AppDefined,
1787 "Couldn't find spatial record %d.", nRCID );
1788 continue;
1789 }
1790
1791 /* -------------------------------------------------------------------- */
1792 /* Establish the number of vertices, and whether we need to */
1793 /* reverse or not. */
1794 /* -------------------------------------------------------------------- */
1795 // poSRecord->Dump(stdout);
1796
1797 OGRLineString *poLine = new OGRLineString();
1798
1799 int nVCount;
1800 int nStart, nEnd, nInc;
1801 DDFField *poSG2D = poSRecord->FindField( "SG2D" );
1802 DDFSubfieldDefn *poXCOO=NULL, *poYCOO=NULL;
1803
1804 if( poSG2D != NULL )
1805 {
1806 poXCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("XCOO");
1807 poYCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("YCOO");
1808
1809 nVCount = poSG2D->GetRepeatCount();
1810 }
1811 else
1812 nVCount = 0;
1813
1814 DDFField * poField = poSRecord->FindField( "VRPT" );
1815 int nVC_RCID0 = 0;
1816 int nVC_RCID1 = 0;
1817 int nVC_RCIDStart, nVC_RCIDEnd;
1818
1819 if(poField && poField->GetRepeatCount() > 1)
1820 {
1821 nVC_RCID0 = ParseName( poField, 0 );
1822 nVC_RCID1 = ParseName( poField, 1 );
1823 }
1824 else
1825 {
1826 if (poField)
1827 nVC_RCID0 = ParseName( poField, 0 );
1828 DDFField * poFieldEnd = poSRecord->FindField( "VRPT", 1 );
1829 if(poFieldEnd)
1830 nVC_RCID1 = ParseName( poFieldEnd, 0 );
1831 }
1832
1833
1834 if( poFRecord->GetIntSubfield( "FSPT", 0, "ORNT", iEdge ) == 2 )
1835 {
1836 nStart = nVCount-1;
1837 nEnd = 0;
1838 nInc = -1;
1839 nVC_RCIDStart = nVC_RCID1; // reversed
1840 nVC_RCIDEnd = nVC_RCID0;
1841 }
1842 else
1843 {
1844 nStart = 0;
1845 nEnd = nVCount-1;
1846 nInc = 1;
1847 nVC_RCIDStart = nVC_RCID0;
1848 nVC_RCIDEnd = nVC_RCID1;
1849 }
1850
1851
1852 /* -------------------------------------------------------------------- */
1853 /* Add the start node. */
1854 /* -------------------------------------------------------------------- */
1855 {
1856 double dfX, dfY;
1857
1858 if( FetchPoint( RCNM_VC, nVC_RCIDStart, &dfX, &dfY ) )
1859 poLine->addPoint( dfX, dfY );
1860 }
1861
1862 /* -------------------------------------------------------------------- */
1863 /* Collect the vertices. */
1864 /* -------------------------------------------------------------------- */
1865 int nVBase = poLine->getNumPoints();
1866
1867 if(nVCount == 1)
1868 {
1869 int jpt = 0;
1870 while(poSRecord->FindField( "SG2D", jpt ))
1871 {
1872 poLine->addPoint(
1873 poSRecord->GetIntSubfield("SG2D",jpt,"XCOO",0) / (double)nCOMF,
1874 poSRecord->GetIntSubfield("SG2D",jpt,"YCOO",0) / (double)nCOMF );
1875 jpt++;
1876
1877 }
1878 }
1879 else
1880 {
1881 poLine->setNumPoints( nVCount+nVBase );
1882
1883 for( int i = nStart; i != nEnd+nInc; i += nInc )
1884 {
1885 double dfX, dfY;
1886 const char *pachData;
1887 int nBytesRemaining;
1888
1889 pachData = poSG2D->GetSubfieldData(poXCOO,&nBytesRemaining,i);
1890
1891 dfX = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL) / (double) nCOMF;
1892
1893 pachData = poSG2D->GetSubfieldData(poYCOO,&nBytesRemaining,i);
1894
1895 dfY = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL) / (double) nCOMF;
1896
1897 poLine->setPoint( nVBase++, dfX, dfY );
1898 }
1899
1900 }
1901 /* -------------------------------------------------------------------- */
1902 /* Add the end node. */
1903 /* -------------------------------------------------------------------- */
1904 {
1905 double dfX, dfY;
1906
1907
1908 if( FetchPoint( RCNM_VC, nVC_RCIDEnd, &dfX, &dfY ) )
1909 poLine->addPoint( dfX, dfY );
1910 }
1911
1912 poLines->addGeometryDirectly( poLine );
1913 }
1914 }
1915
1916 /* -------------------------------------------------------------------- */
1917 /* Build lines into a polygon. */
1918 /* -------------------------------------------------------------------- */
1919 OGRPolygon *poPolygon;
1920 OGRErr eErr;
1921
1922 poPolygon = (OGRPolygon *)
1923 OGRBuildPolygonFromEdges( (OGRGeometryH) poLines,
1924 TRUE, FALSE, 0.0, &eErr );
1925 if( eErr != OGRERR_NONE )
1926 {
1927 CPLError( CE_Warning, CPLE_AppDefined,
1928 "Polygon assembly has failed for feature FIDN=%d,FIDS=%d.\n"
1929 "Geometry may be missing or incomplete.",
1930 poFeature->GetFieldAsInteger( "FIDN" ),
1931 poFeature->GetFieldAsInteger( "FIDS" ) );
1932 }
1933
1934 delete poLines;
1935
1936 if( poPolygon != NULL )
1937 poFeature->SetGeometryDirectly( poPolygon );
1938 }
1939
1940 /************************************************************************/
1941 /* FindFDefn() */
1942 /* */
1943 /* Find the OGRFeatureDefn corresponding to the passed feature */
1944 /* record. It will search based on geometry class, or object */
1945 /* class depending on the bClassBased setting. */
1946 /************************************************************************/
1947
FindFDefn(DDFRecord * poRecord)1948 OGRFeatureDefn * S57Reader::FindFDefn( DDFRecord * poRecord )
1949
1950 {
1951 if( poRegistrar != NULL )
1952 {
1953 int nOBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
1954
1955 if( !poRegistrar->SelectClass( nOBJL ) )
1956 {
1957 for( int i = 0; i < nFDefnCount; i++ )
1958 {
1959 if( EQUAL(papoFDefnList[i]->GetName(),"Generic") )
1960 return papoFDefnList[i];
1961 }
1962 return NULL;
1963 }
1964
1965 for( int i = 0; i < nFDefnCount; i++ )
1966 {
1967 if( EQUAL(papoFDefnList[i]->GetName(),
1968 poRegistrar->GetAcronym()) )
1969 return papoFDefnList[i];
1970 }
1971
1972 return NULL;
1973 }
1974 else
1975 {
1976 int nPRIM = poRecord->GetIntSubfield( "FRID", 0, "PRIM", 0 );
1977 OGRwkbGeometryType eGType;
1978
1979 if( nPRIM == PRIM_P )
1980 eGType = wkbPoint;
1981 else if( nPRIM == PRIM_L )
1982 eGType = wkbLineString;
1983 else if( nPRIM == PRIM_A )
1984 eGType = wkbPolygon;
1985 else
1986 eGType = wkbNone;
1987
1988 for( int i = 0; i < nFDefnCount; i++ )
1989 {
1990 if( papoFDefnList[i]->GetGeomType() == eGType )
1991 return papoFDefnList[i];
1992 }
1993 }
1994
1995 return NULL;
1996 }
1997
1998 /************************************************************************/
1999 /* ParseName() */
2000 /* */
2001 /* Pull the RCNM and RCID values from a NAME field. The RCID */
2002 /* is returned and the RCNM can be gotten via the pnRCNM argument. */
2003 /************************************************************************/
2004
ParseName(DDFField * poField,int nIndex,int * pnRCNM)2005 int S57Reader::ParseName( DDFField * poField, int nIndex, int * pnRCNM )
2006
2007 {
2008 unsigned char *pabyData;
2009
2010 pabyData = (unsigned char *)
2011 poField->GetSubfieldData(
2012 poField->GetFieldDefn()->FindSubfieldDefn( "NAME" ),
2013 NULL, nIndex );
2014
2015 if( pnRCNM != NULL )
2016 *pnRCNM = pabyData[0];
2017
2018 return pabyData[1]
2019 + pabyData[2] * 256
2020 + pabyData[3] * 256 * 256
2021 + pabyData[4] * 256 * 256 * 256;
2022 }
2023
2024 /************************************************************************/
2025 /* AddFeatureDefn() */
2026 /************************************************************************/
2027
AddFeatureDefn(OGRFeatureDefn * poFDefn)2028 void S57Reader::AddFeatureDefn( OGRFeatureDefn * poFDefn )
2029
2030 {
2031 nFDefnCount++;
2032 papoFDefnList = (OGRFeatureDefn **)
2033 CPLRealloc(papoFDefnList, sizeof(OGRFeatureDefn*)*nFDefnCount );
2034
2035 papoFDefnList[nFDefnCount-1] = poFDefn;
2036 }
2037
2038 /************************************************************************/
2039 /* CollectClassList() */
2040 /* */
2041 /* Establish the list of classes (unique OBJL values) that */
2042 /* occur in this dataset. */
2043 /************************************************************************/
2044
CollectClassList(int * panClassCount,int nMaxClass)2045 int S57Reader::CollectClassList(int *panClassCount, int nMaxClass )
2046
2047 {
2048 int bSuccess = TRUE;
2049
2050 if( !bFileIngested )
2051 Ingest();
2052
2053 for( int iFEIndex = 0; iFEIndex < oFE_Index.GetCount(); iFEIndex++ )
2054 {
2055 DDFRecord *poRecord = oFE_Index.GetByIndex( iFEIndex );
2056 int nOBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
2057
2058 if( nOBJL >= nMaxClass )
2059 bSuccess = FALSE;
2060 else
2061 panClassCount[nOBJL]++;
2062
2063 }
2064
2065 return bSuccess;
2066 }
2067
2068 /************************************************************************/
2069 /* ApplyRecordUpdate() */
2070 /* */
2071 /* Update one target record based on an S-57 update record */
2072 /* (RUIN=3). */
2073 /************************************************************************/
2074
ApplyRecordUpdate(DDFRecord * poTarget,DDFRecord * poUpdate)2075 int S57Reader::ApplyRecordUpdate( DDFRecord *poTarget, DDFRecord *poUpdate )
2076
2077 {
2078 const char *pszKey = poUpdate->GetField(1)->GetFieldDefn()->GetName();
2079
2080 /* -------------------------------------------------------------------- */
2081 /* Validate versioning. */
2082 /* -------------------------------------------------------------------- */
2083 if( poTarget->GetIntSubfield( pszKey, 0, "RVER", 0 ) + 1
2084 != poUpdate->GetIntSubfield( pszKey, 0, "RVER", 0 ) )
2085 {
2086 CPLError( CE_Warning, CPLE_AppDefined,
2087 "On RecordUpdate, mismatched RVER value for RCNM=%d,RCID=%d...update RVER is %d, target RVER is %d.",
2088 poTarget->GetIntSubfield( pszKey, 0, "RCNM", 0 ),
2089 poTarget->GetIntSubfield( pszKey, 0, "RCID", 0 ),
2090 poUpdate->GetIntSubfield( pszKey, 0, "RVER", 0 ),
2091 poTarget->GetIntSubfield( pszKey, 0, "RVER", 0 ) );
2092
2093 CPLAssert( FALSE );
2094 return FALSE;
2095 }
2096
2097 // More checks for validity
2098 if( poUpdate->FindField( "FRID" ) != NULL )
2099 {
2100 /*
2101 int up_FIDN = poUpdate->GetIntSubfield( "FOID", 0, "FIDN", 0 );
2102 int up_FIDS = poUpdate->GetIntSubfield( "FOID", 0, "FIDS", 0 );
2103 int tar_FIDN = poTarget->GetIntSubfield( "FOID", 0, "FIDN", 0 );
2104 int tar_FIDS = poTarget->GetIntSubfield( "FOID", 0, "FIDS", 0 );
2105 if((up_FIDN != tar_FIDN) || (up_FIDS != tar_FIDS))
2106 {
2107 CPLError( CE_Warning, CPLE_AppDefined,
2108 "On RecordUpdate, mismatched FIDN/FIDS.... target FIDN=%d, target FIDS=%d update FIDN=%d, update FIDS=%d.",
2109 tar_FIDN, tar_FIDS, up_FIDN, up_FIDS);
2110
2111 return FALSE;
2112 }
2113 */
2114 int up_PRIM = poUpdate->GetIntSubfield( "FRID", 0, "PRIM", 0 );
2115 int tar_PRIM = poTarget->GetIntSubfield( "FRID", 0, "PRIM", 0 );
2116 if(up_PRIM != tar_PRIM)
2117 {
2118 CPLError( CE_Warning, CPLE_AppDefined,
2119 "On RecordUpdate, mismatched PRIM.... target PRIM=%d, update PRIM=%d",
2120 tar_PRIM, up_PRIM);
2121 return FALSE;
2122 }
2123 }
2124
2125
2126 /* -------------------------------------------------------------------- */
2127 /* Update the target version. */
2128 /* -------------------------------------------------------------------- */
2129 unsigned int *pnRVER;
2130 DDFField *poKey = poTarget->FindField( pszKey );
2131 DDFSubfieldDefn *poRVER_SFD;
2132
2133 if( poKey == NULL )
2134 {
2135 CPLAssert( FALSE );
2136 return FALSE;
2137 }
2138
2139 poRVER_SFD = poKey->GetFieldDefn()->FindSubfieldDefn( "RVER" );
2140 if( poRVER_SFD == NULL )
2141 return FALSE;
2142
2143 pnRVER = (unsigned int *) poKey->GetSubfieldData( poRVER_SFD, NULL, 0 );
2144
2145 *pnRVER += 1;
2146
2147 /* -------------------------------------------------------------------- */
2148 /* Check for, and apply record record to spatial record pointer */
2149 /* updates. */
2150 /* -------------------------------------------------------------------- */
2151 if( poUpdate->FindField( "FSPC" ) != NULL )
2152 {
2153 int nFSUI = poUpdate->GetIntSubfield( "FSPC", 0, "FSUI", 0 );
2154 int nFSIX = poUpdate->GetIntSubfield( "FSPC", 0, "FSIX", 0 );
2155 int nNSPT = poUpdate->GetIntSubfield( "FSPC", 0, "NSPT", 0 );
2156 DDFField *poSrcFSPT = poUpdate->FindField( "FSPT" );
2157 DDFField *poDstFSPT = poTarget->FindField( "FSPT" );
2158 int nPtrSize;
2159
2160 if( (poSrcFSPT == NULL && nFSUI != 2) || poDstFSPT == NULL )
2161 {
2162 CPLAssert( FALSE );
2163 return FALSE;
2164 }
2165
2166 nPtrSize = poDstFSPT->GetFieldDefn()->GetFixedWidth();
2167
2168 if( nFSUI == 1 ) /* INSERT */
2169 {
2170 char *pachInsertion;
2171 int nInsertionBytes = nPtrSize * nNSPT;
2172
2173 pachInsertion = (char *) CPLMalloc(nInsertionBytes + nPtrSize);
2174 memcpy( pachInsertion, poSrcFSPT->GetData(), nInsertionBytes );
2175
2176 /*
2177 ** If we are inserting before an instance that already
2178 ** exists, we must add it to the end of the data being
2179 ** inserted.
2180 */
2181 if( nFSIX <= poDstFSPT->GetRepeatCount() )
2182 {
2183 memcpy( pachInsertion + nInsertionBytes,
2184 poDstFSPT->GetData() + nPtrSize * (nFSIX-1),
2185 nPtrSize );
2186 nInsertionBytes += nPtrSize;
2187 }
2188
2189 poTarget->SetFieldRaw( poDstFSPT, nFSIX - 1,
2190 pachInsertion, nInsertionBytes );
2191 CPLFree( pachInsertion );
2192 }
2193 else if( nFSUI == 2 ) /* DELETE */
2194 {
2195 /* Wipe each deleted coordinate */
2196 for( int i = nNSPT-1; i >= 0; i-- )
2197 {
2198 poTarget->SetFieldRaw( poDstFSPT, i + nFSIX - 1, NULL, 0 );
2199 }
2200 }
2201 else if( nFSUI == 3 ) /* MODIFY */
2202 {
2203 /* copy over each ptr */
2204 for( int i = 0; i < nNSPT; i++ )
2205 {
2206 const char *pachRawData;
2207
2208 pachRawData = poSrcFSPT->GetData() + nPtrSize * i;
2209
2210 poTarget->SetFieldRaw( poDstFSPT, i + nFSIX - 1,
2211 pachRawData, nPtrSize );
2212 }
2213 }
2214 }
2215
2216 /* -------------------------------------------------------------------- */
2217 /* Check for, and apply vector record to vector record pointer */
2218 /* updates. */
2219 /* -------------------------------------------------------------------- */
2220 if( poUpdate->FindField( "VRPC" ) != NULL )
2221 {
2222 int nVPUI = poUpdate->GetIntSubfield( "VRPC", 0, "VPUI", 0 );
2223 int nVPIX = poUpdate->GetIntSubfield( "VRPC", 0, "VPIX", 0 );
2224 int nNVPT = poUpdate->GetIntSubfield( "VRPC", 0, "NVPT", 0 );
2225 DDFField *poSrcVRPT = poUpdate->FindField( "VRPT" );
2226 DDFField *poDstVRPT = poTarget->FindField( "VRPT" );
2227 int nPtrSize;
2228
2229 if( (poSrcVRPT == NULL && nVPUI != 2) || poDstVRPT == NULL )
2230 {
2231 CPLAssert( FALSE );
2232 return FALSE;
2233 }
2234
2235 nPtrSize = poDstVRPT->GetFieldDefn()->GetFixedWidth();
2236
2237 if( nVPUI == 1 ) /* INSERT */
2238 {
2239 char *pachInsertion;
2240 int nInsertionBytes = nPtrSize * nNVPT;
2241
2242 pachInsertion = (char *) CPLMalloc(nInsertionBytes + nPtrSize);
2243 memcpy( pachInsertion, poSrcVRPT->GetData(), nInsertionBytes );
2244
2245 /*
2246 ** If we are inserting before an instance that already
2247 ** exists, we must add it to the end of the data being
2248 ** inserted.
2249 */
2250 if( nVPIX <= poDstVRPT->GetRepeatCount() )
2251 {
2252 memcpy( pachInsertion + nInsertionBytes,
2253 poDstVRPT->GetData() + nPtrSize * (nVPIX-1),
2254 nPtrSize );
2255 nInsertionBytes += nPtrSize;
2256 }
2257
2258 poTarget->SetFieldRaw( poDstVRPT, nVPIX - 1,
2259 pachInsertion, nInsertionBytes );
2260 CPLFree( pachInsertion );
2261 }
2262 else if( nVPUI == 2 ) /* DELETE */
2263 {
2264 /* Wipe each deleted coordinate */
2265 for( int i = nNVPT-1; i >= 0; i-- )
2266 {
2267 poTarget->SetFieldRaw( poDstVRPT, i + nVPIX - 1, NULL, 0 );
2268 }
2269 }
2270 else if( nVPUI == 3 ) /* MODIFY */
2271 {
2272 /* copy over each ptr */
2273 for( int i = 0; i < nNVPT; i++ )
2274 {
2275 const char *pachRawData;
2276
2277 pachRawData = poSrcVRPT->GetData() + nPtrSize * i;
2278
2279 poTarget->SetFieldRaw( poDstVRPT, i + nVPIX - 1,
2280 pachRawData, nPtrSize );
2281 }
2282 }
2283 }
2284
2285 /* -------------------------------------------------------------------- */
2286 /* Check for, and apply record update to coordinates. */
2287 /* -------------------------------------------------------------------- */
2288 if( poUpdate->FindField( "SGCC" ) != NULL )
2289 {
2290 int nCCUI = poUpdate->GetIntSubfield( "SGCC", 0, "CCUI", 0 );
2291 int nCCIX = poUpdate->GetIntSubfield( "SGCC", 0, "CCIX", 0 );
2292 int nCCNC = poUpdate->GetIntSubfield( "SGCC", 0, "CCNC", 0 );
2293 DDFField *poSrcSG2D = poUpdate->FindField( "SG2D" );
2294 DDFField *poDstSG2D = poTarget->FindField( "SG2D" );
2295 int nCoordSize;
2296
2297 /* If we don't have SG2D, check for SG3D */
2298 if( poDstSG2D == NULL )
2299 {
2300 poDstSG2D = poTarget->FindField( "SG3D" );
2301 if (poDstSG2D != NULL)
2302 {
2303 poSrcSG2D = poUpdate->FindField("SG3D");
2304 }
2305 }
2306
2307 if(poDstSG2D == NULL && nCCUI == 2){
2308 // Trying to delete a coordinate that does not exist...
2309 // Theoretically, this is an error.
2310 // But we have seen this from some HOs, (China/HongKong) and seems to be OK to ignore
2311 return TRUE;
2312 }
2313
2314 if( (poSrcSG2D == NULL && nCCUI != 2)
2315 || (poDstSG2D == NULL && nCCUI != 1) )
2316 {
2317 //CPLAssert( FALSE );
2318 return FALSE;
2319 }
2320
2321 if (poDstSG2D == NULL)
2322 {
2323 poTarget->AddField(poTarget->GetModule()->FindFieldDefn("SG2D"));
2324 poDstSG2D = poTarget->FindField("SG2D");
2325 if (poDstSG2D == NULL) {
2326 //CPLAssert( FALSE );
2327 return FALSE;
2328 }
2329
2330 // Delete null default data that was created
2331 poTarget->SetFieldRaw( poDstSG2D, 0, NULL, 0 );
2332 }
2333
2334 nCoordSize = poDstSG2D->GetFieldDefn()->GetFixedWidth();
2335
2336 if( nCCUI == 1 ) /* INSERT */
2337 {
2338 char *pachInsertion;
2339 int nInsertionBytes = nCoordSize * nCCNC;
2340
2341 pachInsertion = (char *) CPLMalloc(nInsertionBytes + nCoordSize);
2342 memcpy( pachInsertion, poSrcSG2D->GetData(), nInsertionBytes );
2343
2344 /*
2345 ** If we are inserting before an instance that already
2346 ** exists, we must add it to the end of the data being
2347 ** inserted.
2348 */
2349 if( nCCIX <= poDstSG2D->GetRepeatCount() )
2350 {
2351 memcpy( pachInsertion + nInsertionBytes,
2352 poDstSG2D->GetData() + nCoordSize * (nCCIX-1),
2353 nCoordSize );
2354 nInsertionBytes += nCoordSize;
2355 }
2356
2357 poTarget->SetFieldRaw( poDstSG2D, nCCIX - 1,
2358 pachInsertion, nInsertionBytes );
2359 CPLFree( pachInsertion );
2360
2361 }
2362 else if( nCCUI == 2 ) /* DELETE */
2363 {
2364 /* Wipe each deleted coordinate */
2365 for( int i = nCCNC-1; i >= 0; i-- )
2366 {
2367 poTarget->SetFieldRaw( poDstSG2D, i + nCCIX - 1, NULL, 0 );
2368 }
2369 }
2370 else if( nCCUI == 3 ) /* MODIFY */
2371 {
2372 /* copy over each ptr */
2373 for( int i = 0; i < nCCNC; i++ )
2374 {
2375 const char *pachRawData;
2376
2377 pachRawData = poSrcSG2D->GetData() + nCoordSize * i;
2378
2379 poTarget->SetFieldRaw( poDstSG2D, i + nCCIX - 1,
2380 pachRawData, nCoordSize );
2381 }
2382 }
2383 }
2384
2385 /* -------------------------------------------------------------------- */
2386 /* We don't currently handle FFPC (feature to feature linkage) */
2387 /* issues, but we will at least report them when debugging. */
2388 /* -------------------------------------------------------------------- */
2389 /*
2390 if( poUpdate->FindField( "FFPC" ) != NULL )
2391 {
2392 CPLDebug( "S57", "Found FFPC, but not applying it." );
2393 }
2394 */
2395 /* -------------------------------------------------------------------- */
2396 /* Check for and apply changes to attribute lists. */
2397 /* -------------------------------------------------------------------- */
2398 if( poUpdate->FindField( "ATTF" ) != NULL )
2399 {
2400 bool b_newField = false;
2401 DDFSubfieldDefn *poSrcATVLDefn;
2402 DDFField *poSrcATTF = poUpdate->FindField( "ATTF" );
2403 DDFField *poDstATTF = poTarget->FindField( "ATTF" );
2404
2405 if(NULL == poDstATTF)
2406 {
2407 // This probably means that the update applies to an attribute that doesn't (yet) exist
2408 // To fix, we need to add an attribute, then update it.
2409
2410 DDFFieldDefn *poATTF = poTarget->GetModule()->FindFieldDefn( "ATTF" );
2411 poTarget->AddField(poATTF);
2412 poDstATTF = poTarget->FindField( "ATTF" );
2413 b_newField = true;
2414
2415 }
2416
2417 int nRepeatCount = poSrcATTF->GetRepeatCount();
2418
2419 poSrcATVLDefn = poSrcATTF->GetFieldDefn()->FindSubfieldDefn( "ATVL" );
2420
2421 for( int iAtt = 0; iAtt < nRepeatCount; iAtt++ )
2422 {
2423 int nATTL = poUpdate->GetIntSubfield( "ATTF", 0, "ATTL", iAtt );
2424 int iTAtt, nDataBytes;
2425 const char *pszRawData;
2426
2427 for( iTAtt = poDstATTF->GetRepeatCount()-1; iTAtt >= 0; iTAtt-- )
2428 {
2429 if( poTarget->GetIntSubfield( "ATTF", 0, "ATTL", iTAtt )
2430 == nATTL )
2431 break;
2432 }
2433 if( iTAtt == -1 )
2434 iTAtt = poDstATTF->GetRepeatCount();
2435
2436 // If we just added a new field above, then the first attribute will be 0.
2437 // We should replace this one
2438 if(b_newField){
2439 if( poTarget->GetIntSubfield( "ATTF", 0, "ATTL", 0 ) == 0){
2440 iTAtt = 0;
2441 b_newField = false;
2442 }
2443 }
2444
2445 pszRawData = poSrcATTF->GetInstanceData( iAtt, &nDataBytes );
2446 poTarget->SetFieldRaw( poDstATTF, iTAtt, pszRawData, nDataBytes );
2447 }
2448 }
2449
2450 if( poUpdate->FindField( "NATF" ) != NULL )
2451 {
2452 bool b_newField = false;
2453 DDFSubfieldDefn *poSrcATVLDefn;
2454 DDFField *poSrcATTF = poUpdate->FindField( "NATF" );
2455 DDFField *poDstATTF = poTarget->FindField( "NATF" );
2456
2457 // int up_FIDN = poUpdate->GetIntSubfield( "FOID", 0, "FIDN", 0 );
2458 // if(up_FIDN == 1103712044 /*1225530334*/){
2459 // poTarget->Dump(stdout);
2460 // }
2461
2462 if(NULL == poDstATTF)
2463 {
2464 // This probably means that the update applies to an attribute that doesn't (yet) exist
2465 // To fix, we need to add an attribute, then update it.
2466
2467 DDFFieldDefn *poNATF = poTarget->GetModule()->FindFieldDefn( "NATF" );
2468 poTarget->AddField(poNATF);
2469 poDstATTF = poTarget->FindField( "NATF" );
2470 b_newField = true;
2471
2472 // poTarget->Dump(stdout);
2473
2474 // CPLDebug( "S57","Could not find target ATTF field for attribute update");
2475 // return FALSE;
2476 }
2477
2478 int nRepeatCount = poSrcATTF->GetRepeatCount();
2479
2480 poSrcATVLDefn = poSrcATTF->GetFieldDefn()->FindSubfieldDefn( "ATVL" );
2481
2482 for( int iAtt = 0; iAtt < nRepeatCount; iAtt++ )
2483 {
2484 int nATTL = poUpdate->GetIntSubfield( "NATF", 0, "ATTL", iAtt );
2485 int iTAtt, nDataBytes;
2486 const char *pszRawData;
2487
2488 for( iTAtt = poDstATTF->GetRepeatCount()-1; iTAtt >= 0; iTAtt-- )
2489 {
2490 if( poTarget->GetIntSubfield( "NATF", 0, "ATTL", iTAtt ) == nATTL )
2491 break;
2492 }
2493 if( iTAtt == -1 )
2494 iTAtt = poDstATTF->GetRepeatCount();
2495
2496 // If we just added a new field above, then the first attribute will be 0.
2497 // We should replace this one
2498 if(b_newField){
2499 if( poTarget->GetIntSubfield( "NATF", 0, "ATTL", 0 ) == 0){
2500 iTAtt = 0;
2501 b_newField = false;
2502 }
2503 }
2504
2505
2506 pszRawData = poSrcATTF->GetInstanceData( iAtt, &nDataBytes );
2507
2508 // poTarget->Dump(stdout);
2509 poTarget->SetFieldRaw( poDstATTF, iTAtt, pszRawData, nDataBytes ); ///dsr
2510 // poTarget->Dump(stdout);
2511
2512 }
2513 }
2514
2515 return TRUE;
2516 }
2517
2518
2519 /************************************************************************/
2520 /* ApplyUpdates() */
2521 /* */
2522 /* Read records from an update file, and apply them to the */
2523 /* currently loaded index of features. */
2524 /************************************************************************/
2525
ApplyUpdates(DDFModule * poUpdateModule,int iUpdate)2526 int S57Reader::ApplyUpdates( DDFModule *poUpdateModule, int iUpdate )
2527
2528 {
2529 DDFRecord *poRecord;
2530
2531 int ret_code = 0;
2532
2533 /* -------------------------------------------------------------------- */
2534 /* Ensure base file is loaded. */
2535 /* -------------------------------------------------------------------- */
2536 Ingest();
2537
2538 /* -------------------------------------------------------------------- */
2539 /* Read records, and apply as updates. */
2540 /* -------------------------------------------------------------------- */
2541 while( (poRecord = poUpdateModule->ReadRecord()) != NULL )
2542 {
2543 DDFField *poKeyField = poRecord->GetField(1);
2544 const char *pszKey = poKeyField->GetFieldDefn()->GetName();
2545
2546 if( EQUAL(pszKey,"VRID") || EQUAL(pszKey,"FRID"))
2547 {
2548 int nRCNM = poRecord->GetIntSubfield( pszKey,0, "RCNM",0 );
2549 int nRCID = poRecord->GetIntSubfield( pszKey,0, "RCID",0 );
2550 int nRVER = poRecord->GetIntSubfield( pszKey,0, "RVER",0 );
2551 int nRUIN = poRecord->GetIntSubfield( pszKey,0, "RUIN",0 );
2552 DDFRecordIndex *poIndex = NULL;
2553
2554 if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"VRID") )
2555 {
2556 switch( nRCNM )
2557 {
2558 case RCNM_VI:
2559 poIndex = &oVI_Index;
2560 break;
2561
2562 case RCNM_VC:
2563 poIndex = &oVC_Index;
2564 break;
2565
2566 case RCNM_VE:
2567 poIndex = &oVE_Index;
2568 break;
2569
2570 case RCNM_VF:
2571 poIndex = &oVF_Index;
2572 break;
2573
2574 default:
2575 CPLAssert( FALSE );
2576 break;
2577 }
2578 }
2579 else
2580 {
2581 poIndex = &oFE_Index;
2582 }
2583
2584 if( poIndex != NULL )
2585 {
2586 if( nRUIN == 1 ) /* insert */
2587 {
2588 // CPLDebug( "S57","Insert Record, RCID=%d", nRCID);
2589 poIndex->AddRecord( nRCID, poRecord->CloneOn(poModule) );
2590 }
2591 else if( nRUIN == 2 ) /* delete */
2592 {
2593 // CPLDebug( "S57","Remove Record, RCID=%d", nRCID);
2594 DDFRecord *poTarget;
2595
2596 poTarget = poIndex->FindRecord( nRCID );
2597 if( poTarget == NULL )
2598 {
2599 CPLError( CE_Warning, CPLE_AppDefined,
2600 "While applying update %d, Can't find RCNM=%d,RCID=%d for delete.",
2601 iUpdate, nRCNM, nRCID );
2602 ret_code = BAD_UPDATE;
2603 }
2604 else if( poTarget->GetIntSubfield( pszKey, 0, "RVER", 0 )
2605 != nRVER - 1 )
2606 {
2607 CPLError( CE_Warning, CPLE_AppDefined,
2608 "While applying update %d, On RecordRemove, mismatched RVER value for RCNM=%d,RCID=%d...update RVER is %d, target RVER is %d.",
2609 iUpdate, nRCNM, nRCID, nRVER, poTarget->GetIntSubfield( pszKey, 0, "RVER", 0 ) );
2610 CPLError( CE_Warning, CPLE_AppDefined,
2611 "While applying update %d, Removal of RCNM=%d,RCID=%d failed.",
2612 iUpdate, nRCNM, nRCID );
2613 ret_code = BAD_UPDATE;
2614
2615 }
2616 else
2617 {
2618 poIndex->RemoveRecord( nRCID );
2619 }
2620 }
2621
2622 else if( nRUIN == 3 ) /* modify in place */
2623 {
2624 // CPLDebug( "S57","Update Record, RCID=%d", nRCID);
2625 DDFRecord *poTarget;
2626
2627 poTarget = poIndex->FindRecord( nRCID );
2628 if( poTarget == NULL )
2629 {
2630 CPLError( CE_Warning, CPLE_AppDefined,
2631 "While applying update %d, Can't find RCNM=%d,RCID=%d for update.",
2632 iUpdate, nRCNM, nRCID );
2633 ret_code = BAD_UPDATE;
2634
2635 }
2636 else
2637 {
2638 if( !ApplyRecordUpdate( poTarget, poRecord ) )
2639 {
2640 CPLError( CE_Warning, CPLE_AppDefined,
2641 "While applying update %d, an update to RCNM=%d,RCID=%d failed.",
2642 iUpdate, nRCNM, nRCID );
2643 ret_code = BAD_UPDATE;
2644 }
2645 }
2646 }
2647 }
2648 }
2649
2650 else if( EQUAL(pszKey,"DSID") )
2651 {
2652 /* ignore */;
2653 }
2654
2655 else
2656 {
2657 CPLDebug( "S57",
2658 "While applying update %d, Skipping %s record in S57Reader::ApplyUpdates().",
2659 iUpdate, pszKey );
2660 ret_code = BAD_UPDATE;
2661
2662 }
2663 }
2664
2665 return ret_code;
2666 }
2667
2668 /************************************************************************/
2669 /* FindAndApplyUpdates() */
2670 /* */
2671 /* Find all update files that would appear to apply to this */
2672 /* base file. */
2673 /************************************************************************/
2674
FindAndApplyUpdates(const char * pszPath)2675 int S57Reader::FindAndApplyUpdates( const char * pszPath )
2676
2677 {
2678 int iUpdate;
2679 int bSuccess = TRUE;
2680 int ret_code = 0;
2681
2682 if( pszPath == NULL )
2683 pszPath = pszModuleName;
2684
2685 if( !EQUAL(CPLGetExtension(pszPath),"000") )
2686 {
2687 CPLError( CE_Failure, CPLE_AppDefined,
2688 "Can't apply updates to a base file with a different\n"
2689 "extension than .000." );
2690 return BAD_UPDATE;
2691 }
2692
2693 for( iUpdate = 1; bSuccess; iUpdate++ )
2694 {
2695 char szExtension[16];
2696 char *pszUpdateFilename;
2697 DDFModule oUpdateModule;
2698
2699 assert(iUpdate <= 999);
2700 sprintf( szExtension, "%03d", iUpdate );
2701
2702 pszUpdateFilename = CPLStrdup(CPLResetExtension(pszPath,szExtension));
2703
2704 bSuccess = oUpdateModule.Open( pszUpdateFilename, TRUE );
2705
2706 if( bSuccess )
2707 CPLDebug( "S57", "Applying feature updates from %s.",
2708 pszUpdateFilename );
2709 CPLFree( pszUpdateFilename );
2710
2711 if( bSuccess )
2712 {
2713 int update_ret = ApplyUpdates( &oUpdateModule, iUpdate );
2714 if(update_ret)
2715 ret_code = update_ret;
2716 }
2717 }
2718
2719 return ret_code;
2720 }
2721
2722 /************************************************************************/
2723 /* GetExtent() */
2724 /* */
2725 /* Scan all the cached records collecting spatial bounds as */
2726 /* efficiently as possible for this transfer. */
2727 /************************************************************************/
2728
2729 // Android uses clang compiler.
2730 // Problem also appears on GCC, on __ARM_ARCH.
2731 // At optimization -O3, this function has trouble with alignment of values,
2732 // Specifically, conversion of an int32 from a buffer into double.
2733 // Workaround: We disable optimization for this little used function.
2734 #ifdef __ARM_ARCH
2735 #if defined(__clang__)
2736 [[clang::optnone]]
2737 #elif defined(__GNUC__) || defined(__GNUG__)
2738 #pragma GCC push_options
2739 #pragma GCC optimize ("O0")
2740
2741 #endif
2742 #endif
2743
2744
GetExtent(OGREnvelope * psExtent,int bForce)2745 OGRErr S57Reader::GetExtent( OGREnvelope *psExtent, int bForce )
2746
2747 {
2748 #define INDEX_COUNT 4
2749
2750 DDFRecordIndex *apoIndex[INDEX_COUNT];
2751
2752 /* -------------------------------------------------------------------- */
2753 /* If we aren't forced to get the extent say no if we haven't */
2754 /* already indexed the iso8211 records. */
2755 /* -------------------------------------------------------------------- */
2756 if( !bForce && !bFileIngested )
2757 return OGRERR_FAILURE;
2758
2759 Ingest();
2760
2761 /* -------------------------------------------------------------------- */
2762 /* We will scan all the low level vector elements for extents */
2763 /* coordinates. */
2764 /* -------------------------------------------------------------------- */
2765 int bGotExtents = FALSE;
2766 double nXMin=0, nXMax=0, nYMin=0, nYMax=0;
2767
2768 apoIndex[0] = &oVI_Index;
2769 apoIndex[1] = &oVC_Index;
2770 apoIndex[2] = &oVE_Index;
2771 apoIndex[3] = &oVF_Index;
2772
2773 for( int iIndex = 0; iIndex < INDEX_COUNT; iIndex++ )
2774 {
2775 DDFRecordIndex *poIndex = apoIndex[iIndex];
2776
2777 for( int iVIndex = 0; iVIndex < poIndex->GetCount(); iVIndex++ )
2778 {
2779 DDFRecord *poRecord = poIndex->GetByIndex( iVIndex );
2780 DDFField *poSG3D = poRecord->FindField( "SG3D" );
2781 DDFField *poSG2D = poRecord->FindField( "SG2D" );
2782
2783 if( poSG3D != NULL )
2784 {
2785 int i, nVCount = poSG3D->GetRepeatCount();
2786 GInt32 *panData, nX, nY;
2787
2788 panData = (GInt32 *) poSG3D->GetData();
2789 for( i = 0; i < nVCount; i++ )
2790 {
2791 nX = CPL_LSBWORD32(panData[i*3+1]);
2792 nY = CPL_LSBWORD32(panData[i*3+0]);
2793
2794 double dnX = nX / (double)nCOMF;
2795 double dnY = nY / (double)nCOMF;
2796
2797 if( bGotExtents )
2798 {
2799 nXMin = MIN(nXMin,dnX);
2800 nXMax = MAX(nXMax,dnX);
2801 nYMin = MIN(nYMin,dnY);
2802 nYMax = MAX(nYMax,dnY);
2803 }
2804 else
2805 {
2806 nXMin = nXMax = dnX;
2807 nYMin = nYMax = dnY;
2808 bGotExtents = TRUE;
2809 }
2810 }
2811 }
2812 else if( poSG2D != NULL )
2813 {
2814 int i, nVCount = poSG2D->GetRepeatCount();
2815 GInt32 *panData, nX, nY;
2816
2817 panData = (GInt32 *) poSG2D->GetData();
2818 for( i = 0; i < nVCount; i++ )
2819 {
2820 nX = CPL_LSBWORD32(panData[i*2+1]);
2821 nY = CPL_LSBWORD32(panData[i*2+0]);
2822
2823 double dnX = nX / (double)nCOMF;
2824 double dnY = nY / (double)nCOMF;
2825
2826 if( bGotExtents )
2827 {
2828 nXMin = MIN(nXMin,dnX);
2829 nXMax = MAX(nXMax,dnX);
2830 nYMin = MIN(nYMin,dnY);
2831 nYMax = MAX(nYMax,dnY);
2832 }
2833 else
2834 {
2835 nXMin = nXMax = dnX;
2836 nYMin = nYMax = dnY;
2837 bGotExtents = TRUE;
2838 }
2839 }
2840 }
2841 }
2842 }
2843
2844 if( !bGotExtents )
2845 return OGRERR_FAILURE;
2846 else
2847 {
2848 psExtent->MinX = nXMin;
2849 psExtent->MaxX = nXMax;
2850 psExtent->MinY = nYMin;
2851 psExtent->MaxY = nYMax;
2852
2853 return OGRERR_NONE;
2854 }
2855 }
2856
2857 #ifdef __ARM_ARCH
2858 #if defined(__GNUC__) || defined(__GNUG__)
2859 #pragma GCC pop_options
2860 #endif
2861 #endif
2862