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/gmlas/ogrgmlaslayer.cpp
Line
Count
Source
1
/******************************************************************************
2
 * Project:  OGR
3
 * Purpose:  OGRGMLASDriver implementation
4
 * Author:   Even Rouault, <even dot rouault at spatialys dot com>
5
 *
6
 * Initial development funded by the European Earth observation programme
7
 * Copernicus
8
 *
9
 ******************************************************************************
10
 * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#include "ogr_gmlas.h"
16
#include "ogr_pgdump.h"
17
#include "cpl_minixml.h"
18
19
/************************************************************************/
20
/*                            OGRGMLASLayer()                           */
21
/************************************************************************/
22
23
OGRGMLASLayer::OGRGMLASLayer(OGRGMLASDataSource *poDS,
24
                             const GMLASFeatureClass &oFC,
25
                             OGRGMLASLayer *poParentLayer,
26
                             bool bAlwaysGenerateOGRPKId)
27
40.0k
    : m_poDS(poDS), m_oFC(oFC),
28
40.0k
      m_poFeatureDefn(new OGRFeatureDefn(oFC.GetName())),
29
40.0k
      m_poParentLayer(poParentLayer)
30
40.0k
{
31
40.0k
    m_poFeatureDefn->SetGeomType(wkbNone);
32
40.0k
    m_poFeatureDefn->Reference();
33
34
40.0k
    SetDescription(m_poFeatureDefn->GetName());
35
36
    // Are we a regular table ?
37
40.0k
    if (m_oFC.GetParentXPath().empty())
38
13.7k
    {
39
13.7k
        if (bAlwaysGenerateOGRPKId)
40
0
        {
41
0
            OGRFieldDefn oFieldDefn(szOGR_PKID, OFTString);
42
0
            oFieldDefn.SetNullable(false);
43
0
            m_nIDFieldIdx = m_poFeatureDefn->GetFieldCount();
44
0
            m_bIDFieldIsGenerated = true;
45
0
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
46
0
        }
47
48
        // Determine if we have an xs:ID attribute/elt, and if it is compulsory,
49
        // If so, place it as first field (not strictly required, but more
50
        // readable) or second field (if we also add a ogr_pkid) Furthermore
51
        // restrict that to attributes, because otherwise it is impractical in
52
        // the reader when joining related features.
53
13.7k
        const std::vector<GMLASField> &oFields = m_oFC.GetFields();
54
93.8k
        for (int i = 0; i < static_cast<int>(oFields.size()); i++)
55
82.2k
        {
56
82.2k
            if (oFields[i].GetType() == GMLAS_FT_ID &&
57
2.10k
                oFields[i].IsNotNullable() &&
58
2.09k
                oFields[i].GetXPath().find('@') != std::string::npos)
59
2.09k
            {
60
2.09k
                OGRFieldDefn oFieldDefn(oFields[i].GetName(), OFTString);
61
2.09k
                oFieldDefn.SetNullable(false);
62
2.09k
                const int nOGRIdx = m_poFeatureDefn->GetFieldCount();
63
2.09k
                if (m_nIDFieldIdx < 0)
64
2.09k
                    m_nIDFieldIdx = nOGRIdx;
65
2.09k
                m_oMapFieldXPathToOGRFieldIdx[oFields[i].GetXPath()] = nOGRIdx;
66
2.09k
                m_oMapOGRFieldIdxtoFCFieldIdx[nOGRIdx] = i;
67
2.09k
                m_oMapFieldXPathToFCFieldIdx[oFields[i].GetXPath()] = i;
68
2.09k
                m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
69
2.09k
                break;
70
2.09k
            }
71
82.2k
        }
72
73
        // If we don't have an explicit ID, then we need
74
        // to generate one, so that potentially related classes can reference it
75
        // (We could perhaps try to be clever to determine if we really need it)
76
13.7k
        if (m_nIDFieldIdx < 0)
77
11.6k
        {
78
11.6k
            OGRFieldDefn oFieldDefn(szOGR_PKID, OFTString);
79
11.6k
            oFieldDefn.SetNullable(false);
80
11.6k
            m_nIDFieldIdx = m_poFeatureDefn->GetFieldCount();
81
11.6k
            m_bIDFieldIsGenerated = true;
82
11.6k
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
83
11.6k
        }
84
13.7k
    }
85
86
40.0k
    OGRLayer *poLayersMetadataLayer = m_poDS->GetLayersMetadataLayer();
87
40.0k
    OGRFeature *poLayerDescFeature =
88
40.0k
        new OGRFeature(poLayersMetadataLayer->GetLayerDefn());
89
40.0k
    poLayerDescFeature->SetField(szLAYER_NAME, OGRGMLASLayer::GetName());
90
40.0k
    if (!m_oFC.GetParentXPath().empty())
91
26.3k
    {
92
26.3k
        poLayerDescFeature->SetField(szLAYER_CATEGORY, szJUNCTION_TABLE);
93
26.3k
    }
94
13.7k
    else
95
13.7k
    {
96
13.7k
        poLayerDescFeature->SetField(szLAYER_XPATH, m_oFC.GetXPath());
97
98
13.7k
        poLayerDescFeature->SetField(szLAYER_CATEGORY, m_oFC.IsTopLevelElt()
99
13.7k
                                                           ? szTOP_LEVEL_ELEMENT
100
13.7k
                                                           : szNESTED_ELEMENT);
101
102
13.7k
        if (m_nIDFieldIdx >= 0)
103
13.7k
        {
104
13.7k
            poLayerDescFeature->SetField(
105
13.7k
                szLAYER_PKID_NAME,
106
13.7k
                m_poFeatureDefn->GetFieldDefn(m_nIDFieldIdx)->GetNameRef());
107
13.7k
        }
108
109
        // If we are a child class, then add a field to reference the parent.
110
13.7k
        if (m_poParentLayer != nullptr)
111
4.29k
        {
112
4.29k
            CPLString osFieldName(szPARENT_PREFIX);
113
4.29k
            osFieldName += m_poParentLayer->GetLayerDefn()
114
4.29k
                               ->GetFieldDefn(m_poParentLayer->GetIDFieldIdx())
115
4.29k
                               ->GetNameRef();
116
4.29k
            poLayerDescFeature->SetField(szLAYER_PARENT_PKID_NAME,
117
4.29k
                                         osFieldName.c_str());
118
4.29k
        }
119
120
13.7k
        if (!m_oFC.GetDocumentation().empty())
121
80
        {
122
80
            poLayerDescFeature->SetField(szLAYER_DOCUMENTATION,
123
80
                                         m_oFC.GetDocumentation());
124
80
        }
125
13.7k
    }
126
40.0k
    CPL_IGNORE_RET_VAL(
127
40.0k
        poLayersMetadataLayer->CreateFeature(poLayerDescFeature));
128
40.0k
    delete poLayerDescFeature;
129
40.0k
}
130
131
/************************************************************************/
132
/*                            OGRGMLASLayer()                           */
133
/************************************************************************/
134
135
OGRGMLASLayer::OGRGMLASLayer(const char *pszLayerName)
136
5.36k
    : m_bLayerDefnFinalized(true),
137
5.36k
      m_poFeatureDefn(new OGRFeatureDefn(pszLayerName))
138
139
5.36k
{
140
5.36k
    m_poFeatureDefn->SetGeomType(wkbNone);
141
5.36k
    m_poFeatureDefn->Reference();
142
143
5.36k
    SetDescription(m_poFeatureDefn->GetName());
144
5.36k
}
145
146
/************************************************************************/
147
/*                        GetSWEChildAndType()                          */
148
/************************************************************************/
149
150
static CPLXMLNode *GetSWEChildAndType(CPLXMLNode *psNode, OGRFieldType &eType,
151
                                      OGRFieldSubType &eSubType)
152
8.73k
{
153
8.73k
    eType = OFTString;
154
8.73k
    eSubType = OFSTNone;
155
8.73k
    CPLXMLNode *psChildNode = nullptr;
156
8.73k
    if ((psChildNode = CPLGetXMLNode(psNode, "Time")) != nullptr)
157
4.58k
    {
158
4.58k
        eType = OFTDateTime;
159
4.58k
    }
160
4.14k
    else if ((psChildNode = CPLGetXMLNode(psNode, "Quantity")) != nullptr)
161
1.17k
    {
162
1.17k
        eType = OFTReal;
163
1.17k
    }
164
2.97k
    else if ((psChildNode = CPLGetXMLNode(psNode, "Category")) != nullptr)
165
1.14k
    {
166
1.14k
        eType = OFTString;
167
1.14k
    }
168
1.83k
    else if ((psChildNode = CPLGetXMLNode(psNode, "Count")) != nullptr)
169
537
    {
170
537
        eType = OFTInteger;
171
537
    }
172
1.29k
    else if ((psChildNode = CPLGetXMLNode(psNode, "Text")) != nullptr)
173
466
    {
174
466
        eType = OFTString;
175
466
    }
176
830
    else if ((psChildNode = CPLGetXMLNode(psNode, "Boolean")) != nullptr)
177
392
    {
178
392
        eType = OFTInteger;
179
392
        eSubType = OFSTBoolean;
180
392
    }
181
8.73k
    return psChildNode;
182
8.73k
}
183
184
/************************************************************************/
185
/*              ProcessDataRecordOfDataArrayCreateFields()               */
186
/************************************************************************/
187
188
void OGRGMLASLayer::ProcessDataRecordOfDataArrayCreateFields(
189
    OGRGMLASLayer *poParentLayer, CPLXMLNode *psDataRecord,
190
    OGRLayer *poFieldsMetadataLayer)
191
5.36k
{
192
5.36k
    {
193
5.36k
        CPLString osFieldName(szPARENT_PREFIX);
194
5.36k
        osFieldName += poParentLayer->GetLayerDefn()
195
5.36k
                           ->GetFieldDefn(poParentLayer->GetIDFieldIdx())
196
5.36k
                           ->GetNameRef();
197
5.36k
        OGRFieldDefn oFieldDefn(osFieldName, OFTString);
198
5.36k
        oFieldDefn.SetNullable(false);
199
5.36k
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
200
5.36k
    }
201
202
28.2k
    for (CPLXMLNode *psIter = psDataRecord->psChild; psIter != nullptr;
203
22.8k
         psIter = psIter->psNext)
204
22.8k
    {
205
22.8k
        if (psIter->eType == CXT_Element &&
206
8.74k
            strcmp(psIter->pszValue, "field") == 0)
207
8.73k
        {
208
8.73k
            const char *pszName = CPLGetXMLValue(psIter, "name", "");
209
8.73k
            OGRFieldDefn oFieldDefn(CPLString(pszName).tolower(), OFTString);
210
8.73k
            OGRFieldType eType;
211
8.73k
            OGRFieldSubType eSubType;
212
8.73k
            CPLXMLNode *psNode = GetSWEChildAndType(psIter, eType, eSubType);
213
8.73k
            oFieldDefn.SetType(eType);
214
8.73k
            oFieldDefn.SetSubType(eSubType);
215
8.73k
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
216
217
            // Register field in _ogr_fields_metadata
218
8.73k
            OGRFeature *poFieldDescFeature =
219
8.73k
                new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
220
8.73k
            poFieldDescFeature->SetField(szLAYER_NAME, GetName());
221
8.73k
            m_nMaxFieldIndex = m_poFeatureDefn->GetFieldCount() - 1;
222
8.73k
            poFieldDescFeature->SetField(szFIELD_INDEX, m_nMaxFieldIndex);
223
8.73k
            poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
224
8.73k
            if (psNode)
225
8.29k
            {
226
8.29k
                poFieldDescFeature->SetField(szFIELD_TYPE, psNode->pszValue);
227
8.29k
            }
228
8.73k
            poFieldDescFeature->SetField(szFIELD_IS_LIST, 0);
229
8.73k
            poFieldDescFeature->SetField(szFIELD_MIN_OCCURS, 0);
230
8.73k
            poFieldDescFeature->SetField(szFIELD_MAX_OCCURS, 1);
231
8.73k
            poFieldDescFeature->SetField(szFIELD_CATEGORY, szSWE_FIELD);
232
8.73k
            if (psNode)
233
8.29k
            {
234
8.29k
                char *pszXML = CPLSerializeXMLTree(psNode);
235
8.29k
                poFieldDescFeature->SetField(szFIELD_DOCUMENTATION, pszXML);
236
8.29k
                CPLFree(pszXML);
237
8.29k
            }
238
8.73k
            CPL_IGNORE_RET_VAL(
239
8.73k
                poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
240
8.73k
            delete poFieldDescFeature;
241
8.73k
        }
242
22.8k
    }
243
5.36k
}
244
245
/************************************************************************/
246
/*                ProcessDataRecordCreateFields()                       */
247
/************************************************************************/
248
249
void OGRGMLASLayer::ProcessDataRecordCreateFields(
250
    CPLXMLNode *psDataRecord, const std::vector<OGRFeature *> &apoFeatures,
251
    OGRLayer *poFieldsMetadataLayer)
252
0
{
253
0
    for (CPLXMLNode *psIter = psDataRecord->psChild; psIter != nullptr;
254
0
         psIter = psIter->psNext)
255
0
    {
256
0
        if (psIter->eType == CXT_Element &&
257
0
            strcmp(psIter->pszValue, "field") == 0)
258
0
        {
259
0
            const char *pszName = CPLGetXMLValue(psIter, "name", "");
260
0
            CPLString osName = CPLString(pszName).tolower();
261
0
            OGRFieldDefn oFieldDefn(osName, OFTString);
262
0
            OGRFieldType eType;
263
0
            OGRFieldSubType eSubType;
264
0
            CPLXMLNode *psChildNode =
265
0
                GetSWEChildAndType(psIter, eType, eSubType);
266
0
            oFieldDefn.SetType(eType);
267
0
            oFieldDefn.SetSubType(eSubType);
268
0
            if (psChildNode != nullptr &&
269
0
                m_oMapSWEFieldToOGRFieldName.find(osName) ==
270
0
                    m_oMapSWEFieldToOGRFieldName.end())
271
0
            {
272
0
                const int nValidFields = m_poFeatureDefn->GetFieldCount();
273
274
0
                CPLString osSWEField(osName);
275
0
                if (m_poFeatureDefn->GetFieldIndex(osName) >= 0)
276
0
                    osName = "swe_field_" + osName;
277
0
                m_oMapSWEFieldToOGRFieldName[osSWEField] = osName;
278
0
                oFieldDefn.SetName((osName + "_value").c_str());
279
0
                m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
280
281
                // Register field in _ogr_fields_metadata
282
0
                OGRFeature *poFieldDescFeature =
283
0
                    new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
284
0
                poFieldDescFeature->SetField(szLAYER_NAME, GetName());
285
0
                m_nMaxFieldIndex++;
286
0
                poFieldDescFeature->SetField(szFIELD_INDEX, m_nMaxFieldIndex);
287
0
                poFieldDescFeature->SetField(szFIELD_NAME,
288
0
                                             oFieldDefn.GetNameRef());
289
0
                poFieldDescFeature->SetField(szFIELD_TYPE,
290
0
                                             psChildNode->pszValue);
291
0
                poFieldDescFeature->SetField(szFIELD_IS_LIST, 0);
292
0
                poFieldDescFeature->SetField(szFIELD_MIN_OCCURS, 0);
293
0
                poFieldDescFeature->SetField(szFIELD_MAX_OCCURS, 1);
294
0
                poFieldDescFeature->SetField(szFIELD_CATEGORY, szSWE_FIELD);
295
0
                {
296
0
                    CPLXMLNode *psDupTree = CPLCloneXMLTree(psChildNode);
297
0
                    CPLXMLNode *psValue = CPLGetXMLNode(psDupTree, "value");
298
0
                    if (psValue != nullptr)
299
0
                    {
300
0
                        CPLRemoveXMLChild(psDupTree, psValue);
301
0
                        CPLDestroyXMLNode(psValue);
302
0
                    }
303
0
                    char *pszXML = CPLSerializeXMLTree(psDupTree);
304
0
                    CPLDestroyXMLNode(psDupTree);
305
0
                    poFieldDescFeature->SetField(szFIELD_DOCUMENTATION, pszXML);
306
0
                    CPLFree(pszXML);
307
0
                }
308
0
                CPL_IGNORE_RET_VAL(
309
0
                    poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
310
0
                delete poFieldDescFeature;
311
312
0
                for (CPLXMLNode *psIter2 = psChildNode->psChild;
313
0
                     psIter2 != nullptr; psIter2 = psIter2->psNext)
314
0
                {
315
0
                    if (psIter2->eType == CXT_Element &&
316
0
                        strcmp(psIter2->pszValue, "value") != 0)
317
0
                    {
318
0
                        const CPLString osName2 =
319
0
                            CPLString(osName + "_" + psIter2->pszValue)
320
0
                                .tolower();
321
0
                        for (CPLXMLNode *psIter3 = psIter2->psChild;
322
0
                             psIter3 != nullptr; psIter3 = psIter3->psNext)
323
0
                        {
324
0
                            if (psIter3->eType == CXT_Attribute)
325
0
                            {
326
0
                                const char *pszValue = psIter3->pszValue;
327
0
                                const char *pszColon = strchr(pszValue, ':');
328
0
                                if (pszColon)
329
0
                                    pszValue = pszColon + 1;
330
0
                                OGRFieldDefn oFieldDefn2(
331
0
                                    CPLString(osName2 + "_" + pszValue)
332
0
                                        .tolower(),
333
0
                                    OFTString);
334
0
                                m_poFeatureDefn->AddFieldDefn(&oFieldDefn2);
335
0
                            }
336
0
                            else if (psIter3->eType == CXT_Text)
337
0
                            {
338
0
                                OGRFieldDefn oFieldDefn2(osName2, OFTString);
339
0
                                m_poFeatureDefn->AddFieldDefn(&oFieldDefn2);
340
0
                            }
341
0
                        }
342
0
                    }
343
0
                }
344
345
0
                int *panRemap = static_cast<int *>(
346
0
                    CPLMalloc(sizeof(int) * m_poFeatureDefn->GetFieldCount()));
347
0
                for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); ++i)
348
0
                {
349
0
                    if (i < nValidFields)
350
0
                        panRemap[i] = i;
351
0
                    else
352
0
                        panRemap[i] = -1;
353
0
                }
354
355
0
                for (size_t i = 0; i < apoFeatures.size(); i++)
356
0
                {
357
0
                    apoFeatures[i]->RemapFields(nullptr, panRemap);
358
0
                }
359
360
0
                CPLFree(panRemap);
361
0
            }
362
0
        }
363
0
    }
364
0
}
365
366
/************************************************************************/
367
/*                             SetSWEValue()                            */
368
/************************************************************************/
369
370
static void SetSWEValue(OGRFeature *poFeature, const CPLString &osFieldName,
371
                        const char *pszValue)
372
0
{
373
0
    int iField = poFeature->GetDefnRef()->GetFieldIndex(osFieldName);
374
0
    const OGRFieldDefn *poFieldDefn = poFeature->GetFieldDefnRef(iField);
375
0
    OGRFieldType eType(poFieldDefn->GetType());
376
0
    OGRFieldSubType eSubType(poFieldDefn->GetSubType());
377
0
    if (eType == OFTInteger && eSubType == OFSTBoolean)
378
0
    {
379
0
        poFeature->SetField(
380
0
            iField, EQUAL(pszValue, "1") || EQUAL(pszValue, "True") ? 1 : 0);
381
0
    }
382
0
    else
383
0
    {
384
0
        poFeature->SetField(iField, pszValue);
385
0
    }
386
0
}
387
388
/************************************************************************/
389
/*                    ProcessDataRecordFillFeature()                    */
390
/************************************************************************/
391
392
void OGRGMLASLayer::ProcessDataRecordFillFeature(CPLXMLNode *psDataRecord,
393
                                                 OGRFeature *poFeature)
394
0
{
395
0
    for (CPLXMLNode *psIter = psDataRecord->psChild; psIter != nullptr;
396
0
         psIter = psIter->psNext)
397
0
    {
398
0
        if (psIter->eType == CXT_Element &&
399
0
            strcmp(psIter->pszValue, "field") == 0)
400
0
        {
401
0
            const char *pszName = CPLGetXMLValue(psIter, "name", "");
402
0
            CPLString osName = CPLString(pszName).tolower();
403
0
            OGRFieldDefn oFieldDefn(osName, OFTString);
404
0
            OGRFieldType eType;
405
0
            OGRFieldSubType eSubType;
406
0
            CPLXMLNode *psChildNode =
407
0
                GetSWEChildAndType(psIter, eType, eSubType);
408
0
            oFieldDefn.SetType(eType);
409
0
            oFieldDefn.SetSubType(eSubType);
410
0
            if (psChildNode == nullptr)
411
0
                continue;
412
0
            const auto oIter = m_oMapSWEFieldToOGRFieldName.find(osName);
413
0
            CPLAssert(oIter != m_oMapSWEFieldToOGRFieldName.end());
414
0
            osName = oIter->second;
415
0
            for (CPLXMLNode *psIter2 = psChildNode->psChild; psIter2 != nullptr;
416
0
                 psIter2 = psIter2->psNext)
417
0
            {
418
0
                if (psIter2->eType == CXT_Element)
419
0
                {
420
0
                    const CPLString osName2 =
421
0
                        CPLString(osName + "_" + psIter2->pszValue).tolower();
422
0
                    for (CPLXMLNode *psIter3 = psIter2->psChild;
423
0
                         psIter3 != nullptr; psIter3 = psIter3->psNext)
424
0
                    {
425
0
                        if (psIter3->eType == CXT_Attribute)
426
0
                        {
427
0
                            const char *pszValue = psIter3->pszValue;
428
0
                            const char *pszColon = strchr(pszValue, ':');
429
0
                            if (pszColon)
430
0
                                pszValue = pszColon + 1;
431
0
                            SetSWEValue(
432
0
                                poFeature,
433
0
                                CPLString(osName2 + "_" + pszValue).tolower(),
434
0
                                psIter3->psChild->pszValue);
435
0
                        }
436
0
                        else if (psIter3->eType == CXT_Text)
437
0
                        {
438
0
                            SetSWEValue(poFeature, osName2, psIter3->pszValue);
439
0
                        }
440
0
                    }
441
0
                }
442
0
            }
443
0
        }
444
0
    }
445
0
}
446
447
/************************************************************************/
448
/*                             PostInit()                               */
449
/************************************************************************/
450
451
void OGRGMLASLayer::PostInit(bool bIncludeGeometryXML)
452
40.0k
{
453
40.0k
    const std::vector<GMLASField> &oFields = m_oFC.GetFields();
454
455
40.0k
    OGRLayer *poFieldsMetadataLayer = m_poDS->GetFieldsMetadataLayer();
456
40.0k
    OGRLayer *poRelationshipsLayer = m_poDS->GetRelationshipsLayer();
457
458
    // Is it a junction table ?
459
40.0k
    if (!m_oFC.GetParentXPath().empty())
460
26.3k
    {
461
26.3k
        {
462
26.3k
            OGRFieldDefn oFieldDefn(szOCCURRENCE, OFTInteger);
463
26.3k
            oFieldDefn.SetNullable(false);
464
26.3k
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
465
466
26.3k
            OGRFeature *poFieldDescFeature =
467
26.3k
                new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
468
26.3k
            poFieldDescFeature->SetField(szLAYER_NAME, GetName());
469
26.3k
            poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
470
26.3k
            CPL_IGNORE_RET_VAL(
471
26.3k
                poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
472
26.3k
            delete poFieldDescFeature;
473
26.3k
        }
474
475
26.3k
        {
476
26.3k
            OGRFieldDefn oFieldDefn(szPARENT_PKID, OFTString);
477
26.3k
            oFieldDefn.SetNullable(false);
478
26.3k
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
479
480
26.3k
            OGRFeature *poFieldDescFeature =
481
26.3k
                new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
482
26.3k
            poFieldDescFeature->SetField(szLAYER_NAME, GetName());
483
26.3k
            poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
484
26.3k
            CPL_IGNORE_RET_VAL(
485
26.3k
                poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
486
26.3k
            delete poFieldDescFeature;
487
26.3k
        }
488
26.3k
        {
489
26.3k
            OGRFieldDefn oFieldDefn(szCHILD_PKID, OFTString);
490
26.3k
            oFieldDefn.SetNullable(false);
491
26.3k
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
492
493
26.3k
            OGRFeature *poFieldDescFeature =
494
26.3k
                new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
495
26.3k
            poFieldDescFeature->SetField(szLAYER_NAME, GetName());
496
26.3k
            poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
497
26.3k
            CPL_IGNORE_RET_VAL(
498
26.3k
                poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
499
26.3k
            delete poFieldDescFeature;
500
26.3k
        }
501
502
26.3k
        return;
503
26.3k
    }
504
505
    // If we are a child class, then add a field to reference the parent.
506
13.7k
    if (m_poParentLayer != nullptr)
507
4.29k
    {
508
4.29k
        CPLString osFieldName(szPARENT_PREFIX);
509
4.29k
        osFieldName += m_poParentLayer->GetLayerDefn()
510
4.29k
                           ->GetFieldDefn(m_poParentLayer->GetIDFieldIdx())
511
4.29k
                           ->GetNameRef();
512
4.29k
        OGRFieldDefn oFieldDefn(osFieldName, OFTString);
513
4.29k
        oFieldDefn.SetNullable(false);
514
4.29k
        m_nParentIDFieldIdx = m_poFeatureDefn->GetFieldCount();
515
4.29k
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
516
4.29k
    }
517
518
13.7k
    int nFieldIndex = 0;
519
295k
    for (int i = 0; i < static_cast<int>(oFields.size()); i++)
520
282k
    {
521
282k
        OGRGMLASLayer *poRelatedLayer = nullptr;
522
282k
        const GMLASField &oField(oFields[i]);
523
524
282k
        m_oMapFieldXPathToFCFieldIdx[oField.GetXPath()] = i;
525
282k
        if (oField.IsIgnored())
526
17
            continue;
527
528
282k
        const GMLASField::Category eCategory(oField.GetCategory());
529
282k
        if (!oField.GetRelatedClassXPath().empty())
530
210k
        {
531
210k
            poRelatedLayer =
532
210k
                m_poDS->GetLayerByXPath(oField.GetRelatedClassXPath());
533
210k
            if (poRelatedLayer != nullptr)
534
210k
            {
535
210k
                OGRFeature *poRelationshipsFeature =
536
210k
                    new OGRFeature(poRelationshipsLayer->GetLayerDefn());
537
210k
                poRelationshipsFeature->SetField(szPARENT_LAYER, GetName());
538
210k
                poRelationshipsFeature->SetField(
539
210k
                    szPARENT_PKID, GetLayerDefn()
540
210k
                                       ->GetFieldDefn(GetIDFieldIdx())
541
210k
                                       ->GetNameRef());
542
210k
                if (!oField.GetName().empty())
543
210k
                {
544
210k
                    poRelationshipsFeature->SetField(szPARENT_ELEMENT_NAME,
545
210k
                                                     oField.GetName());
546
210k
                }
547
210k
                poRelationshipsFeature->SetField(szCHILD_LAYER,
548
210k
                                                 poRelatedLayer->GetName());
549
210k
                if (eCategory ==
550
210k
                        GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE ||
551
183k
                    eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_WITH_LINK)
552
205k
                {
553
205k
                    poRelationshipsFeature->SetField(
554
205k
                        szCHILD_PKID,
555
205k
                        poRelatedLayer->GetLayerDefn()
556
205k
                            ->GetFieldDefn(poRelatedLayer->GetIDFieldIdx())
557
205k
                            ->GetNameRef());
558
205k
                }
559
4.29k
                else
560
4.29k
                {
561
4.29k
                    CPLAssert(eCategory ==
562
4.29k
                                  GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
563
4.29k
                              eCategory == GMLASField::GROUP);
564
565
4.29k
                    poRelationshipsFeature->SetField(
566
4.29k
                        szCHILD_PKID, (CPLString(szPARENT_PREFIX) +
567
4.29k
                                       GetLayerDefn()
568
4.29k
                                           ->GetFieldDefn(GetIDFieldIdx())
569
4.29k
                                           ->GetNameRef())
570
4.29k
                                          .c_str());
571
4.29k
                }
572
210k
                CPL_IGNORE_RET_VAL(poRelationshipsLayer->CreateFeature(
573
210k
                    poRelationshipsFeature));
574
210k
                delete poRelationshipsFeature;
575
210k
            }
576
0
            else
577
0
            {
578
0
                CPLDebug("GMLAS", "Cannot find class matching %s",
579
0
                         oField.GetRelatedClassXPath().c_str());
580
0
            }
581
210k
        }
582
583
282k
        OGRFeature *poFieldDescFeature =
584
282k
            new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
585
282k
        poFieldDescFeature->SetField(szLAYER_NAME, GetName());
586
587
282k
        ++nFieldIndex;
588
282k
        m_nMaxFieldIndex = nFieldIndex;
589
282k
        poFieldDescFeature->SetField(szFIELD_INDEX, nFieldIndex);
590
591
282k
        if (oField.GetName().empty())
592
0
        {
593
0
            CPLAssert(eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
594
0
                      eCategory == GMLASField::GROUP);
595
0
        }
596
282k
        else
597
282k
        {
598
282k
            poFieldDescFeature->SetField(szFIELD_NAME,
599
282k
                                         oField.GetName().c_str());
600
282k
        }
601
282k
        if (!oField.GetXPath().empty())
602
282k
        {
603
282k
            poFieldDescFeature->SetField(szFIELD_XPATH,
604
282k
                                         oField.GetXPath().c_str());
605
282k
        }
606
1
        else if (!oField.GetAlternateXPaths().empty())
607
1
        {
608
1
            CPLString osXPath;
609
1
            const std::vector<CPLString> &aoXPaths =
610
1
                oField.GetAlternateXPaths();
611
27
            for (size_t j = 0; j < aoXPaths.size(); j++)
612
26
            {
613
26
                if (j != 0)
614
25
                    osXPath += ",";
615
26
                osXPath += aoXPaths[j];
616
26
            }
617
1
            poFieldDescFeature->SetField(szFIELD_XPATH, osXPath.c_str());
618
1
        }
619
282k
        if (oField.GetTypeName().empty())
620
30.6k
        {
621
30.6k
            CPLAssert(
622
30.6k
                eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
623
30.6k
                eCategory ==
624
30.6k
                    GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE ||
625
30.6k
                eCategory == GMLASField::GROUP);
626
30.6k
        }
627
251k
        else
628
251k
        {
629
251k
            poFieldDescFeature->SetField(szFIELD_TYPE,
630
251k
                                         oField.GetTypeName().c_str());
631
251k
        }
632
282k
        poFieldDescFeature->SetField(szFIELD_IS_LIST,
633
282k
                                     static_cast<int>(oField.IsList()));
634
282k
        if (oField.GetMinOccurs() != -1)
635
265k
        {
636
265k
            poFieldDescFeature->SetField(szFIELD_MIN_OCCURS,
637
265k
                                         oField.GetMinOccurs());
638
265k
        }
639
282k
        if (oField.GetMaxOccurs() == MAXOCCURS_UNLIMITED)
640
30.4k
        {
641
30.4k
            poFieldDescFeature->SetField(szFIELD_MAX_OCCURS, INT_MAX);
642
30.4k
        }
643
251k
        else if (oField.GetMaxOccurs() != -1)
644
235k
        {
645
235k
            poFieldDescFeature->SetField(szFIELD_MAX_OCCURS,
646
235k
                                         oField.GetMaxOccurs());
647
235k
        }
648
282k
        if (oField.GetMaxOccurs() == MAXOCCURS_UNLIMITED ||
649
251k
            oField.GetMaxOccurs() > 1)
650
30.6k
        {
651
30.6k
            poFieldDescFeature->SetField(szFIELD_REPETITION_ON_SEQUENCE,
652
30.6k
                                         oField.GetRepetitionOnSequence() ? 1
653
30.6k
                                                                          : 0);
654
30.6k
        }
655
282k
        if (!oField.GetFixedValue().empty())
656
19
        {
657
19
            poFieldDescFeature->SetField(szFIELD_FIXED_VALUE,
658
19
                                         oField.GetFixedValue());
659
19
        }
660
282k
        if (!oField.GetDefaultValue().empty())
661
0
        {
662
0
            poFieldDescFeature->SetField(szFIELD_DEFAULT_VALUE,
663
0
                                         oField.GetDefaultValue());
664
0
        }
665
282k
        switch (eCategory)
666
282k
        {
667
71.7k
            case GMLASField::REGULAR:
668
71.7k
                poFieldDescFeature->SetField(szFIELD_CATEGORY, szREGULAR);
669
71.7k
                break;
670
4.29k
            case GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK:
671
4.29k
                poFieldDescFeature->SetField(szFIELD_CATEGORY,
672
4.29k
                                             szPATH_TO_CHILD_ELEMENT_NO_LINK);
673
4.29k
                break;
674
179k
            case GMLASField::PATH_TO_CHILD_ELEMENT_WITH_LINK:
675
179k
                poFieldDescFeature->SetField(szFIELD_CATEGORY,
676
179k
                                             szPATH_TO_CHILD_ELEMENT_WITH_LINK);
677
179k
                break;
678
26.3k
            case GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE:
679
26.3k
                poFieldDescFeature->SetField(
680
26.3k
                    szFIELD_CATEGORY,
681
26.3k
                    szPATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE);
682
26.3k
                break;
683
0
            case GMLASField::GROUP:
684
0
                poFieldDescFeature->SetField(szFIELD_CATEGORY, szGROUP);
685
0
                break;
686
0
            default:
687
0
                CPLAssert(FALSE);
688
0
                break;
689
282k
        }
690
282k
        if (poRelatedLayer != nullptr)
691
210k
        {
692
210k
            poFieldDescFeature->SetField(szFIELD_RELATED_LAYER,
693
210k
                                         poRelatedLayer->GetName());
694
210k
        }
695
696
282k
        if (eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE)
697
26.3k
        {
698
26.3k
            const CPLString &osAbstractElementXPath(
699
26.3k
                oField.GetAbstractElementXPath());
700
26.3k
            const CPLString &osNestedXPath(oField.GetRelatedClassXPath());
701
26.3k
            CPLAssert(!osAbstractElementXPath.empty());
702
26.3k
            CPLAssert(!osNestedXPath.empty());
703
704
26.3k
            OGRGMLASLayer *poJunctionLayer = m_poDS->GetLayerByXPath(
705
26.3k
                osAbstractElementXPath + "|" + osNestedXPath);
706
26.3k
            if (poJunctionLayer != nullptr)
707
26.3k
            {
708
26.3k
                poFieldDescFeature->SetField(szFIELD_JUNCTION_LAYER,
709
26.3k
                                             poJunctionLayer->GetName());
710
26.3k
            }
711
26.3k
        }
712
713
282k
        if (!oField.GetDocumentation().empty())
714
177
        {
715
177
            poFieldDescFeature->SetField(szFIELD_DOCUMENTATION,
716
177
                                         oField.GetDocumentation());
717
177
        }
718
719
282k
        CPL_IGNORE_RET_VAL(
720
282k
            poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
721
282k
        delete poFieldDescFeature;
722
723
        // Check whether the field is OGR instanciable
724
282k
        if (eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
725
277k
            eCategory ==
726
277k
                GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE ||
727
251k
            eCategory == GMLASField::GROUP)
728
30.6k
        {
729
30.6k
            continue;
730
30.6k
        }
731
732
251k
        OGRFieldType eType = OFTString;
733
251k
        OGRFieldSubType eSubType = OFSTNone;
734
251k
        CPLString osOGRFieldName(oField.GetName());
735
251k
        switch (oField.GetType())
736
251k
        {
737
196k
            case GMLAS_FT_STRING:
738
196k
                eType = OFTString;
739
196k
                break;
740
29.2k
            case GMLAS_FT_ID:
741
29.2k
            {
742
29.2k
                eType = OFTString;
743
29.2k
                if (oField.IsNotNullable())
744
26.4k
                {
745
26.4k
                    continue;
746
26.4k
                }
747
2.78k
                break;
748
29.2k
            }
749
2.78k
            case GMLAS_FT_BOOLEAN:
750
0
                eType = OFTInteger;
751
0
                eSubType = OFSTBoolean;
752
0
                break;
753
0
            case GMLAS_FT_SHORT:
754
0
                eType = OFTInteger;
755
0
                eSubType = OFSTInt16;
756
0
                break;
757
0
            case GMLAS_FT_INT32:
758
0
                eType = OFTInteger;
759
0
                break;
760
0
            case GMLAS_FT_INT64:
761
0
                eType = OFTInteger64;
762
0
                break;
763
0
            case GMLAS_FT_FLOAT:
764
0
                eType = OFTReal;
765
0
                eSubType = OFSTFloat32;
766
0
                break;
767
0
            case GMLAS_FT_DOUBLE:
768
0
                eType = OFTReal;
769
0
                break;
770
0
            case GMLAS_FT_DECIMAL:
771
0
                eType = OFTReal;
772
0
                break;
773
8
            case GMLAS_FT_DATE:
774
8
                eType = OFTDate;
775
8
                break;
776
0
            case GMLAS_FT_GYEAR:
777
0
                eType = OFTInteger;
778
0
                break;
779
0
            case GMLAS_FT_GYEAR_MONTH:
780
0
                eType = OFTDate;
781
0
                break;
782
0
            case GMLAS_FT_TIME:
783
0
                eType = OFTTime;
784
0
                break;
785
41
            case GMLAS_FT_DATETIME:
786
41
                eType = OFTDateTime;
787
41
                break;
788
0
            case GMLAS_FT_BASE64BINARY:
789
0
            case GMLAS_FT_HEXBINARY:
790
0
                eType = OFTBinary;
791
0
                break;
792
34
            case GMLAS_FT_ANYURI:
793
34
                eType = OFTString;
794
34
                break;
795
23.6k
            case GMLAS_FT_ANYTYPE:
796
23.6k
                eType = OFTString;
797
23.6k
                break;
798
1.96k
            case GMLAS_FT_ANYSIMPLETYPE:
799
1.96k
                eType = OFTString;
800
1.96k
                break;
801
18
            case GMLAS_FT_GEOMETRY:
802
18
            {
803
                // Create a geometry field
804
18
                OGRGeomFieldDefn oGeomFieldDefn(osOGRFieldName,
805
18
                                                oField.GetGeomType());
806
18
                m_poFeatureDefn->AddGeomFieldDefn(&oGeomFieldDefn);
807
808
18
                const int iOGRGeomIdx =
809
18
                    m_poFeatureDefn->GetGeomFieldCount() - 1;
810
18
                if (!oField.GetXPath().empty())
811
18
                {
812
18
                    m_oMapFieldXPathToOGRGeomFieldIdx[oField.GetXPath()] =
813
18
                        iOGRGeomIdx;
814
18
                }
815
0
                else
816
0
                {
817
0
                    const std::vector<CPLString> &aoXPaths =
818
0
                        oField.GetAlternateXPaths();
819
0
                    for (size_t j = 0; j < aoXPaths.size(); j++)
820
0
                    {
821
0
                        m_oMapFieldXPathToOGRGeomFieldIdx[aoXPaths[j]] =
822
0
                            iOGRGeomIdx;
823
0
                    }
824
0
                }
825
826
18
                m_oMapOGRGeomFieldIdxtoFCFieldIdx[iOGRGeomIdx] = i;
827
828
                // Suffix the regular non-geometry field
829
18
                osOGRFieldName += szXML_SUFFIX;
830
18
                eType = OFTString;
831
18
                break;
832
0
            }
833
0
            default:
834
0
                CPLError(CE_Warning, CPLE_AppDefined,
835
0
                         "Unhandled type in enum: %d", oField.GetType());
836
0
                break;
837
251k
        }
838
839
224k
        if (oField.GetType() == GMLAS_FT_GEOMETRY && !bIncludeGeometryXML)
840
18
        {
841
18
            continue;
842
18
        }
843
844
224k
        if (oField.IsArray())
845
6
        {
846
6
            switch (eType)
847
6
            {
848
6
                case OFTString:
849
6
                    eType = OFTStringList;
850
6
                    break;
851
0
                case OFTInteger:
852
0
                    eType = OFTIntegerList;
853
0
                    break;
854
0
                case OFTInteger64:
855
0
                    eType = OFTInteger64List;
856
0
                    break;
857
0
                case OFTReal:
858
0
                    eType = OFTRealList;
859
0
                    break;
860
0
                default:
861
0
                    CPLError(CE_Warning, CPLE_AppDefined,
862
0
                             "Unhandled type in enum: %d", eType);
863
0
                    break;
864
6
            }
865
6
        }
866
224k
        OGRFieldDefn oFieldDefn(osOGRFieldName, eType);
867
224k
        oFieldDefn.SetSubType(eSubType);
868
224k
        if (oField.IsNotNullable())
869
2.36k
            oFieldDefn.SetNullable(false);
870
224k
        CPLString osDefaultOrFixed = oField.GetDefaultValue();
871
224k
        if (osDefaultOrFixed.empty())
872
224k
            osDefaultOrFixed = oField.GetFixedValue();
873
224k
        if (!osDefaultOrFixed.empty())
874
19
        {
875
19
            char *pszEscaped = CPLEscapeString(osDefaultOrFixed, -1, CPLES_SQL);
876
19
            oFieldDefn.SetDefault(
877
19
                (CPLString("'") + pszEscaped + CPLString("'")).c_str());
878
19
            CPLFree(pszEscaped);
879
19
        }
880
224k
        oFieldDefn.SetWidth(oField.GetWidth());
881
224k
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
882
883
224k
        const int iOGRIdx = m_poFeatureDefn->GetFieldCount() - 1;
884
224k
        if (!oField.GetXPath().empty())
885
224k
        {
886
224k
            m_oMapFieldXPathToOGRFieldIdx[oField.GetXPath()] = iOGRIdx;
887
224k
        }
888
1
        else
889
1
        {
890
1
            const std::vector<CPLString> &aoXPaths =
891
1
                oField.GetAlternateXPaths();
892
27
            for (size_t j = 0; j < aoXPaths.size(); j++)
893
26
            {
894
26
                m_oMapFieldXPathToOGRFieldIdx[aoXPaths[j]] = iOGRIdx;
895
26
            }
896
1
        }
897
898
224k
        m_oMapOGRFieldIdxtoFCFieldIdx[iOGRIdx] = i;
899
900
        // Create field to receive resolved xlink:href content, if needed
901
224k
        if (oField.GetXPath().find(szAT_XLINK_HREF) != std::string::npos &&
902
17
            m_poDS->GetConf().m_oXLinkResolution.m_bDefaultResolutionEnabled &&
903
0
            m_poDS->GetConf().m_oXLinkResolution.m_eDefaultResolutionMode ==
904
0
                GMLASXLinkResolutionConf::RawContent)
905
0
        {
906
0
            CPLString osRawContentFieldname(osOGRFieldName);
907
0
            size_t nPos = osRawContentFieldname.find(szHREF_SUFFIX);
908
0
            if (nPos != std::string::npos)
909
0
                osRawContentFieldname.resize(nPos);
910
0
            osRawContentFieldname += szRAW_CONTENT_SUFFIX;
911
0
            OGRFieldDefn oFieldDefnRaw(osRawContentFieldname, OFTString);
912
0
            m_poFeatureDefn->AddFieldDefn(&oFieldDefnRaw);
913
914
0
            m_oMapFieldXPathToOGRFieldIdx
915
0
                [GMLASField::MakeXLinkRawContentFieldXPathFromXLinkHrefXPath(
916
0
                    oField.GetXPath())] = m_poFeatureDefn->GetFieldCount() - 1;
917
0
        }
918
919
224k
        CPL_IGNORE_RET_VAL(osOGRFieldName);
920
224k
    }
921
922
13.7k
    CreateCompoundFoldedMappings();
923
13.7k
}
924
925
/************************************************************************/
926
/*                   CreateCompoundFoldedMappings()                     */
927
/************************************************************************/
928
929
// In the case we have nested elements but we managed to fold into top
930
// level class, then register intermediate paths so they are not reported
931
// as unexpected in debug traces
932
void OGRGMLASLayer::CreateCompoundFoldedMappings()
933
13.7k
{
934
13.7k
    CPLString oFCXPath(m_oFC.GetXPath());
935
13.7k
    if (m_oFC.IsRepeatedSequence())
936
0
    {
937
0
        size_t iPosExtra = oFCXPath.find(szEXTRA_SUFFIX);
938
0
        if (iPosExtra != std::string::npos)
939
0
        {
940
0
            oFCXPath.resize(iPosExtra);
941
0
        }
942
0
    }
943
944
13.7k
    const std::vector<GMLASField> &oFields = m_oFC.GetFields();
945
295k
    for (size_t i = 0; i < oFields.size(); i++)
946
282k
    {
947
282k
        std::vector<CPLString> aoXPaths = oFields[i].GetAlternateXPaths();
948
282k
        if (aoXPaths.empty())
949
282k
            aoXPaths.push_back(oFields[i].GetXPath());
950
564k
        for (size_t j = 0; j < aoXPaths.size(); j++)
951
282k
        {
952
282k
            if (aoXPaths[j].size() > oFCXPath.size())
953
279k
            {
954
                // Split on both '/' and '@'
955
279k
                char **papszTokens = CSLTokenizeString2(
956
279k
                    aoXPaths[j].c_str() + oFCXPath.size() + 1, "/@", 0);
957
279k
                CPLString osSubXPath = oFCXPath;
958
279k
                for (int k = 0;
959
383k
                     papszTokens[k] != nullptr && papszTokens[k + 1] != nullptr;
960
279k
                     k++)
961
103k
                {
962
103k
                    osSubXPath += "/";
963
103k
                    osSubXPath += papszTokens[k];
964
103k
                    if (m_oMapFieldXPathToOGRFieldIdx.find(osSubXPath) ==
965
103k
                        m_oMapFieldXPathToOGRFieldIdx.end())
966
4.64k
                    {
967
4.64k
                        m_oMapFieldXPathToOGRFieldIdx[osSubXPath] =
968
4.64k
                            IDX_COMPOUND_FOLDED;
969
4.64k
                    }
970
103k
                }
971
279k
                CSLDestroy(papszTokens);
972
279k
            }
973
282k
        }
974
282k
    }
975
13.7k
}
976
977
/************************************************************************/
978
/*                           ~OGRGMLASLayer()                           */
979
/************************************************************************/
980
981
OGRGMLASLayer::~OGRGMLASLayer()
982
45.4k
{
983
45.4k
    m_poFeatureDefn->Release();
984
45.4k
}
985
986
/************************************************************************/
987
/*                        DeleteTargetIndex()                           */
988
/************************************************************************/
989
990
static void DeleteTargetIndex(std::map<CPLString, int> &oMap, int nIdx)
991
0
{
992
0
    bool bIterToRemoveValid = false;
993
0
    std::map<CPLString, int>::iterator oIterToRemove;
994
0
    std::map<CPLString, int>::iterator oIter = oMap.begin();
995
0
    for (; oIter != oMap.end(); ++oIter)
996
0
    {
997
0
        if (oIter->second > nIdx)
998
0
            oIter->second--;
999
0
        else if (oIter->second == nIdx)
1000
0
        {
1001
0
            bIterToRemoveValid = true;
1002
0
            oIterToRemove = oIter;
1003
0
        }
1004
0
    }
1005
0
    if (bIterToRemoveValid)
1006
0
        oMap.erase(oIterToRemove);
1007
0
}
1008
1009
/************************************************************************/
1010
/*                            RemoveField()                             */
1011
/************************************************************************/
1012
1013
bool OGRGMLASLayer::RemoveField(int nIdx)
1014
0
{
1015
0
    if (nIdx == m_nIDFieldIdx || nIdx == m_nParentIDFieldIdx)
1016
0
        return false;
1017
1018
0
    m_poFeatureDefn->DeleteFieldDefn(nIdx);
1019
1020
    // Refresh maps
1021
0
    DeleteTargetIndex(m_oMapFieldXPathToOGRFieldIdx, nIdx);
1022
1023
0
    {
1024
0
        std::map<int, int> oMapOGRFieldIdxtoFCFieldIdx;
1025
0
        for (const auto &oIter : m_oMapOGRFieldIdxtoFCFieldIdx)
1026
0
        {
1027
0
            if (oIter.first < nIdx)
1028
0
                oMapOGRFieldIdxtoFCFieldIdx[oIter.first] = oIter.second;
1029
0
            else if (oIter.first > nIdx)
1030
0
                oMapOGRFieldIdxtoFCFieldIdx[oIter.first - 1] = oIter.second;
1031
0
        }
1032
0
        m_oMapOGRFieldIdxtoFCFieldIdx = std::move(oMapOGRFieldIdxtoFCFieldIdx);
1033
0
    }
1034
1035
0
    OGRLayer *poFieldsMetadataLayer = m_poDS->GetFieldsMetadataLayer();
1036
0
    OGRFeature *poFeature;
1037
0
    poFieldsMetadataLayer->ResetReading();
1038
0
    while ((poFeature = poFieldsMetadataLayer->GetNextFeature()) != nullptr)
1039
0
    {
1040
0
        if (strcmp(poFeature->GetFieldAsString(szLAYER_NAME), GetName()) == 0 &&
1041
0
            poFeature->GetFieldAsInteger(szFIELD_INDEX) == nIdx)
1042
0
        {
1043
0
            poFeature->SetField(szFIELD_INDEX, -1);
1044
0
            CPL_IGNORE_RET_VAL(poFieldsMetadataLayer->SetFeature(poFeature));
1045
0
            delete poFeature;
1046
0
            break;
1047
0
        }
1048
0
        delete poFeature;
1049
0
    }
1050
0
    poFieldsMetadataLayer->ResetReading();
1051
1052
0
    return true;
1053
0
}
1054
1055
/************************************************************************/
1056
/*                        InsertTargetIndex()                           */
1057
/************************************************************************/
1058
1059
static void InsertTargetIndex(std::map<CPLString, int> &oMap, int nIdx)
1060
0
{
1061
0
    for (auto &oIter : oMap)
1062
0
    {
1063
0
        if (oIter.second >= nIdx)
1064
0
            oIter.second++;
1065
0
    }
1066
0
}
1067
1068
/************************************************************************/
1069
/*                            InsertNewField()                          */
1070
/************************************************************************/
1071
1072
void OGRGMLASLayer::InsertNewField(int nInsertPos,
1073
                                   const OGRFieldDefn &oFieldDefn,
1074
                                   const CPLString &osXPath)
1075
0
{
1076
0
    CPLAssert(nInsertPos >= 0 &&
1077
0
              nInsertPos <= m_poFeatureDefn->GetFieldCount());
1078
0
    m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
1079
0
    int *panMap = new int[m_poFeatureDefn->GetFieldCount()];
1080
0
    for (int i = 0; i < nInsertPos; ++i)
1081
0
    {
1082
0
        panMap[i] = i;
1083
0
    }
1084
0
    panMap[nInsertPos] = m_poFeatureDefn->GetFieldCount() - 1;
1085
0
    for (int i = nInsertPos + 1; i < m_poFeatureDefn->GetFieldCount(); ++i)
1086
0
    {
1087
0
        panMap[i] = i - 1;
1088
0
    }
1089
0
    m_poFeatureDefn->ReorderFieldDefns(panMap);
1090
0
    delete[] panMap;
1091
1092
    // Refresh maps
1093
0
    InsertTargetIndex(m_oMapFieldXPathToOGRFieldIdx, nInsertPos);
1094
0
    m_oMapFieldXPathToOGRFieldIdx[osXPath] = nInsertPos;
1095
1096
0
    {
1097
0
        std::map<int, int> oMapOGRFieldIdxtoFCFieldIdx;
1098
0
        for (const auto &oIter : m_oMapOGRFieldIdxtoFCFieldIdx)
1099
0
        {
1100
0
            if (oIter.first < nInsertPos)
1101
0
                oMapOGRFieldIdxtoFCFieldIdx[oIter.first] = oIter.second;
1102
0
            else
1103
0
                oMapOGRFieldIdxtoFCFieldIdx[oIter.first + 1] = oIter.second;
1104
0
        }
1105
0
        m_oMapOGRFieldIdxtoFCFieldIdx = std::move(oMapOGRFieldIdxtoFCFieldIdx);
1106
0
    }
1107
1108
0
    OGRLayer *poFieldsMetadataLayer = m_poDS->GetFieldsMetadataLayer();
1109
0
    OGRFeature *poFeature;
1110
0
    poFieldsMetadataLayer->ResetReading();
1111
0
    while ((poFeature = poFieldsMetadataLayer->GetNextFeature()) != nullptr)
1112
0
    {
1113
0
        if (strcmp(poFeature->GetFieldAsString(szLAYER_NAME), GetName()) == 0)
1114
0
        {
1115
0
            int nFieldIndex = poFeature->GetFieldAsInteger(szFIELD_INDEX);
1116
0
            if (nFieldIndex >= nInsertPos && nFieldIndex < INT_MAX)
1117
0
            {
1118
0
                poFeature->SetField(szFIELD_INDEX, nFieldIndex + 1);
1119
0
                CPL_IGNORE_RET_VAL(
1120
0
                    poFieldsMetadataLayer->SetFeature(poFeature));
1121
0
            }
1122
0
        }
1123
0
        delete poFeature;
1124
0
    }
1125
0
    poFieldsMetadataLayer->ResetReading();
1126
0
}
1127
1128
/************************************************************************/
1129
/*                       GetOGRFieldIndexFromXPath()                    */
1130
/************************************************************************/
1131
1132
int OGRGMLASLayer::GetOGRFieldIndexFromXPath(const CPLString &osXPath) const
1133
780k
{
1134
780k
    const auto oIter = m_oMapFieldXPathToOGRFieldIdx.find(osXPath);
1135
780k
    if (oIter == m_oMapFieldXPathToOGRFieldIdx.end())
1136
645k
        return -1;
1137
135k
    return oIter->second;
1138
780k
}
1139
1140
/************************************************************************/
1141
/*                       GetXPathFromOGRFieldIndex()                    */
1142
/************************************************************************/
1143
1144
CPLString OGRGMLASLayer::GetXPathFromOGRFieldIndex(int nIdx) const
1145
0
{
1146
0
    const int nFCIdx = GetFCFieldIndexFromOGRFieldIdx(nIdx);
1147
0
    if (nFCIdx >= 0)
1148
0
        return m_oFC.GetFields()[nFCIdx].GetXPath();
1149
1150
0
    for (const auto &oIter : m_oMapFieldXPathToOGRFieldIdx)
1151
0
    {
1152
0
        if (oIter.second == nIdx)
1153
0
            return oIter.first;
1154
0
    }
1155
0
    return CPLString();
1156
0
}
1157
1158
/************************************************************************/
1159
/*                      GetOGRGeomFieldIndexFromXPath()                 */
1160
/************************************************************************/
1161
1162
int OGRGMLASLayer::GetOGRGeomFieldIndexFromXPath(const CPLString &osXPath) const
1163
340k
{
1164
340k
    const auto oIter = m_oMapFieldXPathToOGRGeomFieldIdx.find(osXPath);
1165
340k
    if (oIter == m_oMapFieldXPathToOGRGeomFieldIdx.end())
1166
340k
        return -1;
1167
0
    return oIter->second;
1168
340k
}
1169
1170
/************************************************************************/
1171
/*                     GetFCFieldIndexFromOGRFieldIdx()                 */
1172
/************************************************************************/
1173
1174
int OGRGMLASLayer::GetFCFieldIndexFromOGRFieldIdx(int iOGRFieldIdx) const
1175
1.04M
{
1176
1.04M
    const auto oIter = m_oMapOGRFieldIdxtoFCFieldIdx.find(iOGRFieldIdx);
1177
1.04M
    if (oIter == m_oMapOGRFieldIdxtoFCFieldIdx.end())
1178
194k
        return -1;
1179
850k
    return oIter->second;
1180
1.04M
}
1181
1182
/************************************************************************/
1183
/*                     GetFCFieldIndexFromXPath()                       */
1184
/************************************************************************/
1185
1186
int OGRGMLASLayer::GetFCFieldIndexFromXPath(const CPLString &osXPath) const
1187
104k
{
1188
104k
    const auto oIter = m_oMapFieldXPathToFCFieldIdx.find(osXPath);
1189
104k
    if (oIter == m_oMapFieldXPathToFCFieldIdx.end())
1190
103k
        return -1;
1191
1.72k
    return oIter->second;
1192
104k
}
1193
1194
/************************************************************************/
1195
/*                  GetFCFieldIndexFromOGRGeomFieldIdx()                */
1196
/************************************************************************/
1197
1198
int OGRGMLASLayer::GetFCFieldIndexFromOGRGeomFieldIdx(
1199
    int iOGRGeomFieldIdx) const
1200
0
{
1201
0
    const auto oIter = m_oMapOGRGeomFieldIdxtoFCFieldIdx.find(iOGRGeomFieldIdx);
1202
0
    if (oIter == m_oMapOGRGeomFieldIdxtoFCFieldIdx.end())
1203
0
        return -1;
1204
0
    return oIter->second;
1205
0
}
1206
1207
/************************************************************************/
1208
/*                 GetXPathOfFieldLinkForAttrToOtherLayer()             */
1209
/************************************************************************/
1210
1211
CPLString OGRGMLASLayer::GetXPathOfFieldLinkForAttrToOtherLayer(
1212
    const CPLString &osFieldName, const CPLString &osTargetLayerXPath)
1213
0
{
1214
0
    const int nOGRFieldIdx = GetLayerDefn()->GetFieldIndex(osFieldName);
1215
0
    CPLAssert(nOGRFieldIdx >= 0);
1216
0
    const int nFCFieldIdx = GetFCFieldIndexFromOGRFieldIdx(nOGRFieldIdx);
1217
0
    CPLAssert(nFCFieldIdx >= 0);
1218
0
    CPLString osXPath(m_oFC.GetFields()[nFCFieldIdx].GetXPath());
1219
0
    size_t nPos = osXPath.find(szAT_XLINK_HREF);
1220
0
    CPLAssert(nPos != std::string::npos);
1221
0
    CPLAssert(nPos + strlen(szAT_XLINK_HREF) == osXPath.size());
1222
0
    CPLString osTargetFieldXPath(osXPath.substr(0, nPos) + osTargetLayerXPath);
1223
0
    return osTargetFieldXPath;
1224
0
}
1225
1226
/************************************************************************/
1227
/*                           LaunderFieldName()                         */
1228
/************************************************************************/
1229
1230
CPLString OGRGMLASLayer::LaunderFieldName(const CPLString &osFieldName)
1231
0
{
1232
0
    int nCounter = 1;
1233
0
    CPLString osLaunderedName(osFieldName);
1234
0
    while (m_poFeatureDefn->GetFieldIndex(osLaunderedName) >= 0)
1235
0
    {
1236
0
        nCounter++;
1237
0
        osLaunderedName = osFieldName + CPLSPrintf("%d", nCounter);
1238
0
    }
1239
1240
0
    const int nIdentifierMaxLength = m_poDS->GetConf().m_nIdentifierMaxLength;
1241
0
    if (nIdentifierMaxLength >= MIN_VALUE_OF_MAX_IDENTIFIER_LENGTH &&
1242
0
        osLaunderedName.size() > static_cast<size_t>(nIdentifierMaxLength))
1243
0
    {
1244
0
        osLaunderedName =
1245
0
            OGRGMLASTruncateIdentifier(osLaunderedName, nIdentifierMaxLength);
1246
0
    }
1247
1248
0
    if (m_poDS->GetConf().m_bPGIdentifierLaundering)
1249
0
    {
1250
0
        char *pszLaundered =
1251
0
            OGRPGCommonLaunderName(osLaunderedName, "GMLAS", false);
1252
0
        osLaunderedName = pszLaundered;
1253
0
        CPLFree(pszLaundered);
1254
0
    }
1255
1256
0
    if (m_poFeatureDefn->GetFieldIndex(osLaunderedName) >= 0)
1257
0
    {
1258
0
        nCounter = 1;
1259
0
        std::string osCandidate;
1260
0
        do
1261
0
        {
1262
0
            nCounter++;
1263
0
            osCandidate = OGRGMLASAddSerialNumber(
1264
0
                osLaunderedName, nCounter, nCounter + 1, nIdentifierMaxLength);
1265
0
        } while (nCounter < 100 &&
1266
0
                 m_poFeatureDefn->GetFieldIndex(osCandidate.c_str()) >= 0);
1267
0
        osLaunderedName = std::move(osCandidate);
1268
0
    }
1269
1270
0
    return osLaunderedName;
1271
0
}
1272
1273
/************************************************************************/
1274
/*                     CreateLinkForAttrToOtherLayer()                  */
1275
/************************************************************************/
1276
1277
/* Create a new field to contain the PKID of the feature pointed by this */
1278
/* osFieldName (a xlink:href attribute), when it is an internal link to */
1279
/* another layer whose xpath is given by osTargetLayerXPath */
1280
1281
CPLString OGRGMLASLayer::CreateLinkForAttrToOtherLayer(
1282
    const CPLString &osFieldName, const CPLString &osTargetLayerXPath)
1283
0
{
1284
0
    CPLString osTargetFieldXPath =
1285
0
        GetXPathOfFieldLinkForAttrToOtherLayer(osFieldName, osTargetLayerXPath);
1286
0
    const int nExistingTgtOGRFieldIdx =
1287
0
        GetOGRFieldIndexFromXPath(osTargetFieldXPath);
1288
0
    if (nExistingTgtOGRFieldIdx >= 0)
1289
0
    {
1290
0
        return GetLayerDefn()
1291
0
            ->GetFieldDefn(nExistingTgtOGRFieldIdx)
1292
0
            ->GetNameRef();
1293
0
    }
1294
1295
0
    const int nOGRFieldIdx = GetLayerDefn()->GetFieldIndex(osFieldName);
1296
0
    CPLAssert(nOGRFieldIdx >= 0);
1297
0
    const int nFCFieldIdx = GetFCFieldIndexFromOGRFieldIdx(nOGRFieldIdx);
1298
0
    CPLAssert(nFCFieldIdx >= 0);
1299
0
    CPLString osXPath(m_oFC.GetFields()[nFCFieldIdx].GetXPath());
1300
0
    size_t nPos = osXPath.find(szAT_XLINK_HREF);
1301
0
    CPLString osXPathStart(osXPath.substr(0, nPos));
1302
1303
    // Find at which position to insert the new field in the layer definition
1304
    // (we could happen at the end, but it will be nicer to insert close to
1305
    // the href field)
1306
0
    int nInsertPos = -1;
1307
0
    for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
1308
0
    {
1309
0
        if (GetXPathFromOGRFieldIndex(i).find(osXPathStart) == 0)
1310
0
        {
1311
0
            nInsertPos = i + 1;
1312
0
        }
1313
0
        else if (nInsertPos >= 0)
1314
0
            break;
1315
0
    }
1316
1317
0
    CPLString osNewFieldName(osFieldName);
1318
0
    nPos = osFieldName.find(szHREF_SUFFIX);
1319
0
    if (nPos != std::string::npos)
1320
0
    {
1321
0
        osNewFieldName.resize(nPos);
1322
0
    }
1323
0
    osNewFieldName += "_";
1324
0
    OGRGMLASLayer *poTargetLayer = m_poDS->GetLayerByXPath(osTargetLayerXPath);
1325
0
    CPLAssert(poTargetLayer);
1326
0
    osNewFieldName += poTargetLayer->GetName();
1327
0
    osNewFieldName += "_pkid";
1328
0
    osNewFieldName = LaunderFieldName(osNewFieldName);
1329
0
    OGRFieldDefn oFieldDefn(osNewFieldName, OFTString);
1330
0
    InsertNewField(nInsertPos, oFieldDefn, osTargetFieldXPath);
1331
1332
0
    OGRLayer *poFieldsMetadataLayer = m_poDS->GetFieldsMetadataLayer();
1333
0
    OGRLayer *poRelationshipsLayer = m_poDS->GetRelationshipsLayer();
1334
1335
    // Find a relevant location of the field metadata layer into which to
1336
    // insert the new feature (same as above, we could potentially insert just
1337
    // at the end)
1338
0
    GIntBig nFieldsMetadataIdxPos = -1;
1339
0
    poFieldsMetadataLayer->ResetReading();
1340
0
    OGRFeature *poFeature;
1341
0
    while ((poFeature = poFieldsMetadataLayer->GetNextFeature()) != nullptr)
1342
0
    {
1343
0
        if (strcmp(poFeature->GetFieldAsString(szLAYER_NAME), GetName()) == 0)
1344
0
        {
1345
0
            if (poFeature->GetFieldAsInteger(szFIELD_INDEX) > nInsertPos)
1346
0
            {
1347
0
                delete poFeature;
1348
0
                break;
1349
0
            }
1350
0
            nFieldsMetadataIdxPos = poFeature->GetFID() + 1;
1351
0
        }
1352
0
        else if (nFieldsMetadataIdxPos >= 0)
1353
0
        {
1354
0
            delete poFeature;
1355
0
            break;
1356
0
        }
1357
0
        delete poFeature;
1358
0
    }
1359
0
    poFieldsMetadataLayer->ResetReading();
1360
1361
    // Move down all features beyond that insertion point
1362
0
    for (GIntBig nFID = poFieldsMetadataLayer->GetFeatureCount() - 1;
1363
0
         nFID >= nFieldsMetadataIdxPos; nFID--)
1364
0
    {
1365
0
        poFeature = poFieldsMetadataLayer->GetFeature(nFID);
1366
0
        if (poFeature)
1367
0
        {
1368
0
            poFeature->SetFID(nFID + 1);
1369
0
            CPL_IGNORE_RET_VAL(poFieldsMetadataLayer->SetFeature(poFeature));
1370
0
            delete poFeature;
1371
0
        }
1372
0
    }
1373
0
    if (nFieldsMetadataIdxPos >= 0)
1374
0
    {
1375
0
        CPL_IGNORE_RET_VAL(
1376
0
            poFieldsMetadataLayer->DeleteFeature(nFieldsMetadataIdxPos));
1377
0
    }
1378
1379
    // Register field in _ogr_fields_metadata
1380
0
    OGRFeature *poFieldDescFeature =
1381
0
        new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
1382
0
    poFieldDescFeature->SetField(szLAYER_NAME, GetName());
1383
0
    poFieldDescFeature->SetField(szFIELD_INDEX, nInsertPos);
1384
0
    poFieldDescFeature->SetField(szFIELD_XPATH, osTargetFieldXPath);
1385
0
    poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
1386
0
    poFieldDescFeature->SetField(szFIELD_TYPE, szXS_STRING);
1387
0
    poFieldDescFeature->SetField(szFIELD_IS_LIST, 0);
1388
0
    poFieldDescFeature->SetField(szFIELD_MIN_OCCURS, 0);
1389
0
    poFieldDescFeature->SetField(szFIELD_MAX_OCCURS, 1);
1390
0
    poFieldDescFeature->SetField(szFIELD_CATEGORY,
1391
0
                                 szPATH_TO_CHILD_ELEMENT_WITH_LINK);
1392
0
    poFieldDescFeature->SetField(szFIELD_RELATED_LAYER,
1393
0
                                 poTargetLayer->GetName());
1394
0
    if (nFieldsMetadataIdxPos >= 0)
1395
0
        poFieldDescFeature->SetFID(nFieldsMetadataIdxPos);
1396
0
    CPL_IGNORE_RET_VAL(
1397
0
        poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
1398
0
    delete poFieldDescFeature;
1399
1400
    // Register relationship in _ogr_layer_relationships
1401
0
    OGRFeature *poRelationshipsFeature =
1402
0
        new OGRFeature(poRelationshipsLayer->GetLayerDefn());
1403
0
    poRelationshipsFeature->SetField(szPARENT_LAYER, GetName());
1404
0
    poRelationshipsFeature->SetField(
1405
0
        szPARENT_PKID,
1406
0
        GetLayerDefn()->GetFieldDefn(GetIDFieldIdx())->GetNameRef());
1407
0
    poRelationshipsFeature->SetField(szPARENT_ELEMENT_NAME, osNewFieldName);
1408
0
    poRelationshipsFeature->SetField(szCHILD_LAYER, poTargetLayer->GetName());
1409
0
    poRelationshipsFeature->SetField(
1410
0
        szCHILD_PKID, poTargetLayer->GetLayerDefn()
1411
0
                          ->GetFieldDefn(poTargetLayer->GetIDFieldIdx())
1412
0
                          ->GetNameRef());
1413
0
    CPL_IGNORE_RET_VAL(
1414
0
        poRelationshipsLayer->CreateFeature(poRelationshipsFeature));
1415
0
    delete poRelationshipsFeature;
1416
1417
0
    return osNewFieldName;
1418
0
}
1419
1420
/************************************************************************/
1421
/*                              GetLayerDefn()                          */
1422
/************************************************************************/
1423
1424
const OGRFeatureDefn *OGRGMLASLayer::GetLayerDefn() const
1425
12.6M
{
1426
12.6M
    if (!m_bLayerDefnFinalized && m_poDS->IsLayerInitFinished())
1427
463
    {
1428
        // If we haven't yet determined the SRS of geometry columns, do it now
1429
463
        m_bLayerDefnFinalized = true;
1430
463
        if (m_poFeatureDefn->GetGeomFieldCount() > 0 ||
1431
458
            m_poDS->GetConf().m_oXLinkResolution.m_bResolveInternalXLinks ||
1432
0
            !m_poDS->GetConf().m_oXLinkResolution.m_aoURLSpecificRules.empty())
1433
463
        {
1434
463
            if (m_poReader == nullptr)
1435
463
            {
1436
463
                const_cast<OGRGMLASLayer *>(this)->InitReader();
1437
                // Avoid keeping too many file descriptor opened
1438
463
                if (m_fpGML != nullptr)
1439
463
                    m_poDS->PushUnusedGMLFilePointer(
1440
463
                        const_cast<std::shared_ptr<VSIVirtualHandle> &>(
1441
463
                            m_fpGML));
1442
463
                const_cast<OGRGMLASLayer *>(this)->m_poReader.reset();
1443
463
            }
1444
463
        }
1445
463
    }
1446
12.6M
    return m_poFeatureDefn;
1447
12.6M
}
1448
1449
/************************************************************************/
1450
/*                              ResetReading()                          */
1451
/************************************************************************/
1452
1453
void OGRGMLASLayer::ResetReading()
1454
0
{
1455
0
    m_poReader.reset();
1456
0
    m_bEOF = false;
1457
0
}
1458
1459
/************************************************************************/
1460
/*                              InitReader()                            */
1461
/************************************************************************/
1462
1463
bool OGRGMLASLayer::InitReader()
1464
5.36k
{
1465
5.36k
    CPLAssert(m_poReader == nullptr);
1466
1467
5.36k
    m_bLayerDefnFinalized = true;
1468
5.36k
    m_poReader.reset(m_poDS->CreateReader(m_fpGML));
1469
5.36k
    if (m_poReader != nullptr)
1470
5.36k
    {
1471
5.36k
        m_poReader->SetLayerOfInterest(this);
1472
5.36k
        return true;
1473
5.36k
    }
1474
0
    return false;
1475
5.36k
}
1476
1477
/************************************************************************/
1478
/*                          GetNextRawFeature()                         */
1479
/************************************************************************/
1480
1481
OGRFeature *OGRGMLASLayer::GetNextRawFeature()
1482
751k
{
1483
751k
    if (m_poReader == nullptr && !InitReader())
1484
0
        return nullptr;
1485
1486
751k
    return m_poReader->GetNextFeature();
1487
751k
}
1488
1489
/************************************************************************/
1490
/*                            EvaluateFilter()                          */
1491
/************************************************************************/
1492
1493
bool OGRGMLASLayer::EvaluateFilter(OGRFeature *poFeature)
1494
747k
{
1495
747k
    return (m_poFilterGeom == nullptr ||
1496
0
            FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
1497
747k
           (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature));
1498
747k
}
1499
1500
/************************************************************************/
1501
/*                            GetNextFeature()                          */
1502
/************************************************************************/
1503
1504
OGRFeature *OGRGMLASLayer::GetNextFeature()
1505
751k
{
1506
751k
    if (m_bEOF)
1507
0
        return nullptr;
1508
1509
751k
    while (true)
1510
751k
    {
1511
751k
        OGRFeature *poFeature = GetNextRawFeature();
1512
751k
        if (poFeature == nullptr)
1513
4.55k
        {
1514
            // Avoid keeping too many file descriptor opened
1515
4.55k
            if (m_fpGML != nullptr)
1516
4.55k
                m_poDS->PushUnusedGMLFilePointer(m_fpGML);
1517
4.55k
            m_poReader.reset();
1518
4.55k
            m_bEOF = true;
1519
4.55k
            return nullptr;
1520
4.55k
        }
1521
1522
747k
        if (EvaluateFilter(poFeature))
1523
747k
        {
1524
747k
            return poFeature;
1525
747k
        }
1526
1527
0
        delete poFeature;
1528
0
    }
1529
751k
}