Coverage Report

Created: 2025-07-23 09:13

/src/gdal/ogr/ogrsf_frmts/gml/gfstemplate.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  GML Reader
4
 * Purpose:  Implementation of GML GFS template management
5
 * Author:   Alessandro Furieri, a.furitier@lqt.it
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2011, Alessandro Furieri
9
 *
10
 * SPDX-License-Identifier: MIT
11
 *
12
 ******************************************************************************
13
 * Contributor: Alessandro Furieri, a.furieri@lqt.it
14
 * Developed for Faunalia ( http://www.faunalia.it) with funding from
15
 * Regione Toscana - Settore SISTEMA INFORMATIVO TERRITORIALE ED AMBIENTALE
16
 *
17
 ****************************************************************************/
18
19
#include "cpl_port.h"
20
#include "gmlreaderp.h"
21
#include "ogr_gml.h"
22
23
#include <cstddef>
24
25
#include "cpl_conv.h"
26
#include "cpl_minixml.h"
27
#include "gmlreader.h"
28
#include "ogr_core.h"
29
30
/************************************************************************/
31
/*                        GFSTemplateItem                               */
32
/************************************************************************/
33
34
class GFSTemplateItem
35
{
36
  private:
37
    char *m_pszName = nullptr;
38
    int n_nItemCount = 0;
39
    int n_nGeomCount = 0;
40
    GFSTemplateItem *pNext = nullptr;
41
42
    CPL_DISALLOW_COPY_ASSIGN(GFSTemplateItem)
43
44
  public:
45
    explicit GFSTemplateItem(const char *pszName);
46
    ~GFSTemplateItem();
47
48
    const char *GetName()
49
0
    {
50
0
        return m_pszName;
51
0
    }
52
53
    void Update(int b_has_geom);
54
55
    int GetCount()
56
0
    {
57
0
        return n_nItemCount;
58
0
    }
59
60
    int GetGeomCount()
61
0
    {
62
0
        return n_nGeomCount;
63
0
    }
64
65
    void SetNext(GFSTemplateItem *pN)
66
0
    {
67
0
        pNext = pN;
68
0
    }
69
70
    GFSTemplateItem *GetNext()
71
0
    {
72
0
        return pNext;
73
0
    }
74
};
75
76
/***************************************************/
77
/*               gmlUpdateFeatureClasses()         */
78
/***************************************************/
79
80
void gmlUpdateFeatureClasses(GFSTemplateList *pCC, GMLReader *pReader,
81
                             int *pbSequentialLayers)
82
0
{
83
    // Updating the FeatureClass list.
84
0
    for (int clIdx = 0; clIdx < pReader->GetClassCount(); clIdx++)
85
0
    {
86
0
        GMLFeatureClass *poClass = pReader->GetClass(clIdx);
87
0
        if (poClass != nullptr)
88
0
            poClass->SetFeatureCount(0);
89
0
    }
90
0
    bool bValid = false;
91
0
    GFSTemplateItem *pItem = pCC->GetFirst();
92
0
    while (pItem != nullptr)
93
0
    {
94
        // Updating Classes.
95
0
        GMLFeatureClass *poClass = pReader->GetClass(pItem->GetName());
96
0
        if (poClass != nullptr)
97
0
        {
98
0
            poClass->SetFeatureCount(pItem->GetCount());
99
0
            if (pItem->GetGeomCount() != 0 &&
100
0
                poClass->GetGeometryPropertyCount() == 0)
101
0
                poClass->AddGeometryProperty(
102
0
                    new GMLGeometryPropertyDefn("", "", wkbUnknown, -1, true));
103
0
            bValid = true;
104
0
        }
105
0
        pItem = pItem->GetNext();
106
0
    }
107
0
    if (bValid && pCC->HaveSequentialLayers())
108
0
        *pbSequentialLayers = TRUE;
109
0
}
110
111
/***************************************************/
112
/*       GMLReader::ReArrangeTemplateClasses()     */
113
/***************************************************/
114
115
bool GMLReader::ReArrangeTemplateClasses(GFSTemplateList *pCC)
116
0
{
117
    // Rearranging the final FeatureClass list [SEQUENTIAL].
118
    // TODO(schwehr): Why the m_ for m_nSavedClassCount?  Not a member.
119
0
    const int m_nSavedClassCount = GetClassCount();
120
121
    // Saving the previous FeatureClass list.
122
0
    GMLFeatureClass **m_papoSavedClass = static_cast<GMLFeatureClass **>(
123
0
        CPLMalloc(sizeof(void *) * m_nSavedClassCount));
124
125
0
    for (int clIdx = 0; clIdx < GetClassCount(); clIdx++)
126
0
    {
127
        // Transferring any previous FeatureClass.
128
0
        m_papoSavedClass[clIdx] = m_papoClass[clIdx];
129
0
    }
130
131
    // Cleaning the previous FeatureClass list.
132
0
    SetClassListLocked(false);
133
0
    CPLFree(m_papoClass);
134
0
    m_nClassCount = 0;
135
0
    m_papoClass = nullptr;
136
137
0
    GFSTemplateItem *pItem = pCC->GetFirst();
138
0
    while (pItem != nullptr)
139
0
    {
140
        // Re-inserting any required FeatureClassup
141
        // accordingly to actual SEQUENTIAL layout.
142
0
        GMLFeatureClass *poClass = nullptr;
143
0
        for (int iClass = 0; iClass < m_nSavedClassCount; iClass++)
144
0
        {
145
0
            GMLFeatureClass *poItem = m_papoSavedClass[iClass];
146
0
            if (EQUAL(poItem->GetName(), pItem->GetName()))
147
0
            {
148
0
                poClass = poItem;
149
0
                break;
150
0
            }
151
0
        }
152
0
        if (poClass != nullptr)
153
0
        {
154
0
            if (poClass->GetFeatureCount() > 0)
155
0
                AddClass(poClass);
156
0
        }
157
0
        pItem = pItem->GetNext();
158
0
    }
159
0
    SetClassListLocked(true);
160
161
    // Destroying the saved List and any unused FeatureClass.
162
0
    for (int iClass = 0; iClass < m_nSavedClassCount; iClass++)
163
0
    {
164
0
        bool bUnused = true;
165
0
        GMLFeatureClass *poClass = m_papoSavedClass[iClass];
166
0
        for (int iClass2 = 0; iClass2 < m_nClassCount; iClass2++)
167
0
        {
168
0
            if (m_papoClass[iClass2] == poClass)
169
0
            {
170
0
                bUnused = false;
171
0
                break;
172
0
            }
173
0
        }
174
0
        if (bUnused)
175
0
            delete poClass;
176
0
    }
177
0
    CPLFree(m_papoSavedClass);
178
0
    return true;
179
0
}
180
181
/***************************************************/
182
/*       GMLReader::PrescanForTemplate()           */
183
/***************************************************/
184
185
bool GMLReader::PrescanForTemplate()
186
0
{
187
    // Below logic is not ready for FeatureProperty/FeaturePropertyList
188
0
    if (ShouldLookForClassAtAnyLevel())
189
0
        return true;
190
191
0
    GMLFeature *poFeature = nullptr;
192
0
    GFSTemplateList *pCC = new GFSTemplateList();
193
194
    // Processing GML features.
195
0
    while ((poFeature = NextFeature()) != nullptr)
196
0
    {
197
0
        GMLFeatureClass *poClass = poFeature->GetClass();
198
0
        const CPLXMLNode *const *papsGeomList = poFeature->GetGeometryList();
199
0
        bool b_has_geom = false;
200
201
0
        if (papsGeomList != nullptr)
202
0
        {
203
0
            int i = 0;
204
0
            const CPLXMLNode *psNode = papsGeomList[i];
205
0
            while (psNode != nullptr)
206
0
            {
207
0
                b_has_geom = true;
208
0
                i++;
209
0
                psNode = papsGeomList[i];
210
0
            }
211
0
        }
212
0
        pCC->Update(poClass->GetElementName(), b_has_geom);
213
214
0
        delete poFeature;
215
0
    }
216
217
0
    gmlUpdateFeatureClasses(pCC, this, &m_nHasSequentialLayers);
218
0
    if (m_nHasSequentialLayers == TRUE)
219
0
        ReArrangeTemplateClasses(pCC);
220
0
    const int iCount = pCC->GetClassCount();
221
0
    delete pCC;
222
0
    CleanupParser();
223
0
    return iCount > 0;
224
0
}
225
226
/***************************************************/
227
/*                 GFSTemplateList()               */
228
/***************************************************/
229
230
GFSTemplateList::GFSTemplateList()
231
0
    : m_bSequentialLayers(true), pFirst(nullptr), pLast(nullptr)
232
0
{
233
0
}
234
235
/***************************************************/
236
/*                 GFSTemplateList()               */
237
/***************************************************/
238
239
GFSTemplateList::~GFSTemplateList()
240
0
{
241
0
    GFSTemplateItem *pItem = pFirst;
242
0
    while (pItem != nullptr)
243
0
    {
244
0
        GFSTemplateItem *pNext = pItem->GetNext();
245
0
        delete pItem;
246
0
        pItem = pNext;
247
0
    }
248
0
}
249
250
/***************************************************/
251
/*             GFSTemplateList::Insert()           */
252
/***************************************************/
253
254
GFSTemplateItem *GFSTemplateList::Insert(const char *pszName)
255
0
{
256
0
    GFSTemplateItem *pItem = new GFSTemplateItem(pszName);
257
258
    // Inserting into the linked list.
259
0
    if (pFirst == nullptr)
260
0
        pFirst = pItem;
261
0
    if (pLast != nullptr)
262
0
        pLast->SetNext(pItem);
263
0
    pLast = pItem;
264
0
    return pItem;
265
0
}
266
267
/***************************************************/
268
/*             GFSTemplateList::Update()           */
269
/***************************************************/
270
271
void GFSTemplateList::Update(const char *pszName, int bHasGeom)
272
0
{
273
0
    GFSTemplateItem *pItem = nullptr;
274
275
0
    if (pFirst == nullptr)
276
0
    {
277
        // Empty List: first item.
278
0
        pItem = Insert(pszName);
279
0
        pItem->Update(bHasGeom);
280
0
        return;
281
0
    }
282
0
    if (EQUAL(pszName, pLast->GetName()))
283
0
    {
284
        // Continuing with the current Class Item.
285
0
        pLast->Update(bHasGeom);
286
0
        return;
287
0
    }
288
289
0
    pItem = pFirst;
290
0
    while (pItem != nullptr)
291
0
    {
292
0
        if (EQUAL(pszName, pItem->GetName()))
293
0
        {
294
            // Class Item previously declared: NOT SEQUENTIAL.
295
0
            m_bSequentialLayers = false;
296
0
            pItem->Update(bHasGeom);
297
0
            return;
298
0
        }
299
0
        pItem = pItem->GetNext();
300
0
    }
301
302
    // Inserting a new Class Item.
303
0
    pItem = Insert(pszName);
304
0
    pItem->Update(bHasGeom);
305
0
}
306
307
/***************************************************/
308
/*          GFSTemplateList::GetClassCount()       */
309
/***************************************************/
310
311
int GFSTemplateList::GetClassCount()
312
0
{
313
0
    int iCount = 0;
314
0
    GFSTemplateItem *pItem = pFirst;
315
0
    while (pItem != nullptr)
316
0
    {
317
0
        iCount++;
318
0
        pItem = pItem->GetNext();
319
0
    }
320
321
0
    return iCount;
322
0
}
323
324
/***************************************************/
325
/*                 GFSTemplateItem()               */
326
/***************************************************/
327
328
GFSTemplateItem::GFSTemplateItem(const char *pszName)
329
0
    : m_pszName(CPLStrdup(pszName))
330
0
{
331
0
}
332
333
/***************************************************/
334
/*                ~GFSTemplateItem()               */
335
/***************************************************/
336
337
GFSTemplateItem::~GFSTemplateItem()
338
0
{
339
0
    CPLFree(m_pszName);
340
0
}
341
342
/***************************************************/
343
/*             GFSTemplateItem::Update()           */
344
/***************************************************/
345
346
void GFSTemplateItem::Update(int bHasGeom)
347
0
{
348
0
    n_nItemCount++;
349
0
    if (bHasGeom == TRUE)
350
0
        n_nGeomCount++;
351
0
}