LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ili - ili2reader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 314 454 69.2 %
Date: 2025-11-12 21:50:40 Functions: 30 32 93.8 %

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

Generated by: LCOV version 1.14