LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/s57 - s57reader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1076 495 46.0 %
Date: 2010-01-09 Functions: 36 27 75.0 %

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

Generated by: LCOV version 1.7