Coverage Report

Created: 2026-09-26 08:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/s57/ogrs57datasource.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  S-57 Translator
4
 * Purpose:  Implements OGRS57DataSource class
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999, Frank Warmerdam
9
 * Copyright (c) 2010-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_s57.h"
17
18
#include <algorithm>
19
#include <set>
20
21
/************************************************************************/
22
/*                          OGRS57DataSource()                          */
23
/************************************************************************/
24
25
OGRS57DataSource::OGRS57DataSource(CSLConstList papszOpenOptionsIn)
26
418
    : nLayers(0), papoLayers(nullptr), poSpatialRef(new OGRSpatialReference()),
27
418
      papszOptions(nullptr), nModules(0), papoModules(nullptr),
28
418
      poWriter(nullptr), poClassContentExplorer(nullptr), bExtentsSet(false)
29
418
{
30
418
    poSpatialRef->SetWellKnownGeogCS("WGS84");
31
418
    poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
32
33
    /* -------------------------------------------------------------------- */
34
    /*      Allow initialization of options from the environment.           */
35
    /* -------------------------------------------------------------------- */
36
418
    const char *pszOptString = CPLGetConfigOption("OGR_S57_OPTIONS", nullptr);
37
38
418
    if (pszOptString != nullptr)
39
0
    {
40
0
        papszOptions =
41
0
            CSLTokenizeStringComplex(pszOptString, ",", FALSE, FALSE);
42
43
0
        if (papszOptions && *papszOptions)
44
0
        {
45
0
            CPLDebug("S57", "The following S57 options are being set:");
46
0
            CSLConstList papszCurOption = papszOptions;
47
0
            while (*papszCurOption)
48
0
                CPLDebug("S57", "    %s", *papszCurOption++);
49
0
        }
50
0
    }
51
52
    /* -------------------------------------------------------------------- */
53
    /*      And from open options.                                          */
54
    /* -------------------------------------------------------------------- */
55
418
    for (CSLConstList papszIter = papszOpenOptionsIn; papszIter && *papszIter;
56
418
         ++papszIter)
57
0
    {
58
0
        char *pszKey = nullptr;
59
0
        const char *pszValue = CPLParseNameValue(*papszIter, &pszKey);
60
0
        if (pszKey && pszValue)
61
0
        {
62
0
            papszOptions = CSLSetNameValue(papszOptions, pszKey, pszValue);
63
0
        }
64
0
        CPLFree(pszKey);
65
0
    }
66
418
}
67
68
/************************************************************************/
69
/*                         ~OGRS57DataSource()                          */
70
/************************************************************************/
71
72
OGRS57DataSource::~OGRS57DataSource()
73
74
418
{
75
712
    for (int i = 0; i < nLayers; i++)
76
294
        delete papoLayers[i];
77
78
418
    CPLFree(papoLayers);
79
80
712
    for (int i = 0; i < nModules; i++)
81
294
        delete papoModules[i];
82
418
    CPLFree(papoModules);
83
84
418
    CSLDestroy(papszOptions);
85
86
418
    poSpatialRef->Release();
87
88
418
    if (poWriter != nullptr)
89
0
    {
90
0
        poWriter->Close();
91
0
        delete poWriter;
92
0
    }
93
418
    delete poClassContentExplorer;
94
418
}
95
96
/************************************************************************/
97
/*                           SetOptionList()                            */
98
/************************************************************************/
99
100
void OGRS57DataSource::SetOptionList(char **papszNewOptions)
101
102
0
{
103
0
    CSLDestroy(papszOptions);
104
0
    papszOptions = CSLDuplicate(papszNewOptions);
105
0
}
106
107
/************************************************************************/
108
/*                             GetOption()                              */
109
/************************************************************************/
110
111
const char *OGRS57DataSource::GetOption(const char *pszOption)
112
113
4.76k
{
114
4.76k
    return CSLFetchNameValue(papszOptions, pszOption);
115
4.76k
}
116
117
/************************************************************************/
118
/*                           TestCapability()                           */
119
/************************************************************************/
120
121
bool OGRS57DataSource::TestCapability(const char *pszCap) const
122
123
0
{
124
0
    if (EQUAL(pszCap, ODsCZGeometries))
125
0
        return true;
126
127
0
    return false;
128
0
}
129
130
/************************************************************************/
131
/*                                Open()                                */
132
/************************************************************************/
133
134
int OGRS57DataSource::Open(const char *pszFilename)
135
136
418
{
137
    /* -------------------------------------------------------------------- */
138
    /*      Setup reader options.                                           */
139
    /* -------------------------------------------------------------------- */
140
418
    char **papszReaderOptions = nullptr;
141
142
418
    if (GetOption(S57O_LNAM_REFS) == nullptr)
143
418
        papszReaderOptions =
144
418
            CSLSetNameValue(papszReaderOptions, S57O_LNAM_REFS, "ON");
145
0
    else
146
0
        papszReaderOptions = CSLSetNameValue(papszReaderOptions, S57O_LNAM_REFS,
147
0
                                             GetOption(S57O_LNAM_REFS));
148
149
418
    if (GetOption(S57O_UPDATES) != nullptr)
150
0
        papszReaderOptions = CSLSetNameValue(papszReaderOptions, S57O_UPDATES,
151
0
                                             GetOption(S57O_UPDATES));
152
153
418
    if (GetOption(S57O_SPLIT_MULTIPOINT) != nullptr)
154
0
        papszReaderOptions =
155
0
            CSLSetNameValue(papszReaderOptions, S57O_SPLIT_MULTIPOINT,
156
0
                            GetOption(S57O_SPLIT_MULTIPOINT));
157
158
418
    if (GetOption(S57O_ADD_SOUNDG_DEPTH) != nullptr)
159
0
        papszReaderOptions =
160
0
            CSLSetNameValue(papszReaderOptions, S57O_ADD_SOUNDG_DEPTH,
161
0
                            GetOption(S57O_ADD_SOUNDG_DEPTH));
162
163
418
    if (GetOption(S57O_PRESERVE_EMPTY_NUMBERS) != nullptr)
164
0
        papszReaderOptions =
165
0
            CSLSetNameValue(papszReaderOptions, S57O_PRESERVE_EMPTY_NUMBERS,
166
0
                            GetOption(S57O_PRESERVE_EMPTY_NUMBERS));
167
168
418
    if (GetOption(S57O_RETURN_PRIMITIVES) != nullptr)
169
0
        papszReaderOptions =
170
0
            CSLSetNameValue(papszReaderOptions, S57O_RETURN_PRIMITIVES,
171
0
                            GetOption(S57O_RETURN_PRIMITIVES));
172
173
418
    if (GetOption(S57O_RETURN_LINKAGES) != nullptr)
174
0
        papszReaderOptions =
175
0
            CSLSetNameValue(papszReaderOptions, S57O_RETURN_LINKAGES,
176
0
                            GetOption(S57O_RETURN_LINKAGES));
177
178
418
    if (GetOption(S57O_RETURN_DSID) != nullptr)
179
0
        papszReaderOptions = CSLSetNameValue(
180
0
            papszReaderOptions, S57O_RETURN_DSID, GetOption(S57O_RETURN_DSID));
181
182
418
    if (GetOption(S57O_RECODE_BY_DSSI) != nullptr)
183
0
        papszReaderOptions =
184
0
            CSLSetNameValue(papszReaderOptions, S57O_RECODE_BY_DSSI,
185
0
                            GetOption(S57O_RECODE_BY_DSSI));
186
187
418
    if (GetOption(S57O_LIST_AS_STRING) != nullptr)
188
0
        papszReaderOptions =
189
0
            CSLSetNameValue(papszReaderOptions, S57O_LIST_AS_STRING,
190
0
                            GetOption(S57O_LIST_AS_STRING));
191
192
418
    S57Reader *poModule = new S57Reader(pszFilename);
193
418
    bool bRet = poModule->SetOptions(papszReaderOptions);
194
418
    CSLDestroy(papszReaderOptions);
195
196
418
    if (!bRet)
197
0
    {
198
0
        delete poModule;
199
0
        return FALSE;
200
0
    }
201
202
    /* -------------------------------------------------------------------- */
203
    /*      Try opening.                                                    */
204
    /*                                                                      */
205
    /*      Eventually this should check for catalogs, and if found         */
206
    /*      instantiate a whole series of modules.                          */
207
    /* -------------------------------------------------------------------- */
208
418
    if (!poModule->Open(TRUE))
209
124
    {
210
124
        delete poModule;
211
212
124
        return FALSE;
213
124
    }
214
215
294
    bool bSuccess = true;
216
217
294
    nModules = 1;
218
294
    papoModules = static_cast<S57Reader **>(CPLMalloc(sizeof(void *)));
219
294
    papoModules[0] = poModule;
220
221
    /* -------------------------------------------------------------------- */
222
    /*      Add the header layers if they are called for.                   */
223
    /* -------------------------------------------------------------------- */
224
294
    if (GetOption(S57O_RETURN_DSID) == nullptr ||
225
0
        CPLTestBool(GetOption(S57O_RETURN_DSID)))
226
294
    {
227
294
        OGRFeatureDefn *poDefn = S57GenerateDSIDFeatureDefn();
228
294
        AddLayer(new OGRS57Layer(this, poDefn));
229
294
    }
230
231
    /* -------------------------------------------------------------------- */
232
    /*      Add the primitive layers if they are called for.                */
233
    /* -------------------------------------------------------------------- */
234
294
    if (GetOption(S57O_RETURN_PRIMITIVES) != nullptr)
235
0
    {
236
0
        OGRFeatureDefn *poDefn = S57GenerateVectorPrimitiveFeatureDefn(
237
0
            RCNM_VI, poModule->GetOptionFlags());
238
0
        AddLayer(new OGRS57Layer(this, poDefn));
239
240
0
        poDefn = S57GenerateVectorPrimitiveFeatureDefn(
241
0
            RCNM_VC, poModule->GetOptionFlags());
242
0
        AddLayer(new OGRS57Layer(this, poDefn));
243
244
0
        poDefn = S57GenerateVectorPrimitiveFeatureDefn(
245
0
            RCNM_VE, poModule->GetOptionFlags());
246
0
        AddLayer(new OGRS57Layer(this, poDefn));
247
248
0
        poDefn = S57GenerateVectorPrimitiveFeatureDefn(
249
0
            RCNM_VF, poModule->GetOptionFlags());
250
0
        AddLayer(new OGRS57Layer(this, poDefn));
251
0
    }
252
253
    /* -------------------------------------------------------------------- */
254
    /*      Initialize a layer for each type of geometry.  Eventually       */
255
    /*      we will do this by object class.                                */
256
    /* -------------------------------------------------------------------- */
257
294
    if (OGRS57Driver::GetS57Registrar() == nullptr)
258
0
    {
259
0
        OGRFeatureDefn *poDefn =
260
0
            S57GenerateGeomFeatureDefn(wkbPoint, poModule->GetOptionFlags());
261
0
        AddLayer(new OGRS57Layer(this, poDefn));
262
263
0
        poDefn = S57GenerateGeomFeatureDefn(wkbLineString,
264
0
                                            poModule->GetOptionFlags());
265
0
        AddLayer(new OGRS57Layer(this, poDefn));
266
267
0
        poDefn =
268
0
            S57GenerateGeomFeatureDefn(wkbPolygon, poModule->GetOptionFlags());
269
0
        AddLayer(new OGRS57Layer(this, poDefn));
270
271
0
        poDefn =
272
0
            S57GenerateGeomFeatureDefn(wkbNone, poModule->GetOptionFlags());
273
0
        AddLayer(new OGRS57Layer(this, poDefn));
274
0
    }
275
276
    /* -------------------------------------------------------------------- */
277
    /*      Initialize a feature definition for each class that actually    */
278
    /*      occurs in the dataset.                                          */
279
    /* -------------------------------------------------------------------- */
280
294
    else
281
294
    {
282
294
        poClassContentExplorer =
283
294
            new S57ClassContentExplorer(OGRS57Driver::GetS57Registrar());
284
285
588
        for (int iModule = 0; iModule < nModules; iModule++)
286
294
            papoModules[iModule]->SetClassBased(OGRS57Driver::GetS57Registrar(),
287
294
                                                poClassContentExplorer);
288
289
294
        std::vector<int> anClassCount;
290
291
588
        for (int iModule = 0; iModule < nModules; iModule++)
292
294
        {
293
294
            bSuccess = bSuccess &&
294
294
                       papoModules[iModule]->CollectClassList(anClassCount);
295
294
        }
296
297
294
        bool bGeneric = false;
298
299
294
        for (unsigned int iClass = 0; iClass < anClassCount.size(); iClass++)
300
0
        {
301
0
            if (anClassCount[iClass] > 0)
302
0
            {
303
0
                OGRFeatureDefn *poDefn = S57GenerateObjectClassDefn(
304
0
                    OGRS57Driver::GetS57Registrar(), poClassContentExplorer,
305
0
                    iClass, poModule->GetOptionFlags());
306
307
0
                if (poDefn != nullptr)
308
0
                    AddLayer(
309
0
                        new OGRS57Layer(this, poDefn, anClassCount[iClass]));
310
0
                else
311
0
                {
312
0
                    bGeneric = true;
313
0
                    CPLDebug("S57", "Unable to find definition for OBJL=%d\n",
314
0
                             iClass);
315
0
                }
316
0
            }
317
0
        }
318
319
294
        if (bGeneric)
320
0
        {
321
0
            OGRFeatureDefn *poDefn = S57GenerateGeomFeatureDefn(
322
0
                wkbUnknown, poModule->GetOptionFlags());
323
0
            AddLayer(new OGRS57Layer(this, poDefn));
324
0
        }
325
294
    }
326
327
    /* -------------------------------------------------------------------- */
328
    /*      Attach the layer definitions to each of the readers.            */
329
    /* -------------------------------------------------------------------- */
330
588
    for (int iModule = 0; iModule < nModules; iModule++)
331
294
    {
332
588
        for (int iLayer = 0; iLayer < nLayers; iLayer++)
333
294
        {
334
294
            OGRLayer *poLayer = papoLayers[iLayer];
335
294
            papoModules[iModule]->AddFeatureDefn(poLayer->GetLayerDefn());
336
294
        }
337
294
    }
338
339
294
    return bSuccess;
340
418
}
341
342
/************************************************************************/
343
/*                              GetLayer()                              */
344
/************************************************************************/
345
346
const OGRLayer *OGRS57DataSource::GetLayer(int iLayer) const
347
348
0
{
349
0
    if (iLayer < 0 || iLayer >= nLayers)
350
0
        return nullptr;
351
352
0
    return papoLayers[iLayer];
353
0
}
354
355
/************************************************************************/
356
/*                              AddLayer()                              */
357
/************************************************************************/
358
359
void OGRS57DataSource::AddLayer(OGRS57Layer *poNewLayer)
360
361
294
{
362
294
    papoLayers = static_cast<OGRS57Layer **>(
363
294
        CPLRealloc(papoLayers, sizeof(void *) * ++nLayers));
364
365
294
    papoLayers[nLayers - 1] = poNewLayer;
366
294
}
367
368
/************************************************************************/
369
/*                             GetModule()                              */
370
/************************************************************************/
371
372
S57Reader *OGRS57DataSource::GetModule(int i)
373
374
0
{
375
0
    if (i < 0 || i >= nModules)
376
0
        return nullptr;
377
378
0
    return papoModules[i];
379
0
}
380
381
/************************************************************************/
382
/*                            GetDSExtent()                             */
383
/************************************************************************/
384
385
OGRErr OGRS57DataSource::GetDSExtent(OGREnvelope *psExtent, int bForce)
386
387
0
{
388
    /* -------------------------------------------------------------------- */
389
    /*      If we have it, return it immediately.                           */
390
    /* -------------------------------------------------------------------- */
391
0
    if (bExtentsSet)
392
0
    {
393
0
        *psExtent = oExtents;
394
0
        return OGRERR_NONE;
395
0
    }
396
397
0
    if (nModules == 0)
398
0
        return OGRERR_FAILURE;
399
400
    /* -------------------------------------------------------------------- */
401
    /*      Otherwise try asking each of the readers for it.                */
402
    /* -------------------------------------------------------------------- */
403
0
    for (int iModule = 0; iModule < nModules; iModule++)
404
0
    {
405
0
        OGREnvelope oModuleEnvelope;
406
407
0
        OGRErr eErr = papoModules[iModule]->GetExtent(&oModuleEnvelope, bForce);
408
0
        if (eErr != OGRERR_NONE)
409
0
            return eErr;
410
411
0
        if (iModule == 0)
412
0
            oExtents = oModuleEnvelope;
413
0
        else
414
0
        {
415
0
            oExtents.MinX = std::min(oExtents.MinX, oModuleEnvelope.MinX);
416
0
            oExtents.MaxX = std::max(oExtents.MaxX, oModuleEnvelope.MaxX);
417
0
            oExtents.MinY = std::min(oExtents.MinY, oModuleEnvelope.MinY);
418
0
            oExtents.MaxX = std::max(oExtents.MaxY, oModuleEnvelope.MaxY);
419
0
        }
420
0
    }
421
422
0
    *psExtent = oExtents;
423
0
    bExtentsSet = true;
424
425
0
    return OGRERR_NONE;
426
0
}
427
428
/************************************************************************/
429
/*                               Create()                               */
430
/*                                                                      */
431
/*      Create a new S57 file, and represent it as a datasource.        */
432
/************************************************************************/
433
434
int OGRS57DataSource::Create(const char *pszFilename,
435
                             CSLConstList papszOptionsIn)
436
0
{
437
    /* -------------------------------------------------------------------- */
438
    /*      Instantiate the class registrar if possible.                    */
439
    /* -------------------------------------------------------------------- */
440
0
    if (OGRS57Driver::GetS57Registrar() == nullptr)
441
0
    {
442
0
        CPLError(CE_Failure, CPLE_AppDefined,
443
0
                 "Unable to load s57objectclasses.csv.  Unable to continue.");
444
0
        return FALSE;
445
0
    }
446
447
    /* -------------------------------------------------------------------- */
448
    /*      Create the S-57 file with definition record.                    */
449
    /* -------------------------------------------------------------------- */
450
0
    poWriter = new S57Writer();
451
452
0
    if (!poWriter->CreateS57File(pszFilename))
453
0
        return FALSE;
454
455
0
    poClassContentExplorer =
456
0
        new S57ClassContentExplorer(OGRS57Driver::GetS57Registrar());
457
458
0
    poWriter->SetClassBased(OGRS57Driver::GetS57Registrar(),
459
0
                            poClassContentExplorer);
460
461
    /* -------------------------------------------------------------------- */
462
    /*      Add the primitive layers if they are called for.                */
463
    /* -------------------------------------------------------------------- */
464
0
    int nOptionFlags = S57M_RETURN_LINKAGES | S57M_LNAM_REFS;
465
466
0
    OGRFeatureDefn *poDefn =
467
0
        S57GenerateVectorPrimitiveFeatureDefn(RCNM_VI, nOptionFlags);
468
0
    AddLayer(new OGRS57Layer(this, poDefn));
469
470
0
    poDefn = S57GenerateVectorPrimitiveFeatureDefn(RCNM_VC, nOptionFlags);
471
0
    AddLayer(new OGRS57Layer(this, poDefn));
472
473
0
    poDefn = S57GenerateVectorPrimitiveFeatureDefn(RCNM_VE, nOptionFlags);
474
0
    AddLayer(new OGRS57Layer(this, poDefn));
475
476
0
    poDefn = S57GenerateVectorPrimitiveFeatureDefn(RCNM_VF, nOptionFlags);
477
0
    AddLayer(new OGRS57Layer(this, poDefn));
478
479
    /* -------------------------------------------------------------------- */
480
    /*      Initialize a feature definition for each object class.          */
481
    /* -------------------------------------------------------------------- */
482
0
    poClassContentExplorer->Rewind();
483
0
    std::set<int> aoSetOBJL;
484
0
    while (poClassContentExplorer->NextClass())
485
0
    {
486
0
        const int nOBJL = poClassContentExplorer->GetOBJL();
487
        // Detect potential duplicates in the classes
488
0
        if (aoSetOBJL.find(nOBJL) != aoSetOBJL.end())
489
0
        {
490
0
            CPLDebug("S57", "OBJL %d already registered!", nOBJL);
491
0
            continue;
492
0
        }
493
0
        aoSetOBJL.insert(nOBJL);
494
0
        poDefn = S57GenerateObjectClassDefn(OGRS57Driver::GetS57Registrar(),
495
0
                                            poClassContentExplorer, nOBJL,
496
0
                                            nOptionFlags);
497
498
0
        AddLayer(new OGRS57Layer(this, poDefn, 0, nOBJL));
499
0
    }
500
501
    /* -------------------------------------------------------------------- */
502
    /*      Write out "header" records.                                     */
503
    /* -------------------------------------------------------------------- */
504
0
    int nEXPP =
505
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_EXPP",
506
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_EXPP)));
507
0
    int nINTU =
508
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_INTU",
509
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_INTU)));
510
0
    const char *pszEDTN = CSLFetchNameValue(papszOptionsIn, "S57_EDTN");
511
0
    const char *pszUPDN = CSLFetchNameValue(papszOptionsIn, "S57_UPDN");
512
0
    const char *pszUADT = CSLFetchNameValue(papszOptionsIn, "S57_UADT");
513
0
    const char *pszISDT = CSLFetchNameValue(papszOptionsIn, "S57_ISDT");
514
0
    const char *pszSTED = CSLFetchNameValue(papszOptionsIn, "S57_STED");
515
0
    int nAGEN =
516
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_AGEN",
517
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_AGEN)));
518
0
    const char *pszCOMT = CSLFetchNameValue(papszOptionsIn, "S57_COMT");
519
0
    int nAALL = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_AALL", "0"));
520
0
    int nNALL = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NALL", "0"));
521
0
    int nNOMR = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOMR", "0"));
522
0
    int nNOGR = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOGR", "0"));
523
0
    int nNOLR = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOLR", "0"));
524
0
    int nNOIN = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOIN", "0"));
525
0
    int nNOCN = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOCN", "0"));
526
0
    int nNOED = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOED", "0"));
527
0
    poWriter->WriteDSID(nEXPP, nINTU, CPLGetFilename(pszFilename), pszEDTN,
528
0
                        pszUPDN, pszUADT, pszISDT, pszSTED, nAGEN, pszCOMT,
529
0
                        nAALL, nNALL, nNOMR, nNOGR, nNOLR, nNOIN, nNOCN, nNOED);
530
531
0
    int nHDAT =
532
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_HDAT",
533
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_HDAT)));
534
0
    int nVDAT =
535
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_VDAT",
536
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_VDAT)));
537
0
    int nSDAT =
538
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_SDAT",
539
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_SDAT)));
540
0
    int nCSCL =
541
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_CSCL",
542
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_CSCL)));
543
0
    int nCOMF =
544
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_COMF",
545
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_COMF)));
546
0
    int nSOMF =
547
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_SOMF",
548
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_SOMF)));
549
0
    poWriter->WriteDSPM(nHDAT, nVDAT, nSDAT, nCSCL, nCOMF, nSOMF);
550
551
0
    return TRUE;
552
0
}