LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/s57 - s57writer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 431 475 90.7 %
Date: 2024-04-28 18:08:58 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  S-57 Translator
       4             :  * Purpose:  Implements S57Writer class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2003, Frank Warmerdam
       9             :  * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.com>
      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 "cpl_conv.h"
      31             : #include "cpl_string.h"
      32             : #include "ogr_api.h"
      33             : #include "s57.h"
      34             : 
      35             : /************************************************************************/
      36             : /*                             S57Writer()                              */
      37             : /************************************************************************/
      38             : 
      39          19 : S57Writer::S57Writer()
      40             :     : poModule(nullptr), nNext0001Index(0), poRegistrar(nullptr),
      41             :       poClassContentExplorer(nullptr), m_nCOMF(nDEFAULT_COMF),
      42          19 :       m_nSOMF(nDEFAULT_SOMF)
      43             : {
      44          19 : }
      45             : 
      46             : /************************************************************************/
      47             : /*                             ~S57Writer()                             */
      48             : /************************************************************************/
      49             : 
      50          38 : S57Writer::~S57Writer()
      51             : 
      52             : {
      53          19 :     Close();
      54          19 : }
      55             : 
      56             : /************************************************************************/
      57             : /*                               Close()                                */
      58             : /*                                                                      */
      59             : /*      Close the current S-57 dataset.                                 */
      60             : /************************************************************************/
      61             : 
      62          57 : bool S57Writer::Close()
      63             : 
      64             : {
      65          57 :     if (poModule != nullptr)
      66             :     {
      67          18 :         poModule->Close();
      68          18 :         delete poModule;
      69          18 :         poModule = nullptr;
      70             :     }
      71          57 :     return true;
      72             : }
      73             : 
      74             : /************************************************************************/
      75             : /*                           CreateS57File()                            */
      76             : /*                                                                      */
      77             : /*      Create a new output ISO8211 file with all the S-57 data         */
      78             : /*      definitions.                                                    */
      79             : /************************************************************************/
      80             : 
      81          19 : bool S57Writer::CreateS57File(const char *pszFilename)
      82             : 
      83             : {
      84             :     // TODO: What was oModule for if it was unused?
      85             :     // DDFModule  oModule;
      86          19 :     Close();
      87             : 
      88          19 :     nNext0001Index = 1;
      89             : 
      90             :     /* -------------------------------------------------------------------- */
      91             :     /*      Create and initialize new module.                               */
      92             :     /* -------------------------------------------------------------------- */
      93          19 :     poModule = new DDFModule();
      94          19 :     poModule->Initialize();
      95             : 
      96             :     /* -------------------------------------------------------------------- */
      97             :     /*      Create the '0000' definition.                                   */
      98             :     /* -------------------------------------------------------------------- */
      99          19 :     DDFFieldDefn *poFDefn = new DDFFieldDefn();
     100             : 
     101          19 :     poFDefn->Create("0000", "",
     102             :                     "0001DSIDDSIDDSSI0001DSPM0001VRIDVRIDATTVVRIDVRPCVRID"
     103             :                     "VRPTVRIDSGCCVRIDSG2DVRIDSG3D0001FRIDFRIDFOIDFRIDATTF"
     104             :                     "FRIDNATFFRIDFFPCFRIDFFPTFRIDFSPCFRIDFSPT",
     105             :                     dsc_elementary, dtc_char_string);
     106             : 
     107          19 :     poModule->AddField(poFDefn);
     108             : 
     109             :     /* -------------------------------------------------------------------- */
     110             :     /*      Create the '0001' definition.                                   */
     111             :     /* -------------------------------------------------------------------- */
     112          19 :     poFDefn = new DDFFieldDefn();
     113             : 
     114          19 :     poFDefn->Create("0001", "ISO 8211 Record Identifier", "", dsc_elementary,
     115             :                     dtc_bit_string, "(b12)");
     116             : 
     117          19 :     poModule->AddField(poFDefn);
     118             : 
     119             :     /* -------------------------------------------------------------------- */
     120             :     /*      Create the DSID field.                                          */
     121             :     /* -------------------------------------------------------------------- */
     122          19 :     poFDefn = new DDFFieldDefn();
     123             : 
     124          19 :     poFDefn->Create("DSID", "Data set identification field", "", dsc_vector,
     125             :                     dtc_mixed_data_type);
     126             : 
     127          19 :     poFDefn->AddSubfield("RCNM", "b11");
     128          19 :     poFDefn->AddSubfield("RCID", "b14");
     129          19 :     poFDefn->AddSubfield("EXPP", "b11");
     130          19 :     poFDefn->AddSubfield("INTU", "b11");
     131          19 :     poFDefn->AddSubfield("DSNM", "A");
     132          19 :     poFDefn->AddSubfield("EDTN", "A");
     133          19 :     poFDefn->AddSubfield("UPDN", "A");
     134          19 :     poFDefn->AddSubfield("UADT", "A(8)");
     135          19 :     poFDefn->AddSubfield("ISDT", "A(8)");
     136          19 :     poFDefn->AddSubfield("STED", "R(4)");
     137          19 :     poFDefn->AddSubfield("PRSP", "b11");
     138          19 :     poFDefn->AddSubfield("PSDN", "A");
     139          19 :     poFDefn->AddSubfield("PRED", "A");
     140          19 :     poFDefn->AddSubfield("PROF", "b11");
     141          19 :     poFDefn->AddSubfield("AGEN", "b12");
     142          19 :     poFDefn->AddSubfield("COMT", "A");
     143             : 
     144          19 :     poModule->AddField(poFDefn);
     145             : 
     146             :     /* -------------------------------------------------------------------- */
     147             :     /*      Create the DSSI field.                                          */
     148             :     /* -------------------------------------------------------------------- */
     149          19 :     poFDefn = new DDFFieldDefn();
     150             : 
     151          19 :     poFDefn->Create("DSSI", "Data set structure information field", "",
     152             :                     dsc_vector, dtc_mixed_data_type);
     153             : 
     154          19 :     poFDefn->AddSubfield("DSTR", "b11");
     155          19 :     poFDefn->AddSubfield("AALL", "b11");
     156          19 :     poFDefn->AddSubfield("NALL", "b11");
     157          19 :     poFDefn->AddSubfield("NOMR", "b14");
     158          19 :     poFDefn->AddSubfield("NOCR", "b14");
     159          19 :     poFDefn->AddSubfield("NOGR", "b14");
     160          19 :     poFDefn->AddSubfield("NOLR", "b14");
     161          19 :     poFDefn->AddSubfield("NOIN", "b14");
     162          19 :     poFDefn->AddSubfield("NOCN", "b14");
     163          19 :     poFDefn->AddSubfield("NOED", "b14");
     164          19 :     poFDefn->AddSubfield("NOFA", "b14");
     165             : 
     166          19 :     poModule->AddField(poFDefn);
     167             : 
     168             :     /* -------------------------------------------------------------------- */
     169             :     /*      Create the DSPM field.                                          */
     170             :     /* -------------------------------------------------------------------- */
     171          19 :     poFDefn = new DDFFieldDefn();
     172             : 
     173          19 :     poFDefn->Create("DSPM", "Data set parameter field", "", dsc_vector,
     174             :                     dtc_mixed_data_type);
     175             : 
     176          19 :     poFDefn->AddSubfield("RCNM", "b11");
     177          19 :     poFDefn->AddSubfield("RCID", "b14");
     178          19 :     poFDefn->AddSubfield("HDAT", "b11");
     179          19 :     poFDefn->AddSubfield("VDAT", "b11");
     180          19 :     poFDefn->AddSubfield("SDAT", "b11");
     181          19 :     poFDefn->AddSubfield("CSCL", "b14");
     182          19 :     poFDefn->AddSubfield("DUNI", "b11");
     183          19 :     poFDefn->AddSubfield("HUNI", "b11");
     184          19 :     poFDefn->AddSubfield("PUNI", "b11");
     185          19 :     poFDefn->AddSubfield("COUN", "b11");
     186          19 :     poFDefn->AddSubfield("COMF", "b14");
     187          19 :     poFDefn->AddSubfield("SOMF", "b14");
     188          19 :     poFDefn->AddSubfield("COMT", "A");
     189             : 
     190          19 :     poModule->AddField(poFDefn);
     191             : 
     192             :     /* -------------------------------------------------------------------- */
     193             :     /*      Create the VRID field.                                          */
     194             :     /* -------------------------------------------------------------------- */
     195          19 :     poFDefn = new DDFFieldDefn();
     196             : 
     197          19 :     poFDefn->Create("VRID", "Vector record identifier field", "", dsc_vector,
     198             :                     dtc_mixed_data_type);
     199             : 
     200          19 :     poFDefn->AddSubfield("RCNM", "b11");
     201          19 :     poFDefn->AddSubfield("RCID", "b14");
     202          19 :     poFDefn->AddSubfield("RVER", "b12");
     203          19 :     poFDefn->AddSubfield("RUIN", "b11");
     204             : 
     205          19 :     poModule->AddField(poFDefn);
     206             : 
     207             :     /* -------------------------------------------------------------------- */
     208             :     /*      Create the VRPC field.                                          */
     209             :     /* -------------------------------------------------------------------- */
     210          19 :     poFDefn = new DDFFieldDefn();
     211             : 
     212          19 :     poFDefn->Create("VRPC", "Vector Record Pointer Control field", "",
     213             :                     dsc_vector, dtc_mixed_data_type);
     214             : 
     215          19 :     poFDefn->AddSubfield("VPUI", "b11");
     216          19 :     poFDefn->AddSubfield("VPIX", "b12");
     217          19 :     poFDefn->AddSubfield("NVPT", "b12");
     218             : 
     219          19 :     poModule->AddField(poFDefn);
     220             : 
     221             :     /* -------------------------------------------------------------------- */
     222             :     /*      Create the VRPT field.                                          */
     223             :     /* -------------------------------------------------------------------- */
     224          19 :     poFDefn = new DDFFieldDefn();
     225             : 
     226          19 :     poFDefn->Create("VRPT", "Vector record pointer field", "*", dsc_array,
     227             :                     dtc_mixed_data_type);
     228             : 
     229          19 :     poFDefn->AddSubfield("NAME", "B(40)");
     230          19 :     poFDefn->AddSubfield("ORNT", "b11");
     231          19 :     poFDefn->AddSubfield("USAG", "b11");
     232          19 :     poFDefn->AddSubfield("TOPI", "b11");
     233          19 :     poFDefn->AddSubfield("MASK", "b11");
     234             : 
     235          19 :     poModule->AddField(poFDefn);
     236             : 
     237             :     /* -------------------------------------------------------------------- */
     238             :     /*      Create the ATTV field.                                          */
     239             :     /* -------------------------------------------------------------------- */
     240          19 :     poFDefn = new DDFFieldDefn();
     241             : 
     242          19 :     poFDefn->Create("ATTV", "Vector record attribute field", "*", dsc_array,
     243             :                     dtc_mixed_data_type);
     244             : 
     245          19 :     poFDefn->AddSubfield("ATTL", "b12");
     246          19 :     poFDefn->AddSubfield("ATVL", "A");
     247             : 
     248          19 :     poModule->AddField(poFDefn);
     249             : 
     250             :     /* -------------------------------------------------------------------- */
     251             :     /*      Create the SGCC field.                                          */
     252             :     /* -------------------------------------------------------------------- */
     253          19 :     poFDefn = new DDFFieldDefn();
     254             : 
     255          19 :     poFDefn->Create("SGCC", "Coordinate Control Field", "", dsc_vector,
     256             :                     dtc_mixed_data_type);
     257             : 
     258          19 :     poFDefn->AddSubfield("CCUI", "b11");
     259          19 :     poFDefn->AddSubfield("CCIX", "b12");
     260          19 :     poFDefn->AddSubfield("CCNC", "b12");
     261             : 
     262          19 :     poModule->AddField(poFDefn);
     263             : 
     264             :     /* -------------------------------------------------------------------- */
     265             :     /*      Create the SG2D field.                                          */
     266             :     /* -------------------------------------------------------------------- */
     267          19 :     poFDefn = new DDFFieldDefn();
     268             : 
     269          19 :     poFDefn->Create("SG2D", "2-D coordinate field", "*", dsc_array,
     270             :                     dtc_bit_string);
     271             : 
     272          19 :     poFDefn->AddSubfield("YCOO", "b24");
     273          19 :     poFDefn->AddSubfield("XCOO", "b24");
     274             : 
     275          19 :     poModule->AddField(poFDefn);
     276             : 
     277             :     /* -------------------------------------------------------------------- */
     278             :     /*      Create the SG3D field.                                          */
     279             :     /* -------------------------------------------------------------------- */
     280          19 :     poFDefn = new DDFFieldDefn();
     281             : 
     282          19 :     poFDefn->Create("SG3D", "3-D coordinate (sounding array) field", "*",
     283             :                     dsc_array, dtc_bit_string);
     284             : 
     285          19 :     poFDefn->AddSubfield("YCOO", "b24");
     286          19 :     poFDefn->AddSubfield("XCOO", "b24");
     287          19 :     poFDefn->AddSubfield("VE3D", "b24");
     288             : 
     289          19 :     poModule->AddField(poFDefn);
     290             : 
     291             :     /* -------------------------------------------------------------------- */
     292             :     /*      Create the FRID field.                                          */
     293             :     /* -------------------------------------------------------------------- */
     294          19 :     poFDefn = new DDFFieldDefn();
     295             : 
     296          19 :     poFDefn->Create("FRID", "Feature record identifier field", "", dsc_vector,
     297             :                     dtc_mixed_data_type);
     298             : 
     299          19 :     poFDefn->AddSubfield("RCNM", "b11");
     300          19 :     poFDefn->AddSubfield("RCID", "b14");
     301          19 :     poFDefn->AddSubfield("PRIM", "b11");
     302          19 :     poFDefn->AddSubfield("GRUP", "b11");
     303          19 :     poFDefn->AddSubfield("OBJL", "b12");
     304          19 :     poFDefn->AddSubfield("RVER", "b12");
     305          19 :     poFDefn->AddSubfield("RUIN", "b11");
     306             : 
     307          19 :     poModule->AddField(poFDefn);
     308             : 
     309             :     /* -------------------------------------------------------------------- */
     310             :     /*      Create the FOID field.                                          */
     311             :     /* -------------------------------------------------------------------- */
     312          19 :     poFDefn = new DDFFieldDefn();
     313             : 
     314          19 :     poFDefn->Create("FOID", "Feature object identifier field", "", dsc_vector,
     315             :                     dtc_mixed_data_type);
     316             : 
     317          19 :     poFDefn->AddSubfield("AGEN", "b12");
     318          19 :     poFDefn->AddSubfield("FIDN", "b14");
     319          19 :     poFDefn->AddSubfield("FIDS", "b12");
     320             : 
     321          19 :     poModule->AddField(poFDefn);
     322             : 
     323             :     /* -------------------------------------------------------------------- */
     324             :     /*      Create the ATTF field.                                          */
     325             :     /* -------------------------------------------------------------------- */
     326          19 :     poFDefn = new DDFFieldDefn();
     327             : 
     328          19 :     poFDefn->Create("ATTF", "Feature record attribute field", "*", dsc_array,
     329             :                     dtc_mixed_data_type);
     330             : 
     331          19 :     poFDefn->AddSubfield("ATTL", "b12");
     332          19 :     poFDefn->AddSubfield("ATVL", "A");
     333             : 
     334          19 :     poModule->AddField(poFDefn);
     335             : 
     336             :     /* -------------------------------------------------------------------- */
     337             :     /*      Create the NATF field.                                          */
     338             :     /* -------------------------------------------------------------------- */
     339          19 :     poFDefn = new DDFFieldDefn();
     340             : 
     341          19 :     poFDefn->Create("NATF", "Feature record national attribute field", "*",
     342             :                     dsc_array, dtc_mixed_data_type);
     343             : 
     344          19 :     poFDefn->AddSubfield("ATTL", "b12");
     345          19 :     poFDefn->AddSubfield("ATVL", "A");
     346             : 
     347          19 :     poModule->AddField(poFDefn);
     348             : 
     349             :     /* -------------------------------------------------------------------- */
     350             :     /*      Create the FFPC field.                                          */
     351             :     /* -------------------------------------------------------------------- */
     352          19 :     poFDefn = new DDFFieldDefn();
     353             : 
     354          19 :     poFDefn->Create("FFPC",
     355             :                     "Feature record to feature object pointer control field",
     356             :                     "", dsc_vector, dtc_mixed_data_type);
     357             : 
     358          19 :     poFDefn->AddSubfield("FFUI", "b11");
     359          19 :     poFDefn->AddSubfield("FFIX", "b12");
     360          19 :     poFDefn->AddSubfield("NFPT", "b12");
     361             : 
     362          19 :     poModule->AddField(poFDefn);
     363             : 
     364             :     /* -------------------------------------------------------------------- */
     365             :     /*      Create the FFPT field.                                          */
     366             :     /* -------------------------------------------------------------------- */
     367          19 :     poFDefn = new DDFFieldDefn();
     368             : 
     369          19 :     poFDefn->Create("FFPT", "Feature record to feature object pointer field",
     370             :                     "*", dsc_array, dtc_mixed_data_type);
     371             : 
     372          19 :     poFDefn->AddSubfield("LNAM", "B(64)");
     373          19 :     poFDefn->AddSubfield("RIND", "b11");
     374          19 :     poFDefn->AddSubfield("COMT", "A");
     375             : 
     376          19 :     poModule->AddField(poFDefn);
     377             : 
     378             :     /* -------------------------------------------------------------------- */
     379             :     /*      Create the FSPC field.                                          */
     380             :     /* -------------------------------------------------------------------- */
     381          19 :     poFDefn = new DDFFieldDefn();
     382             : 
     383          19 :     poFDefn->Create("FSPC",
     384             :                     "Feature record to spatial record pointer control field",
     385             :                     "", dsc_vector, dtc_mixed_data_type);
     386             : 
     387          19 :     poFDefn->AddSubfield("FSUI", "b11");
     388          19 :     poFDefn->AddSubfield("FSIX", "b12");
     389          19 :     poFDefn->AddSubfield("NSPT", "b12");
     390             : 
     391          19 :     poModule->AddField(poFDefn);
     392             : 
     393             :     /* -------------------------------------------------------------------- */
     394             :     /*      Create the FSPT field.                                          */
     395             :     /* -------------------------------------------------------------------- */
     396          19 :     poFDefn = new DDFFieldDefn();
     397             : 
     398          19 :     poFDefn->Create("FSPT", "Feature record to spatial record pointer field",
     399             :                     "*", dsc_array, dtc_mixed_data_type);
     400             : 
     401          19 :     poFDefn->AddSubfield("NAME", "B(40)");
     402          19 :     poFDefn->AddSubfield("ORNT", "b11");
     403          19 :     poFDefn->AddSubfield("USAG", "b11");
     404          19 :     poFDefn->AddSubfield("MASK", "b11");
     405             : 
     406          19 :     poModule->AddField(poFDefn);
     407             : 
     408             :     /* -------------------------------------------------------------------- */
     409             :     /*      Create file.                                                    */
     410             :     /* -------------------------------------------------------------------- */
     411          19 :     if (!poModule->Create(pszFilename))
     412             :     {
     413           1 :         delete poModule;
     414           1 :         poModule = nullptr;
     415           1 :         return false;
     416             :     }
     417             : 
     418          18 :     return true;
     419             : }
     420             : 
     421             : /************************************************************************/
     422             : /*                             WriteDSID()                              */
     423             : /************************************************************************/
     424             : 
     425          18 : bool S57Writer::WriteDSID(int nEXPP, int nINTU, const char *pszDSNM,
     426             :                           const char *pszEDTN, const char *pszUPDN,
     427             :                           const char *pszUADT, const char *pszISDT,
     428             :                           const char *pszSTED, int nAGEN, const char *pszCOMT,
     429             :                           int nAALL, int nNALL, int nNOMR, int nNOGR, int nNOLR,
     430             :                           int nNOIN, int nNOCN, int nNOED)
     431             : 
     432             : {
     433             :     /* -------------------------------------------------------------------- */
     434             :     /*      Default values.                                                 */
     435             :     /* -------------------------------------------------------------------- */
     436          18 :     if (pszDSNM == nullptr)
     437           0 :         pszDSNM = "";
     438          18 :     if (pszEDTN == nullptr)
     439          18 :         pszEDTN = "2";
     440          18 :     if (pszUPDN == nullptr)
     441          18 :         pszUPDN = "0";
     442          18 :     if (pszISDT == nullptr)
     443          18 :         pszISDT = "20030801";
     444          18 :     if (pszUADT == nullptr)
     445          18 :         pszUADT = pszISDT;
     446          18 :     if (pszSTED == nullptr)
     447          18 :         pszSTED = "03.1";
     448          18 :     if (pszCOMT == nullptr)
     449          18 :         pszCOMT = "";
     450             : 
     451             :     /* -------------------------------------------------------------------- */
     452             :     /*      Add the DSID field.                                             */
     453             :     /* -------------------------------------------------------------------- */
     454          18 :     DDFRecord *poRec = MakeRecord();
     455             : 
     456             :     // DDFField *poField =
     457          18 :     poRec->AddField(poModule->FindFieldDefn("DSID"));
     458             : 
     459          18 :     poRec->SetIntSubfield("DSID", 0, "RCNM", 0, 10);
     460          18 :     poRec->SetIntSubfield("DSID", 0, "RCID", 0, 1);
     461          18 :     poRec->SetIntSubfield("DSID", 0, "EXPP", 0, nEXPP);
     462          18 :     poRec->SetIntSubfield("DSID", 0, "INTU", 0, nINTU);
     463          18 :     poRec->SetStringSubfield("DSID", 0, "DSNM", 0, pszDSNM);
     464          18 :     poRec->SetStringSubfield("DSID", 0, "EDTN", 0, pszEDTN);
     465          18 :     poRec->SetStringSubfield("DSID", 0, "UPDN", 0, pszUPDN);
     466          18 :     poRec->SetStringSubfield("DSID", 0, "UADT", 0, pszUADT);
     467          18 :     poRec->SetStringSubfield("DSID", 0, "ISDT", 0, pszISDT);
     468          18 :     poRec->SetStringSubfield("DSID", 0, "STED", 0, pszSTED);
     469          18 :     poRec->SetIntSubfield("DSID", 0, "PRSP", 0, 1);
     470          18 :     poRec->SetStringSubfield("DSID", 0, "PSDN", 0, "");
     471          18 :     poRec->SetStringSubfield("DSID", 0, "PRED", 0, "2.0");
     472          18 :     poRec->SetIntSubfield("DSID", 0, "PROF", 0, 1);
     473          18 :     poRec->SetIntSubfield("DSID", 0, "AGEN", 0, nAGEN);
     474          18 :     poRec->SetStringSubfield("DSID", 0, "COMT", 0, pszCOMT);
     475             : 
     476             :     /* -------------------------------------------------------------------- */
     477             :     /*      Add the DSSI record.  Eventually we will need to return and     */
     478             :     /*      correct these when we are finished writing.                     */
     479             :     /* -------------------------------------------------------------------- */
     480          18 :     /* poField = */ poRec->AddField(poModule->FindFieldDefn("DSSI"));
     481             : 
     482          18 :     poRec->SetIntSubfield("DSSI", 0, "DSTR", 0, 2);  // "Chain node"
     483          18 :     poRec->SetIntSubfield("DSSI", 0, "AALL", 0, nAALL);
     484          18 :     poRec->SetIntSubfield("DSSI", 0, "NALL", 0, nNALL);
     485          18 :     poRec->SetIntSubfield("DSSI", 0, "NOMR", 0, nNOMR);  // Meta records
     486             :     // Cartographic records are not permitted in ENC.
     487          18 :     poRec->SetIntSubfield("DSSI", 0, "NOCR", 0, 0);
     488          18 :     poRec->SetIntSubfield("DSSI", 0, "NOGR", 0, nNOGR);  // Geo records
     489             :     // Collection records.
     490          18 :     poRec->SetIntSubfield("DSSI", 0, "NOLR", 0, nNOLR);
     491             :     // Isolated node records.
     492          18 :     poRec->SetIntSubfield("DSSI", 0, "NOIN", 0, nNOIN);
     493             :     // Connected node records.
     494          18 :     poRec->SetIntSubfield("DSSI", 0, "NOCN", 0, nNOCN);
     495          18 :     poRec->SetIntSubfield("DSSI", 0, "NOED", 0, nNOED);  // Edge records
     496             :     // Face are not permitted in chain node structure.
     497          18 :     poRec->SetIntSubfield("DSSI", 0, "NOFA", 0, 0);
     498             : 
     499             :     /* -------------------------------------------------------------------- */
     500             :     /*      Write out the record.                                           */
     501             :     /* -------------------------------------------------------------------- */
     502          18 :     poRec->Write();
     503          18 :     delete poRec;
     504             : 
     505          18 :     return true;
     506             : }
     507             : 
     508             : /************************************************************************/
     509             : /*                             WriteDSPM()                              */
     510             : /************************************************************************/
     511             : 
     512          18 : bool S57Writer::WriteDSPM(int nHDAT, int nVDAT, int nSDAT, int nCSCL, int nCOMF,
     513             :                           int nSOMF)
     514             : 
     515             : {
     516          18 :     m_nCOMF = nCOMF;
     517          18 :     m_nSOMF = nSOMF;
     518             : 
     519             :     /* -------------------------------------------------------------------- */
     520             :     /*      Add the DSID field.                                             */
     521             :     /* -------------------------------------------------------------------- */
     522          18 :     DDFRecord *poRec = MakeRecord();
     523             : 
     524             :     // DDFField *poField =
     525          18 :     poRec->AddField(poModule->FindFieldDefn("DSPM"));
     526             : 
     527          18 :     poRec->SetIntSubfield("DSPM", 0, "RCNM", 0, 20);
     528          18 :     poRec->SetIntSubfield("DSPM", 0, "RCID", 0, 1);
     529             :     // Must be 2 for ENC.
     530          18 :     poRec->SetIntSubfield("DSPM", 0, "HDAT", 0, nHDAT);
     531          18 :     poRec->SetIntSubfield("DSPM", 0, "VDAT", 0, nVDAT);
     532          18 :     poRec->SetIntSubfield("DSPM", 0, "SDAT", 0, nSDAT);
     533          18 :     poRec->SetIntSubfield("DSPM", 0, "CSCL", 0, nCSCL);
     534          18 :     poRec->SetIntSubfield("DSPM", 0, "DUNI", 0, 1);
     535          18 :     poRec->SetIntSubfield("DSPM", 0, "HUNI", 0, 1);
     536          18 :     poRec->SetIntSubfield("DSPM", 0, "PUNI", 0, 1);
     537          18 :     poRec->SetIntSubfield("DSPM", 0, "COUN", 0, 1);
     538          18 :     poRec->SetIntSubfield("DSPM", 0, "COMF", 0, nCOMF);
     539          18 :     poRec->SetIntSubfield("DSPM", 0, "SOMF", 0, nSOMF);
     540             : 
     541             :     /* -------------------------------------------------------------------- */
     542             :     /*      Write out the record.                                           */
     543             :     /* -------------------------------------------------------------------- */
     544          18 :     poRec->Write();
     545          18 :     delete poRec;
     546             : 
     547          18 :     return true;
     548             : }
     549             : 
     550             : /************************************************************************/
     551             : /*                             MakeRecord()                             */
     552             : /*                                                                      */
     553             : /*      Create a new empty record, and append a 0001 field with a       */
     554             : /*      properly set record index in it.                                */
     555             : /************************************************************************/
     556             : 
     557         154 : DDFRecord *S57Writer::MakeRecord()
     558             : 
     559             : {
     560             :     unsigned char abyData[2] = {
     561         154 :         static_cast<unsigned char>(nNext0001Index % 256),
     562         154 :         static_cast<unsigned char>(nNext0001Index / 256)};
     563             : 
     564         154 :     DDFRecord *poRec = new DDFRecord(poModule);
     565         154 :     DDFField *poField = poRec->AddField(poModule->FindFieldDefn("0001"));
     566         154 :     poRec->SetFieldRaw(poField, 0, (const char *)abyData, 2);
     567             : 
     568         154 :     nNext0001Index++;
     569             : 
     570         154 :     return poRec;
     571             : }
     572             : 
     573             : /************************************************************************/
     574             : /*                           WriteGeometry()                            */
     575             : /************************************************************************/
     576             : 
     577          70 : bool S57Writer::WriteGeometry(DDFRecord *poRec, int nVertCount,
     578             :                               const double *padfX, const double *padfY,
     579             :                               const double *padfZ)
     580             : 
     581             : {
     582          70 :     const char *pszFieldName = "SG2D";
     583             : 
     584          70 :     if (padfZ != nullptr)
     585           4 :         pszFieldName = "SG3D";
     586             : 
     587          70 :     DDFField *poField = poRec->AddField(poModule->FindFieldDefn(pszFieldName));
     588             : 
     589          70 :     const int nRawDataSize = padfZ ? 12 * nVertCount : 8 * nVertCount;
     590             : 
     591             :     unsigned char *pabyRawData =
     592          70 :         static_cast<unsigned char *>(CPLMalloc(nRawDataSize));
     593             : 
     594         252 :     for (int i = 0; i < nVertCount; i++)
     595             :     {
     596         182 :         const GInt32 nXCOO =
     597         182 :             CPL_LSBWORD32(static_cast<GInt32>(floor(padfX[i] * m_nCOMF + 0.5)));
     598         182 :         const GInt32 nYCOO =
     599         182 :             CPL_LSBWORD32(static_cast<GInt32>(floor(padfY[i] * m_nCOMF + 0.5)));
     600             : 
     601         182 :         if (padfZ == nullptr)
     602             :         {
     603         160 :             memcpy(pabyRawData + i * 8, &nYCOO, 4);
     604         160 :             memcpy(pabyRawData + i * 8 + 4, &nXCOO, 4);
     605             :         }
     606             :         else
     607             :         {
     608          22 :             const GInt32 nVE3D = CPL_LSBWORD32(
     609             :                 static_cast<GInt32>(floor(padfZ[i] * m_nSOMF + 0.5)));
     610          22 :             memcpy(pabyRawData + i * 12, &nYCOO, 4);
     611          22 :             memcpy(pabyRawData + i * 12 + 4, &nXCOO, 4);
     612          22 :             memcpy(pabyRawData + i * 12 + 8, &nVE3D, 4);
     613             :         }
     614             :     }
     615             : 
     616          70 :     const bool nSuccess = CPL_TO_BOOL(poRec->SetFieldRaw(
     617             :         poField, 0, reinterpret_cast<const char *>(pabyRawData), nRawDataSize));
     618             : 
     619          70 :     CPLFree(pabyRawData);
     620             : 
     621          70 :     return nSuccess;
     622             : }
     623             : 
     624             : /************************************************************************/
     625             : /*                           WritePrimitive()                           */
     626             : /************************************************************************/
     627             : 
     628          94 : bool S57Writer::WritePrimitive(OGRFeature *poFeature)
     629             : 
     630             : {
     631          94 :     DDFRecord *poRec = MakeRecord();
     632          94 :     const OGRGeometry *poGeom = poFeature->GetGeometryRef();
     633             : 
     634             :     /* -------------------------------------------------------------------- */
     635             :     /*      Add the VRID field.                                             */
     636             :     /* -------------------------------------------------------------------- */
     637             : 
     638             :     // DDFField *poField =
     639          94 :     poRec->AddField(poModule->FindFieldDefn("VRID"));
     640             : 
     641          94 :     poRec->SetIntSubfield("VRID", 0, "RCNM", 0,
     642             :                           poFeature->GetFieldAsInteger("RCNM"));
     643          94 :     poRec->SetIntSubfield("VRID", 0, "RCID", 0,
     644             :                           poFeature->GetFieldAsInteger("RCID"));
     645          94 :     poRec->SetIntSubfield("VRID", 0, "RVER", 0, 1);
     646          94 :     poRec->SetIntSubfield("VRID", 0, "RUIN", 0, 1);
     647             : 
     648          94 :     bool bRet = true;
     649             : 
     650             :     /* -------------------------------------------------------------------- */
     651             :     /*      Handle simple point.                                            */
     652             :     /* -------------------------------------------------------------------- */
     653          94 :     if (poGeom != nullptr && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
     654             :     {
     655          40 :         const OGRPoint *poPoint = poGeom->toPoint();
     656             : 
     657          40 :         CPLAssert(poFeature->GetFieldAsInteger("RCNM") == RCNM_VI ||
     658             :                   poFeature->GetFieldAsInteger("RCNM") == RCNM_VC);
     659             : 
     660          40 :         const double adfX[1] = {poPoint->getX()};
     661          40 :         const double adfY[1] = {poPoint->getY()};
     662          40 :         const double adfZ[1] = {poPoint->getZ()};
     663             : 
     664          40 :         if (adfZ[0] == 0.0)
     665          40 :             bRet = WriteGeometry(poRec, 1, &adfX[0], &adfY[0], nullptr);
     666             :         else
     667           0 :             bRet = WriteGeometry(poRec, 1, &adfX[0], &adfY[0], &adfZ[0]);
     668             :     }
     669             : 
     670             :     /* -------------------------------------------------------------------- */
     671             :     /*      For multipoints we assuming SOUNDG, and write out as SG3D.      */
     672             :     /* -------------------------------------------------------------------- */
     673         108 :     else if (poGeom != nullptr &&
     674          54 :              wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
     675             :     {
     676           4 :         const OGRMultiPoint *poMP = poGeom->toMultiPoint();
     677           4 :         const int nVCount = poMP->getNumGeometries();
     678             : 
     679           4 :         CPLAssert(poFeature->GetFieldAsInteger("RCNM") == RCNM_VI ||
     680             :                   poFeature->GetFieldAsInteger("RCNM") == RCNM_VC);
     681             : 
     682           4 :         double *padfX = (double *)CPLMalloc(sizeof(double) * nVCount);
     683           4 :         double *padfY = (double *)CPLMalloc(sizeof(double) * nVCount);
     684           4 :         double *padfZ = (double *)CPLMalloc(sizeof(double) * nVCount);
     685             : 
     686          26 :         for (int i = 0; i < nVCount; i++)
     687             :         {
     688          22 :             const OGRPoint *poPoint = poMP->getGeometryRef(i);
     689          22 :             padfX[i] = poPoint->getX();
     690          22 :             padfY[i] = poPoint->getY();
     691          22 :             padfZ[i] = poPoint->getZ();
     692             :         }
     693             : 
     694           4 :         bRet = WriteGeometry(poRec, nVCount, padfX, padfY, padfZ);
     695             : 
     696           4 :         CPLFree(padfX);
     697           4 :         CPLFree(padfY);
     698           4 :         CPLFree(padfZ);
     699             :     }
     700             : 
     701             :     /* -------------------------------------------------------------------- */
     702             :     /*      Handle LINESTRINGs (edge) geometry.                             */
     703             :     /* -------------------------------------------------------------------- */
     704         100 :     else if (poGeom != nullptr &&
     705          50 :              wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
     706             :     {
     707          50 :         const OGRLineString *poLS = poGeom->toLineString();
     708          50 :         const int nVCount = poLS->getNumPoints();
     709             : 
     710          50 :         CPLAssert(poFeature->GetFieldAsInteger("RCNM") == RCNM_VE);
     711             : 
     712          50 :         double *padfX = (double *)CPLMalloc(sizeof(double) * nVCount);
     713          50 :         double *padfY = (double *)CPLMalloc(sizeof(double) * nVCount);
     714             : 
     715         170 :         for (int i = 0; i < nVCount; i++)
     716             :         {
     717         120 :             padfX[i] = poLS->getX(i);
     718         120 :             padfY[i] = poLS->getY(i);
     719             :         }
     720             : 
     721          50 :         if (nVCount)
     722          26 :             bRet = WriteGeometry(poRec, nVCount, padfX, padfY, nullptr);
     723             : 
     724          50 :         CPLFree(padfX);
     725          50 :         CPLFree(padfY);
     726             :     }
     727             : 
     728             :     /* -------------------------------------------------------------------- */
     729             :     /*      edge node linkages.                                             */
     730             :     /* -------------------------------------------------------------------- */
     731          94 :     if (poFeature->GetDefnRef()->GetFieldIndex("NAME_RCNM_0") >= 0)
     732             :     {
     733          50 :         CPLAssert(poFeature->GetFieldAsInteger("NAME_RCNM_0") == RCNM_VC);
     734             : 
     735             :         // DDFField *poField =
     736          50 :         poRec->AddField(poModule->FindFieldDefn("VRPT"));
     737             : 
     738          50 :         const int nRCID0 = poFeature->GetFieldAsInteger("NAME_RCID_0");
     739          50 :         char szName0[5] = {RCNM_VC, static_cast<char>(nRCID0 & 0xff),
     740          50 :                            static_cast<char>((nRCID0 & 0xff00) >> 8),
     741          50 :                            static_cast<char>((nRCID0 & 0xff0000) >> 16),
     742          50 :                            static_cast<char>((nRCID0 & 0xff000000) >> 24)};
     743             : 
     744          50 :         poRec->SetStringSubfield("VRPT", 0, "NAME", 0, szName0, 5);
     745          50 :         poRec->SetIntSubfield("VRPT", 0, "ORNT", 0,
     746             :                               poFeature->GetFieldAsInteger("ORNT_0"));
     747          50 :         poRec->SetIntSubfield("VRPT", 0, "USAG", 0,
     748             :                               poFeature->GetFieldAsInteger("USAG_0"));
     749          50 :         poRec->SetIntSubfield("VRPT", 0, "TOPI", 0,
     750             :                               poFeature->GetFieldAsInteger("TOPI_0"));
     751          50 :         poRec->SetIntSubfield("VRPT", 0, "MASK", 0,
     752             :                               poFeature->GetFieldAsInteger("MASK_0"));
     753             : 
     754          50 :         const int nRCID1 = poFeature->GetFieldAsInteger("NAME_RCID_1");
     755          50 :         const char szName1[5] = {
     756             :             RCNM_VC, static_cast<char>(nRCID1 & 0xff),
     757          50 :             static_cast<char>((nRCID1 & 0xff00) >> 8),
     758          50 :             static_cast<char>((nRCID1 & 0xff0000) >> 16),
     759          50 :             static_cast<char>((nRCID1 & 0xff000000) >> 24)};
     760             : 
     761          50 :         poRec->SetStringSubfield("VRPT", 0, "NAME", 1, szName1, 5);
     762          50 :         poRec->SetIntSubfield("VRPT", 0, "ORNT", 1,
     763             :                               poFeature->GetFieldAsInteger("ORNT_1"));
     764          50 :         poRec->SetIntSubfield("VRPT", 0, "USAG", 1,
     765             :                               poFeature->GetFieldAsInteger("USAG_1"));
     766          50 :         poRec->SetIntSubfield("VRPT", 0, "TOPI", 1,
     767             :                               poFeature->GetFieldAsInteger("TOPI_1"));
     768          50 :         poRec->SetIntSubfield("VRPT", 0, "MASK", 1,
     769             :                               poFeature->GetFieldAsInteger("MASK_1"));
     770             :     }
     771             : 
     772             :     /* -------------------------------------------------------------------- */
     773             :     /*      Write out the record.                                           */
     774             :     /* -------------------------------------------------------------------- */
     775          94 :     if (!poRec->Write())
     776           0 :         bRet = false;
     777          94 :     delete poRec;
     778             : 
     779          94 :     return bRet;
     780             : }
     781             : 
     782             : /************************************************************************/
     783             : /*                             GetHEXChar()                             */
     784             : /************************************************************************/
     785             : 
     786           0 : static char GetHEXChar(const char *pszSrcHEXString)
     787             : 
     788             : {
     789           0 :     if (pszSrcHEXString[0] == '\0' || pszSrcHEXString[1] == '\0')
     790           0 :         return (char)0;
     791             : 
     792           0 :     int nResult = 0;
     793             : 
     794           0 :     if (pszSrcHEXString[0] >= '0' && pszSrcHEXString[0] <= '9')
     795           0 :         nResult += (pszSrcHEXString[0] - '0') * 16;
     796           0 :     else if (pszSrcHEXString[0] >= 'a' && pszSrcHEXString[0] <= 'f')
     797           0 :         nResult += (pszSrcHEXString[0] - 'a' + 10) * 16;
     798           0 :     else if (pszSrcHEXString[0] >= 'A' && pszSrcHEXString[0] <= 'F')
     799           0 :         nResult += (pszSrcHEXString[0] - 'A' + 10) * 16;
     800             : 
     801           0 :     if (pszSrcHEXString[1] >= '0' && pszSrcHEXString[1] <= '9')
     802           0 :         nResult += pszSrcHEXString[1] - '0';
     803           0 :     else if (pszSrcHEXString[1] >= 'a' && pszSrcHEXString[1] <= 'f')
     804           0 :         nResult += pszSrcHEXString[1] - 'a' + 10;
     805           0 :     else if (pszSrcHEXString[1] >= 'A' && pszSrcHEXString[1] <= 'F')
     806           0 :         nResult += pszSrcHEXString[1] - 'A' + 10;
     807             : 
     808           0 :     return (char)nResult;
     809             : }
     810             : 
     811             : /************************************************************************/
     812             : /*                        WriteCompleteFeature()                        */
     813             : /************************************************************************/
     814             : 
     815         118 : bool S57Writer::WriteCompleteFeature(OGRFeature *poFeature)
     816             : 
     817             : {
     818         118 :     OGRFeatureDefn *poFDefn = poFeature->GetDefnRef();
     819             : 
     820             :     /* -------------------------------------------------------------------- */
     821             :     /*      We handle primitives in a separate method.                      */
     822             :     /* -------------------------------------------------------------------- */
     823         118 :     if (EQUAL(poFDefn->GetName(), OGRN_VI) ||
     824         192 :         EQUAL(poFDefn->GetName(), OGRN_VC) ||
     825          74 :         EQUAL(poFDefn->GetName(), OGRN_VE))
     826          94 :         return WritePrimitive(poFeature);
     827             : 
     828             :     /* -------------------------------------------------------------------- */
     829             :     /*      Create the record.                                              */
     830             :     /* -------------------------------------------------------------------- */
     831          24 :     DDFRecord *poRec = MakeRecord();
     832             : 
     833             :     /* -------------------------------------------------------------------- */
     834             :     /*      Add the FRID.                                                   */
     835             :     /* -------------------------------------------------------------------- */
     836             :     // DDFField *poField =
     837          24 :     poRec->AddField(poModule->FindFieldDefn("FRID"));
     838             : 
     839          24 :     poRec->SetIntSubfield("FRID", 0, "RCNM", 0, 100);
     840          24 :     poRec->SetIntSubfield("FRID", 0, "RCID", 0,
     841             :                           poFeature->GetFieldAsInteger("RCID"));
     842          24 :     poRec->SetIntSubfield("FRID", 0, "PRIM", 0,
     843             :                           poFeature->GetFieldAsInteger("PRIM"));
     844          24 :     poRec->SetIntSubfield("FRID", 0, "GRUP", 0,
     845             :                           poFeature->GetFieldAsInteger("GRUP"));
     846          24 :     poRec->SetIntSubfield("FRID", 0, "OBJL", 0,
     847             :                           poFeature->GetFieldAsInteger("OBJL"));
     848          24 :     poRec->SetIntSubfield("FRID", 0, "RVER", 0, 1); /* always new insert*/
     849          24 :     poRec->SetIntSubfield("FRID", 0, "RUIN", 0, 1);
     850             : 
     851             :     /* -------------------------------------------------------------------- */
     852             :     /*      Add the FOID                                                    */
     853             :     /* -------------------------------------------------------------------- */
     854          24 :     /*poField = */ poRec->AddField(poModule->FindFieldDefn("FOID"));
     855             : 
     856          24 :     poRec->SetIntSubfield("FOID", 0, "AGEN", 0,
     857             :                           poFeature->GetFieldAsInteger("AGEN"));
     858          24 :     poRec->SetIntSubfield("FOID", 0, "FIDN", 0,
     859             :                           poFeature->GetFieldAsInteger("FIDN"));
     860          24 :     poRec->SetIntSubfield("FOID", 0, "FIDS", 0,
     861             :                           poFeature->GetFieldAsInteger("FIDS"));
     862             : 
     863             :     /* -------------------------------------------------------------------- */
     864             :     /*      ATTF support.                                                   */
     865             :     /* -------------------------------------------------------------------- */
     866             : 
     867          72 :     if (poRegistrar != nullptr &&
     868          24 :         poClassContentExplorer->SelectClass(
     869          48 :             poFeature->GetDefnRef()->GetName()) &&
     870          24 :         !WriteATTF(poRec, poFeature))
     871             :     {
     872           0 :         delete poRec;
     873           0 :         return false;
     874             :     }
     875             : 
     876             :     /* -------------------------------------------------------------------- */
     877             :     /*      Add the FSPT if needed.                                         */
     878             :     /* -------------------------------------------------------------------- */
     879          24 :     if (poFeature->IsFieldSetAndNotNull(poFeature->GetFieldIndex("NAME_RCNM")))
     880             :     {
     881          24 :         int nItemCount = 0;
     882             : 
     883             :         const int *panRCNM =
     884          24 :             poFeature->GetFieldAsIntegerList("NAME_RCNM", &nItemCount);
     885             :         const int *panRCID =
     886          24 :             poFeature->GetFieldAsIntegerList("NAME_RCID", &nItemCount);
     887             :         const int *panORNT =
     888          24 :             poFeature->GetFieldAsIntegerList("ORNT", &nItemCount);
     889             :         const int *panUSAG =
     890          24 :             poFeature->GetFieldAsIntegerList("USAG", &nItemCount);
     891             :         const int *panMASK =
     892          24 :             poFeature->GetFieldAsIntegerList("MASK", &nItemCount);
     893             : 
     894             :         // cppcheck-suppress duplicateExpression
     895             :         CPLAssert(sizeof(int) == sizeof(GInt32));
     896             : 
     897          24 :         const int nRawDataSize = nItemCount * 8;
     898          24 :         unsigned char *pabyRawData = (unsigned char *)CPLMalloc(nRawDataSize);
     899             : 
     900         124 :         for (int i = 0; i < nItemCount; i++)
     901             :         {
     902         100 :             GInt32 nRCID = CPL_LSBWORD32(panRCID[i]);
     903             : 
     904         100 :             pabyRawData[i * 8 + 0] = (GByte)panRCNM[i];
     905         100 :             memcpy(pabyRawData + i * 8 + 1, &nRCID, 4);
     906         100 :             pabyRawData[i * 8 + 5] = (GByte)panORNT[i];
     907         100 :             pabyRawData[i * 8 + 6] = (GByte)panUSAG[i];
     908         100 :             pabyRawData[i * 8 + 7] = (GByte)panMASK[i];
     909             :         }
     910             : 
     911          24 :         DDFField *poField = poRec->AddField(poModule->FindFieldDefn("FSPT"));
     912          24 :         poRec->SetFieldRaw(poField, 0, (const char *)pabyRawData, nRawDataSize);
     913          24 :         CPLFree(pabyRawData);
     914             :     }
     915             : 
     916             :     /* -------------------------------------------------------------------- */
     917             :     /*      Add the FFPT if needed.                                         */
     918             :     /* -------------------------------------------------------------------- */
     919          24 :     char **papszLNAM_REFS = poFeature->GetFieldAsStringList("LNAM_REFS");
     920             : 
     921          24 :     if (CSLCount(papszLNAM_REFS) > 0)
     922             :     {
     923           0 :         int i, nRefCount = CSLCount(papszLNAM_REFS);
     924             :         const int *panRIND =
     925           0 :             poFeature->GetFieldAsIntegerList("FFPT_RIND", nullptr);
     926             : 
     927           0 :         poRec->AddField(poModule->FindFieldDefn("FFPT"));
     928             : 
     929           0 :         for (i = 0; i < nRefCount; i++)
     930             :         {
     931             :             char szLNAM[9];
     932             : 
     933           0 :             if (strlen(papszLNAM_REFS[i]) < 16)
     934           0 :                 continue;
     935             : 
     936             :             // AGEN
     937           0 :             szLNAM[1] = GetHEXChar(papszLNAM_REFS[i] + 0);
     938           0 :             szLNAM[0] = GetHEXChar(papszLNAM_REFS[i] + 2);
     939             : 
     940             :             // FIDN
     941           0 :             szLNAM[5] = GetHEXChar(papszLNAM_REFS[i] + 4);
     942           0 :             szLNAM[4] = GetHEXChar(papszLNAM_REFS[i] + 6);
     943           0 :             szLNAM[3] = GetHEXChar(papszLNAM_REFS[i] + 8);
     944           0 :             szLNAM[2] = GetHEXChar(papszLNAM_REFS[i] + 10);
     945             : 
     946             :             // FIDS
     947           0 :             szLNAM[7] = GetHEXChar(papszLNAM_REFS[i] + 12);
     948           0 :             szLNAM[6] = GetHEXChar(papszLNAM_REFS[i] + 14);
     949             : 
     950           0 :             szLNAM[8] = '\0';
     951             : 
     952           0 :             poRec->SetStringSubfield("FFPT", 0, "LNAM", i, (char *)szLNAM, 8);
     953           0 :             poRec->SetIntSubfield("FFPT", 0, "RIND", i, panRIND[i]);
     954             :         }
     955             :     }
     956             : 
     957             :     /* -------------------------------------------------------------------- */
     958             :     /*      Write out the record.                                           */
     959             :     /* -------------------------------------------------------------------- */
     960          24 :     poRec->Write();
     961          24 :     delete poRec;
     962             : 
     963          24 :     return true;
     964             : }
     965             : 
     966             : /************************************************************************/
     967             : /*                           SetClassBased()                            */
     968             : /************************************************************************/
     969             : 
     970          18 : void S57Writer::SetClassBased(S57ClassRegistrar *poReg,
     971             :                               S57ClassContentExplorer *poClassContentExplorerIn)
     972             : 
     973             : {
     974          18 :     poRegistrar = poReg;
     975          18 :     poClassContentExplorer = poClassContentExplorerIn;
     976          18 : }
     977             : 
     978             : /************************************************************************/
     979             : /*                             WriteATTF()                              */
     980             : /************************************************************************/
     981             : 
     982          24 : bool S57Writer::WriteATTF(DDFRecord *poRec, OGRFeature *poFeature)
     983             : {
     984          24 :     CPLAssert(poRegistrar != nullptr);
     985             : 
     986             :     /* -------------------------------------------------------------------- */
     987             :     /*      Loop over all attributes.                                       */
     988             :     /* -------------------------------------------------------------------- */
     989          24 :     int nRawSize = 0;
     990          24 :     int nACount = 0;
     991          24 :     char achRawData[5000] = {};
     992             : 
     993          24 :     char **papszAttrList = poClassContentExplorer->GetAttributeList(nullptr);
     994             : 
     995         414 :     for (int iAttr = 0; papszAttrList[iAttr] != nullptr; iAttr++)
     996             :     {
     997         390 :         const int iField = poFeature->GetFieldIndex(papszAttrList[iAttr]);
     998         390 :         if (iField < 0)
     999         363 :             continue;
    1000             : 
    1001             :         const OGRFieldType eFldType =
    1002         390 :             poFeature->GetDefnRef()->GetFieldDefn(iField)->GetType();
    1003             : 
    1004         390 :         if (!poFeature->IsFieldSetAndNotNull(iField))
    1005         363 :             continue;
    1006             : 
    1007             :         const int nATTLInt =
    1008          27 :             poRegistrar->FindAttrByAcronym(papszAttrList[iAttr]);
    1009          27 :         if (nATTLInt == -1)
    1010           0 :             continue;
    1011             : 
    1012          27 :         GUInt16 nATTL = (GUInt16)nATTLInt;
    1013          27 :         CPL_LSBPTR16(&nATTL);
    1014          27 :         memcpy(achRawData + nRawSize, &nATTL, 2);
    1015          27 :         nRawSize += 2;
    1016             : 
    1017          27 :         CPLString osATVL;
    1018          27 :         if (eFldType == OFTStringList)
    1019             :         {
    1020             :             const char *const *papszTokens =
    1021           6 :                 poFeature->GetFieldAsStringList(iField);
    1022          12 :             for (auto papszIter = papszTokens; papszIter && *papszIter;
    1023             :                  ++papszIter)
    1024             :             {
    1025           6 :                 if (!osATVL.empty())
    1026           0 :                     osATVL += ',';
    1027           6 :                 osATVL += *papszIter;
    1028             :             }
    1029             :         }
    1030             :         else
    1031             :         {
    1032          21 :             osATVL = poFeature->GetFieldAsString(iField);
    1033             :         }
    1034             : 
    1035             :         // Special hack to handle special "empty" marker in integer fields.
    1036          48 :         if ((eFldType == OFTInteger || eFldType == OFTReal) &&
    1037          21 :             atoi(osATVL) == EMPTY_NUMBER_MARKER)
    1038           0 :             osATVL.clear();
    1039             : 
    1040             :         // Watch for really long data.
    1041          27 :         if (osATVL.size() + nRawSize + 10 > sizeof(achRawData))
    1042             :         {
    1043           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1044             :                      "Too much ATTF data for fixed buffer size.");
    1045           0 :             return false;
    1046             :         }
    1047             : 
    1048             :         // copy data into record buffer.
    1049          27 :         if (!osATVL.empty())
    1050             :         {
    1051          27 :             memcpy(achRawData + nRawSize, osATVL.data(), osATVL.size());
    1052          27 :             nRawSize += static_cast<int>(osATVL.size());
    1053             :         }
    1054          27 :         achRawData[nRawSize++] = DDF_UNIT_TERMINATOR;
    1055             : 
    1056          27 :         nACount++;
    1057             :     }
    1058             : 
    1059             :     /* -------------------------------------------------------------------- */
    1060             :     /*      If we got no attributes, return without adding ATTF.            */
    1061             :     /* -------------------------------------------------------------------- */
    1062          24 :     if (nACount == 0)
    1063           5 :         return true;
    1064             : 
    1065             :     /* -------------------------------------------------------------------- */
    1066             :     /*      Write the new field value.                                      */
    1067             :     /* -------------------------------------------------------------------- */
    1068          19 :     DDFField *poField = poRec->AddField(poModule->FindFieldDefn("ATTF"));
    1069             : 
    1070          19 :     return CPL_TO_BOOL(poRec->SetFieldRaw(poField, 0, achRawData, nRawSize));
    1071             : }

Generated by: LCOV version 1.14