Line data Source code
1 : /**********************************************************************
2 : *
3 : * Project: GML Reader
4 : * Purpose: Implementation of GMLPropertyDefn
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : **********************************************************************
8 : * Copyright (c) 2002, Frank Warmerdam
9 : * Copyright (c) 2008-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 <cstring>
18 :
19 : #include "cpl_conv.h"
20 : #include "cpl_string.h"
21 :
22 : /************************************************************************/
23 : /* GMLPropertyDefn */
24 : /************************************************************************/
25 :
26 3079 : GMLPropertyDefn::GMLPropertyDefn(const char *pszName, const char *pszSrcElement)
27 3079 : : m_pszName(CPLStrdup(pszName)),
28 3079 : m_pszSrcElement(pszSrcElement ? CPLStrdup(pszSrcElement) : nullptr),
29 6158 : m_nSrcElementLen(pszSrcElement ? strlen(pszSrcElement) : 0)
30 : {
31 3079 : }
32 :
33 : /************************************************************************/
34 : /* ~GMLPropertyDefn() */
35 : /************************************************************************/
36 :
37 3079 : GMLPropertyDefn::~GMLPropertyDefn()
38 :
39 : {
40 3079 : CPLFree(m_pszName);
41 3079 : CPLFree(m_pszSrcElement);
42 3079 : CPLFree(m_pszCondition);
43 3079 : }
44 :
45 : /************************************************************************/
46 : /* SetSrcElement() */
47 : /************************************************************************/
48 :
49 200 : void GMLPropertyDefn::SetSrcElement(const char *pszSrcElement)
50 :
51 : {
52 200 : CPLFree(m_pszSrcElement);
53 200 : if (pszSrcElement != nullptr)
54 : {
55 200 : m_nSrcElementLen = strlen(pszSrcElement);
56 200 : m_pszSrcElement = CPLStrdup(pszSrcElement);
57 : }
58 : else
59 : {
60 0 : m_nSrcElementLen = 0;
61 0 : m_pszSrcElement = nullptr;
62 : }
63 200 : }
64 :
65 : /************************************************************************/
66 : /* SetCondition() */
67 : /************************************************************************/
68 :
69 4 : void GMLPropertyDefn::SetCondition(const char *pszCondition)
70 : {
71 4 : CPLFree(m_pszCondition);
72 4 : m_pszCondition =
73 4 : pszCondition != nullptr ? CPLStrdup(pszCondition) : nullptr;
74 4 : }
75 :
76 : /************************************************************************/
77 : /* AnalysePropertyValue() */
78 : /* */
79 : /* Examine the passed property value, and see if we need to */
80 : /* make the field type more specific, or more general. */
81 : /************************************************************************/
82 :
83 5131 : void GMLPropertyDefn::AnalysePropertyValue(const GMLProperty *psGMLProperty,
84 : bool bSetWidth)
85 :
86 : {
87 : /* -------------------------------------------------------------------- */
88 : /* Does the string consist entirely of numeric values? */
89 : /* -------------------------------------------------------------------- */
90 5131 : bool bIsReal = false;
91 :
92 10432 : for (int j = 0; j < psGMLProperty->nSubProperties; j++)
93 : {
94 5301 : if (j > 0)
95 : {
96 170 : if (m_eType == GMLPT_Integer)
97 : {
98 3 : m_eType = GMLPT_IntegerList;
99 : }
100 167 : else if (m_eType == GMLPT_Integer64)
101 : {
102 0 : m_eType = GMLPT_Integer64List;
103 : }
104 167 : else if (m_eType == GMLPT_Real)
105 : {
106 2 : m_eType = GMLPT_RealList;
107 : }
108 165 : else if (m_eType == GMLPT_String)
109 : {
110 36 : m_eType = GMLPT_StringList;
111 36 : m_nWidth = 0;
112 : }
113 129 : else if (m_eType == GMLPT_Boolean)
114 1 : m_eType = GMLPT_BooleanList;
115 : }
116 5301 : const char *pszValue = psGMLProperty->papszSubProperties[j];
117 : /* --------------------------------------------------------------------
118 : */
119 : /* If it is a zero length string, just return. We can't deduce */
120 : /* much from this. */
121 : /* --------------------------------------------------------------------
122 : */
123 5301 : if (*pszValue == '\0')
124 12 : continue;
125 :
126 5289 : const CPLValueType valueType = CPLGetValueType(pszValue);
127 :
128 5289 : if (valueType == CPL_VALUE_STRING && m_eType != GMLPT_String &&
129 801 : m_eType != GMLPT_StringList)
130 : {
131 423 : if ((m_eType == GMLPT_Untyped || m_eType == GMLPT_Boolean) &&
132 354 : (strcmp(pszValue, "true") == 0 ||
133 344 : strcmp(pszValue, "false") == 0))
134 : {
135 18 : m_eType = GMLPT_Boolean;
136 : }
137 405 : else if (m_eType == GMLPT_BooleanList)
138 : {
139 4 : if (!(strcmp(pszValue, "true") == 0 ||
140 2 : strcmp(pszValue, "false") == 0))
141 0 : m_eType = GMLPT_StringList;
142 : }
143 401 : else if (m_eType == GMLPT_IntegerList ||
144 401 : m_eType == GMLPT_Integer64List ||
145 401 : m_eType == GMLPT_RealList)
146 : {
147 0 : m_eType = GMLPT_StringList;
148 : }
149 : else
150 : {
151 1856 : const auto IsDigitLowerOrEqual = [](char c, int max)
152 1856 : { return c >= '0' && c <= '0' + max; };
153 :
154 65 : if ((m_eType == GMLPT_Untyped || m_eType == GMLPT_DateTime ||
155 439 : m_eType == GMLPT_Date) &&
156 573 : IsDigitLowerOrEqual(pszValue[0], 9) &&
157 326 : IsDigitLowerOrEqual(pszValue[1], 9) &&
158 279 : IsDigitLowerOrEqual(pszValue[2], 9) &&
159 357 : IsDigitLowerOrEqual(pszValue[3], 9) && pszValue[4] == '-' &&
160 202 : IsDigitLowerOrEqual(pszValue[5], 1) &&
161 303 : IsDigitLowerOrEqual(pszValue[6], 9) && pszValue[7] == '-' &&
162 903 : IsDigitLowerOrEqual(pszValue[8], 3) &&
163 101 : IsDigitLowerOrEqual(pszValue[9], 9))
164 : {
165 37 : if (pszValue[10] == 'T' &&
166 74 : IsDigitLowerOrEqual(pszValue[11], 2) &&
167 37 : IsDigitLowerOrEqual(pszValue[12], 9) &&
168 74 : pszValue[13] == ':' &&
169 74 : IsDigitLowerOrEqual(pszValue[14], 5) &&
170 37 : IsDigitLowerOrEqual(pszValue[15], 9) &&
171 74 : pszValue[16] == ':' &&
172 74 : IsDigitLowerOrEqual(pszValue[17], 6) &&
173 175 : IsDigitLowerOrEqual(pszValue[18], 9) &&
174 37 : (pszValue[19] == '\0' || pszValue[19] == '.' ||
175 25 : pszValue[19] == 'Z' || pszValue[19] == '+' ||
176 0 : pszValue[19] == '-'))
177 : {
178 37 : m_eType = GMLPT_DateTime;
179 : }
180 64 : else if (pszValue[10] == '\0')
181 : {
182 63 : if (m_eType != GMLPT_DateTime)
183 63 : m_eType = GMLPT_Date;
184 : }
185 : else
186 : {
187 1 : m_eType = GMLPT_String;
188 : }
189 : }
190 303 : else if ((m_eType == GMLPT_Untyped || m_eType == GMLPT_Time) &&
191 362 : IsDigitLowerOrEqual(pszValue[0], 2) &&
192 63 : IsDigitLowerOrEqual(pszValue[1], 9) &&
193 41 : pszValue[2] == ':' &&
194 8 : IsDigitLowerOrEqual(pszValue[3], 5) &&
195 4 : IsDigitLowerOrEqual(pszValue[4], 9) &&
196 8 : pszValue[5] == ':' &&
197 8 : IsDigitLowerOrEqual(pszValue[6], 6) &&
198 604 : IsDigitLowerOrEqual(pszValue[7], 9) &&
199 4 : (pszValue[8] == '\0' || pszValue[8] == '.'))
200 : {
201 4 : m_eType = GMLPT_Time;
202 : }
203 : else
204 : {
205 296 : m_eType = GMLPT_String;
206 : }
207 423 : }
208 : }
209 : else
210 : {
211 4866 : bIsReal = valueType == CPL_VALUE_REAL;
212 : }
213 :
214 5289 : if (m_eType == GMLPT_String)
215 : {
216 3238 : if (bSetWidth)
217 : {
218 : // Grow the Width to the length of the string passed in.
219 3214 : const int nWidth = static_cast<int>(strlen(pszValue));
220 3214 : if (m_nWidth < nWidth)
221 352 : SetWidth(nWidth);
222 : }
223 : }
224 2051 : else if (m_eType == GMLPT_Untyped || m_eType == GMLPT_Integer ||
225 678 : m_eType == GMLPT_Integer64)
226 : {
227 1375 : if (bIsReal)
228 33 : m_eType = GMLPT_Real;
229 1342 : else if (m_eType != GMLPT_Integer64)
230 : {
231 1340 : const GIntBig nVal = CPLAtoGIntBig(pszValue);
232 1340 : if (!CPL_INT64_FITS_ON_INT32(nVal))
233 1 : m_eType = GMLPT_Integer64;
234 : else
235 1339 : m_eType = GMLPT_Integer;
236 1375 : }
237 : }
238 676 : else if ((m_eType == GMLPT_IntegerList ||
239 676 : m_eType == GMLPT_Integer64List) &&
240 : bIsReal)
241 : {
242 0 : m_eType = GMLPT_RealList;
243 : }
244 676 : else if (m_eType == GMLPT_IntegerList && valueType == CPL_VALUE_INTEGER)
245 : {
246 12 : GIntBig nVal = CPLAtoGIntBig(pszValue);
247 12 : if (!CPL_INT64_FITS_ON_INT32(nVal))
248 1 : m_eType = GMLPT_Integer64List;
249 : }
250 : }
251 5131 : }
252 :
253 : /************************************************************************/
254 : /* GMLGeometryPropertyDefn */
255 : /************************************************************************/
256 :
257 931 : GMLGeometryPropertyDefn::GMLGeometryPropertyDefn(
258 : const char *pszName, const char *pszSrcElement, OGRwkbGeometryType nType,
259 : int nAttributeIndex, bool bNullable,
260 931 : const OGRGeomCoordinatePrecision &oCoordPrec)
261 922 : : m_pszName((pszName == nullptr || pszName[0] == '\0')
262 993 : ? CPLStrdup(pszSrcElement)
263 860 : : CPLStrdup(pszName)),
264 1862 : m_pszSrcElement(CPLStrdup(pszSrcElement)), m_nGeometryType(nType),
265 : m_nAttributeIndex(nAttributeIndex), m_bNullable(bNullable),
266 931 : m_oCoordPrecision(oCoordPrec)
267 : {
268 931 : }
269 :
270 : /************************************************************************/
271 : /* ~GMLGeometryPropertyDefn */
272 : /************************************************************************/
273 :
274 931 : GMLGeometryPropertyDefn::~GMLGeometryPropertyDefn()
275 : {
276 931 : CPLFree(m_pszName);
277 931 : CPLFree(m_pszSrcElement);
278 931 : }
279 :
280 : /************************************************************************/
281 : /* MergeSRSName() */
282 : /************************************************************************/
283 :
284 9 : void GMLGeometryPropertyDefn::MergeSRSName(const std::string &osSRSName)
285 :
286 : {
287 9 : if (!m_bSRSNameConsistent)
288 0 : return;
289 :
290 9 : if (m_osSRSName.empty())
291 : {
292 7 : m_osSRSName = osSRSName;
293 : }
294 : else
295 : {
296 2 : m_bSRSNameConsistent = osSRSName == m_osSRSName;
297 2 : if (!m_bSRSNameConsistent)
298 : {
299 1 : m_osSRSName.clear();
300 : }
301 : }
302 : }
|