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