/src/gdal/ogr/ogrsf_frmts/jml/ogrjmllayer.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: JML Translator |
4 | | * Purpose: Implements OGRJMLLayer class. |
5 | | * |
6 | | ****************************************************************************** |
7 | | * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com> |
8 | | * |
9 | | * SPDX-License-Identifier: MIT |
10 | | ****************************************************************************/ |
11 | | |
12 | | #include "cpl_conv.h" |
13 | | #include "ogr_jml.h" |
14 | | #include "ogr_p.h" |
15 | | |
16 | | #ifdef HAVE_EXPAT |
17 | | |
18 | | constexpr int PARSER_BUF_SIZE = 8192; |
19 | | |
20 | | /************************************************************************/ |
21 | | /* OGRJMLLayer() */ |
22 | | /************************************************************************/ |
23 | | |
24 | | OGRJMLLayer::OGRJMLLayer(const char *pszLayerName, OGRJMLDataset *poDSIn, |
25 | | VSILFILE *fpIn) |
26 | 1.16k | : m_poDS(poDSIn), poFeatureDefn(new OGRFeatureDefn(pszLayerName)), |
27 | 1.16k | nNextFID(0), fp(fpIn), bHasReadSchema(false), currentDepth(0), |
28 | 1.16k | bStopParsing(false), nWithoutEventCounter(0), nDataHandlerCounter(0), |
29 | 1.16k | bAccumulateElementValue(false), |
30 | 1.16k | pszElementValue(static_cast<char *>(CPLCalloc(1024, 1))), |
31 | 1.16k | nElementValueLen(0), nElementValueAlloc(1024), poFeature(nullptr), |
32 | 1.16k | ppoFeatureTab(nullptr), nFeatureTabLength(0), nFeatureTabIndex(0), |
33 | 1.16k | bSchemaFinished(false), nJCSGMLInputTemplateDepth(0), |
34 | 1.16k | nCollectionElementDepth(0), nFeatureCollectionDepth(0), |
35 | 1.16k | nFeatureElementDepth(0), nGeometryElementDepth(0), nColumnDepth(0), |
36 | 1.16k | nNameDepth(0), nTypeDepth(0), nAttributeElementDepth(0), iAttr(-1), |
37 | 1.16k | iRGBField(-1) |
38 | 1.16k | { |
39 | 1.16k | SetDescription(poFeatureDefn->GetName()); |
40 | 1.16k | poFeatureDefn->Reference(); |
41 | 1.16k | } |
42 | | |
43 | | /************************************************************************/ |
44 | | /* ~OGRJMLLayer() */ |
45 | | /************************************************************************/ |
46 | | |
47 | | OGRJMLLayer::~OGRJMLLayer() |
48 | | |
49 | 1.16k | { |
50 | 1.16k | poFeatureDefn->Release(); |
51 | | |
52 | 1.16k | CPLFree(pszElementValue); |
53 | | |
54 | 1.16k | for (int i = nFeatureTabIndex; i < nFeatureTabLength; i++) |
55 | 0 | delete ppoFeatureTab[i]; |
56 | 1.16k | CPLFree(ppoFeatureTab); |
57 | | |
58 | 1.16k | if (poFeature) |
59 | 2 | delete poFeature; |
60 | 1.16k | } |
61 | | |
62 | | /************************************************************************/ |
63 | | /* GetLayerDefn() */ |
64 | | /************************************************************************/ |
65 | | |
66 | | const OGRFeatureDefn *OGRJMLLayer::GetLayerDefn() const |
67 | 2.13k | { |
68 | 2.13k | if (!bHasReadSchema) |
69 | 747 | const_cast<OGRJMLLayer *>(this)->LoadSchema(); |
70 | | |
71 | 2.13k | return poFeatureDefn; |
72 | 2.13k | } |
73 | | |
74 | | static void XMLCALL startElementCbk(void *pUserData, const char *pszName, |
75 | | const char **ppszAttr) |
76 | 5.02k | { |
77 | 5.02k | static_cast<OGRJMLLayer *>(pUserData)->startElementCbk(pszName, ppszAttr); |
78 | 5.02k | } |
79 | | |
80 | | static void XMLCALL endElementCbk(void *pUserData, const char *pszName) |
81 | 4.81k | { |
82 | 4.81k | static_cast<OGRJMLLayer *>(pUserData)->endElementCbk(pszName); |
83 | 4.81k | } |
84 | | |
85 | | static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen) |
86 | 85.2k | { |
87 | 85.2k | static_cast<OGRJMLLayer *>(pUserData)->dataHandlerCbk(data, nLen); |
88 | 85.2k | } |
89 | | |
90 | | /************************************************************************/ |
91 | | /* ResetReading() */ |
92 | | /************************************************************************/ |
93 | | |
94 | | void OGRJMLLayer::ResetReading() |
95 | | |
96 | 748 | { |
97 | 748 | nNextFID = 0; |
98 | | |
99 | 748 | VSIFSeekL(fp, 0, SEEK_SET); |
100 | 748 | VSIFClearErrL(fp); |
101 | | |
102 | 748 | poParser.reset(OGRCreateExpatXMLParser()); |
103 | 748 | XML_SetElementHandler(poParser.get(), ::startElementCbk, ::endElementCbk); |
104 | 748 | XML_SetCharacterDataHandler(poParser.get(), ::dataHandlerCbk); |
105 | 748 | XML_SetUserData(poParser.get(), this); |
106 | | |
107 | 748 | for (int i = nFeatureTabIndex; i < nFeatureTabLength; i++) |
108 | 0 | delete ppoFeatureTab[i]; |
109 | 748 | nFeatureTabIndex = 0; |
110 | 748 | nFeatureTabLength = 0; |
111 | 748 | delete poFeature; |
112 | 748 | poFeature = nullptr; |
113 | | |
114 | 748 | currentDepth = 0; |
115 | | |
116 | 748 | nCollectionElementDepth = 0; |
117 | 748 | nFeatureElementDepth = 0; |
118 | 748 | nGeometryElementDepth = 0; |
119 | 748 | nAttributeElementDepth = 0; |
120 | 748 | iAttr = -1; |
121 | | |
122 | 748 | bAccumulateElementValue = false; |
123 | 748 | nElementValueLen = 0; |
124 | 748 | pszElementValue[0] = '\0'; |
125 | 748 | } |
126 | | |
127 | | /************************************************************************/ |
128 | | /* startElementCbk() */ |
129 | | /************************************************************************/ |
130 | | |
131 | | void OGRJMLLayer::startElementCbk(const char *pszName, const char **ppszAttr) |
132 | 5.02k | { |
133 | 5.02k | if (bStopParsing) |
134 | 0 | return; |
135 | | |
136 | 5.02k | nWithoutEventCounter = 0; |
137 | | |
138 | 5.02k | if (nFeatureElementDepth > 0 && nAttributeElementDepth == 0 && |
139 | 580 | nGeometryElementDepth == 0 && osGeometryElement.compare(pszName) == 0) |
140 | 65 | { |
141 | 65 | nGeometryElementDepth = currentDepth; |
142 | 65 | bAccumulateElementValue = true; |
143 | 65 | } |
144 | 4.96k | else if (nFeatureElementDepth > 0 && nAttributeElementDepth == 0 && |
145 | 515 | nGeometryElementDepth == 0) |
146 | 390 | { |
147 | | /* We assume that attributes are present in the order they are */ |
148 | | /* declared, so as a first guess, we can try the aoColumns[iAttr + 1] */ |
149 | 390 | int i = (iAttr + 1 < poFeatureDefn->GetFieldCount()) ? -1 : 0; |
150 | 2.73k | for (; i < static_cast<int>(aoColumns.size()); i++) |
151 | 2.53k | { |
152 | 2.53k | const OGRJMLColumn &oColumn = |
153 | 2.53k | (i < 0) ? aoColumns[iAttr + 1] : aoColumns[i]; |
154 | 2.53k | if (oColumn.osElementName != pszName) |
155 | 1.74k | continue; |
156 | | |
157 | 785 | if (oColumn.bIsBody) |
158 | 771 | { |
159 | 771 | if (!oColumn.osAttributeName.empty() && ppszAttr != nullptr && |
160 | 744 | ppszAttr[0] != nullptr && ppszAttr[1] != nullptr && |
161 | 739 | oColumn.osAttributeName.compare(ppszAttr[0]) == 0 && |
162 | 712 | oColumn.osAttributeValue.compare(ppszAttr[1]) == 0) |
163 | 150 | { |
164 | | /* <osElementName |
165 | | * osAttributeName="osAttributeValue">value</osElementName> |
166 | | */ |
167 | | |
168 | 150 | bAccumulateElementValue = true; |
169 | 150 | nAttributeElementDepth = currentDepth; |
170 | 150 | iAttr = (i < 0) ? iAttr + 1 : i; |
171 | 150 | break; |
172 | 150 | } |
173 | 621 | else if (oColumn.osAttributeName.empty()) |
174 | 27 | { |
175 | | /* <osElementName>value</osElementName> */ |
176 | | |
177 | 27 | bAccumulateElementValue = true; |
178 | 27 | nAttributeElementDepth = currentDepth; |
179 | 27 | iAttr = (i < 0) ? iAttr + 1 : i; |
180 | 27 | break; |
181 | 27 | } |
182 | 771 | } |
183 | 14 | else if (!oColumn.osAttributeName.empty() && ppszAttr != nullptr && |
184 | 14 | ppszAttr[0] != nullptr && ppszAttr[1] != nullptr && |
185 | 9 | oColumn.osAttributeName.compare(ppszAttr[0]) == 0) |
186 | 8 | { |
187 | | /* <osElementName osAttributeName="value"></osElementName> */ |
188 | | |
189 | 8 | AddStringToElementValue(ppszAttr[1], (int)strlen(ppszAttr[1])); |
190 | | |
191 | 8 | nAttributeElementDepth = currentDepth; |
192 | 8 | iAttr = (i < 0) ? iAttr + 1 : i; |
193 | 8 | break; |
194 | 8 | } |
195 | 785 | } |
196 | 390 | } |
197 | 4.57k | else if (nGeometryElementDepth > 0) |
198 | 125 | { |
199 | 125 | AddStringToElementValue("<", 1); |
200 | 125 | AddStringToElementValue(pszName, (int)strlen(pszName)); |
201 | | |
202 | 125 | const char **papszIter = ppszAttr; |
203 | 146 | while (papszIter && *papszIter != nullptr) |
204 | 21 | { |
205 | 21 | AddStringToElementValue(" ", 1); |
206 | 21 | AddStringToElementValue(papszIter[0], (int)strlen(papszIter[0])); |
207 | 21 | AddStringToElementValue("=\"", 2); |
208 | 21 | AddStringToElementValue(papszIter[1], (int)strlen(papszIter[1])); |
209 | 21 | AddStringToElementValue("\"", 1); |
210 | 21 | papszIter += 2; |
211 | 21 | } |
212 | | |
213 | 125 | AddStringToElementValue(">", 1); |
214 | 125 | } |
215 | 4.44k | else if (nFeatureCollectionDepth > 0 && nFeatureElementDepth == 0 && |
216 | 526 | osFeatureElement.compare(pszName) == 0) |
217 | 62 | { |
218 | 62 | nFeatureElementDepth = currentDepth; |
219 | 62 | poFeature = new OGRFeature(poFeatureDefn); |
220 | 62 | } |
221 | 4.38k | else if (nFeatureCollectionDepth == 0 && |
222 | 3.90k | osCollectionElement.compare(pszName) == 0) |
223 | 31 | { |
224 | 31 | nFeatureCollectionDepth = currentDepth; |
225 | 31 | } |
226 | | |
227 | 5.02k | currentDepth++; |
228 | 5.02k | } |
229 | | |
230 | | /************************************************************************/ |
231 | | /* StopAccumulate() */ |
232 | | /************************************************************************/ |
233 | | |
234 | | void OGRJMLLayer::StopAccumulate() |
235 | 4.37k | { |
236 | 4.37k | bAccumulateElementValue = false; |
237 | 4.37k | nElementValueLen = 0; |
238 | 4.37k | pszElementValue[0] = '\0'; |
239 | 4.37k | } |
240 | | |
241 | | /************************************************************************/ |
242 | | /* endElementCbk() */ |
243 | | /************************************************************************/ |
244 | | |
245 | | void OGRJMLLayer::endElementCbk(const char *pszName) |
246 | 4.81k | { |
247 | 4.81k | if (bStopParsing) |
248 | 0 | return; |
249 | | |
250 | 4.81k | nWithoutEventCounter = 0; |
251 | | |
252 | 4.81k | currentDepth--; |
253 | | |
254 | 4.81k | if (nAttributeElementDepth == currentDepth) |
255 | 204 | { |
256 | 204 | if (nElementValueLen) |
257 | 165 | poFeature->SetField(iAttr, pszElementValue); |
258 | 39 | else if (iAttr >= 0) |
259 | 20 | poFeature->SetFieldNull(iAttr); |
260 | 204 | nAttributeElementDepth = 0; |
261 | 204 | StopAccumulate(); |
262 | 204 | } |
263 | 4.61k | else if (nGeometryElementDepth > 0 && currentDepth > nGeometryElementDepth) |
264 | 123 | { |
265 | 123 | AddStringToElementValue("</", 2); |
266 | 123 | AddStringToElementValue(pszName, static_cast<int>(strlen(pszName))); |
267 | 123 | AddStringToElementValue(">", 1); |
268 | 123 | } |
269 | 4.49k | else if (nGeometryElementDepth == currentDepth) |
270 | 64 | { |
271 | 64 | if (nElementValueLen) |
272 | 40 | { |
273 | 40 | OGRGeometry *poGeom = |
274 | 40 | OGRGeometry::FromHandle(OGR_G_CreateFromGML(pszElementValue)); |
275 | 40 | if (poGeom != nullptr && |
276 | 33 | poGeom->getGeometryType() == wkbGeometryCollection && |
277 | 0 | poGeom->IsEmpty()) |
278 | 0 | { |
279 | 0 | delete poGeom; |
280 | 0 | } |
281 | 40 | else |
282 | 40 | poFeature->SetGeometryDirectly(poGeom); |
283 | 40 | } |
284 | | |
285 | 64 | nGeometryElementDepth = 0; |
286 | 64 | StopAccumulate(); |
287 | 64 | } |
288 | 4.42k | else if (nFeatureElementDepth == currentDepth) |
289 | 60 | { |
290 | | /* Builds a style string from R_G_B if we don't already have a */ |
291 | | /* style string */ |
292 | 60 | OGRGeometry *poGeom = poFeature->GetGeometryRef(); |
293 | 60 | unsigned int R = 0; |
294 | 60 | unsigned int G = 0; |
295 | 60 | unsigned int B = 0; |
296 | 60 | if (iRGBField >= 0 && poFeature->IsFieldSetAndNotNull(iRGBField) && |
297 | 22 | poFeature->GetStyleString() == nullptr && poGeom != nullptr && |
298 | 18 | sscanf(poFeature->GetFieldAsString(iRGBField), "%02X%02X%02X", &R, |
299 | 18 | &G, &B) == 3) |
300 | 18 | { |
301 | 18 | const OGRwkbGeometryType eGeomType = |
302 | 18 | wkbFlatten(poGeom->getGeometryType()); |
303 | 18 | if (eGeomType == wkbPoint || eGeomType == wkbMultiPoint || |
304 | 7 | eGeomType == wkbLineString || eGeomType == wkbMultiLineString) |
305 | 11 | { |
306 | 11 | poFeature->SetStyleString( |
307 | 11 | CPLSPrintf("PEN(c:#%02X%02X%02X)", R, G, B)); |
308 | 11 | } |
309 | 7 | else if (eGeomType == wkbPolygon || eGeomType == wkbMultiPolygon) |
310 | 7 | { |
311 | 7 | poFeature->SetStyleString( |
312 | 7 | CPLSPrintf("BRUSH(fc:#%02X%02X%02X)", R, G, B)); |
313 | 7 | } |
314 | 18 | } |
315 | | |
316 | 60 | poFeature->SetFID(nNextFID++); |
317 | | |
318 | 60 | if ((m_poFilterGeom == nullptr || FilterGeometry(poGeom)) && |
319 | 60 | (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature))) |
320 | 60 | { |
321 | 60 | ppoFeatureTab = static_cast<OGRFeature **>(CPLRealloc( |
322 | 60 | ppoFeatureTab, sizeof(OGRFeature *) * (nFeatureTabLength + 1))); |
323 | 60 | ppoFeatureTab[nFeatureTabLength] = poFeature; |
324 | 60 | nFeatureTabLength++; |
325 | 60 | } |
326 | 0 | else |
327 | 0 | { |
328 | 0 | delete poFeature; |
329 | 0 | } |
330 | 60 | poFeature = nullptr; |
331 | 60 | iAttr = -1; |
332 | | |
333 | 60 | nFeatureElementDepth = 0; |
334 | 60 | } |
335 | 4.36k | else if (nFeatureCollectionDepth == currentDepth) |
336 | 22 | { |
337 | 22 | nFeatureCollectionDepth = 0; |
338 | 22 | } |
339 | 4.81k | } |
340 | | |
341 | | /************************************************************************/ |
342 | | /* AddStringToElementValue() */ |
343 | | /************************************************************************/ |
344 | | |
345 | | void OGRJMLLayer::AddStringToElementValue(const char *data, int nLen) |
346 | 6.16k | { |
347 | 6.16k | if (nLen > INT_MAX - nElementValueLen - 1 - 1000) |
348 | 0 | { |
349 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, |
350 | 0 | "Too much data in a single element"); |
351 | 0 | XML_StopParser(poParser.get(), XML_FALSE); |
352 | 0 | bStopParsing = true; |
353 | 0 | return; |
354 | 0 | } |
355 | 6.16k | if (nElementValueLen + nLen + 1 > nElementValueAlloc) |
356 | 0 | { |
357 | 0 | char *pszNewElementValue = static_cast<char *>(VSI_REALLOC_VERBOSE( |
358 | 0 | pszElementValue, nElementValueLen + nLen + 1 + 1000)); |
359 | 0 | if (pszNewElementValue == nullptr) |
360 | 0 | { |
361 | 0 | XML_StopParser(poParser.get(), XML_FALSE); |
362 | 0 | bStopParsing = true; |
363 | 0 | return; |
364 | 0 | } |
365 | 0 | nElementValueAlloc = nElementValueLen + nLen + 1 + 1000; |
366 | 0 | pszElementValue = pszNewElementValue; |
367 | 0 | } |
368 | 6.16k | memcpy(pszElementValue + nElementValueLen, data, nLen); |
369 | 6.16k | nElementValueLen += nLen; |
370 | 6.16k | pszElementValue[nElementValueLen] = '\0'; |
371 | 6.16k | } |
372 | | |
373 | | /************************************************************************/ |
374 | | /* dataHandlerCbk() */ |
375 | | /************************************************************************/ |
376 | | |
377 | | void OGRJMLLayer::dataHandlerCbk(const char *data, int nLen) |
378 | 85.2k | { |
379 | 85.2k | if (bStopParsing) |
380 | 0 | return; |
381 | | |
382 | 85.2k | nDataHandlerCounter++; |
383 | 85.2k | if (nDataHandlerCounter >= PARSER_BUF_SIZE) |
384 | 0 | { |
385 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
386 | 0 | "File probably corrupted (million laugh pattern)"); |
387 | 0 | XML_StopParser(poParser.get(), XML_FALSE); |
388 | 0 | bStopParsing = true; |
389 | 0 | return; |
390 | 0 | } |
391 | | |
392 | 85.2k | nWithoutEventCounter = 0; |
393 | | |
394 | 85.2k | if (bAccumulateElementValue) |
395 | 5.30k | { |
396 | 5.30k | AddStringToElementValue(data, nLen); |
397 | 5.30k | } |
398 | 85.2k | } |
399 | | |
400 | | /************************************************************************/ |
401 | | /* GetNextFeature() */ |
402 | | /************************************************************************/ |
403 | | |
404 | | OGRFeature *OGRJMLLayer::GetNextFeature() |
405 | 755 | { |
406 | 755 | if (!bHasReadSchema) |
407 | 0 | LoadSchema(); |
408 | | |
409 | 755 | if (bStopParsing) |
410 | 665 | return nullptr; |
411 | | |
412 | 90 | if (nFeatureTabIndex < nFeatureTabLength) |
413 | 38 | { |
414 | 38 | return ppoFeatureTab[nFeatureTabIndex++]; |
415 | 38 | } |
416 | | |
417 | 52 | if (VSIFEofL(fp) || VSIFErrorL(fp)) |
418 | 19 | return nullptr; |
419 | | |
420 | 33 | std::vector<char> aBuf(PARSER_BUF_SIZE); |
421 | | |
422 | 33 | this->nFeatureTabLength = 0; |
423 | 33 | nFeatureTabIndex = 0; |
424 | | |
425 | 33 | nWithoutEventCounter = 0; |
426 | | |
427 | 33 | int nDone = 0; |
428 | 33 | do |
429 | 46 | { |
430 | 46 | nDataHandlerCounter = 0; |
431 | 46 | unsigned int nLen = |
432 | 46 | (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fp); |
433 | 46 | nDone = (nLen < aBuf.size()); |
434 | 46 | if (XML_Parse(poParser.get(), aBuf.data(), nLen, nDone) == |
435 | 46 | XML_STATUS_ERROR) |
436 | 13 | { |
437 | 13 | CPLError(CE_Failure, CPLE_AppDefined, |
438 | 13 | "XML parsing of JML file failed : %s " |
439 | 13 | "at line %d, column %d", |
440 | 13 | XML_ErrorString(XML_GetErrorCode(poParser.get())), |
441 | 13 | (int)XML_GetCurrentLineNumber(poParser.get()), |
442 | 13 | (int)XML_GetCurrentColumnNumber(poParser.get())); |
443 | 13 | bStopParsing = true; |
444 | 13 | } |
445 | 46 | nWithoutEventCounter++; |
446 | 46 | } while (!nDone && !bStopParsing && this->nFeatureTabLength == 0 && |
447 | 13 | nWithoutEventCounter < 10); |
448 | | |
449 | 33 | if (nWithoutEventCounter == 10) |
450 | 0 | { |
451 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
452 | 0 | "Too much data inside one element. File probably corrupted"); |
453 | 0 | bStopParsing = true; |
454 | 0 | } |
455 | | |
456 | 33 | return (this->nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] |
457 | 33 | : nullptr; |
458 | 52 | } |
459 | | |
460 | | static void XMLCALL startElementLoadSchemaCbk(void *pUserData, |
461 | | const char *pszName, |
462 | | const char **ppszAttr) |
463 | 87.5k | { |
464 | 87.5k | static_cast<OGRJMLLayer *>(pUserData)->startElementLoadSchemaCbk(pszName, |
465 | 87.5k | ppszAttr); |
466 | 87.5k | } |
467 | | |
468 | | static void XMLCALL endElementLoadSchemaCbk(void *pUserData, |
469 | | const char *pszName) |
470 | 66.2k | { |
471 | 66.2k | static_cast<OGRJMLLayer *>(pUserData)->endElementLoadSchemaCbk(pszName); |
472 | 66.2k | } |
473 | | |
474 | | /************************************************************************/ |
475 | | /* LoadSchema() */ |
476 | | /************************************************************************/ |
477 | | |
478 | | /** This function parses the beginning of the file to detect the fields */ |
479 | | void OGRJMLLayer::LoadSchema() |
480 | 747 | { |
481 | 747 | if (bHasReadSchema) |
482 | 0 | return; |
483 | | |
484 | 747 | bHasReadSchema = true; |
485 | | |
486 | 747 | poParser.reset(OGRCreateExpatXMLParser()); |
487 | 747 | XML_SetElementHandler(poParser.get(), ::startElementLoadSchemaCbk, |
488 | 747 | ::endElementLoadSchemaCbk); |
489 | 747 | XML_SetCharacterDataHandler(poParser.get(), ::dataHandlerCbk); |
490 | 747 | XML_SetUserData(poParser.get(), this); |
491 | | |
492 | 747 | VSIFSeekL(fp, 0, SEEK_SET); |
493 | | |
494 | 747 | std::vector<char> aBuf(PARSER_BUF_SIZE); |
495 | 747 | int nDone = 0; |
496 | 747 | do |
497 | 1.15k | { |
498 | 1.15k | nDataHandlerCounter = 0; |
499 | 1.15k | const unsigned int nLen = static_cast<unsigned int>( |
500 | 1.15k | VSIFReadL(aBuf.data(), 1, aBuf.size(), fp)); |
501 | 1.15k | nDone = (nLen < aBuf.size()); |
502 | 1.15k | if (XML_Parse(poParser.get(), aBuf.data(), nLen, nDone) == |
503 | 1.15k | XML_STATUS_ERROR) |
504 | 712 | { |
505 | 712 | CPLError( |
506 | 712 | CE_Failure, CPLE_AppDefined, |
507 | 712 | "XML parsing of JML file failed : %s at line %d, " |
508 | 712 | "column %d", |
509 | 712 | XML_ErrorString(XML_GetErrorCode(poParser.get())), |
510 | 712 | static_cast<int>(XML_GetCurrentLineNumber(poParser.get())), |
511 | 712 | static_cast<int>(XML_GetCurrentColumnNumber(poParser.get()))); |
512 | 712 | bStopParsing = true; |
513 | 712 | } |
514 | 1.15k | nWithoutEventCounter++; |
515 | 1.15k | } while (!nDone && !bStopParsing && !bSchemaFinished && |
516 | 410 | nWithoutEventCounter < 10); |
517 | | |
518 | 747 | poParser.reset(); |
519 | | |
520 | 747 | if (nWithoutEventCounter == 10) |
521 | 3 | { |
522 | 3 | CPLError(CE_Failure, CPLE_AppDefined, |
523 | 3 | "Too much data inside one element. File probably corrupted"); |
524 | 3 | bStopParsing = true; |
525 | 3 | } |
526 | | |
527 | 747 | if (osCollectionElement.empty() || osFeatureElement.empty() || |
528 | 127 | osGeometryElement.empty()) |
529 | 636 | { |
530 | 636 | CPLError(CE_Failure, CPLE_AppDefined, |
531 | 636 | "Missing CollectionElement, FeatureElement or " |
532 | 636 | "GeometryElement"); |
533 | 636 | bStopParsing = true; |
534 | 636 | } |
535 | | |
536 | 747 | if (!osSRSName.empty()) |
537 | 2 | { |
538 | 2 | if (osSRSName.find("http://www.opengis.net/gml/srs/epsg.xml#") == 0) |
539 | 1 | { |
540 | 1 | OGRSpatialReference *poSRS = new OGRSpatialReference(); |
541 | 1 | poSRS->importFromEPSG(atoi( |
542 | 1 | osSRSName |
543 | 1 | .substr(strlen("http://www.opengis.net/gml/srs/epsg.xml#")) |
544 | 1 | .c_str())); |
545 | 1 | poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
546 | 1 | poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS); |
547 | 1 | poSRS->Release(); |
548 | 1 | } |
549 | 2 | } |
550 | | |
551 | 747 | nJCSGMLInputTemplateDepth = 0; |
552 | 747 | nCollectionElementDepth = 0; |
553 | 747 | nFeatureCollectionDepth = 0; |
554 | 747 | nFeatureElementDepth = 0; |
555 | 747 | nGeometryElementDepth = 0; |
556 | 747 | nColumnDepth = 0; |
557 | 747 | nNameDepth = 0; |
558 | 747 | nTypeDepth = 0; |
559 | 747 | nAttributeElementDepth = 0; |
560 | | |
561 | 747 | ResetReading(); |
562 | 747 | } |
563 | | |
564 | | /************************************************************************/ |
565 | | /* startElementLoadSchemaCbk() */ |
566 | | /************************************************************************/ |
567 | | |
568 | | void OGRJMLLayer::startElementLoadSchemaCbk(const char *pszName, |
569 | | const char **ppszAttr) |
570 | 87.5k | { |
571 | 87.5k | if (bStopParsing) |
572 | 0 | return; |
573 | | |
574 | 87.5k | nWithoutEventCounter = 0; |
575 | | |
576 | 87.5k | if (nJCSGMLInputTemplateDepth == 0 && |
577 | 77.4k | strcmp(pszName, "JCSGMLInputTemplate") == 0) |
578 | 169 | nJCSGMLInputTemplateDepth = currentDepth; |
579 | 87.4k | else if (nJCSGMLInputTemplateDepth > 0) |
580 | 10.1k | { |
581 | 10.1k | if (nCollectionElementDepth == 0 && |
582 | 10.0k | strcmp(pszName, "CollectionElement") == 0) |
583 | 304 | { |
584 | 304 | nCollectionElementDepth = currentDepth; |
585 | 304 | bAccumulateElementValue = true; |
586 | 304 | } |
587 | 9.85k | else if (nFeatureElementDepth == 0 && |
588 | 9.77k | strcmp(pszName, "FeatureElement") == 0) |
589 | 300 | { |
590 | 300 | nFeatureElementDepth = currentDepth; |
591 | 300 | bAccumulateElementValue = true; |
592 | 300 | } |
593 | 9.55k | else if (nGeometryElementDepth == 0 && |
594 | 9.11k | strcmp(pszName, "GeometryElement") == 0) |
595 | 257 | { |
596 | 257 | nGeometryElementDepth = currentDepth; |
597 | 257 | bAccumulateElementValue = true; |
598 | 257 | } |
599 | 9.30k | else if (nColumnDepth == 0 && strcmp(pszName, "column") == 0) |
600 | 1.00k | { |
601 | 1.00k | nColumnDepth = currentDepth; |
602 | 1.00k | oCurColumn.osName = ""; |
603 | 1.00k | oCurColumn.osType = ""; |
604 | 1.00k | oCurColumn.osElementName = ""; |
605 | 1.00k | oCurColumn.osAttributeName = ""; |
606 | 1.00k | oCurColumn.osAttributeValue = ""; |
607 | 1.00k | oCurColumn.bIsBody = false; |
608 | 1.00k | } |
609 | 8.29k | else if (nColumnDepth > 0) |
610 | 8.04k | { |
611 | 8.04k | if (nNameDepth == 0 && strcmp(pszName, "name") == 0) |
612 | 1.66k | { |
613 | 1.66k | nNameDepth = currentDepth; |
614 | 1.66k | bAccumulateElementValue = true; |
615 | 1.66k | } |
616 | 6.38k | else if (nTypeDepth == 0 && strcmp(pszName, "type") == 0) |
617 | 1.68k | { |
618 | 1.68k | nTypeDepth = currentDepth; |
619 | 1.68k | bAccumulateElementValue = true; |
620 | 1.68k | } |
621 | 4.69k | else if (strcmp(pszName, "valueElement") == 0) |
622 | 1.52k | { |
623 | 1.52k | const char **papszIter = ppszAttr; |
624 | 5.45k | while (papszIter && *papszIter != nullptr) |
625 | 3.92k | { |
626 | 3.92k | if (strcmp(*papszIter, "elementName") == 0) |
627 | 1.51k | oCurColumn.osElementName = papszIter[1]; |
628 | 2.41k | else if (strcmp(*papszIter, "attributeName") == 0) |
629 | 1.17k | oCurColumn.osAttributeName = papszIter[1]; |
630 | 1.23k | else if (strcmp(*papszIter, "attributeValue") == 0) |
631 | 1.17k | oCurColumn.osAttributeValue = papszIter[1]; |
632 | 3.92k | papszIter += 2; |
633 | 3.92k | } |
634 | 1.52k | } |
635 | 3.16k | else if (strcmp(pszName, "valueLocation") == 0) |
636 | 1.43k | { |
637 | 1.43k | const char **papszIter = ppszAttr; |
638 | 2.99k | while (papszIter && *papszIter != nullptr) |
639 | 1.55k | { |
640 | 1.55k | if (strcmp(*papszIter, "position") == 0) |
641 | 1.09k | oCurColumn.bIsBody = strcmp(papszIter[1], "body") == 0; |
642 | 465 | else if (strcmp(*papszIter, "attributeName") == 0) |
643 | 128 | oCurColumn.osAttributeName = papszIter[1]; |
644 | 1.55k | papszIter += 2; |
645 | 1.55k | } |
646 | 1.43k | } |
647 | 8.04k | } |
648 | 10.1k | } |
649 | 77.2k | else if (nFeatureCollectionDepth == 0 && |
650 | 76.3k | osCollectionElement.compare(pszName) == 0) |
651 | 31 | { |
652 | 31 | nFeatureCollectionDepth = currentDepth; |
653 | 31 | } |
654 | 77.2k | else if (nFeatureCollectionDepth > 0 && |
655 | 875 | currentDepth == nFeatureCollectionDepth + 2 && |
656 | 147 | strcmp(pszName, "gml:Box") == 0) |
657 | 3 | { |
658 | 3 | const char **papszIter = ppszAttr; |
659 | 6 | while (papszIter && *papszIter != nullptr) |
660 | 3 | { |
661 | 3 | if (strcmp(*papszIter, "srsName") == 0) |
662 | 3 | osSRSName = papszIter[1]; |
663 | 3 | papszIter += 2; |
664 | 3 | } |
665 | 3 | bSchemaFinished = true; |
666 | 3 | } |
667 | 77.2k | else if (nFeatureCollectionDepth >= 0 && |
668 | 77.2k | currentDepth >= nFeatureCollectionDepth + 1 && |
669 | 76.9k | osFeatureElement.compare(pszName) == 0) |
670 | 126 | { |
671 | 126 | bSchemaFinished = true; |
672 | 126 | } |
673 | | |
674 | 87.5k | currentDepth++; |
675 | 87.5k | } |
676 | | |
677 | | /************************************************************************/ |
678 | | /* endElementLoadSchemaCbk() */ |
679 | | /************************************************************************/ |
680 | | |
681 | | void OGRJMLLayer::endElementLoadSchemaCbk(const char * /* pszName */) |
682 | 66.2k | { |
683 | 66.2k | if (bStopParsing) |
684 | 0 | return; |
685 | | |
686 | 66.2k | nWithoutEventCounter = 0; |
687 | | |
688 | 66.2k | currentDepth--; |
689 | | |
690 | 66.2k | if (nJCSGMLInputTemplateDepth == currentDepth) |
691 | 77 | { |
692 | 77 | nJCSGMLInputTemplateDepth = 0; |
693 | 77 | } |
694 | 66.1k | else if (nCollectionElementDepth == currentDepth) |
695 | 291 | { |
696 | 291 | nCollectionElementDepth = 0; |
697 | 291 | osCollectionElement = pszElementValue; |
698 | | #ifdef DEBUG_VERBOSE |
699 | | CPLDebug("JML", "osCollectionElement = %s", |
700 | | osCollectionElement.c_str()); |
701 | | #endif |
702 | 291 | StopAccumulate(); |
703 | 291 | } |
704 | 65.8k | else if (nFeatureElementDepth == currentDepth) |
705 | 286 | { |
706 | 286 | nFeatureElementDepth = 0; |
707 | 286 | osFeatureElement = pszElementValue; |
708 | | #ifdef DEBUG_VERBOSE |
709 | | CPLDebug("JML", "osFeatureElement = %s", osFeatureElement.c_str()); |
710 | | #endif |
711 | 286 | StopAccumulate(); |
712 | 286 | } |
713 | 65.5k | else if (nGeometryElementDepth == currentDepth) |
714 | 232 | { |
715 | 232 | nGeometryElementDepth = 0; |
716 | 232 | osGeometryElement = pszElementValue; |
717 | | #ifdef DEBUG_VERBOSE |
718 | | CPLDebug("JML", "osGeometryElement = %s", osGeometryElement.c_str()); |
719 | | #endif |
720 | 232 | StopAccumulate(); |
721 | 232 | } |
722 | 65.3k | else if (nColumnDepth == currentDepth) |
723 | 918 | { |
724 | 918 | bool bIsOK = true; |
725 | 918 | if (oCurColumn.osName.empty()) |
726 | 30 | bIsOK = false; |
727 | 918 | if (oCurColumn.osType.empty()) |
728 | 71 | bIsOK = false; |
729 | 918 | if (oCurColumn.osElementName.empty()) |
730 | 114 | bIsOK = false; |
731 | 918 | if (oCurColumn.bIsBody) |
732 | 558 | { |
733 | 558 | if (oCurColumn.osAttributeName.empty() && |
734 | 66 | !oCurColumn.osAttributeValue.empty()) |
735 | 12 | bIsOK = false; |
736 | 558 | if (!oCurColumn.osAttributeName.empty() && |
737 | 492 | oCurColumn.osAttributeValue.empty()) |
738 | 7 | bIsOK = false; |
739 | | /* Only 2 valid possibilities : */ |
740 | | /* <osElementName |
741 | | * osAttributeName="osAttributeValue">value</osElementName> */ |
742 | | /* <osElementName>value</osElementName> */ |
743 | 558 | } |
744 | 360 | else |
745 | 360 | { |
746 | | /* <osElementName osAttributeName="value"></osElementName> */ |
747 | 360 | if (oCurColumn.osAttributeName.empty()) |
748 | 148 | bIsOK = false; |
749 | 360 | if (!oCurColumn.osAttributeValue.empty()) |
750 | 141 | bIsOK = false; |
751 | 360 | } |
752 | | |
753 | 918 | if (bIsOK) |
754 | 579 | { |
755 | 579 | OGRFieldType eType = OFTString; |
756 | 579 | if (EQUAL(oCurColumn.osType, "INTEGER")) |
757 | 55 | eType = OFTInteger; |
758 | 524 | else if (EQUAL(oCurColumn.osType, "DOUBLE")) |
759 | 30 | eType = OFTReal; |
760 | 494 | else if (EQUAL(oCurColumn.osType, "DATE")) |
761 | 123 | eType = OFTDateTime; |
762 | 579 | OGRFieldDefn oField(oCurColumn.osName, eType); |
763 | | |
764 | 579 | if (oCurColumn.osName == "R_G_B" && eType == OFTString) |
765 | 38 | iRGBField = poFeatureDefn->GetFieldCount(); |
766 | | |
767 | 579 | poFeatureDefn->AddFieldDefn(&oField); |
768 | 579 | aoColumns.push_back(oCurColumn); |
769 | 579 | } |
770 | 339 | else |
771 | 339 | { |
772 | 339 | CPLDebug("JML", |
773 | 339 | "Invalid column definition: name = %s, type = %s, " |
774 | 339 | "elementName = %s, attributeName = %s, " |
775 | 339 | "attributeValue = %s, bIsBody = %d", |
776 | 339 | oCurColumn.osName.c_str(), oCurColumn.osType.c_str(), |
777 | 339 | oCurColumn.osElementName.c_str(), |
778 | 339 | oCurColumn.osAttributeName.c_str(), |
779 | 339 | oCurColumn.osAttributeValue.c_str(), |
780 | 339 | static_cast<int>(oCurColumn.bIsBody)); |
781 | 339 | } |
782 | | |
783 | 918 | nColumnDepth = 0; |
784 | 918 | } |
785 | 64.4k | else if (nNameDepth == currentDepth) |
786 | 1.62k | { |
787 | 1.62k | nNameDepth = 0; |
788 | 1.62k | oCurColumn.osName = pszElementValue; |
789 | | #ifdef DEBUG_VERBOSE |
790 | | CPLDebug("JML", "oCurColumn.osName = %s", oCurColumn.osName.c_str()); |
791 | | #endif |
792 | 1.62k | StopAccumulate(); |
793 | 1.62k | } |
794 | 62.7k | else if (nTypeDepth == currentDepth) |
795 | 1.67k | { |
796 | 1.67k | nTypeDepth = 0; |
797 | 1.67k | oCurColumn.osType = pszElementValue; |
798 | | #ifdef DEBUG_VERBOSE |
799 | | CPLDebug("JML", "oCurColumn.osType = %s", oCurColumn.osType.c_str()); |
800 | | #endif |
801 | 1.67k | StopAccumulate(); |
802 | 1.67k | } |
803 | 66.2k | } |
804 | | |
805 | | /************************************************************************/ |
806 | | /* TestCapability() */ |
807 | | /************************************************************************/ |
808 | | |
809 | | int OGRJMLLayer::TestCapability(const char *pszCap) const |
810 | | |
811 | 1 | { |
812 | 1 | if (EQUAL(pszCap, OLCStringsAsUTF8)) |
813 | 0 | return true; |
814 | 1 | else if (EQUAL(pszCap, OLCZGeometries)) |
815 | 0 | return true; |
816 | | |
817 | 1 | return false; |
818 | 1 | } |
819 | | |
820 | | #endif /* HAVE_EXPAT */ |