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

Generated by: LCOV version 1.14