/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 | } |