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/gmlutils/gmlfeature.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * Project:  GML Reader
4
 * Purpose:  Implementation of GMLFeature.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 **********************************************************************
8
 * Copyright (c) 2002, Frank Warmerdam
9
 * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "gmlfeature.h"
16
17
#include <cstdio>
18
19
#include "cpl_conv.h"
20
#include "cpl_error.h"
21
#include "cpl_minixml.h"
22
#include "cpl_string.h"
23
24
/************************************************************************/
25
/*                             GMLFeature()                             */
26
/************************************************************************/
27
28
GMLFeature::GMLFeature(GMLFeatureClass *poClass)
29
88.8k
    : m_poClass(poClass), m_pszFID(nullptr), m_nPropertyCount(0),
30
88.8k
      m_pasProperties(nullptr), m_nGeometryCount(0),
31
88.8k
      m_papsGeometry(m_apsGeometry)  // TODO(schwehr): Allowed in init list?
32
88.8k
{
33
88.8k
    m_apsGeometry[0] = nullptr;
34
88.8k
    m_apsGeometry[1] = nullptr;
35
88.8k
}
36
37
/************************************************************************/
38
/*                            ~GMLFeature()                             */
39
/************************************************************************/
40
41
GMLFeature::~GMLFeature()
42
43
88.8k
{
44
88.8k
    CPLFree(m_pszFID);
45
46
117k
    for (int i = 0; i < m_nPropertyCount; i++)
47
28.3k
    {
48
28.3k
        const int nSubProperties = m_pasProperties[i].nSubProperties;
49
28.3k
        if (nSubProperties == 1)
50
16.5k
        {
51
16.5k
            CPLFree(m_pasProperties[i].aszSubProperties[0]);
52
16.5k
        }
53
11.7k
        else if (nSubProperties > 1)
54
8.88k
        {
55
42.9k
            for (int j = 0; j < nSubProperties; j++)
56
34.0k
                CPLFree(m_pasProperties[i].papszSubProperties[j]);
57
8.88k
            CPLFree(m_pasProperties[i].papszSubProperties);
58
8.88k
        }
59
28.3k
    }
60
61
88.8k
    if (m_nGeometryCount == 1)
62
9.69k
    {
63
9.69k
        CPLDestroyXMLNode(m_apsGeometry[0]);
64
9.69k
    }
65
79.1k
    else if (m_nGeometryCount > 1)
66
216
    {
67
1.86k
        for (int i = 0; i < m_nGeometryCount; i++)
68
1.65k
            CPLDestroyXMLNode(m_papsGeometry[i]);
69
216
        CPLFree(m_papsGeometry);
70
216
    }
71
72
88.8k
    if (m_psBoundedByGeometry)
73
0
        CPLDestroyXMLNode(m_psBoundedByGeometry);
74
75
88.8k
    CPLFree(m_pasProperties);
76
88.8k
}
77
78
/************************************************************************/
79
/*                               SetFID()                               */
80
/************************************************************************/
81
82
void GMLFeature::SetFID(const char *pszFID)
83
84
3.30k
{
85
3.30k
    CPLFree(m_pszFID);
86
3.30k
    if (pszFID != nullptr)
87
3.30k
        m_pszFID = CPLStrdup(pszFID);
88
0
    else
89
0
        m_pszFID = nullptr;
90
3.30k
}
91
92
/************************************************************************/
93
/*                        SetPropertyDirectly()                         */
94
/************************************************************************/
95
96
void GMLFeature::SetPropertyDirectly(int iIndex, char *pszValue)
97
98
50.6k
{
99
50.6k
    CPLAssert(pszValue);
100
50.6k
    if (iIndex >= m_nPropertyCount)
101
17.4k
    {
102
17.4k
        const int nClassPropertyCount = m_poClass->GetPropertyCount();
103
17.4k
        m_pasProperties = static_cast<GMLProperty *>(CPLRealloc(
104
17.4k
            m_pasProperties, sizeof(GMLProperty) * nClassPropertyCount));
105
177k
        for (int i = 0; i < m_nPropertyCount; i++)
106
159k
        {
107
            // Make sure papszSubProperties point to the right address in case
108
            // m_pasProperties has been relocated.
109
159k
            if (m_pasProperties[i].nSubProperties <= 1)
110
85.7k
                m_pasProperties[i].papszSubProperties =
111
85.7k
                    m_pasProperties[i].aszSubProperties;
112
159k
        }
113
45.8k
        for (int i = m_nPropertyCount; i < nClassPropertyCount; i++)
114
28.3k
        {
115
28.3k
            m_pasProperties[i].nSubProperties = 0;
116
28.3k
            m_pasProperties[i].papszSubProperties =
117
28.3k
                m_pasProperties[i].aszSubProperties;
118
28.3k
            m_pasProperties[i].aszSubProperties[0] = nullptr;
119
28.3k
            m_pasProperties[i].aszSubProperties[1] = nullptr;
120
28.3k
        }
121
17.4k
        m_nPropertyCount = nClassPropertyCount;
122
17.4k
    }
123
124
50.6k
    GMLProperty *psProperty = &m_pasProperties[iIndex];
125
50.6k
    const int nSubProperties = psProperty->nSubProperties;
126
50.6k
    if (nSubProperties == 0)
127
25.4k
    {
128
25.4k
        psProperty->aszSubProperties[0] = pszValue;
129
25.4k
    }
130
25.1k
    else if (nSubProperties == 1)
131
8.88k
    {
132
8.88k
        psProperty->papszSubProperties = static_cast<char **>(
133
8.88k
            CPLMalloc(sizeof(char *) * (nSubProperties + 2)));
134
8.88k
        psProperty->papszSubProperties[0] = psProperty->aszSubProperties[0];
135
8.88k
        psProperty->aszSubProperties[0] = nullptr;
136
8.88k
        psProperty->papszSubProperties[nSubProperties] = pszValue;
137
8.88k
        psProperty->papszSubProperties[nSubProperties + 1] = nullptr;
138
8.88k
    }
139
16.2k
    else
140
16.2k
    {
141
16.2k
        psProperty->papszSubProperties = static_cast<char **>(
142
16.2k
            CPLRealloc(psProperty->papszSubProperties,
143
16.2k
                       sizeof(char *) * (nSubProperties + 2)));
144
16.2k
        psProperty->papszSubProperties[nSubProperties] = pszValue;
145
16.2k
        psProperty->papszSubProperties[nSubProperties + 1] = nullptr;
146
16.2k
    }
147
50.6k
    psProperty->nSubProperties++;
148
50.6k
}
149
150
/************************************************************************/
151
/*                                Dump()                                */
152
/************************************************************************/
153
154
void GMLFeature::Dump(CPL_UNUSED FILE *fp)
155
0
{
156
0
    printf("GMLFeature(%s):\n", m_poClass->GetName()); /*ok*/
157
158
0
    if (m_pszFID != nullptr)
159
0
        printf("  FID = %s\n", m_pszFID); /*ok*/
160
161
0
    for (int i = 0; i < m_nPropertyCount; i++)
162
0
    {
163
0
        const GMLProperty *psGMLProperty = GetProperty(i);
164
0
        printf("  %s = ", m_poClass->GetProperty(i)->GetName()); /*ok*/
165
0
        if (psGMLProperty != nullptr)
166
0
        {
167
0
            for (int j = 0; j < psGMLProperty->nSubProperties; j++)
168
0
            {
169
0
                if (j > 0)
170
0
                    printf(", ");                                   /*ok*/
171
0
                printf("%s", psGMLProperty->papszSubProperties[j]); /*ok*/
172
0
            }
173
0
            printf("\n"); /*ok*/
174
0
        }
175
0
    }
176
177
0
    for (int i = 0; i < m_nGeometryCount; i++)
178
0
    {
179
0
        char *pszXML = CPLSerializeXMLTree(m_papsGeometry[i]);
180
0
        printf("  %s\n", pszXML); /*ok*/
181
0
        CPLFree(pszXML);
182
0
    }
183
0
}
184
185
/************************************************************************/
186
/*                        SetGeometryDirectly()                         */
187
/************************************************************************/
188
189
void GMLFeature::SetGeometryDirectly(CPLXMLNode *psGeom)
190
191
27.1k
{
192
27.1k
    if (m_apsGeometry[0] != nullptr)
193
17.2k
        CPLDestroyXMLNode(m_apsGeometry[0]);
194
27.1k
    m_nGeometryCount = 1;
195
27.1k
    m_apsGeometry[0] = psGeom;
196
27.1k
}
197
198
/************************************************************************/
199
/*                        SetGeometryDirectly()                         */
200
/************************************************************************/
201
202
void GMLFeature::SetGeometryDirectly(int nIdx, CPLXMLNode *psGeom)
203
204
1.88k
{
205
1.88k
    if (nIdx == 0 && m_nGeometryCount <= 1)
206
59
    {
207
59
        SetGeometryDirectly(psGeom);
208
59
        return;
209
59
    }
210
1.82k
    else if (nIdx > 0 && m_nGeometryCount <= 1)
211
216
    {
212
216
        m_papsGeometry =
213
216
            static_cast<CPLXMLNode **>(CPLMalloc(2 * sizeof(CPLXMLNode *)));
214
216
        m_papsGeometry[0] = m_apsGeometry[0];
215
216
        m_papsGeometry[1] = nullptr;
216
216
        m_apsGeometry[0] = nullptr;
217
216
    }
218
219
1.82k
    if (nIdx >= m_nGeometryCount)
220
1.24k
    {
221
1.24k
        m_papsGeometry = static_cast<CPLXMLNode **>(
222
1.24k
            CPLRealloc(m_papsGeometry, (nIdx + 2) * sizeof(CPLXMLNode *)));
223
3.92k
        for (int i = m_nGeometryCount; i <= nIdx + 1; i++)
224
2.68k
            m_papsGeometry[i] = nullptr;
225
1.24k
        m_nGeometryCount = nIdx + 1;
226
1.24k
    }
227
1.82k
    if (m_papsGeometry[nIdx] != nullptr)
228
520
        CPLDestroyXMLNode(m_papsGeometry[nIdx]);
229
1.82k
    m_papsGeometry[nIdx] = psGeom;
230
1.82k
}
231
232
/************************************************************************/
233
/*                          GetGeometryRef()                            */
234
/************************************************************************/
235
236
const CPLXMLNode *GMLFeature::GetGeometryRef(int nIdx) const
237
29.2k
{
238
29.2k
    if (nIdx < 0 || nIdx >= m_nGeometryCount)
239
11.3k
        return nullptr;
240
17.8k
    return m_papsGeometry[nIdx];
241
29.2k
}
242
243
/************************************************************************/
244
/*                             AddGeometry()                            */
245
/************************************************************************/
246
247
void GMLFeature::AddGeometry(CPLXMLNode *psGeom)
248
249
0
{
250
0
    if (m_nGeometryCount == 0)
251
0
    {
252
0
        m_apsGeometry[0] = psGeom;
253
0
    }
254
0
    else if (m_nGeometryCount == 1)
255
0
    {
256
0
        m_papsGeometry = static_cast<CPLXMLNode **>(
257
0
            CPLMalloc((m_nGeometryCount + 2) * sizeof(CPLXMLNode *)));
258
0
        m_papsGeometry[0] = m_apsGeometry[0];
259
0
        m_apsGeometry[0] = nullptr;
260
0
        m_papsGeometry[m_nGeometryCount] = psGeom;
261
0
        m_papsGeometry[m_nGeometryCount + 1] = nullptr;
262
0
    }
263
0
    else
264
0
    {
265
0
        m_papsGeometry = static_cast<CPLXMLNode **>(CPLRealloc(
266
0
            m_papsGeometry, (m_nGeometryCount + 2) * sizeof(CPLXMLNode *)));
267
0
        m_papsGeometry[m_nGeometryCount] = psGeom;
268
0
        m_papsGeometry[m_nGeometryCount + 1] = nullptr;
269
0
    }
270
0
    m_nGeometryCount++;
271
0
}
272
273
/************************************************************************/
274
/*                         SetBoundedByGeometry()                       */
275
/************************************************************************/
276
277
void GMLFeature::SetBoundedByGeometry(CPLXMLNode *psGeom)
278
279
0
{
280
0
    if (m_psBoundedByGeometry)
281
0
        CPLDestroyXMLNode(m_psBoundedByGeometry);
282
0
    m_psBoundedByGeometry = psGeom;
283
0
}