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