LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/s57 - s57reader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1167 629 53.9 %
Date: 2012-04-28 Functions: 39 30 76.9 %

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

Generated by: LCOV version 1.7