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 : "at line %d, column %d",
440 : XML_ErrorString(XML_GetErrorCode(poParser.get())),
441 0 : (int)XML_GetCurrentLineNumber(poParser.get()),
442 0 : (int)XML_GetCurrentColumnNumber(poParser.get()));
443 0 : bStopParsing = true;
444 : }
445 56 : nWithoutEventCounter++;
446 56 : } while (!nDone && !bStopParsing && this->nFeatureTabLength == 0 &&
447 0 : nWithoutEventCounter < 10);
448 :
449 56 : if (nWithoutEventCounter == 10)
450 : {
451 0 : CPLError(CE_Failure, CPLE_AppDefined,
452 : "Too much data inside one element. File probably corrupted");
453 0 : bStopParsing = true;
454 : }
455 :
456 56 : return (this->nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++]
457 56 : : nullptr;
458 : }
459 :
460 304 : static void XMLCALL startElementLoadSchemaCbk(void *pUserData,
461 : const char *pszName,
462 : const char **ppszAttr)
463 : {
464 304 : static_cast<OGRJMLLayer *>(pUserData)->startElementLoadSchemaCbk(pszName,
465 : ppszAttr);
466 304 : }
467 :
468 296 : static void XMLCALL endElementLoadSchemaCbk(void *pUserData,
469 : const char *pszName)
470 : {
471 296 : static_cast<OGRJMLLayer *>(pUserData)->endElementLoadSchemaCbk(pszName);
472 296 : }
473 :
474 : /************************************************************************/
475 : /* LoadSchema() */
476 : /************************************************************************/
477 :
478 : /** This function parses the beginning of the file to detect the fields */
479 8 : void OGRJMLLayer::LoadSchema()
480 : {
481 8 : if (bHasReadSchema)
482 0 : return;
483 :
484 8 : bHasReadSchema = true;
485 :
486 8 : poParser.reset(OGRCreateExpatXMLParser());
487 8 : XML_SetElementHandler(poParser.get(), ::startElementLoadSchemaCbk,
488 : ::endElementLoadSchemaCbk);
489 8 : XML_SetCharacterDataHandler(poParser.get(), ::dataHandlerCbk);
490 8 : XML_SetUserData(poParser.get(), this);
491 :
492 8 : VSIFSeekL(fp, 0, SEEK_SET);
493 :
494 16 : std::vector<char> aBuf(PARSER_BUF_SIZE);
495 8 : int nDone = 0;
496 0 : do
497 : {
498 8 : nDataHandlerCounter = 0;
499 : const unsigned int nLen = static_cast<unsigned int>(
500 8 : VSIFReadL(aBuf.data(), 1, aBuf.size(), fp));
501 8 : nDone = (nLen < aBuf.size());
502 8 : if (XML_Parse(poParser.get(), aBuf.data(), nLen, nDone) ==
503 : XML_STATUS_ERROR)
504 : {
505 3 : CPLError(
506 : CE_Failure, CPLE_AppDefined,
507 : "XML parsing of JML file failed : %s at line %d, "
508 : "column %d",
509 : XML_ErrorString(XML_GetErrorCode(poParser.get())),
510 3 : static_cast<int>(XML_GetCurrentLineNumber(poParser.get())),
511 3 : static_cast<int>(XML_GetCurrentColumnNumber(poParser.get())));
512 3 : bStopParsing = true;
513 : }
514 8 : nWithoutEventCounter++;
515 8 : } while (!nDone && !bStopParsing && !bSchemaFinished &&
516 0 : nWithoutEventCounter < 10);
517 :
518 8 : poParser.reset();
519 :
520 8 : if (nWithoutEventCounter == 10)
521 : {
522 0 : CPLError(CE_Failure, CPLE_AppDefined,
523 : "Too much data inside one element. File probably corrupted");
524 0 : bStopParsing = true;
525 : }
526 :
527 15 : if (osCollectionElement.empty() || osFeatureElement.empty() ||
528 7 : osGeometryElement.empty())
529 : {
530 1 : CPLError(CE_Failure, CPLE_AppDefined,
531 : "Missing CollectionElement, FeatureElement or "
532 : "GeometryElement");
533 1 : bStopParsing = true;
534 : }
535 :
536 8 : if (!osSRSName.empty())
537 : {
538 1 : if (osSRSName.find("http://www.opengis.net/gml/srs/epsg.xml#") == 0)
539 : {
540 1 : OGRSpatialReference *poSRS = new OGRSpatialReference();
541 1 : poSRS->importFromEPSG(atoi(
542 : osSRSName
543 2 : .substr(strlen("http://www.opengis.net/gml/srs/epsg.xml#"))
544 : .c_str()));
545 1 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
546 1 : poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
547 1 : poSRS->Release();
548 : }
549 : }
550 :
551 8 : nJCSGMLInputTemplateDepth = 0;
552 8 : nCollectionElementDepth = 0;
553 8 : nFeatureCollectionDepth = 0;
554 8 : nFeatureElementDepth = 0;
555 8 : nGeometryElementDepth = 0;
556 8 : nColumnDepth = 0;
557 8 : nNameDepth = 0;
558 8 : nTypeDepth = 0;
559 8 : nAttributeElementDepth = 0;
560 :
561 8 : ResetReading();
562 : }
563 :
564 : /************************************************************************/
565 : /* startElementLoadSchemaCbk() */
566 : /************************************************************************/
567 :
568 304 : void OGRJMLLayer::startElementLoadSchemaCbk(const char *pszName,
569 : const char **ppszAttr)
570 : {
571 304 : if (bStopParsing)
572 0 : return;
573 :
574 304 : nWithoutEventCounter = 0;
575 :
576 304 : if (nJCSGMLInputTemplateDepth == 0 &&
577 111 : strcmp(pszName, "JCSGMLInputTemplate") == 0)
578 8 : nJCSGMLInputTemplateDepth = currentDepth;
579 296 : else if (nJCSGMLInputTemplateDepth > 0)
580 : {
581 193 : if (nCollectionElementDepth == 0 &&
582 193 : strcmp(pszName, "CollectionElement") == 0)
583 : {
584 7 : nCollectionElementDepth = currentDepth;
585 7 : bAccumulateElementValue = true;
586 : }
587 186 : else if (nFeatureElementDepth == 0 &&
588 186 : strcmp(pszName, "FeatureElement") == 0)
589 : {
590 7 : nFeatureElementDepth = currentDepth;
591 7 : bAccumulateElementValue = true;
592 : }
593 179 : else if (nGeometryElementDepth == 0 &&
594 179 : strcmp(pszName, "GeometryElement") == 0)
595 : {
596 7 : nGeometryElementDepth = currentDepth;
597 7 : bAccumulateElementValue = true;
598 : }
599 172 : else if (nColumnDepth == 0 && strcmp(pszName, "column") == 0)
600 : {
601 32 : nColumnDepth = currentDepth;
602 32 : oCurColumn.osName = "";
603 32 : oCurColumn.osType = "";
604 32 : oCurColumn.osElementName = "";
605 32 : oCurColumn.osAttributeName = "";
606 32 : oCurColumn.osAttributeValue = "";
607 32 : oCurColumn.bIsBody = false;
608 : }
609 140 : else if (nColumnDepth > 0)
610 : {
611 128 : if (nNameDepth == 0 && strcmp(pszName, "name") == 0)
612 : {
613 31 : nNameDepth = currentDepth;
614 31 : bAccumulateElementValue = true;
615 : }
616 97 : else if (nTypeDepth == 0 && strcmp(pszName, "type") == 0)
617 : {
618 31 : nTypeDepth = currentDepth;
619 31 : bAccumulateElementValue = true;
620 : }
621 66 : else if (strcmp(pszName, "valueElement") == 0)
622 : {
623 31 : const char **papszIter = ppszAttr;
624 115 : while (papszIter && *papszIter != nullptr)
625 : {
626 84 : if (strcmp(*papszIter, "elementName") == 0)
627 30 : oCurColumn.osElementName = papszIter[1];
628 54 : else if (strcmp(*papszIter, "attributeName") == 0)
629 25 : oCurColumn.osAttributeName = papszIter[1];
630 29 : else if (strcmp(*papszIter, "attributeValue") == 0)
631 25 : oCurColumn.osAttributeValue = papszIter[1];
632 84 : papszIter += 2;
633 : }
634 : }
635 35 : else if (strcmp(pszName, "valueLocation") == 0)
636 : {
637 31 : const char **papszIter = ppszAttr;
638 64 : while (papszIter && *papszIter != nullptr)
639 : {
640 33 : if (strcmp(*papszIter, "position") == 0)
641 31 : oCurColumn.bIsBody = strcmp(papszIter[1], "body") == 0;
642 2 : else if (strcmp(*papszIter, "attributeName") == 0)
643 2 : oCurColumn.osAttributeName = papszIter[1];
644 33 : papszIter += 2;
645 : }
646 : }
647 : }
648 : }
649 132 : else if (nFeatureCollectionDepth == 0 &&
650 29 : osCollectionElement.compare(pszName) == 0)
651 : {
652 6 : nFeatureCollectionDepth = currentDepth;
653 : }
654 97 : else if (nFeatureCollectionDepth > 0 &&
655 74 : currentDepth == nFeatureCollectionDepth + 2 &&
656 15 : strcmp(pszName, "gml:Box") == 0)
657 : {
658 1 : const char **papszIter = ppszAttr;
659 2 : while (papszIter && *papszIter != nullptr)
660 : {
661 1 : if (strcmp(*papszIter, "srsName") == 0)
662 1 : osSRSName = papszIter[1];
663 1 : papszIter += 2;
664 : }
665 1 : bSchemaFinished = true;
666 : }
667 288 : else if (nFeatureCollectionDepth >= 0 &&
668 184 : currentDepth >= nFeatureCollectionDepth + 1 &&
669 88 : osFeatureElement.compare(pszName) == 0)
670 : {
671 11 : bSchemaFinished = true;
672 : }
673 :
674 304 : currentDepth++;
675 : }
676 :
677 : /************************************************************************/
678 : /* endElementLoadSchemaCbk() */
679 : /************************************************************************/
680 :
681 296 : void OGRJMLLayer::endElementLoadSchemaCbk(const char * /* pszName */)
682 : {
683 296 : if (bStopParsing)
684 0 : return;
685 :
686 296 : nWithoutEventCounter = 0;
687 :
688 296 : currentDepth--;
689 :
690 296 : if (nJCSGMLInputTemplateDepth == currentDepth)
691 : {
692 12 : nJCSGMLInputTemplateDepth = 0;
693 : }
694 284 : else if (nCollectionElementDepth == currentDepth)
695 : {
696 7 : nCollectionElementDepth = 0;
697 7 : osCollectionElement = pszElementValue;
698 : #ifdef DEBUG_VERBOSE
699 : CPLDebug("JML", "osCollectionElement = %s",
700 : osCollectionElement.c_str());
701 : #endif
702 7 : StopAccumulate();
703 : }
704 277 : else if (nFeatureElementDepth == currentDepth)
705 : {
706 7 : nFeatureElementDepth = 0;
707 7 : osFeatureElement = pszElementValue;
708 : #ifdef DEBUG_VERBOSE
709 : CPLDebug("JML", "osFeatureElement = %s", osFeatureElement.c_str());
710 : #endif
711 7 : StopAccumulate();
712 : }
713 270 : else if (nGeometryElementDepth == currentDepth)
714 : {
715 7 : nGeometryElementDepth = 0;
716 7 : osGeometryElement = pszElementValue;
717 : #ifdef DEBUG_VERBOSE
718 : CPLDebug("JML", "osGeometryElement = %s", osGeometryElement.c_str());
719 : #endif
720 7 : StopAccumulate();
721 : }
722 263 : else if (nColumnDepth == currentDepth)
723 : {
724 32 : bool bIsOK = true;
725 32 : if (oCurColumn.osName.empty())
726 1 : bIsOK = false;
727 32 : if (oCurColumn.osType.empty())
728 1 : bIsOK = false;
729 32 : if (oCurColumn.osElementName.empty())
730 2 : bIsOK = false;
731 32 : if (oCurColumn.bIsBody)
732 : {
733 32 : if (oCurColumn.osAttributeName.empty() &&
734 4 : !oCurColumn.osAttributeValue.empty())
735 1 : bIsOK = false;
736 52 : if (!oCurColumn.osAttributeName.empty() &&
737 24 : oCurColumn.osAttributeValue.empty())
738 1 : bIsOK = false;
739 : /* Only 2 valid possibilities : */
740 : /* <osElementName
741 : * osAttributeName="osAttributeValue">value</osElementName> */
742 : /* <osElementName>value</osElementName> */
743 : }
744 : else
745 : {
746 : /* <osElementName osAttributeName="value"></osElementName> */
747 4 : if (oCurColumn.osAttributeName.empty())
748 1 : bIsOK = false;
749 4 : if (!oCurColumn.osAttributeValue.empty())
750 1 : bIsOK = false;
751 : }
752 :
753 32 : if (bIsOK)
754 : {
755 24 : OGRFieldType eType = OFTString;
756 24 : if (EQUAL(oCurColumn.osType, "INTEGER"))
757 2 : eType = OFTInteger;
758 22 : else if (EQUAL(oCurColumn.osType, "DOUBLE"))
759 2 : eType = OFTReal;
760 20 : else if (EQUAL(oCurColumn.osType, "DATE"))
761 4 : eType = OFTDateTime;
762 48 : OGRFieldDefn oField(oCurColumn.osName, eType);
763 :
764 24 : if (oCurColumn.osName == "R_G_B" && eType == OFTString)
765 2 : iRGBField = poFeatureDefn->GetFieldCount();
766 :
767 24 : poFeatureDefn->AddFieldDefn(&oField);
768 24 : aoColumns.push_back(oCurColumn);
769 : }
770 : else
771 : {
772 8 : CPLDebug("JML",
773 : "Invalid column definition: name = %s, type = %s, "
774 : "elementName = %s, attributeName = %s, "
775 : "attributeValue = %s, bIsBody = %d",
776 : oCurColumn.osName.c_str(), oCurColumn.osType.c_str(),
777 : oCurColumn.osElementName.c_str(),
778 : oCurColumn.osAttributeName.c_str(),
779 : oCurColumn.osAttributeValue.c_str(),
780 8 : static_cast<int>(oCurColumn.bIsBody));
781 : }
782 :
783 32 : nColumnDepth = 0;
784 : }
785 231 : else if (nNameDepth == currentDepth)
786 : {
787 31 : nNameDepth = 0;
788 31 : oCurColumn.osName = pszElementValue;
789 : #ifdef DEBUG_VERBOSE
790 : CPLDebug("JML", "oCurColumn.osName = %s", oCurColumn.osName.c_str());
791 : #endif
792 31 : StopAccumulate();
793 : }
794 200 : else if (nTypeDepth == currentDepth)
795 : {
796 31 : nTypeDepth = 0;
797 31 : oCurColumn.osType = pszElementValue;
798 : #ifdef DEBUG_VERBOSE
799 : CPLDebug("JML", "oCurColumn.osType = %s", oCurColumn.osType.c_str());
800 : #endif
801 31 : StopAccumulate();
802 : }
803 : }
804 :
805 : /************************************************************************/
806 : /* TestCapability() */
807 : /************************************************************************/
808 :
809 37 : int OGRJMLLayer::TestCapability(const char *pszCap) const
810 :
811 : {
812 37 : if (EQUAL(pszCap, OLCStringsAsUTF8))
813 13 : return true;
814 24 : else if (EQUAL(pszCap, OLCZGeometries))
815 3 : return true;
816 :
817 21 : return false;
818 : }
819 :
820 : #endif /* HAVE_EXPAT */
|