Coverage Report

Created: 2025-11-15 08:43

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(char **papszOpenOptionsIn)
26
327
    : nLayers(0), papoLayers(nullptr), poSpatialRef(new OGRSpatialReference()),
27
327
      papszOptions(nullptr), nModules(0), papoModules(nullptr),
28
327
      poWriter(nullptr), poClassContentExplorer(nullptr), bExtentsSet(false)
29
327
{
30
327
    poSpatialRef->SetWellKnownGeogCS("WGS84");
31
327
    poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
32
33
    /* -------------------------------------------------------------------- */
34
    /*      Allow initialization of options from the environment.           */
35
    /* -------------------------------------------------------------------- */
36
327
    const char *pszOptString = CPLGetConfigOption("OGR_S57_OPTIONS", nullptr);
37
38
327
    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
            char **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
327
    for (char **papszIter = papszOpenOptionsIn; papszIter && *papszIter;
56
327
         ++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
327
}
67
68
/************************************************************************/
69
/*                         ~OGRS57DataSource()                          */
70
/************************************************************************/
71
72
OGRS57DataSource::~OGRS57DataSource()
73
74
327
{
75
562
    for (int i = 0; i < nLayers; i++)
76
235
        delete papoLayers[i];
77
78
327
    CPLFree(papoLayers);
79
80
562
    for (int i = 0; i < nModules; i++)
81
235
        delete papoModules[i];
82
327
    CPLFree(papoModules);
83
84
327
    CSLDestroy(papszOptions);
85
86
327
    poSpatialRef->Release();
87
88
327
    if (poWriter != nullptr)
89
0
    {
90
0
        poWriter->Close();
91
0
        delete poWriter;
92
0
    }
93
327
    delete poClassContentExplorer;
94
327
}
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
3.74k
{
114
3.74k
    return CSLFetchNameValue(papszOptions, pszOption);
115
3.74k
}
116
117
/************************************************************************/
118
/*                           TestCapability()                           */
119
/************************************************************************/
120
121
int 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
327
{
137
    /* -------------------------------------------------------------------- */
138
    /*      Setup reader options.                                           */
139
    /* -------------------------------------------------------------------- */
140
327
    char **papszReaderOptions = nullptr;
141
142
327
    if (GetOption(S57O_LNAM_REFS) == nullptr)
143
327
        papszReaderOptions =
144
327
            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
327
    if (GetOption(S57O_UPDATES) != nullptr)
150
0
        papszReaderOptions = CSLSetNameValue(papszReaderOptions, S57O_UPDATES,
151
0
                                             GetOption(S57O_UPDATES));
152
153
327
    if (GetOption(S57O_SPLIT_MULTIPOINT) != nullptr)
154
0
        papszReaderOptions =
155
0
            CSLSetNameValue(papszReaderOptions, S57O_SPLIT_MULTIPOINT,
156
0
                            GetOption(S57O_SPLIT_MULTIPOINT));
157
158
327
    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
327
    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
327
    if (GetOption(S57O_RETURN_PRIMITIVES) != nullptr)
169
0
        papszReaderOptions =
170
0
            CSLSetNameValue(papszReaderOptions, S57O_RETURN_PRIMITIVES,
171
0
                            GetOption(S57O_RETURN_PRIMITIVES));
172
173
327
    if (GetOption(S57O_RETURN_LINKAGES) != nullptr)
174
0
        papszReaderOptions =
175
0
            CSLSetNameValue(papszReaderOptions, S57O_RETURN_LINKAGES,
176
0
                            GetOption(S57O_RETURN_LINKAGES));
177
178
327
    if (GetOption(S57O_RETURN_DSID) != nullptr)
179
0
        papszReaderOptions = CSLSetNameValue(
180
0
            papszReaderOptions, S57O_RETURN_DSID, GetOption(S57O_RETURN_DSID));
181
182
327
    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
327
    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
327
    S57Reader *poModule = new S57Reader(pszFilename);
193
327
    bool bRet = poModule->SetOptions(papszReaderOptions);
194
327
    CSLDestroy(papszReaderOptions);
195
196
327
    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
327
    if (!poModule->Open(TRUE))
209
92
    {
210
92
        delete poModule;
211
212
92
        return FALSE;
213
92
    }
214
215
235
    bool bSuccess = true;
216
217
235
    nModules = 1;
218
235
    papoModules = static_cast<S57Reader **>(CPLMalloc(sizeof(void *)));
219
235
    papoModules[0] = poModule;
220
221
    /* -------------------------------------------------------------------- */
222
    /*      Add the header layers if they are called for.                   */
223
    /* -------------------------------------------------------------------- */
224
235
    if (GetOption(S57O_RETURN_DSID) == nullptr ||
225
0
        CPLTestBool(GetOption(S57O_RETURN_DSID)))
226
235
    {
227
235
        OGRFeatureDefn *poDefn = S57GenerateDSIDFeatureDefn();
228
235
        AddLayer(new OGRS57Layer(this, poDefn));
229
235
    }
230
231
    /* -------------------------------------------------------------------- */
232
    /*      Add the primitive layers if they are called for.                */
233
    /* -------------------------------------------------------------------- */
234
235
    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
235
    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
235
    else
281
235
    {
282
235
        poClassContentExplorer =
283
235
            new S57ClassContentExplorer(OGRS57Driver::GetS57Registrar());
284
285
470
        for (int iModule = 0; iModule < nModules; iModule++)
286
235
            papoModules[iModule]->SetClassBased(OGRS57Driver::GetS57Registrar(),
287
235
                                                poClassContentExplorer);
288
289
235
        std::vector<int> anClassCount;
290
291
470
        for (int iModule = 0; iModule < nModules; iModule++)
292
235
        {
293
235
            bSuccess &= CPL_TO_BOOL(
294
235
                papoModules[iModule]->CollectClassList(anClassCount));
295
235
        }
296
297
235
        bool bGeneric = false;
298
299
235
        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
235
        if (bGeneric)
320
0
        {
321
0
            OGRFeatureDefn *poDefn = S57GenerateGeomFeatureDefn(
322
0
                wkbUnknown, poModule->GetOptionFlags());
323
0
            AddLayer(new OGRS57Layer(this, poDefn));
324
0
        }
325
235
    }
326
327
    /* -------------------------------------------------------------------- */
328
    /*      Attach the layer definitions to each of the readers.            */
329
    /* -------------------------------------------------------------------- */
330
470
    for (int iModule = 0; iModule < nModules; iModule++)
331
235
    {
332
470
        for (int iLayer = 0; iLayer < nLayers; iLayer++)
333
235
        {
334
235
            OGRLayer *poLayer = papoLayers[iLayer];
335
235
            papoModules[iModule]->AddFeatureDefn(poLayer->GetLayerDefn());
336
235
        }
337
235
    }
338
339
235
    return bSuccess;
340
327
}
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
235
{
362
235
    papoLayers = static_cast<OGRS57Layer **>(
363
235
        CPLRealloc(papoLayers, sizeof(void *) * ++nLayers));
364
365
235
    papoLayers[nLayers - 1] = poNewLayer;
366
235
}
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, char **papszOptionsIn)
435
0
{
436
    /* -------------------------------------------------------------------- */
437
    /*      Instantiate the class registrar if possible.                    */
438
    /* -------------------------------------------------------------------- */
439
0
    if (OGRS57Driver::GetS57Registrar() == nullptr)
440
0
    {
441
0
        CPLError(CE_Failure, CPLE_AppDefined,
442
0
                 "Unable to load s57objectclasses.csv.  Unable to continue.");
443
0
        return FALSE;
444
0
    }
445
446
    /* -------------------------------------------------------------------- */
447
    /*      Create the S-57 file with definition record.                    */
448
    /* -------------------------------------------------------------------- */
449
0
    poWriter = new S57Writer();
450
451
0
    if (!poWriter->CreateS57File(pszFilename))
452
0
        return FALSE;
453
454
0
    poClassContentExplorer =
455
0
        new S57ClassContentExplorer(OGRS57Driver::GetS57Registrar());
456
457
0
    poWriter->SetClassBased(OGRS57Driver::GetS57Registrar(),
458
0
                            poClassContentExplorer);
459
460
    /* -------------------------------------------------------------------- */
461
    /*      Add the primitive layers if they are called for.                */
462
    /* -------------------------------------------------------------------- */
463
0
    int nOptionFlags = S57M_RETURN_LINKAGES | S57M_LNAM_REFS;
464
465
0
    OGRFeatureDefn *poDefn =
466
0
        S57GenerateVectorPrimitiveFeatureDefn(RCNM_VI, nOptionFlags);
467
0
    AddLayer(new OGRS57Layer(this, poDefn));
468
469
0
    poDefn = S57GenerateVectorPrimitiveFeatureDefn(RCNM_VC, nOptionFlags);
470
0
    AddLayer(new OGRS57Layer(this, poDefn));
471
472
0
    poDefn = S57GenerateVectorPrimitiveFeatureDefn(RCNM_VE, nOptionFlags);
473
0
    AddLayer(new OGRS57Layer(this, poDefn));
474
475
0
    poDefn = S57GenerateVectorPrimitiveFeatureDefn(RCNM_VF, nOptionFlags);
476
0
    AddLayer(new OGRS57Layer(this, poDefn));
477
478
    /* -------------------------------------------------------------------- */
479
    /*      Initialize a feature definition for each object class.          */
480
    /* -------------------------------------------------------------------- */
481
0
    poClassContentExplorer->Rewind();
482
0
    std::set<int> aoSetOBJL;
483
0
    while (poClassContentExplorer->NextClass())
484
0
    {
485
0
        const int nOBJL = poClassContentExplorer->GetOBJL();
486
        // Detect potential duplicates in the classes
487
0
        if (aoSetOBJL.find(nOBJL) != aoSetOBJL.end())
488
0
        {
489
0
            CPLDebug("S57", "OBJL %d already registered!", nOBJL);
490
0
            continue;
491
0
        }
492
0
        aoSetOBJL.insert(nOBJL);
493
0
        poDefn = S57GenerateObjectClassDefn(OGRS57Driver::GetS57Registrar(),
494
0
                                            poClassContentExplorer, nOBJL,
495
0
                                            nOptionFlags);
496
497
0
        AddLayer(new OGRS57Layer(this, poDefn, 0, nOBJL));
498
0
    }
499
500
    /* -------------------------------------------------------------------- */
501
    /*      Write out "header" records.                                     */
502
    /* -------------------------------------------------------------------- */
503
0
    int nEXPP =
504
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_EXPP",
505
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_EXPP)));
506
0
    int nINTU =
507
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_INTU",
508
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_INTU)));
509
0
    const char *pszEDTN = CSLFetchNameValue(papszOptionsIn, "S57_EDTN");
510
0
    const char *pszUPDN = CSLFetchNameValue(papszOptionsIn, "S57_UPDN");
511
0
    const char *pszUADT = CSLFetchNameValue(papszOptionsIn, "S57_UADT");
512
0
    const char *pszISDT = CSLFetchNameValue(papszOptionsIn, "S57_ISDT");
513
0
    const char *pszSTED = CSLFetchNameValue(papszOptionsIn, "S57_STED");
514
0
    int nAGEN =
515
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_AGEN",
516
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_AGEN)));
517
0
    const char *pszCOMT = CSLFetchNameValue(papszOptionsIn, "S57_COMT");
518
0
    int nAALL = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_AALL", "0"));
519
0
    int nNALL = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NALL", "0"));
520
0
    int nNOMR = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOMR", "0"));
521
0
    int nNOGR = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOGR", "0"));
522
0
    int nNOLR = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOLR", "0"));
523
0
    int nNOIN = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOIN", "0"));
524
0
    int nNOCN = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOCN", "0"));
525
0
    int nNOED = atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_NOED", "0"));
526
0
    poWriter->WriteDSID(nEXPP, nINTU, CPLGetFilename(pszFilename), pszEDTN,
527
0
                        pszUPDN, pszUADT, pszISDT, pszSTED, nAGEN, pszCOMT,
528
0
                        nAALL, nNALL, nNOMR, nNOGR, nNOLR, nNOIN, nNOCN, nNOED);
529
530
0
    int nHDAT =
531
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_HDAT",
532
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_HDAT)));
533
0
    int nVDAT =
534
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_VDAT",
535
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_VDAT)));
536
0
    int nSDAT =
537
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_SDAT",
538
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_SDAT)));
539
0
    int nCSCL =
540
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_CSCL",
541
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_CSCL)));
542
0
    int nCOMF =
543
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_COMF",
544
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_COMF)));
545
0
    int nSOMF =
546
0
        atoi(CSLFetchNameValueDef(papszOptionsIn, "S57_SOMF",
547
0
                                  CPLSPrintf("%d", S57Writer::nDEFAULT_SOMF)));
548
0
    poWriter->WriteDSPM(nHDAT, nVDAT, nSDAT, nCSCL, nCOMF, nSOMF);
549
550
0
    return TRUE;
551
0
}