Coverage Report

Created: 2025-06-09 08:44

/src/gdal/ogr/ogrsf_frmts/gmlas/ogrgmlaslayer.cpp
Line
Count
Source (jump to first uncovered line)
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
7.45k
    : m_poDS(poDS), m_oFC(oFC),
28
7.45k
      m_poFeatureDefn(new OGRFeatureDefn(oFC.GetName())),
29
7.45k
      m_poParentLayer(poParentLayer)
30
7.45k
{
31
7.45k
    m_poFeatureDefn->SetGeomType(wkbNone);
32
7.45k
    m_poFeatureDefn->Reference();
33
34
7.45k
    SetDescription(m_poFeatureDefn->GetName());
35
36
    // Are we a regular table ?
37
7.45k
    if (m_oFC.GetParentXPath().empty())
38
4.87k
    {
39
4.87k
        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
4.87k
        const std::vector<GMLASField> &oFields = m_oFC.GetFields();
54
88.0k
        for (int i = 0; i < static_cast<int>(oFields.size()); i++)
55
83.2k
        {
56
83.2k
            if (oFields[i].GetType() == GMLAS_FT_ID &&
57
83.2k
                oFields[i].IsNotNullable() &&
58
83.2k
                oFields[i].GetXPath().find('@') != std::string::npos)
59
7
            {
60
7
                OGRFieldDefn oFieldDefn(oFields[i].GetName(), OFTString);
61
7
                oFieldDefn.SetNullable(false);
62
7
                const int nOGRIdx = m_poFeatureDefn->GetFieldCount();
63
7
                if (m_nIDFieldIdx < 0)
64
7
                    m_nIDFieldIdx = nOGRIdx;
65
7
                m_oMapFieldXPathToOGRFieldIdx[oFields[i].GetXPath()] = nOGRIdx;
66
7
                m_oMapOGRFieldIdxtoFCFieldIdx[nOGRIdx] = i;
67
7
                m_oMapFieldXPathToFCFieldIdx[oFields[i].GetXPath()] = i;
68
7
                m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
69
7
                break;
70
7
            }
71
83.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
4.87k
        if (m_nIDFieldIdx < 0)
77
4.86k
        {
78
4.86k
            OGRFieldDefn oFieldDefn(szOGR_PKID, OFTString);
79
4.86k
            oFieldDefn.SetNullable(false);
80
4.86k
            m_nIDFieldIdx = m_poFeatureDefn->GetFieldCount();
81
4.86k
            m_bIDFieldIsGenerated = true;
82
4.86k
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
83
4.86k
        }
84
4.87k
    }
85
86
7.45k
    OGRLayer *poLayersMetadataLayer = m_poDS->GetLayersMetadataLayer();
87
7.45k
    OGRFeature *poLayerDescFeature =
88
7.45k
        new OGRFeature(poLayersMetadataLayer->GetLayerDefn());
89
7.45k
    poLayerDescFeature->SetField(szLAYER_NAME, OGRGMLASLayer::GetName());
90
7.45k
    if (!m_oFC.GetParentXPath().empty())
91
2.58k
    {
92
2.58k
        poLayerDescFeature->SetField(szLAYER_CATEGORY, szJUNCTION_TABLE);
93
2.58k
    }
94
4.87k
    else
95
4.87k
    {
96
4.87k
        poLayerDescFeature->SetField(szLAYER_XPATH, m_oFC.GetXPath());
97
98
4.87k
        poLayerDescFeature->SetField(szLAYER_CATEGORY, m_oFC.IsTopLevelElt()
99
4.87k
                                                           ? szTOP_LEVEL_ELEMENT
100
4.87k
                                                           : szNESTED_ELEMENT);
101
102
4.87k
        if (m_nIDFieldIdx >= 0)
103
4.87k
        {
104
4.87k
            poLayerDescFeature->SetField(
105
4.87k
                szLAYER_PKID_NAME,
106
4.87k
                m_poFeatureDefn->GetFieldDefn(m_nIDFieldIdx)->GetNameRef());
107
4.87k
        }
108
109
        // If we are a child class, then add a field to reference the parent.
110
4.87k
        if (m_poParentLayer != nullptr)
111
2.11k
        {
112
2.11k
            CPLString osFieldName(szPARENT_PREFIX);
113
2.11k
            osFieldName += m_poParentLayer->GetLayerDefn()
114
2.11k
                               ->GetFieldDefn(m_poParentLayer->GetIDFieldIdx())
115
2.11k
                               ->GetNameRef();
116
2.11k
            poLayerDescFeature->SetField(szLAYER_PARENT_PKID_NAME,
117
2.11k
                                         osFieldName.c_str());
118
2.11k
        }
119
120
4.87k
        if (!m_oFC.GetDocumentation().empty())
121
0
        {
122
0
            poLayerDescFeature->SetField(szLAYER_DOCUMENTATION,
123
0
                                         m_oFC.GetDocumentation());
124
0
        }
125
4.87k
    }
126
7.45k
    CPL_IGNORE_RET_VAL(
127
7.45k
        poLayersMetadataLayer->CreateFeature(poLayerDescFeature));
128
7.45k
    delete poLayerDescFeature;
129
7.45k
}
130
131
/************************************************************************/
132
/*                            OGRGMLASLayer()                           */
133
/************************************************************************/
134
135
OGRGMLASLayer::OGRGMLASLayer(const char *pszLayerName)
136
2.22k
    : m_bLayerDefnFinalized(true),
137
2.22k
      m_poFeatureDefn(new OGRFeatureDefn(pszLayerName))
138
139
2.22k
{
140
2.22k
    m_poFeatureDefn->SetGeomType(wkbNone);
141
2.22k
    m_poFeatureDefn->Reference();
142
143
2.22k
    SetDescription(m_poFeatureDefn->GetName());
144
2.22k
}
145
146
/************************************************************************/
147
/*                        GetSWEChildAndType()                          */
148
/************************************************************************/
149
150
static CPLXMLNode *GetSWEChildAndType(CPLXMLNode *psNode, OGRFieldType &eType,
151
                                      OGRFieldSubType &eSubType)
152
4.24k
{
153
4.24k
    eType = OFTString;
154
4.24k
    eSubType = OFSTNone;
155
4.24k
    CPLXMLNode *psChildNode = nullptr;
156
4.24k
    if ((psChildNode = CPLGetXMLNode(psNode, "Time")) != nullptr)
157
2.07k
    {
158
2.07k
        eType = OFTDateTime;
159
2.07k
    }
160
2.16k
    else if ((psChildNode = CPLGetXMLNode(psNode, "Quantity")) != nullptr)
161
1.32k
    {
162
1.32k
        eType = OFTReal;
163
1.32k
    }
164
847
    else if ((psChildNode = CPLGetXMLNode(psNode, "Category")) != nullptr)
165
426
    {
166
426
        eType = OFTString;
167
426
    }
168
421
    else if ((psChildNode = CPLGetXMLNode(psNode, "Count")) != nullptr)
169
7
    {
170
7
        eType = OFTInteger;
171
7
    }
172
414
    else if ((psChildNode = CPLGetXMLNode(psNode, "Text")) != nullptr)
173
152
    {
174
152
        eType = OFTString;
175
152
    }
176
262
    else if ((psChildNode = CPLGetXMLNode(psNode, "Boolean")) != nullptr)
177
145
    {
178
145
        eType = OFTInteger;
179
145
        eSubType = OFSTBoolean;
180
145
    }
181
4.24k
    return psChildNode;
182
4.24k
}
183
184
/************************************************************************/
185
/*              ProcessDataRecordOfDataArrayCreateFields()               */
186
/************************************************************************/
187
188
void OGRGMLASLayer::ProcessDataRecordOfDataArrayCreateFields(
189
    OGRGMLASLayer *poParentLayer, CPLXMLNode *psDataRecord,
190
    OGRLayer *poFieldsMetadataLayer)
191
2.22k
{
192
2.22k
    {
193
2.22k
        CPLString osFieldName(szPARENT_PREFIX);
194
2.22k
        osFieldName += poParentLayer->GetLayerDefn()
195
2.22k
                           ->GetFieldDefn(poParentLayer->GetIDFieldIdx())
196
2.22k
                           ->GetNameRef();
197
2.22k
        OGRFieldDefn oFieldDefn(osFieldName, OFTString);
198
2.22k
        oFieldDefn.SetNullable(false);
199
2.22k
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
200
2.22k
    }
201
202
12.9k
    for (CPLXMLNode *psIter = psDataRecord->psChild; psIter != nullptr;
203
10.7k
         psIter = psIter->psNext)
204
10.7k
    {
205
10.7k
        if (psIter->eType == CXT_Element &&
206
10.7k
            strcmp(psIter->pszValue, "field") == 0)
207
4.24k
        {
208
4.24k
            const char *pszName = CPLGetXMLValue(psIter, "name", "");
209
4.24k
            OGRFieldDefn oFieldDefn(CPLString(pszName).tolower(), OFTString);
210
4.24k
            OGRFieldType eType;
211
4.24k
            OGRFieldSubType eSubType;
212
4.24k
            CPLXMLNode *psNode = GetSWEChildAndType(psIter, eType, eSubType);
213
4.24k
            oFieldDefn.SetType(eType);
214
4.24k
            oFieldDefn.SetSubType(eSubType);
215
4.24k
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
216
217
            // Register field in _ogr_fields_metadata
218
4.24k
            OGRFeature *poFieldDescFeature =
219
4.24k
                new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
220
4.24k
            poFieldDescFeature->SetField(szLAYER_NAME, GetName());
221
4.24k
            m_nMaxFieldIndex = m_poFeatureDefn->GetFieldCount() - 1;
222
4.24k
            poFieldDescFeature->SetField(szFIELD_INDEX, m_nMaxFieldIndex);
223
4.24k
            poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
224
4.24k
            if (psNode)
225
4.12k
            {
226
4.12k
                poFieldDescFeature->SetField(szFIELD_TYPE, psNode->pszValue);
227
4.12k
            }
228
4.24k
            poFieldDescFeature->SetField(szFIELD_IS_LIST, 0);
229
4.24k
            poFieldDescFeature->SetField(szFIELD_MIN_OCCURS, 0);
230
4.24k
            poFieldDescFeature->SetField(szFIELD_MAX_OCCURS, 1);
231
4.24k
            poFieldDescFeature->SetField(szFIELD_CATEGORY, szSWE_FIELD);
232
4.24k
            if (psNode)
233
4.12k
            {
234
4.12k
                char *pszXML = CPLSerializeXMLTree(psNode);
235
4.12k
                poFieldDescFeature->SetField(szFIELD_DOCUMENTATION, pszXML);
236
4.12k
                CPLFree(pszXML);
237
4.12k
            }
238
4.24k
            CPL_IGNORE_RET_VAL(
239
4.24k
                poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
240
4.24k
            delete poFieldDescFeature;
241
4.24k
        }
242
10.7k
    }
243
2.22k
}
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
    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
7.45k
{
453
7.45k
    const std::vector<GMLASField> &oFields = m_oFC.GetFields();
454
455
7.45k
    OGRLayer *poFieldsMetadataLayer = m_poDS->GetFieldsMetadataLayer();
456
7.45k
    OGRLayer *poRelationshipsLayer = m_poDS->GetRelationshipsLayer();
457
458
    // Is it a junction table ?
459
7.45k
    if (!m_oFC.GetParentXPath().empty())
460
2.58k
    {
461
2.58k
        {
462
2.58k
            OGRFieldDefn oFieldDefn(szOCCURRENCE, OFTInteger);
463
2.58k
            oFieldDefn.SetNullable(false);
464
2.58k
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
465
466
2.58k
            OGRFeature *poFieldDescFeature =
467
2.58k
                new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
468
2.58k
            poFieldDescFeature->SetField(szLAYER_NAME, GetName());
469
2.58k
            poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
470
2.58k
            CPL_IGNORE_RET_VAL(
471
2.58k
                poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
472
2.58k
            delete poFieldDescFeature;
473
2.58k
        }
474
475
2.58k
        {
476
2.58k
            OGRFieldDefn oFieldDefn(szPARENT_PKID, OFTString);
477
2.58k
            oFieldDefn.SetNullable(false);
478
2.58k
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
479
480
2.58k
            OGRFeature *poFieldDescFeature =
481
2.58k
                new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
482
2.58k
            poFieldDescFeature->SetField(szLAYER_NAME, GetName());
483
2.58k
            poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
484
2.58k
            CPL_IGNORE_RET_VAL(
485
2.58k
                poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
486
2.58k
            delete poFieldDescFeature;
487
2.58k
        }
488
2.58k
        {
489
2.58k
            OGRFieldDefn oFieldDefn(szCHILD_PKID, OFTString);
490
2.58k
            oFieldDefn.SetNullable(false);
491
2.58k
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
492
493
2.58k
            OGRFeature *poFieldDescFeature =
494
2.58k
                new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
495
2.58k
            poFieldDescFeature->SetField(szLAYER_NAME, GetName());
496
2.58k
            poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
497
2.58k
            CPL_IGNORE_RET_VAL(
498
2.58k
                poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
499
2.58k
            delete poFieldDescFeature;
500
2.58k
        }
501
502
2.58k
        return;
503
2.58k
    }
504
505
    // If we are a child class, then add a field to reference the parent.
506
4.87k
    if (m_poParentLayer != nullptr)
507
2.11k
    {
508
2.11k
        CPLString osFieldName(szPARENT_PREFIX);
509
2.11k
        osFieldName += m_poParentLayer->GetLayerDefn()
510
2.11k
                           ->GetFieldDefn(m_poParentLayer->GetIDFieldIdx())
511
2.11k
                           ->GetNameRef();
512
2.11k
        OGRFieldDefn oFieldDefn(osFieldName, OFTString);
513
2.11k
        oFieldDefn.SetNullable(false);
514
2.11k
        m_nParentIDFieldIdx = m_poFeatureDefn->GetFieldCount();
515
2.11k
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
516
2.11k
    }
517
518
4.87k
    int nFieldIndex = 0;
519
92.7k
    for (int i = 0; i < static_cast<int>(oFields.size()); i++)
520
87.8k
    {
521
87.8k
        OGRGMLASLayer *poRelatedLayer = nullptr;
522
87.8k
        const GMLASField &oField(oFields[i]);
523
524
87.8k
        m_oMapFieldXPathToFCFieldIdx[oField.GetXPath()] = i;
525
87.8k
        if (oField.IsIgnored())
526
0
            continue;
527
528
87.8k
        const GMLASField::Category eCategory(oField.GetCategory());
529
87.8k
        if (!oField.GetRelatedClassXPath().empty())
530
19.3k
        {
531
19.3k
            poRelatedLayer =
532
19.3k
                m_poDS->GetLayerByXPath(oField.GetRelatedClassXPath());
533
19.3k
            if (poRelatedLayer != nullptr)
534
19.3k
            {
535
19.3k
                OGRFeature *poRelationshipsFeature =
536
19.3k
                    new OGRFeature(poRelationshipsLayer->GetLayerDefn());
537
19.3k
                poRelationshipsFeature->SetField(szPARENT_LAYER, GetName());
538
19.3k
                poRelationshipsFeature->SetField(
539
19.3k
                    szPARENT_PKID, GetLayerDefn()
540
19.3k
                                       ->GetFieldDefn(GetIDFieldIdx())
541
19.3k
                                       ->GetNameRef());
542
19.3k
                if (!oField.GetName().empty())
543
19.3k
                {
544
19.3k
                    poRelationshipsFeature->SetField(szPARENT_ELEMENT_NAME,
545
19.3k
                                                     oField.GetName());
546
19.3k
                }
547
19.3k
                poRelationshipsFeature->SetField(szCHILD_LAYER,
548
19.3k
                                                 poRelatedLayer->GetName());
549
19.3k
                if (eCategory ==
550
19.3k
                        GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE ||
551
19.3k
                    eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_WITH_LINK)
552
17.2k
                {
553
17.2k
                    poRelationshipsFeature->SetField(
554
17.2k
                        szCHILD_PKID,
555
17.2k
                        poRelatedLayer->GetLayerDefn()
556
17.2k
                            ->GetFieldDefn(poRelatedLayer->GetIDFieldIdx())
557
17.2k
                            ->GetNameRef());
558
17.2k
                }
559
2.11k
                else
560
2.11k
                {
561
2.11k
                    CPLAssert(eCategory ==
562
2.11k
                                  GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
563
2.11k
                              eCategory == GMLASField::GROUP);
564
565
2.11k
                    poRelationshipsFeature->SetField(
566
2.11k
                        szCHILD_PKID, (CPLString(szPARENT_PREFIX) +
567
2.11k
                                       GetLayerDefn()
568
2.11k
                                           ->GetFieldDefn(GetIDFieldIdx())
569
2.11k
                                           ->GetNameRef())
570
2.11k
                                          .c_str());
571
2.11k
                }
572
19.3k
                CPL_IGNORE_RET_VAL(poRelationshipsLayer->CreateFeature(
573
19.3k
                    poRelationshipsFeature));
574
19.3k
                delete poRelationshipsFeature;
575
19.3k
            }
576
0
            else
577
0
            {
578
0
                CPLDebug("GMLAS", "Cannot find class matching %s",
579
0
                         oField.GetRelatedClassXPath().c_str());
580
0
            }
581
19.3k
        }
582
583
87.8k
        OGRFeature *poFieldDescFeature =
584
87.8k
            new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
585
87.8k
        poFieldDescFeature->SetField(szLAYER_NAME, GetName());
586
587
87.8k
        ++nFieldIndex;
588
87.8k
        m_nMaxFieldIndex = nFieldIndex;
589
87.8k
        poFieldDescFeature->SetField(szFIELD_INDEX, nFieldIndex);
590
591
87.8k
        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
87.8k
        else
597
87.8k
        {
598
87.8k
            poFieldDescFeature->SetField(szFIELD_NAME,
599
87.8k
                                         oField.GetName().c_str());
600
87.8k
        }
601
87.8k
        if (!oField.GetXPath().empty())
602
87.8k
        {
603
87.8k
            poFieldDescFeature->SetField(szFIELD_XPATH,
604
87.8k
                                         oField.GetXPath().c_str());
605
87.8k
        }
606
0
        else if (!oField.GetAlternateXPaths().empty())
607
0
        {
608
0
            CPLString osXPath;
609
0
            const std::vector<CPLString> &aoXPaths =
610
0
                oField.GetAlternateXPaths();
611
0
            for (size_t j = 0; j < aoXPaths.size(); j++)
612
0
            {
613
0
                if (j != 0)
614
0
                    osXPath += ",";
615
0
                osXPath += aoXPaths[j];
616
0
            }
617
0
            poFieldDescFeature->SetField(szFIELD_XPATH, osXPath.c_str());
618
0
        }
619
87.8k
        if (oField.GetTypeName().empty())
620
4.70k
        {
621
4.70k
            CPLAssert(
622
4.70k
                eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
623
4.70k
                eCategory ==
624
4.70k
                    GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE ||
625
4.70k
                eCategory == GMLASField::GROUP);
626
4.70k
        }
627
83.1k
        else
628
83.1k
        {
629
83.1k
            poFieldDescFeature->SetField(szFIELD_TYPE,
630
83.1k
                                         oField.GetTypeName().c_str());
631
83.1k
        }
632
87.8k
        poFieldDescFeature->SetField(szFIELD_IS_LIST,
633
87.8k
                                     static_cast<int>(oField.IsList()));
634
87.8k
        if (oField.GetMinOccurs() != -1)
635
57.1k
        {
636
57.1k
            poFieldDescFeature->SetField(szFIELD_MIN_OCCURS,
637
57.1k
                                         oField.GetMinOccurs());
638
57.1k
        }
639
87.8k
        if (oField.GetMaxOccurs() == MAXOCCURS_UNLIMITED)
640
4.64k
        {
641
4.64k
            poFieldDescFeature->SetField(szFIELD_MAX_OCCURS, INT_MAX);
642
4.64k
        }
643
83.1k
        else if (oField.GetMaxOccurs() != -1)
644
52.3k
        {
645
52.3k
            poFieldDescFeature->SetField(szFIELD_MAX_OCCURS,
646
52.3k
                                         oField.GetMaxOccurs());
647
52.3k
        }
648
87.8k
        if (oField.GetMaxOccurs() == MAXOCCURS_UNLIMITED ||
649
87.8k
            oField.GetMaxOccurs() > 1)
650
4.70k
        {
651
4.70k
            poFieldDescFeature->SetField(szFIELD_REPETITION_ON_SEQUENCE,
652
4.70k
                                         oField.GetRepetitionOnSequence() ? 1
653
4.70k
                                                                          : 0);
654
4.70k
        }
655
87.8k
        if (!oField.GetFixedValue().empty())
656
1
        {
657
1
            poFieldDescFeature->SetField(szFIELD_FIXED_VALUE,
658
1
                                         oField.GetFixedValue());
659
1
        }
660
87.8k
        if (!oField.GetDefaultValue().empty())
661
0
        {
662
0
            poFieldDescFeature->SetField(szFIELD_DEFAULT_VALUE,
663
0
                                         oField.GetDefaultValue());
664
0
        }
665
87.8k
        switch (eCategory)
666
87.8k
        {
667
68.5k
            case GMLASField::REGULAR:
668
68.5k
                poFieldDescFeature->SetField(szFIELD_CATEGORY, szREGULAR);
669
68.5k
                break;
670
2.11k
            case GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK:
671
2.11k
                poFieldDescFeature->SetField(szFIELD_CATEGORY,
672
2.11k
                                             szPATH_TO_CHILD_ELEMENT_NO_LINK);
673
2.11k
                break;
674
14.6k
            case GMLASField::PATH_TO_CHILD_ELEMENT_WITH_LINK:
675
14.6k
                poFieldDescFeature->SetField(szFIELD_CATEGORY,
676
14.6k
                                             szPATH_TO_CHILD_ELEMENT_WITH_LINK);
677
14.6k
                break;
678
2.58k
            case GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE:
679
2.58k
                poFieldDescFeature->SetField(
680
2.58k
                    szFIELD_CATEGORY,
681
2.58k
                    szPATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE);
682
2.58k
                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
87.8k
        }
690
87.8k
        if (poRelatedLayer != nullptr)
691
19.3k
        {
692
19.3k
            poFieldDescFeature->SetField(szFIELD_RELATED_LAYER,
693
19.3k
                                         poRelatedLayer->GetName());
694
19.3k
        }
695
696
87.8k
        if (eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE)
697
2.58k
        {
698
2.58k
            const CPLString &osAbstractElementXPath(
699
2.58k
                oField.GetAbstractElementXPath());
700
2.58k
            const CPLString &osNestedXPath(oField.GetRelatedClassXPath());
701
2.58k
            CPLAssert(!osAbstractElementXPath.empty());
702
2.58k
            CPLAssert(!osNestedXPath.empty());
703
704
2.58k
            OGRGMLASLayer *poJunctionLayer = m_poDS->GetLayerByXPath(
705
2.58k
                osAbstractElementXPath + "|" + osNestedXPath);
706
2.58k
            if (poJunctionLayer != nullptr)
707
2.58k
            {
708
2.58k
                poFieldDescFeature->SetField(szFIELD_JUNCTION_LAYER,
709
2.58k
                                             poJunctionLayer->GetName());
710
2.58k
            }
711
2.58k
        }
712
713
87.8k
        if (!oField.GetDocumentation().empty())
714
0
        {
715
0
            poFieldDescFeature->SetField(szFIELD_DOCUMENTATION,
716
0
                                         oField.GetDocumentation());
717
0
        }
718
719
87.8k
        CPL_IGNORE_RET_VAL(
720
87.8k
            poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
721
87.8k
        delete poFieldDescFeature;
722
723
        // Check whether the field is OGR instanciable
724
87.8k
        if (eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
725
87.8k
            eCategory ==
726
85.7k
                GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE ||
727
87.8k
            eCategory == GMLASField::GROUP)
728
4.70k
        {
729
4.70k
            continue;
730
4.70k
        }
731
732
83.1k
        OGRFieldType eType = OFTString;
733
83.1k
        OGRFieldSubType eSubType = OFSTNone;
734
83.1k
        CPLString osOGRFieldName(oField.GetName());
735
83.1k
        switch (oField.GetType())
736
83.1k
        {
737
45.4k
            case GMLAS_FT_STRING:
738
45.4k
                eType = OFTString;
739
45.4k
                break;
740
4.32k
            case GMLAS_FT_ID:
741
4.32k
            {
742
4.32k
                eType = OFTString;
743
4.32k
                if (oField.IsNotNullable())
744
3.70k
                {
745
3.70k
                    continue;
746
3.70k
                }
747
620
                break;
748
4.32k
            }
749
620
            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
0
            case GMLAS_FT_DATE:
774
0
                eType = OFTDate;
775
0
                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
14
            case GMLAS_FT_DATETIME:
786
14
                eType = OFTDateTime;
787
14
                break;
788
0
            case GMLAS_FT_BASE64BINARY:
789
0
            case GMLAS_FT_HEXBINARY:
790
0
                eType = OFTBinary;
791
0
                break;
792
0
            case GMLAS_FT_ANYURI:
793
0
                eType = OFTString;
794
0
                break;
795
33.3k
            case GMLAS_FT_ANYTYPE:
796
33.3k
                eType = OFTString;
797
33.3k
                break;
798
0
            case GMLAS_FT_ANYSIMPLETYPE:
799
0
                eType = OFTString;
800
0
                break;
801
0
            case GMLAS_FT_GEOMETRY:
802
0
            {
803
                // Create a geometry field
804
0
                OGRGeomFieldDefn oGeomFieldDefn(osOGRFieldName,
805
0
                                                oField.GetGeomType());
806
0
                m_poFeatureDefn->AddGeomFieldDefn(&oGeomFieldDefn);
807
808
0
                const int iOGRGeomIdx =
809
0
                    m_poFeatureDefn->GetGeomFieldCount() - 1;
810
0
                if (!oField.GetXPath().empty())
811
0
                {
812
0
                    m_oMapFieldXPathToOGRGeomFieldIdx[oField.GetXPath()] =
813
0
                        iOGRGeomIdx;
814
0
                }
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
0
                m_oMapOGRGeomFieldIdxtoFCFieldIdx[iOGRGeomIdx] = i;
827
828
                // Suffix the regular non-geometry field
829
0
                osOGRFieldName += szXML_SUFFIX;
830
0
                eType = OFTString;
831
0
                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
83.1k
        }
838
839
79.4k
        if (oField.GetType() == GMLAS_FT_GEOMETRY && !bIncludeGeometryXML)
840
0
        {
841
0
            continue;
842
0
        }
843
844
79.4k
        if (oField.IsArray())
845
3
        {
846
3
            switch (eType)
847
3
            {
848
3
                case OFTString:
849
3
                    eType = OFTStringList;
850
3
                    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
3
            }
865
3
        }
866
79.4k
        OGRFieldDefn oFieldDefn(osOGRFieldName, eType);
867
79.4k
        oFieldDefn.SetSubType(eSubType);
868
79.4k
        if (oField.IsNotNullable())
869
1.93k
            oFieldDefn.SetNullable(false);
870
79.4k
        CPLString osDefaultOrFixed = oField.GetDefaultValue();
871
79.4k
        if (osDefaultOrFixed.empty())
872
79.4k
            osDefaultOrFixed = oField.GetFixedValue();
873
79.4k
        if (!osDefaultOrFixed.empty())
874
1
        {
875
1
            char *pszEscaped = CPLEscapeString(osDefaultOrFixed, -1, CPLES_SQL);
876
1
            oFieldDefn.SetDefault(
877
1
                (CPLString("'") + pszEscaped + CPLString("'")).c_str());
878
1
            CPLFree(pszEscaped);
879
1
        }
880
79.4k
        oFieldDefn.SetWidth(oField.GetWidth());
881
79.4k
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
882
883
79.4k
        const int iOGRIdx = m_poFeatureDefn->GetFieldCount() - 1;
884
79.4k
        if (!oField.GetXPath().empty())
885
79.4k
        {
886
79.4k
            m_oMapFieldXPathToOGRFieldIdx[oField.GetXPath()] = iOGRIdx;
887
79.4k
        }
888
0
        else
889
0
        {
890
0
            const std::vector<CPLString> &aoXPaths =
891
0
                oField.GetAlternateXPaths();
892
0
            for (size_t j = 0; j < aoXPaths.size(); j++)
893
0
            {
894
0
                m_oMapFieldXPathToOGRFieldIdx[aoXPaths[j]] = iOGRIdx;
895
0
            }
896
0
        }
897
898
79.4k
        m_oMapOGRFieldIdxtoFCFieldIdx[iOGRIdx] = i;
899
900
        // Create field to receive resolved xlink:href content, if needed
901
79.4k
        if (oField.GetXPath().find(szAT_XLINK_HREF) != std::string::npos &&
902
79.4k
            m_poDS->GetConf().m_oXLinkResolution.m_bDefaultResolutionEnabled &&
903
79.4k
            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
79.4k
        CPL_IGNORE_RET_VAL(osOGRFieldName);
920
79.4k
    }
921
922
4.87k
    CreateCompoundFoldedMappings();
923
4.87k
}
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
4.87k
{
934
4.87k
    CPLString oFCXPath(m_oFC.GetXPath());
935
4.87k
    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
4.87k
    const std::vector<GMLASField> &oFields = m_oFC.GetFields();
945
92.7k
    for (size_t i = 0; i < oFields.size(); i++)
946
87.8k
    {
947
87.8k
        std::vector<CPLString> aoXPaths = oFields[i].GetAlternateXPaths();
948
87.8k
        if (aoXPaths.empty())
949
87.8k
            aoXPaths.push_back(oFields[i].GetXPath());
950
175k
        for (size_t j = 0; j < aoXPaths.size(); j++)
951
87.8k
        {
952
87.8k
            if (aoXPaths[j].size() > oFCXPath.size())
953
85.9k
            {
954
                // Split on both '/' and '@'
955
85.9k
                char **papszTokens = CSLTokenizeString2(
956
85.9k
                    aoXPaths[j].c_str() + oFCXPath.size() + 1, "/@", 0);
957
85.9k
                CPLString osSubXPath = oFCXPath;
958
85.9k
                for (int k = 0;
959
238k
                     papszTokens[k] != nullptr && papszTokens[k + 1] != nullptr;
960
152k
                     k++)
961
152k
                {
962
152k
                    osSubXPath += "/";
963
152k
                    osSubXPath += papszTokens[k];
964
152k
                    if (m_oMapFieldXPathToOGRFieldIdx.find(osSubXPath) ==
965
152k
                        m_oMapFieldXPathToOGRFieldIdx.end())
966
313
                    {
967
313
                        m_oMapFieldXPathToOGRFieldIdx[osSubXPath] =
968
313
                            IDX_COMPOUND_FOLDED;
969
313
                    }
970
152k
                }
971
85.9k
                CSLDestroy(papszTokens);
972
85.9k
            }
973
87.8k
        }
974
87.8k
    }
975
4.87k
}
976
977
/************************************************************************/
978
/*                           ~OGRGMLASLayer()                           */
979
/************************************************************************/
980
981
OGRGMLASLayer::~OGRGMLASLayer()
982
9.68k
{
983
9.68k
    m_poFeatureDefn->Release();
984
9.68k
}
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
279k
{
1134
279k
    const auto oIter = m_oMapFieldXPathToOGRFieldIdx.find(osXPath);
1135
279k
    if (oIter == m_oMapFieldXPathToOGRFieldIdx.end())
1136
270k
        return -1;
1137
9.62k
    return oIter->second;
1138
279k
}
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
138k
{
1164
138k
    const auto oIter = m_oMapFieldXPathToOGRGeomFieldIdx.find(osXPath);
1165
138k
    if (oIter == m_oMapFieldXPathToOGRGeomFieldIdx.end())
1166
138k
        return -1;
1167
0
    return oIter->second;
1168
138k
}
1169
1170
/************************************************************************/
1171
/*                     GetFCFieldIndexFromOGRFieldIdx()                 */
1172
/************************************************************************/
1173
1174
int OGRGMLASLayer::GetFCFieldIndexFromOGRFieldIdx(int iOGRFieldIdx) const
1175
152k
{
1176
152k
    const auto oIter = m_oMapOGRFieldIdxtoFCFieldIdx.find(iOGRFieldIdx);
1177
152k
    if (oIter == m_oMapOGRFieldIdxtoFCFieldIdx.end())
1178
68.2k
        return -1;
1179
83.7k
    return oIter->second;
1180
152k
}
1181
1182
/************************************************************************/
1183
/*                     GetFCFieldIndexFromXPath()                       */
1184
/************************************************************************/
1185
1186
int OGRGMLASLayer::GetFCFieldIndexFromXPath(const CPLString &osXPath) const
1187
65.4k
{
1188
65.4k
    const auto oIter = m_oMapFieldXPathToFCFieldIdx.find(osXPath);
1189
65.4k
    if (oIter == m_oMapFieldXPathToFCFieldIdx.end())
1190
65.4k
        return -1;
1191
0
    return oIter->second;
1192
65.4k
}
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
OGRFeatureDefn *OGRGMLASLayer::GetLayerDefn()
1425
3.75M
{
1426
3.75M
    if (!m_bLayerDefnFinalized && m_poDS->IsLayerInitFinished())
1427
99
    {
1428
        // If we haven't yet determined the SRS of geometry columns, do it now
1429
99
        m_bLayerDefnFinalized = true;
1430
99
        if (m_poFeatureDefn->GetGeomFieldCount() > 0 ||
1431
99
            m_poDS->GetConf().m_oXLinkResolution.m_bResolveInternalXLinks ||
1432
99
            !m_poDS->GetConf().m_oXLinkResolution.m_aoURLSpecificRules.empty())
1433
0
        {
1434
0
            if (m_poReader == nullptr)
1435
0
            {
1436
0
                InitReader();
1437
                // Avoid keeping too many file descriptor opened
1438
0
                if (m_fpGML != nullptr)
1439
0
                    m_poDS->PushUnusedGMLFilePointer(m_fpGML);
1440
0
                m_poReader.reset();
1441
0
            }
1442
0
        }
1443
99
    }
1444
3.75M
    return m_poFeatureDefn;
1445
3.75M
}
1446
1447
/************************************************************************/
1448
/*                              ResetReading()                          */
1449
/************************************************************************/
1450
1451
void OGRGMLASLayer::ResetReading()
1452
0
{
1453
0
    m_poReader.reset();
1454
0
    m_bEOF = false;
1455
0
}
1456
1457
/************************************************************************/
1458
/*                              InitReader()                            */
1459
/************************************************************************/
1460
1461
bool OGRGMLASLayer::InitReader()
1462
1.04k
{
1463
1.04k
    CPLAssert(m_poReader == nullptr);
1464
1465
1.04k
    m_bLayerDefnFinalized = true;
1466
1.04k
    m_poReader.reset(m_poDS->CreateReader(m_fpGML));
1467
1.04k
    if (m_poReader != nullptr)
1468
1.04k
    {
1469
1.04k
        m_poReader->SetLayerOfInterest(this);
1470
1.04k
        return true;
1471
1.04k
    }
1472
0
    return false;
1473
1.04k
}
1474
1475
/************************************************************************/
1476
/*                          GetNextRawFeature()                         */
1477
/************************************************************************/
1478
1479
OGRFeature *OGRGMLASLayer::GetNextRawFeature()
1480
74.7k
{
1481
74.7k
    if (m_poReader == nullptr && !InitReader())
1482
0
        return nullptr;
1483
1484
74.7k
    return m_poReader->GetNextFeature();
1485
74.7k
}
1486
1487
/************************************************************************/
1488
/*                            EvaluateFilter()                          */
1489
/************************************************************************/
1490
1491
bool OGRGMLASLayer::EvaluateFilter(OGRFeature *poFeature)
1492
73.7k
{
1493
73.7k
    return (m_poFilterGeom == nullptr ||
1494
73.7k
            FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
1495
73.7k
           (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature));
1496
73.7k
}
1497
1498
/************************************************************************/
1499
/*                            GetNextFeature()                          */
1500
/************************************************************************/
1501
1502
OGRFeature *OGRGMLASLayer::GetNextFeature()
1503
74.7k
{
1504
74.7k
    if (m_bEOF)
1505
0
        return nullptr;
1506
1507
74.7k
    while (true)
1508
74.7k
    {
1509
74.7k
        OGRFeature *poFeature = GetNextRawFeature();
1510
74.7k
        if (poFeature == nullptr)
1511
1.00k
        {
1512
            // Avoid keeping too many file descriptor opened
1513
1.00k
            if (m_fpGML != nullptr)
1514
1.00k
                m_poDS->PushUnusedGMLFilePointer(m_fpGML);
1515
1.00k
            m_poReader.reset();
1516
1.00k
            m_bEOF = true;
1517
1.00k
            return nullptr;
1518
1.00k
        }
1519
1520
73.7k
        if (EvaluateFilter(poFeature))
1521
73.7k
        {
1522
73.7k
            return poFeature;
1523
73.7k
        }
1524
1525
0
        delete poFeature;
1526
0
    }
1527
74.7k
}