Coverage Report

Created: 2026-06-30 08:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/s57/s57featuredefns.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  S-57 Translator
4
 * Purpose:  Implements methods to create OGRFeatureDefns for various
5
 *           object classes, and primitive features.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1999, 2001, 2003 Frank Warmerdam
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
/*                     S57GenerateGeomFeatureDefn()                     */
21
/************************************************************************/
22
23
OGRFeatureDefn *S57GenerateDSIDFeatureDefn()
24
25
315
{
26
315
    OGRFeatureDefn *poFDefn = new OGRFeatureDefn("DSID");
27
28
315
    poFDefn->SetGeomType(wkbNone);
29
315
    poFDefn->Reference();
30
31
    /* -------------------------------------------------------------------- */
32
    /*      DSID fields.                                                    */
33
    /* -------------------------------------------------------------------- */
34
315
    OGRFieldDefn oField("", OFTInteger);
35
36
315
    oField.Set("DSID_EXPP", OFTInteger, 3, 0);
37
315
    poFDefn->AddFieldDefn(&oField);
38
39
315
    oField.Set("DSID_INTU", OFTInteger, 3, 0);
40
315
    poFDefn->AddFieldDefn(&oField);
41
42
315
    oField.Set("DSID_DSNM", OFTString, 0, 0);
43
315
    poFDefn->AddFieldDefn(&oField);
44
45
315
    oField.Set("DSID_EDTN", OFTString, 0, 0);
46
315
    poFDefn->AddFieldDefn(&oField);
47
48
315
    oField.Set("DSID_UPDN", OFTString, 0, 0);
49
315
    poFDefn->AddFieldDefn(&oField);
50
51
315
    oField.Set("DSID_UADT", OFTString, 8, 0);
52
315
    poFDefn->AddFieldDefn(&oField);
53
54
315
    oField.Set("DSID_ISDT", OFTString, 8, 0);
55
315
    poFDefn->AddFieldDefn(&oField);
56
57
315
    oField.Set("DSID_STED", OFTReal, 11, 6);
58
315
    poFDefn->AddFieldDefn(&oField);
59
60
315
    oField.Set("DSID_PRSP", OFTInteger, 3, 0);
61
315
    poFDefn->AddFieldDefn(&oField);
62
63
315
    oField.Set("DSID_PSDN", OFTString, 0, 0);
64
315
    poFDefn->AddFieldDefn(&oField);
65
66
315
    oField.Set("DSID_PRED", OFTString, 0, 0);
67
315
    poFDefn->AddFieldDefn(&oField);
68
69
315
    oField.Set("DSID_PROF", OFTInteger, 3, 0);
70
315
    poFDefn->AddFieldDefn(&oField);
71
72
315
    oField.Set("DSID_AGEN", OFTInteger, 5, 0);
73
315
    poFDefn->AddFieldDefn(&oField);
74
75
315
    oField.Set("DSID_COMT", OFTString, 0, 0);
76
315
    poFDefn->AddFieldDefn(&oField);
77
78
    /* -------------------------------------------------------------------- */
79
    /*      DSSI fields.                                                    */
80
    /* -------------------------------------------------------------------- */
81
82
315
    oField.Set("DSSI_DSTR", OFTInteger, 3, 0);
83
315
    poFDefn->AddFieldDefn(&oField);
84
85
315
    oField.Set("DSSI_AALL", OFTInteger, 3, 0);
86
315
    poFDefn->AddFieldDefn(&oField);
87
88
315
    oField.Set("DSSI_NALL", OFTInteger, 3, 0);
89
315
    poFDefn->AddFieldDefn(&oField);
90
91
315
    oField.Set("DSSI_NOMR", OFTInteger, 10, 0);
92
315
    poFDefn->AddFieldDefn(&oField);
93
94
315
    oField.Set("DSSI_NOCR", OFTInteger, 10, 0);
95
315
    poFDefn->AddFieldDefn(&oField);
96
97
315
    oField.Set("DSSI_NOGR", OFTInteger, 10, 0);
98
315
    poFDefn->AddFieldDefn(&oField);
99
100
315
    oField.Set("DSSI_NOLR", OFTInteger, 10, 0);
101
315
    poFDefn->AddFieldDefn(&oField);
102
103
315
    oField.Set("DSSI_NOIN", OFTInteger, 10, 0);
104
315
    poFDefn->AddFieldDefn(&oField);
105
106
315
    oField.Set("DSSI_NOCN", OFTInteger, 10, 0);
107
315
    poFDefn->AddFieldDefn(&oField);
108
109
315
    oField.Set("DSSI_NOED", OFTInteger, 10, 0);
110
315
    poFDefn->AddFieldDefn(&oField);
111
112
315
    oField.Set("DSSI_NOFA", OFTInteger, 10, 0);
113
315
    poFDefn->AddFieldDefn(&oField);
114
115
    /* -------------------------------------------------------------------- */
116
    /*      DSPM fields.                                                    */
117
    /* -------------------------------------------------------------------- */
118
119
315
    oField.Set("DSPM_HDAT", OFTInteger, 3, 0);
120
315
    poFDefn->AddFieldDefn(&oField);
121
122
315
    oField.Set("DSPM_VDAT", OFTInteger, 3, 0);
123
315
    poFDefn->AddFieldDefn(&oField);
124
125
315
    oField.Set("DSPM_SDAT", OFTInteger, 3, 0);
126
315
    poFDefn->AddFieldDefn(&oField);
127
128
315
    oField.Set("DSPM_CSCL", OFTInteger, 10, 0);
129
315
    poFDefn->AddFieldDefn(&oField);
130
131
315
    oField.Set("DSPM_DUNI", OFTInteger, 3, 0);
132
315
    poFDefn->AddFieldDefn(&oField);
133
134
315
    oField.Set("DSPM_HUNI", OFTInteger, 3, 0);
135
315
    poFDefn->AddFieldDefn(&oField);
136
137
315
    oField.Set("DSPM_PUNI", OFTInteger, 3, 0);
138
315
    poFDefn->AddFieldDefn(&oField);
139
140
315
    oField.Set("DSPM_COUN", OFTInteger, 3, 0);
141
315
    poFDefn->AddFieldDefn(&oField);
142
143
315
    oField.Set("DSPM_COMF", OFTInteger, 10, 0);
144
315
    poFDefn->AddFieldDefn(&oField);
145
146
315
    oField.Set("DSPM_SOMF", OFTInteger, 10, 0);
147
315
    poFDefn->AddFieldDefn(&oField);
148
149
315
    oField.Set("DSPM_COMT", OFTString, 0, 0);
150
315
    poFDefn->AddFieldDefn(&oField);
151
152
315
    return poFDefn;
153
315
}
154
155
/************************************************************************/
156
/*                     S57GenerateGeomFeatureDefn()                     */
157
/************************************************************************/
158
159
OGRFeatureDefn *S57GenerateGeomFeatureDefn(OGRwkbGeometryType eGType,
160
                                           int nOptionFlags)
161
162
0
{
163
0
    OGRFeatureDefn *poFDefn = nullptr;
164
165
0
    if (eGType == wkbPoint)
166
0
    {
167
0
        poFDefn = new OGRFeatureDefn("Point");
168
0
        poFDefn->SetGeomType(eGType);
169
0
    }
170
0
    else if (eGType == wkbLineString)
171
0
    {
172
0
        poFDefn = new OGRFeatureDefn("Line");
173
0
        poFDefn->SetGeomType(eGType);
174
0
    }
175
0
    else if (eGType == wkbPolygon)
176
0
    {
177
0
        poFDefn = new OGRFeatureDefn("Area");
178
0
        poFDefn->SetGeomType(eGType);
179
0
    }
180
0
    else if (eGType == wkbNone)
181
0
    {
182
0
        poFDefn = new OGRFeatureDefn("Meta");
183
0
        poFDefn->SetGeomType(eGType);
184
0
    }
185
0
    else if (eGType == wkbUnknown)
186
0
    {
187
0
        poFDefn = new OGRFeatureDefn("Generic");
188
0
        poFDefn->SetGeomType(eGType);
189
0
    }
190
0
    else
191
0
        return nullptr;
192
193
0
    poFDefn->Reference();
194
0
    S57GenerateStandardAttributes(poFDefn, nOptionFlags);
195
196
0
    return poFDefn;
197
0
}
198
199
/************************************************************************/
200
/*               S57GenerateVectorPrimitiveFeatureDefn()                */
201
/************************************************************************/
202
203
OGRFeatureDefn *S57GenerateVectorPrimitiveFeatureDefn(int nRCNM,
204
                                                      int /* nOptionFlags */)
205
0
{
206
0
    OGRFeatureDefn *poFDefn = nullptr;
207
208
0
    if (nRCNM == RCNM_VI)
209
0
    {
210
0
        poFDefn = new OGRFeatureDefn(OGRN_VI);
211
0
        poFDefn->SetGeomType(wkbPoint);
212
0
    }
213
0
    else if (nRCNM == RCNM_VC)
214
0
    {
215
0
        poFDefn = new OGRFeatureDefn(OGRN_VC);
216
0
        poFDefn->SetGeomType(wkbPoint);
217
0
    }
218
0
    else if (nRCNM == RCNM_VE)
219
0
    {
220
0
        poFDefn = new OGRFeatureDefn(OGRN_VE);
221
0
        poFDefn->SetGeomType(wkbUnknown);
222
0
    }
223
0
    else if (nRCNM == RCNM_VF)
224
0
    {
225
0
        poFDefn = new OGRFeatureDefn(OGRN_VF);
226
0
        poFDefn->SetGeomType(wkbPolygon);
227
0
    }
228
0
    else
229
0
        return nullptr;
230
231
0
    poFDefn->Reference();
232
233
    /* -------------------------------------------------------------------- */
234
    /*      Core vector primitive attributes                                */
235
    /* -------------------------------------------------------------------- */
236
0
    OGRFieldDefn oField("", OFTInteger);
237
238
0
    oField.Set("RCNM", OFTInteger, 3, 0);
239
0
    poFDefn->AddFieldDefn(&oField);
240
241
0
    oField.Set("RCID", OFTInteger, 8, 0);
242
0
    poFDefn->AddFieldDefn(&oField);
243
244
0
    oField.Set("RVER", OFTInteger, 2, 0);
245
0
    poFDefn->AddFieldDefn(&oField);
246
247
0
    oField.Set("RUIN", OFTInteger, 2, 0);
248
0
    poFDefn->AddFieldDefn(&oField);
249
250
    /* -------------------------------------------------------------------- */
251
    /*      Geometric primitive attributes                                  */
252
    /* -------------------------------------------------------------------- */
253
0
    oField.Set("POSACC", OFTReal, 10, 2);
254
0
    poFDefn->AddFieldDefn(&oField);
255
256
0
    oField.Set("QUAPOS", OFTInteger, 2, 0);
257
0
    poFDefn->AddFieldDefn(&oField);
258
259
    /* -------------------------------------------------------------------- */
260
    /*      For lines we want to capture the point links for the first      */
261
    /*      and last nodes.                                                 */
262
    /* -------------------------------------------------------------------- */
263
0
    if (nRCNM == RCNM_VE)
264
0
    {
265
0
        oField.Set("NAME_RCNM_0", OFTInteger, 3, 0);
266
0
        poFDefn->AddFieldDefn(&oField);
267
268
0
        oField.Set("NAME_RCID_0", OFTInteger, 8, 0);
269
0
        poFDefn->AddFieldDefn(&oField);
270
271
0
        oField.Set("ORNT_0", OFTInteger, 3, 0);
272
0
        poFDefn->AddFieldDefn(&oField);
273
274
0
        oField.Set("USAG_0", OFTInteger, 3, 0);
275
0
        poFDefn->AddFieldDefn(&oField);
276
277
0
        oField.Set("TOPI_0", OFTInteger, 1, 0);
278
0
        poFDefn->AddFieldDefn(&oField);
279
280
0
        oField.Set("MASK_0", OFTInteger, 3, 0);
281
0
        poFDefn->AddFieldDefn(&oField);
282
283
0
        oField.Set("NAME_RCNM_1", OFTInteger, 3, 0);
284
0
        poFDefn->AddFieldDefn(&oField);
285
286
0
        oField.Set("NAME_RCID_1", OFTInteger, 8, 0);
287
0
        poFDefn->AddFieldDefn(&oField);
288
289
0
        oField.Set("ORNT_1", OFTInteger, 3, 0);
290
0
        poFDefn->AddFieldDefn(&oField);
291
292
0
        oField.Set("USAG_1", OFTInteger, 3, 0);
293
0
        poFDefn->AddFieldDefn(&oField);
294
295
0
        oField.Set("TOPI_1", OFTInteger, 1, 0);
296
0
        poFDefn->AddFieldDefn(&oField);
297
298
0
        oField.Set("MASK_1", OFTInteger, 3, 0);
299
0
        poFDefn->AddFieldDefn(&oField);
300
0
    }
301
302
0
    return poFDefn;
303
0
}
304
305
/************************************************************************/
306
/*                     S57GenerateObjectClassDefn()                     */
307
/************************************************************************/
308
309
OGRFeatureDefn *
310
S57GenerateObjectClassDefn(S57ClassRegistrar *poCR,
311
                           S57ClassContentExplorer *poClassContentExplorer,
312
                           int nOBJL, int nOptionFlags)
313
314
0
{
315
0
    if (!poClassContentExplorer->SelectClass(nOBJL))
316
0
        return nullptr;
317
318
    /* -------------------------------------------------------------------- */
319
    /*      Create the feature definition based on the object class         */
320
    /*      acronym.                                                        */
321
    /* -------------------------------------------------------------------- */
322
0
    OGRFeatureDefn *poFDefn =
323
0
        new OGRFeatureDefn(poClassContentExplorer->GetAcronym());
324
0
    poFDefn->Reference();
325
326
    /* -------------------------------------------------------------------- */
327
    /*      Try and establish the geometry type.  If more than one          */
328
    /*      geometry type is allowed we just fall back to wkbUnknown.       */
329
    /* -------------------------------------------------------------------- */
330
0
    char **papszGeomPrim = poClassContentExplorer->GetPrimitives();
331
0
    if (CSLCount(papszGeomPrim) == 0)
332
0
    {
333
0
        poFDefn->SetGeomType(wkbNone);
334
0
    }
335
0
    else if (CSLCount(papszGeomPrim) > 1)
336
0
    {
337
        // leave as unknown geometry type.
338
0
    }
339
0
    else if (papszGeomPrim[0][0] == 'P')
340
0
    {
341
0
        if (EQUAL(poClassContentExplorer->GetAcronym(), "SOUNDG"))
342
0
        {
343
0
            if (nOptionFlags & S57M_SPLIT_MULTIPOINT)
344
0
                poFDefn->SetGeomType(wkbPoint25D);
345
0
            else
346
0
                poFDefn->SetGeomType(wkbMultiPoint25D);
347
0
        }
348
0
        else
349
0
            poFDefn->SetGeomType(wkbPoint);
350
0
    }
351
0
    else if (papszGeomPrim[0][0] == 'A')
352
0
    {
353
0
        poFDefn->SetGeomType(wkbPolygon);
354
0
    }
355
0
    else if (papszGeomPrim[0][0] == 'L')
356
0
    {
357
        // unfortunately this could be a multilinestring
358
0
        poFDefn->SetGeomType(wkbUnknown);
359
0
    }
360
361
    /* -------------------------------------------------------------------- */
362
    /*      Add the standard attributes.                                    */
363
    /* -------------------------------------------------------------------- */
364
0
    S57GenerateStandardAttributes(poFDefn, nOptionFlags);
365
366
    /* -------------------------------------------------------------------- */
367
    /*      Add the attributes specific to this object class.               */
368
    /* -------------------------------------------------------------------- */
369
0
    char **papszAttrList = poClassContentExplorer->GetAttributeList();
370
371
0
    for (int iAttr = 0;
372
0
         papszAttrList != nullptr && papszAttrList[iAttr] != nullptr; iAttr++)
373
0
    {
374
0
        const int iAttrIndex = poCR->FindAttrByAcronym(papszAttrList[iAttr]);
375
376
0
        if (iAttrIndex == -1)
377
0
        {
378
0
            CPLDebug("S57", "Can't find attribute %s from class %s:%s.",
379
0
                     papszAttrList[iAttr], poClassContentExplorer->GetAcronym(),
380
0
                     poClassContentExplorer->GetDescription());
381
0
            continue;
382
0
        }
383
384
0
        OGRFieldDefn oField(papszAttrList[iAttr], OFTInteger);
385
386
0
        switch (poCR->GetAttrType(iAttrIndex))
387
0
        {
388
0
            case SAT_ENUM:
389
0
            case SAT_INT:
390
0
                oField.SetType(OFTInteger);
391
0
                break;
392
393
0
            case SAT_FLOAT:
394
0
                oField.SetType(OFTReal);
395
0
                break;
396
397
0
            case SAT_CODE_STRING:
398
0
            case SAT_FREE_TEXT:
399
0
                oField.SetType(OFTString);
400
0
                break;
401
402
0
            case SAT_LIST:
403
0
                if ((nOptionFlags & S57M_LIST_AS_STRING))
404
0
                {
405
                    // Legacy behavior
406
0
                    oField.SetType(OFTString);
407
0
                }
408
0
                else
409
0
                {
410
0
                    oField.SetType(OFTStringList);
411
0
                }
412
0
                break;
413
0
        }
414
415
0
        poFDefn->AddFieldDefn(&oField);
416
0
    }
417
418
    /* -------------------------------------------------------------------- */
419
    /*      Do we need to add DEPTH attributes to soundings?                */
420
    /* -------------------------------------------------------------------- */
421
0
    const char *pszClassAcronym = poClassContentExplorer->GetAcronym();
422
0
    if (pszClassAcronym != nullptr && EQUAL(pszClassAcronym, "SOUNDG") &&
423
0
        (nOptionFlags & S57M_ADD_SOUNDG_DEPTH))
424
0
    {
425
0
        OGRFieldDefn oField("DEPTH", OFTReal);
426
0
        poFDefn->AddFieldDefn(&oField);
427
0
    }
428
429
0
    return poFDefn;
430
0
}
431
432
/************************************************************************/
433
/*                   S57GenerateStandardAttributes()                    */
434
/*                                                                      */
435
/*      Attach standard feature attributes to a feature definition.     */
436
/************************************************************************/
437
438
void S57GenerateStandardAttributes(OGRFeatureDefn *poFDefn, int nOptionFlags)
439
440
0
{
441
0
    OGRFieldDefn oField("", OFTInteger);
442
443
    /* -------------------------------------------------------------------- */
444
    /*      RCID                                                            */
445
    /* -------------------------------------------------------------------- */
446
0
    oField.Set("RCID", OFTInteger, 10, 0);
447
0
    poFDefn->AddFieldDefn(&oField);
448
449
    /* -------------------------------------------------------------------- */
450
    /*      PRIM                                                            */
451
    /* -------------------------------------------------------------------- */
452
0
    oField.Set("PRIM", OFTInteger, 3, 0);
453
0
    poFDefn->AddFieldDefn(&oField);
454
455
    /* -------------------------------------------------------------------- */
456
    /*      GRUP                                                            */
457
    /* -------------------------------------------------------------------- */
458
0
    oField.Set("GRUP", OFTInteger, 3, 0);
459
0
    poFDefn->AddFieldDefn(&oField);
460
461
    /* -------------------------------------------------------------------- */
462
    /*      OBJL                                                            */
463
    /* -------------------------------------------------------------------- */
464
0
    oField.Set("OBJL", OFTInteger, 5, 0);
465
0
    poFDefn->AddFieldDefn(&oField);
466
467
    /* -------------------------------------------------------------------- */
468
    /*      RVER                                                            */
469
    /* -------------------------------------------------------------------- */
470
0
    oField.Set("RVER", OFTInteger, 3, 0);
471
0
    poFDefn->AddFieldDefn(&oField);
472
473
    /* -------------------------------------------------------------------- */
474
    /*      AGEN                                                            */
475
    /* -------------------------------------------------------------------- */
476
0
    oField.Set("AGEN", OFTInteger, 5, 0);
477
0
    poFDefn->AddFieldDefn(&oField);
478
479
    /* -------------------------------------------------------------------- */
480
    /*      FIDN                                                            */
481
    /* -------------------------------------------------------------------- */
482
0
    oField.Set("FIDN", OFTInteger, 10, 0);
483
0
    poFDefn->AddFieldDefn(&oField);
484
485
    /* -------------------------------------------------------------------- */
486
    /*      FIDS                                                            */
487
    /* -------------------------------------------------------------------- */
488
0
    oField.Set("FIDS", OFTInteger, 5, 0);
489
0
    poFDefn->AddFieldDefn(&oField);
490
491
    /* -------------------------------------------------------------------- */
492
    /*      LNAM - only generated when LNAM strings are being used.         */
493
    /* -------------------------------------------------------------------- */
494
0
    if (nOptionFlags & S57M_LNAM_REFS)
495
0
    {
496
0
        oField.Set("LNAM", OFTString, 16, 0);
497
0
        poFDefn->AddFieldDefn(&oField);
498
499
0
        oField.Set("LNAM_REFS", OFTStringList, 16, 0);
500
0
        poFDefn->AddFieldDefn(&oField);
501
502
0
        oField.Set("FFPT_RIND", OFTIntegerList, 1, 0);
503
0
        poFDefn->AddFieldDefn(&oField);
504
505
        // We should likely include FFPT_COMT here.
506
0
    }
507
508
    /* -------------------------------------------------------------------- */
509
    /*      Values from FSPT field.                                         */
510
    /* -------------------------------------------------------------------- */
511
0
    if (nOptionFlags & S57M_RETURN_LINKAGES)
512
0
    {
513
0
        oField.Set("NAME_RCNM", OFTIntegerList, 3, 0);
514
0
        poFDefn->AddFieldDefn(&oField);
515
516
0
        oField.Set("NAME_RCID", OFTIntegerList, 10, 0);
517
0
        poFDefn->AddFieldDefn(&oField);
518
519
0
        oField.Set("ORNT", OFTIntegerList, 1, 0);
520
0
        poFDefn->AddFieldDefn(&oField);
521
522
0
        oField.Set("USAG", OFTIntegerList, 1, 0);
523
0
        poFDefn->AddFieldDefn(&oField);
524
525
0
        oField.Set("MASK", OFTIntegerList, 3, 0);
526
0
        poFDefn->AddFieldDefn(&oField);
527
0
    }
528
0
}