Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Interlis 2 Reader
4 : * Purpose: Implementation of ILI2Reader class.
5 : * Author: Markus Schnider, Sourcepole AG
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG
9 : * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "ili2readerp.h"
15 : #include "ogr_ili2.h"
16 : #include "cpl_conv.h"
17 : #include "cpl_string.h"
18 :
19 : #include "ili2reader.h"
20 :
21 : using namespace std;
22 :
23 : //
24 : // constants
25 : //
26 : static const char *const ILI2_TID = "TID";
27 : static const XMLCh xmlch_ILI2_TID[] = {'T', 'I', 'D', '\0'};
28 : static const XMLCh ILI2_REF[] = {'R', 'E', 'F', '\0'};
29 :
30 : constexpr int ILI2_STRING_TYPE = 0;
31 : constexpr int ILI2_COORD_TYPE = 1;
32 : constexpr int ILI2_ARC_TYPE = 2;
33 : constexpr int ILI2_POLYLINE_TYPE = 4;
34 : constexpr int ILI2_BOUNDARY_TYPE = 8;
35 : constexpr int ILI2_AREA_TYPE = 16; // also SURFACE
36 : constexpr int ILI2_GEOMCOLL_TYPE = 32;
37 :
38 : static const char *const ILI2_COORD = "COORD";
39 : static const char *const ILI2_ARC = "ARC";
40 : static const char *const ILI2_POLYLINE = "POLYLINE";
41 : static const char *const ILI2_BOUNDARY = "BOUNDARY";
42 : static const char *const ILI2_AREA = "AREA";
43 : static const char *const ILI2_SURFACE = "SURFACE";
44 :
45 : namespace gdal
46 : {
47 : namespace ili2
48 : {
49 : //
50 : // helper functions
51 : //
52 37649 : int cmpStr(const string &s1, const string &s2)
53 : {
54 37649 : string::const_iterator p1 = s1.begin();
55 37649 : string::const_iterator p2 = s2.begin();
56 :
57 124938 : while (p1 != s1.end() && p2 != s2.end())
58 : {
59 117396 : if (CPLToupper(static_cast<unsigned char>(*p1)) !=
60 117396 : CPLToupper(static_cast<unsigned char>(*p2)))
61 30107 : return (CPLToupper(static_cast<unsigned char>(*p1)) <
62 30107 : CPLToupper(static_cast<unsigned char>(*p2)))
63 30107 : ? -1
64 30107 : : 1;
65 87289 : ++p1;
66 87289 : ++p2;
67 : }
68 :
69 7542 : return (s2.size() == s1.size()) ? 0 : (s1.size() < s2.size()) ? -1 : 1;
70 : }
71 :
72 5987 : string ltrim(const string &tmpstr)
73 : {
74 5987 : size_t i = 0;
75 22664 : while (i < tmpstr.length() && (tmpstr[i] == ' ' || tmpstr[i] == '\t' ||
76 5987 : tmpstr[i] == '\r' || tmpstr[i] == '\n'))
77 10690 : ++i;
78 5987 : return i > 0 ? tmpstr.substr(i, tmpstr.length() - i) : tmpstr;
79 : }
80 :
81 5987 : string rtrim(const string &tmpstr)
82 : {
83 5987 : if (tmpstr.empty())
84 702 : return tmpstr;
85 5285 : size_t i = tmpstr.length() - 1U;
86 10570 : while (tmpstr[i] == ' ' || tmpstr[i] == '\t' || tmpstr[i] == '\r' ||
87 5285 : tmpstr[i] == '\n')
88 0 : --i;
89 5285 : return i < tmpstr.length() - 1 ? tmpstr.substr(0, i + 1) : tmpstr;
90 : }
91 :
92 5987 : string trim(const string &tmpstr)
93 : {
94 5987 : auto ret = ltrim(tmpstr);
95 5987 : ret = rtrim(ret);
96 5987 : return ret;
97 : }
98 : } // namespace ili2
99 : } // namespace gdal
100 :
101 : using namespace gdal::ili2;
102 :
103 3876 : static int getGeometryTypeOfElem(DOMElement *elem)
104 : {
105 3876 : int type = ILI2_STRING_TYPE;
106 3876 : if (elem == nullptr)
107 0 : return type;
108 3876 : char *pszTagName = XMLString::transcode(elem->getTagName());
109 :
110 3876 : if (elem->getNodeType() == DOMNode::ELEMENT_NODE)
111 : {
112 3876 : if (cmpStr(ILI2_COORD, pszTagName) == 0)
113 : {
114 34 : type = ILI2_COORD_TYPE;
115 : }
116 3842 : else if (cmpStr(ILI2_ARC, pszTagName) == 0)
117 : {
118 0 : type = ILI2_ARC_TYPE;
119 : }
120 3842 : else if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
121 : {
122 29 : type = ILI2_POLYLINE_TYPE;
123 : }
124 3813 : else if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0)
125 : {
126 0 : type = ILI2_BOUNDARY_TYPE;
127 : }
128 3813 : else if (cmpStr(ILI2_AREA, pszTagName) == 0)
129 : {
130 0 : type = ILI2_AREA_TYPE;
131 : }
132 3813 : else if (cmpStr(ILI2_SURFACE, pszTagName) == 0)
133 : {
134 121 : type = ILI2_AREA_TYPE;
135 : }
136 : }
137 3876 : XMLString::release(&pszTagName);
138 3876 : return type;
139 : }
140 :
141 5756 : static char *getObjValue(DOMElement *elem)
142 : {
143 5756 : DOMNode *child = elem->getFirstChild();
144 5756 : if ((child != nullptr) && (child->getNodeType() == DOMNode::TEXT_NODE))
145 : {
146 4967 : return CPLStrdup(transcode(child->getNodeValue()));
147 : }
148 :
149 789 : return nullptr;
150 : }
151 :
152 789 : static char *getREFValue(DOMElement *elem)
153 : {
154 1578 : CPLString osREFValue(transcode(elem->getAttribute(ILI2_REF)));
155 1578 : return CPLStrdup(osREFValue);
156 : }
157 :
158 2219 : static OGRPoint *getPoint(DOMElement *elem)
159 : {
160 : // elem -> COORD (or ARC)
161 2219 : DOMElement *coordElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
162 2219 : if (coordElem == nullptr)
163 0 : return nullptr;
164 2219 : OGRPoint *pt = new OGRPoint();
165 :
166 6657 : while (coordElem != nullptr)
167 : {
168 4438 : char *pszTagName = XMLString::transcode(coordElem->getTagName());
169 4438 : char *pszObjValue = getObjValue(coordElem);
170 4438 : if (pszObjValue)
171 : {
172 4438 : if (cmpStr("C1", pszTagName) == 0)
173 2219 : pt->setX(CPLAtof(pszObjValue));
174 2219 : else if (cmpStr("C2", pszTagName) == 0)
175 2219 : pt->setY(CPLAtof(pszObjValue));
176 0 : else if (cmpStr("C3", pszTagName) == 0)
177 0 : pt->setZ(CPLAtof(pszObjValue));
178 : }
179 4438 : CPLFree(pszObjValue);
180 4438 : XMLString::release(&pszTagName);
181 4438 : coordElem = dynamic_cast<DOMElement *>(coordElem->getNextSibling());
182 : }
183 2219 : pt->flattenTo2D();
184 2219 : return pt;
185 : }
186 :
187 0 : OGRCircularString *ILI2Reader::getArc(DOMElement *elem)
188 : {
189 : // previous point -> start point
190 0 : auto elemPrev = dynamic_cast<DOMElement *>(elem->getPreviousSibling());
191 0 : if (elemPrev == nullptr)
192 0 : return nullptr;
193 0 : OGRPoint *ptStart = getPoint(elemPrev); // COORD or ARC
194 0 : if (ptStart == nullptr)
195 0 : return nullptr;
196 :
197 : // elem -> ARC
198 0 : OGRCircularString *arc = new OGRCircularString();
199 : // end point
200 0 : OGRPoint *ptEnd = new OGRPoint();
201 : // point on the arc
202 0 : OGRPoint *ptOnArc = new OGRPoint();
203 : // double radius = 0; // radius
204 :
205 0 : DOMElement *arcElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
206 0 : while (arcElem != nullptr)
207 : {
208 0 : char *pszTagName = XMLString::transcode(arcElem->getTagName());
209 0 : char *pszObjValue = getObjValue(arcElem);
210 0 : if (pszObjValue)
211 : {
212 0 : if (cmpStr("C1", pszTagName) == 0)
213 0 : ptEnd->setX(CPLAtof(pszObjValue));
214 0 : else if (cmpStr("C2", pszTagName) == 0)
215 0 : ptEnd->setY(CPLAtof(pszObjValue));
216 0 : else if (cmpStr("C3", pszTagName) == 0)
217 0 : ptEnd->setZ(CPLAtof(pszObjValue));
218 0 : else if (cmpStr("A1", pszTagName) == 0)
219 0 : ptOnArc->setX(CPLAtof(pszObjValue));
220 0 : else if (cmpStr("A2", pszTagName) == 0)
221 0 : ptOnArc->setY(CPLAtof(pszObjValue));
222 0 : else if (cmpStr("A3", pszTagName) == 0)
223 0 : ptOnArc->setZ(CPLAtof(pszObjValue));
224 0 : else if (cmpStr("R", pszTagName) == 0)
225 : {
226 : // radius = CPLAtof(pszObjValue);
227 : }
228 : }
229 0 : CPLFree(pszObjValue);
230 0 : XMLString::release(&pszTagName);
231 0 : arcElem = dynamic_cast<DOMElement *>(arcElem->getNextSibling());
232 : }
233 0 : arc->addPoint(ptStart);
234 0 : arc->addPoint(ptOnArc);
235 0 : arc->addPoint(ptEnd);
236 0 : delete ptStart;
237 0 : delete ptOnArc;
238 0 : delete ptEnd;
239 0 : return arc;
240 : }
241 :
242 81 : static OGRCompoundCurve *getPolyline(DOMElement *elem)
243 : {
244 : // elem -> POLYLINE
245 81 : OGRCompoundCurve *ogrCurve = new OGRCompoundCurve();
246 81 : OGRLineString *ls = new OGRLineString();
247 :
248 81 : DOMElement *lineElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
249 2314 : while (lineElem != nullptr)
250 : {
251 2233 : char *pszTagName = XMLString::transcode(lineElem->getTagName());
252 2233 : if (cmpStr(ILI2_COORD, pszTagName) == 0)
253 : {
254 2203 : OGRPoint *poPoint = getPoint(lineElem);
255 2203 : if (poPoint)
256 : {
257 2203 : ls->addPoint(poPoint);
258 2203 : delete poPoint;
259 : }
260 : }
261 30 : else if (cmpStr(ILI2_ARC, pszTagName) == 0)
262 : {
263 : // Finish line and start arc
264 0 : if (ls->getNumPoints() > 1)
265 : {
266 0 : ogrCurve->addCurveDirectly(ls);
267 0 : ls = new OGRLineString();
268 : }
269 : else
270 : {
271 0 : ls->empty();
272 : }
273 0 : OGRCircularString *arc = new OGRCircularString();
274 : // end point
275 0 : OGRPoint *ptEnd = new OGRPoint();
276 : // point on the arc
277 0 : OGRPoint *ptOnArc = new OGRPoint();
278 : // radius
279 : // double radius = 0;
280 :
281 : DOMElement *arcElem =
282 0 : dynamic_cast<DOMElement *>(lineElem->getFirstChild());
283 0 : while (arcElem != nullptr)
284 : {
285 0 : char *pszTagName2 = XMLString::transcode(arcElem->getTagName());
286 0 : char *pszObjValue = getObjValue(arcElem);
287 0 : if (pszObjValue)
288 : {
289 0 : if (cmpStr("C1", pszTagName2) == 0)
290 0 : ptEnd->setX(CPLAtof(pszObjValue));
291 0 : else if (cmpStr("C2", pszTagName2) == 0)
292 0 : ptEnd->setY(CPLAtof(pszObjValue));
293 0 : else if (cmpStr("C3", pszTagName2) == 0)
294 0 : ptEnd->setZ(CPLAtof(pszObjValue));
295 0 : else if (cmpStr("A1", pszTagName2) == 0)
296 0 : ptOnArc->setX(CPLAtof(pszObjValue));
297 0 : else if (cmpStr("A2", pszTagName2) == 0)
298 0 : ptOnArc->setY(CPLAtof(pszObjValue));
299 0 : else if (cmpStr("A3", pszTagName2) == 0)
300 0 : ptOnArc->setZ(CPLAtof(pszObjValue));
301 0 : else if (cmpStr("R", pszTagName2) == 0)
302 : {
303 : // radius = CPLAtof(pszObjValue);
304 : }
305 : }
306 0 : CPLFree(pszObjValue);
307 0 : XMLString::release(&pszTagName2);
308 :
309 0 : arcElem = dynamic_cast<DOMElement *>(arcElem->getNextSibling());
310 : }
311 :
312 : auto elemPrev =
313 0 : dynamic_cast<DOMElement *>(lineElem->getPreviousSibling());
314 0 : if (elemPrev)
315 : {
316 0 : OGRPoint *ptStart = getPoint(elemPrev); // COORD or ARC
317 0 : if (ptStart)
318 0 : arc->addPoint(ptStart);
319 0 : delete ptStart;
320 : }
321 0 : arc->addPoint(ptOnArc);
322 0 : arc->addPoint(ptEnd);
323 0 : ogrCurve->addCurveDirectly(arc);
324 :
325 : // Add arc endpoint as next start point, if COORD sequence follows.
326 : DOMElement *nextElem =
327 0 : dynamic_cast<DOMElement *>(lineElem->getNextSibling());
328 0 : if (nextElem)
329 : {
330 : char *nextTagName =
331 0 : XMLString::transcode(nextElem->getTagName());
332 0 : if (cmpStr(ILI2_COORD, nextTagName) == 0)
333 : {
334 0 : ls->addPoint(ptEnd);
335 : }
336 0 : XMLString::release(&nextTagName);
337 : }
338 :
339 0 : delete ptEnd;
340 0 : delete ptOnArc;
341 : } /* else { // TODO: StructureValue in Polyline not yet supported
342 : } */
343 2233 : XMLString::release(&pszTagName);
344 :
345 2233 : lineElem = dynamic_cast<DOMElement *>(lineElem->getNextSibling());
346 : }
347 :
348 81 : if (ls->getNumPoints() > 1)
349 : {
350 81 : ogrCurve->addCurveDirectly(ls);
351 : }
352 : else
353 : {
354 0 : delete ls;
355 : }
356 81 : return ogrCurve;
357 : }
358 :
359 67 : static OGRCompoundCurve *getBoundary(DOMElement *elem)
360 : {
361 :
362 67 : DOMElement *lineElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
363 67 : if (lineElem != nullptr)
364 : {
365 67 : char *pszTagName = XMLString::transcode(lineElem->getTagName());
366 67 : if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
367 : {
368 67 : XMLString::release(&pszTagName);
369 67 : return getPolyline(lineElem);
370 : }
371 0 : XMLString::release(&pszTagName);
372 : }
373 :
374 0 : return new OGRCompoundCurve();
375 : }
376 :
377 60 : static OGRCurvePolygon *getPolygon(DOMElement *elem)
378 : {
379 60 : OGRCurvePolygon *pg = new OGRCurvePolygon();
380 :
381 : DOMElement *boundaryElem =
382 60 : dynamic_cast<DOMElement *>(elem->getFirstChild()); // outer boundary
383 127 : while (boundaryElem != nullptr)
384 : {
385 67 : char *pszTagName = XMLString::transcode(boundaryElem->getTagName());
386 67 : if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0)
387 : {
388 67 : OGRCompoundCurve *poCC = getBoundary(boundaryElem);
389 67 : if (pg->addRingDirectly(poCC) != OGRERR_NONE)
390 : {
391 0 : delete poCC;
392 : }
393 : }
394 67 : XMLString::release(&pszTagName);
395 67 : boundaryElem = dynamic_cast<DOMElement *>(
396 67 : boundaryElem->getNextSibling()); // inner boundaries
397 : }
398 :
399 60 : return pg;
400 : }
401 :
402 90 : OGRGeometry *ILI2Reader::getGeometry(DOMElement *elem, int type)
403 : {
404 90 : OGRGeometryCollection *gm = new OGRGeometryCollection();
405 :
406 90 : DOMElement *childElem = elem;
407 90 : while (childElem != nullptr)
408 : {
409 90 : char *pszTagName = XMLString::transcode(childElem->getTagName());
410 90 : switch (type)
411 : {
412 16 : case ILI2_COORD_TYPE:
413 16 : if (cmpStr(ILI2_COORD, pszTagName) == 0)
414 : {
415 16 : delete gm;
416 16 : XMLString::release(&pszTagName);
417 90 : return getPoint(childElem);
418 : }
419 0 : break;
420 0 : case ILI2_ARC_TYPE:
421 : // is it possible here? It have to be a ARC or COORD before
422 : // (getPreviousSibling)
423 0 : if (cmpStr(ILI2_ARC, pszTagName) == 0)
424 : {
425 0 : delete gm;
426 0 : XMLString::release(&pszTagName);
427 0 : return getArc(childElem);
428 : }
429 0 : break;
430 14 : case ILI2_POLYLINE_TYPE:
431 14 : if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
432 : {
433 14 : delete gm;
434 14 : XMLString::release(&pszTagName);
435 14 : return getPolyline(childElem);
436 : }
437 0 : break;
438 0 : case ILI2_BOUNDARY_TYPE:
439 0 : if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0)
440 : {
441 0 : delete gm;
442 0 : XMLString::release(&pszTagName);
443 0 : return getPolyline(childElem);
444 : }
445 0 : break;
446 60 : case ILI2_AREA_TYPE:
447 180 : if ((cmpStr(ILI2_AREA, pszTagName) == 0) ||
448 120 : (cmpStr(ILI2_SURFACE, pszTagName) == 0))
449 : {
450 60 : delete gm;
451 60 : XMLString::release(&pszTagName);
452 60 : return getPolygon(childElem);
453 : }
454 0 : break;
455 0 : default:
456 0 : if (type >= ILI2_GEOMCOLL_TYPE)
457 : {
458 0 : int subType = getGeometryTypeOfElem(childElem); //????
459 0 : OGRGeometry *poSubGeom = getGeometry(childElem, subType);
460 0 : if (poSubGeom)
461 0 : gm->addGeometryDirectly(poSubGeom);
462 : }
463 0 : break;
464 : }
465 0 : XMLString::release(&pszTagName);
466 :
467 : // GEOMCOLL
468 0 : childElem = dynamic_cast<DOMElement *>(childElem->getNextSibling());
469 : }
470 :
471 0 : return gm;
472 : }
473 :
474 2 : int ILI2Reader::ReadModel(OGRILI2DataSource *poDS, ImdReader *poImdReader,
475 : const char *modelFilename)
476 : {
477 2 : poImdReader->ReadModel(modelFilename);
478 32 : for (FeatureDefnInfos::const_iterator it =
479 2 : poImdReader->featureDefnInfos.begin();
480 34 : it != poImdReader->featureDefnInfos.end(); ++it)
481 : {
482 32 : m_listLayer.push_back(std::make_unique<OGRILI2Layer>(
483 64 : it->GetTableDefnRef(), it->poGeomFieldInfos, poDS));
484 : }
485 2 : return 0;
486 : }
487 :
488 : // Detect field name of value element
489 1659 : static char *fieldName(DOMElement *elem)
490 : {
491 1659 : DOMNode *node = elem;
492 1659 : if (getGeometryTypeOfElem(elem))
493 : {
494 90 : int depth = 0; // Depth of value elem node
495 540 : for (node = elem; node; node = node->getParentNode())
496 450 : ++depth;
497 : // Field name is on level 4
498 90 : node = elem;
499 180 : for (int d = 0; d < depth - 4; ++d)
500 90 : node = node->getParentNode();
501 : }
502 1659 : if (node == nullptr)
503 : {
504 0 : CPLError(CE_Failure, CPLE_AssertionFailed, "node == NULL");
505 0 : return CPLStrdup("***bug***");
506 : }
507 1659 : return CPLStrdup(transcode(node->getNodeName()));
508 : }
509 :
510 14 : void ILI2Reader::setFieldDefn(OGRFeatureDefn *featureDef, DOMElement *elem)
511 : {
512 14 : int type = 0;
513 : // recursively search children
514 14 : for (DOMNode *childNode = elem->getFirstChild();
515 64 : type == 0 && childNode &&
516 25 : childNode->getNodeType() == DOMNode::ELEMENT_NODE;
517 25 : childNode = childNode->getNextSibling())
518 : {
519 25 : DOMElement *childElem = dynamic_cast<DOMElement *>(childNode);
520 25 : CPLAssert(childElem);
521 25 : type = getGeometryTypeOfElem(childElem);
522 25 : if (type == 0)
523 : {
524 39 : if (childElem->getFirstChild() &&
525 18 : childElem->getFirstChild()->getNodeType() ==
526 : DOMNode::ELEMENT_NODE)
527 : {
528 8 : setFieldDefn(featureDef, childElem);
529 : }
530 : else
531 : {
532 13 : char *fName = fieldName(childElem);
533 13 : if (featureDef->GetFieldIndex(fName) == -1)
534 : {
535 13 : CPLDebug("OGR_ILI", "AddFieldDefn: %s", fName);
536 26 : OGRFieldDefn oFieldDefn(fName, OFTString);
537 13 : featureDef->AddFieldDefn(&oFieldDefn);
538 : }
539 13 : CPLFree(fName);
540 : }
541 : }
542 : }
543 14 : }
544 :
545 1037 : void ILI2Reader::SetFieldValues(OGRFeature *feature, DOMElement *elem)
546 : {
547 1037 : int type = 0;
548 : // recursively search children
549 1037 : for (DOMNode *childNode = elem->getFirstChild();
550 5421 : type == 0 && childNode &&
551 2192 : childNode->getNodeType() == DOMNode::ELEMENT_NODE;
552 2192 : childNode = childNode->getNextSibling())
553 : {
554 2192 : DOMElement *childElem = dynamic_cast<DOMElement *>(childNode);
555 2192 : CPLAssert(childElem);
556 2192 : type = getGeometryTypeOfElem(childElem);
557 2192 : if (type == 0)
558 : {
559 3415 : if (childElem->getFirstChild() &&
560 1313 : childElem->getFirstChild()->getNodeType() ==
561 : DOMNode::ELEMENT_NODE)
562 : {
563 546 : SetFieldValues(feature, childElem);
564 : }
565 : else
566 : {
567 1556 : char *fName = fieldName(childElem);
568 1556 : int fIndex = feature->GetFieldIndex(fName);
569 1556 : if (fIndex != -1)
570 : {
571 1318 : char *objVal = getObjValue(childElem);
572 1318 : if (objVal == nullptr)
573 789 : objVal = getREFValue(childElem); // only to try
574 1318 : feature->SetField(fIndex, objVal);
575 1318 : CPLFree(objVal);
576 : }
577 : else
578 : {
579 238 : CPLDebug("OGR_ILI", "Attribute '%s' not found", fName);
580 238 : m_missAttrs.push_back(fName);
581 : }
582 1556 : CPLFree(fName);
583 : }
584 : }
585 : else
586 : {
587 90 : char *fName = fieldName(childElem);
588 90 : int fIndex = feature->GetGeomFieldIndex(fName);
589 90 : OGRGeometry *geom = getGeometry(childElem, type);
590 90 : if (geom)
591 : {
592 90 : if (fIndex == -1)
593 : { // Unknown model
594 27 : feature->SetGeometryDirectly(geom);
595 : }
596 : else
597 : {
598 : OGRwkbGeometryType geomType =
599 63 : feature->GetGeomFieldDefnRef(fIndex)->GetType();
600 63 : if (geomType == wkbMultiLineString ||
601 : geomType == wkbPolygon)
602 : {
603 19 : feature->SetGeomFieldDirectly(
604 19 : fIndex, geom->getLinearGeometry());
605 19 : delete geom;
606 : }
607 : else
608 : {
609 44 : feature->SetGeomFieldDirectly(fIndex, geom);
610 : }
611 : }
612 : }
613 90 : CPLFree(fName);
614 : }
615 : }
616 1037 : }
617 :
618 : //
619 : // ILI2Reader
620 : //
621 3 : IILI2Reader::~IILI2Reader()
622 : {
623 3 : }
624 :
625 3 : ILI2Reader::ILI2Reader()
626 : : m_pszFilename(nullptr), m_poILI2Handler(nullptr), m_poSAXReader(nullptr),
627 3 : m_bReadStarted(FALSE), m_bXercesInitialized(false)
628 : {
629 3 : SetupParser();
630 3 : }
631 :
632 6 : ILI2Reader::~ILI2Reader()
633 : {
634 3 : CPLFree(m_pszFilename);
635 :
636 3 : CleanupParser();
637 :
638 3 : if (m_bXercesInitialized)
639 3 : OGRDeinitializeXerces();
640 6 : }
641 :
642 3 : void ILI2Reader::SetSourceFile(const char *pszFilename)
643 : {
644 3 : CPLFree(m_pszFilename);
645 3 : m_pszFilename = CPLStrdup(pszFilename);
646 3 : }
647 :
648 3 : int ILI2Reader::SetupParser()
649 : {
650 :
651 3 : if (!m_bXercesInitialized)
652 : {
653 3 : if (!OGRInitializeXerces())
654 0 : return FALSE;
655 3 : m_bXercesInitialized = true;
656 : }
657 :
658 : // Cleanup any old parser.
659 3 : if (m_poSAXReader != nullptr)
660 0 : CleanupParser();
661 :
662 : // Create and initialize parser.
663 3 : m_poSAXReader = XMLReaderFactory::createXMLReader();
664 :
665 3 : m_poILI2Handler = new ILI2Handler(this);
666 :
667 3 : m_poSAXReader->setContentHandler(m_poILI2Handler);
668 3 : m_poSAXReader->setErrorHandler(m_poILI2Handler);
669 3 : m_poSAXReader->setLexicalHandler(m_poILI2Handler);
670 3 : m_poSAXReader->setEntityResolver(m_poILI2Handler);
671 3 : m_poSAXReader->setDTDHandler(m_poILI2Handler);
672 3 : m_poSAXReader->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution,
673 3 : true);
674 :
675 : /* No Validation
676 : #if (OGR_ILI2_VALIDATION)
677 : m_poSAXReader->setFeature(
678 : XMLString::transcode("http://xml.org/sax/features/validation"),
679 : true); m_poSAXReader->setFeature(
680 : XMLString::transcode("http://xml.org/sax/features/namespaces"),
681 : true);
682 :
683 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
684 : m_poSAXReader->setFeature( XMLUni::fgXercesSchema, true );
685 :
686 : // m_poSAXReader->setDoSchema(true);
687 : // m_poSAXReader->setValidationSchemaFullChecking(true);
688 : #else
689 : */
690 : XMLCh *tmpCh =
691 3 : XMLString::transcode("http://xml.org/sax/features/validation");
692 3 : m_poSAXReader->setFeature(tmpCh, false);
693 3 : XMLString::release(&tmpCh);
694 3 : tmpCh = XMLString::transcode("http://xml.org/sax/features/namespaces");
695 3 : m_poSAXReader->setFeature(tmpCh, false);
696 3 : XMLString::release(&tmpCh);
697 : // #endif
698 :
699 3 : m_bReadStarted = FALSE;
700 :
701 3 : return TRUE;
702 : }
703 :
704 3 : void ILI2Reader::CleanupParser()
705 : {
706 3 : if (m_poSAXReader == nullptr)
707 0 : return;
708 :
709 3 : delete m_poSAXReader;
710 3 : m_poSAXReader = nullptr;
711 :
712 3 : delete m_poILI2Handler;
713 3 : m_poILI2Handler = nullptr;
714 :
715 3 : m_bReadStarted = FALSE;
716 : }
717 :
718 3 : int ILI2Reader::SaveClasses(const char *pszFile = nullptr)
719 : {
720 :
721 : // Add logic later to determine reasonable default schema file.
722 3 : if (pszFile == nullptr)
723 0 : return FALSE;
724 :
725 3 : VSILFILE *fp = VSIFOpenL(pszFile, "rb");
726 3 : if (fp == nullptr)
727 0 : return FALSE;
728 :
729 3 : InputSource *is = OGRCreateXercesInputSource(fp);
730 :
731 : // parse and create layers and features
732 : try
733 : {
734 3 : CPLDebug("OGR_ILI", "Parsing %s", pszFile);
735 3 : m_poSAXReader->parse(*is);
736 3 : VSIFCloseL(fp);
737 3 : OGRDestroyXercesInputSource(is);
738 : }
739 0 : catch (const DOMException &toCatch)
740 : {
741 : // Can happen with createElement() in ILI2Handler::startElement()
742 0 : CPLError(CE_Failure, CPLE_AppDefined, "DOMException: %s\n",
743 0 : transcode(toCatch.getMessage()).c_str());
744 0 : VSIFCloseL(fp);
745 0 : OGRDestroyXercesInputSource(is);
746 0 : return FALSE;
747 : }
748 0 : catch (const SAXException &toCatch)
749 : {
750 0 : CPLError(CE_Failure, CPLE_AppDefined, "Parsing failed: %s\n",
751 0 : transcode(toCatch.getMessage()).c_str());
752 0 : VSIFCloseL(fp);
753 0 : OGRDestroyXercesInputSource(is);
754 0 : return FALSE;
755 : }
756 :
757 3 : if (!m_missAttrs.empty())
758 : {
759 1 : m_missAttrs.sort();
760 1 : m_missAttrs.unique();
761 2 : string attrs = "";
762 1 : list<string>::const_iterator it;
763 3 : for (it = m_missAttrs.begin(); it != m_missAttrs.end(); ++it)
764 2 : attrs += *it + ", ";
765 :
766 1 : CPLError(CE_Warning, CPLE_NotSupported,
767 : "Failed to add new definition to existing layers, attributes "
768 : "not saved: %s",
769 : attrs.c_str());
770 : }
771 :
772 3 : return TRUE;
773 : }
774 :
775 71 : std::vector<std::unique_ptr<OGRLayer>> &ILI2Reader::GetLayers()
776 : {
777 71 : return m_listLayer;
778 : }
779 :
780 39 : int ILI2Reader::GetLayerCount()
781 : {
782 39 : return static_cast<int>(m_listLayer.size());
783 : }
784 :
785 491 : OGRLayer *ILI2Reader::GetLayer(const char *pszName)
786 : {
787 5354 : for (auto it = m_listLayer.rbegin(); it != m_listLayer.rend(); ++it)
788 : {
789 5348 : const OGRFeatureDefn *fDef = (*it)->GetLayerDefn();
790 5348 : if (cmpStr(fDef->GetName(), pszName) == 0)
791 : {
792 485 : return it->get();
793 : }
794 : }
795 6 : return nullptr;
796 : }
797 :
798 491 : int ILI2Reader::AddFeature(DOMElement *elem)
799 : {
800 982 : CPLString osName(transcode(elem->getTagName()));
801 : // CPLDebug( "OGR_ILI", "Reading layer: %s", osName.c_str() );
802 :
803 : // test if this layer exist
804 491 : OGRILI2Layer *curLayer = cpl::down_cast<OGRILI2Layer *>(GetLayer(osName));
805 491 : const bool needsNewLayer = (curLayer == nullptr);
806 0 : std::unique_ptr<OGRILI2Layer> newLayer;
807 :
808 : // add a layer
809 491 : if (needsNewLayer)
810 : {
811 6 : CPLDebug("OGR_ILI", "Adding layer: %s", osName.c_str());
812 6 : OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(osName);
813 6 : poFeatureDefn->SetGeomType(wkbUnknown);
814 12 : GeomFieldInfos oGeomFieldInfos;
815 6 : newLayer = std::make_unique<OGRILI2Layer>(poFeatureDefn,
816 6 : oGeomFieldInfos, nullptr);
817 6 : curLayer = newLayer.get();
818 : }
819 :
820 : // the feature and field definition
821 491 : OGRFeatureDefn *featureDef = curLayer->GetLayerDefn();
822 491 : if (needsNewLayer)
823 : {
824 : // add TID field
825 12 : OGRFieldDefn ofieldDefn(ILI2_TID, OFTString);
826 6 : featureDef->AddFieldDefn(&ofieldDefn);
827 :
828 6 : setFieldDefn(featureDef, elem);
829 : }
830 :
831 : // add the features
832 491 : OGRFeature *feature = new OGRFeature(featureDef);
833 :
834 : // assign TID
835 491 : int fIndex = feature->GetFieldIndex(ILI2_TID);
836 491 : if (fIndex != -1)
837 : {
838 491 : feature->SetField(
839 982 : fIndex, transcode(elem->getAttribute(xmlch_ILI2_TID)).c_str());
840 : }
841 : else
842 : {
843 0 : CPLDebug("OGR_ILI", "'%s' not found", ILI2_TID);
844 : }
845 :
846 491 : SetFieldValues(feature, elem);
847 491 : curLayer->AddFeature(feature);
848 :
849 491 : if (needsNewLayer)
850 6 : m_listLayer.push_back(std::move(newLayer));
851 :
852 982 : return 0;
853 : }
854 :
855 3 : IILI2Reader *CreateILI2Reader()
856 : {
857 3 : return new ILI2Reader();
858 : }
859 :
860 55 : void DestroyILI2Reader(IILI2Reader *reader)
861 : {
862 55 : if (reader)
863 3 : delete reader;
864 55 : }
|