LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ili - ili2reader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 313 455 68.8 %
Date: 2024-11-21 22:18:42 Functions: 29 32 90.6 %

          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       40583 : int cmpStr(const string &s1, const string &s2)
      53             : {
      54       40583 :     string::const_iterator p1 = s1.begin();
      55       40583 :     string::const_iterator p2 = s2.begin();
      56             : 
      57      132372 :     while (p1 != s1.end() && p2 != s2.end())
      58             :     {
      59      124238 :         if (CPLToupper(static_cast<unsigned char>(*p1)) !=
      60      124238 :             CPLToupper(static_cast<unsigned char>(*p2)))
      61       32449 :             return (CPLToupper(static_cast<unsigned char>(*p1)) <
      62       32449 :                     CPLToupper(static_cast<unsigned char>(*p2)))
      63       32449 :                        ? -1
      64       32449 :                        : 1;
      65       91789 :         ++p1;
      66       91789 :         ++p2;
      67             :     }
      68             : 
      69        8134 :     return (s2.size() == s1.size()) ? 0 : (s1.size() < s2.size()) ? -1 : 1;
      70             : }
      71             : 
      72        6686 : string ltrim(const string &tmpstr)
      73             : {
      74        6686 :     size_t i = 0;
      75       29407 :     while (i < tmpstr.length() && (tmpstr[i] == ' ' || tmpstr[i] == '\t' ||
      76        6686 :                                    tmpstr[i] == '\r' || tmpstr[i] == '\n'))
      77       16035 :         ++i;
      78        6686 :     return i > 0 ? tmpstr.substr(i, tmpstr.length() - i) : tmpstr;
      79             : }
      80             : 
      81        6686 : string rtrim(const string &tmpstr)
      82             : {
      83        6686 :     if (tmpstr.empty())
      84        1053 :         return tmpstr;
      85        5633 :     size_t i = tmpstr.length() - 1U;
      86       11266 :     while (tmpstr[i] == ' ' || tmpstr[i] == '\t' || tmpstr[i] == '\r' ||
      87        5633 :            tmpstr[i] == '\n')
      88           0 :         --i;
      89        5633 :     return i < tmpstr.length() - 1 ? tmpstr.substr(0, i + 1) : tmpstr;
      90             : }
      91             : 
      92        6686 : string trim(const string &tmpstr)
      93             : {
      94        6686 :     auto ret = ltrim(tmpstr);
      95        6686 :     ret = rtrim(ret);
      96        6686 :     return ret;
      97             : }
      98             : }  // namespace ili2
      99             : }  // namespace gdal
     100             : 
     101             : using namespace gdal::ili2;
     102             : 
     103        4041 : static int getGeometryTypeOfElem(DOMElement *elem)
     104             : {
     105        4041 :     int type = ILI2_STRING_TYPE;
     106        4041 :     if (elem == nullptr)
     107           0 :         return type;
     108        4041 :     char *pszTagName = XMLString::transcode(elem->getTagName());
     109             : 
     110        4041 :     if (elem->getNodeType() == DOMNode::ELEMENT_NODE)
     111             :     {
     112        4041 :         if (cmpStr(ILI2_COORD, pszTagName) == 0)
     113             :         {
     114          50 :             type = ILI2_COORD_TYPE;
     115             :         }
     116        3991 :         else if (cmpStr(ILI2_ARC, pszTagName) == 0)
     117             :         {
     118           0 :             type = ILI2_ARC_TYPE;
     119             :         }
     120        3991 :         else if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
     121             :         {
     122          43 :             type = ILI2_POLYLINE_TYPE;
     123             :         }
     124        3948 :         else if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0)
     125             :         {
     126           0 :             type = ILI2_BOUNDARY_TYPE;
     127             :         }
     128        3948 :         else if (cmpStr(ILI2_AREA, pszTagName) == 0)
     129             :         {
     130           0 :             type = ILI2_AREA_TYPE;
     131             :         }
     132        3948 :         else if (cmpStr(ILI2_SURFACE, pszTagName) == 0)
     133             :         {
     134         145 :             type = ILI2_AREA_TYPE;
     135             :         }
     136             :     }
     137        4041 :     XMLString::release(&pszTagName);
     138        4041 :     return type;
     139             : }
     140             : 
     141        6100 : static char *getObjValue(DOMElement *elem)
     142             : {
     143        6100 :     DOMNode *child = elem->getFirstChild();
     144        6100 :     if ((child != nullptr) && (child->getNodeType() == DOMNode::TEXT_NODE))
     145             :     {
     146        5300 :         return CPLStrdup(transcode(child->getNodeValue()));
     147             :     }
     148             : 
     149         800 :     return nullptr;
     150             : }
     151             : 
     152         800 : static char *getREFValue(DOMElement *elem)
     153             : {
     154        1600 :     CPLString osREFValue(transcode(elem->getAttribute(ILI2_REF)));
     155        1600 :     return CPLStrdup(osREFValue);
     156             : }
     157             : 
     158        2370 : static OGRPoint *getPoint(DOMElement *elem)
     159             : {
     160             :     // elem -> COORD (or ARC)
     161        2370 :     DOMElement *coordElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
     162        2370 :     if (coordElem == nullptr)
     163           0 :         return nullptr;
     164        2370 :     OGRPoint *pt = new OGRPoint();
     165             : 
     166        7110 :     while (coordElem != nullptr)
     167             :     {
     168        4740 :         char *pszTagName = XMLString::transcode(coordElem->getTagName());
     169        4740 :         char *pszObjValue = getObjValue(coordElem);
     170        4740 :         if (pszObjValue)
     171             :         {
     172        4740 :             if (cmpStr("C1", pszTagName) == 0)
     173        2370 :                 pt->setX(CPLAtof(pszObjValue));
     174        2370 :             else if (cmpStr("C2", pszTagName) == 0)
     175        2370 :                 pt->setY(CPLAtof(pszObjValue));
     176           0 :             else if (cmpStr("C3", pszTagName) == 0)
     177           0 :                 pt->setZ(CPLAtof(pszObjValue));
     178             :         }
     179        4740 :         CPLFree(pszObjValue);
     180        4740 :         XMLString::release(&pszTagName);
     181        4740 :         coordElem = dynamic_cast<DOMElement *>(coordElem->getNextSibling());
     182             :     }
     183        2370 :     pt->flattenTo2D();
     184        2370 :     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         103 : static OGRCompoundCurve *getPolyline(DOMElement *elem)
     243             : {
     244             :     // elem -> POLYLINE
     245         103 :     OGRCompoundCurve *ogrCurve = new OGRCompoundCurve();
     246         103 :     OGRLineString *ls = new OGRLineString();
     247             : 
     248         103 :     DOMElement *lineElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
     249        2494 :     while (lineElem != nullptr)
     250             :     {
     251        2391 :         char *pszTagName = XMLString::transcode(lineElem->getTagName());
     252        2391 :         if (cmpStr(ILI2_COORD, pszTagName) == 0)
     253             :         {
     254        2346 :             OGRPoint *poPoint = getPoint(lineElem);
     255        2346 :             if (poPoint)
     256             :             {
     257        2346 :                 ls->addPoint(poPoint);
     258        2346 :                 delete poPoint;
     259             :             }
     260             :         }
     261          45 :         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        2391 :         XMLString::release(&pszTagName);
     344             : 
     345        2391 :         lineElem = dynamic_cast<DOMElement *>(lineElem->getNextSibling());
     346             :     }
     347             : 
     348         103 :     if (ls->getNumPoints() > 1)
     349             :     {
     350         103 :         ogrCurve->addCurveDirectly(ls);
     351             :     }
     352             :     else
     353             :     {
     354           0 :         delete ls;
     355             :     }
     356         103 :     return ogrCurve;
     357             : }
     358             : 
     359          82 : static OGRCompoundCurve *getBoundary(DOMElement *elem)
     360             : {
     361             : 
     362          82 :     DOMElement *lineElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
     363          82 :     if (lineElem != nullptr)
     364             :     {
     365          82 :         char *pszTagName = XMLString::transcode(lineElem->getTagName());
     366          82 :         if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
     367             :         {
     368          82 :             XMLString::release(&pszTagName);
     369          82 :             return getPolyline(lineElem);
     370             :         }
     371           0 :         XMLString::release(&pszTagName);
     372             :     }
     373             : 
     374           0 :     return new OGRCompoundCurve();
     375             : }
     376             : 
     377          72 : static OGRCurvePolygon *getPolygon(DOMElement *elem)
     378             : {
     379          72 :     OGRCurvePolygon *pg = new OGRCurvePolygon();
     380             : 
     381             :     DOMElement *boundaryElem =
     382          72 :         dynamic_cast<DOMElement *>(elem->getFirstChild());  // outer boundary
     383         154 :     while (boundaryElem != nullptr)
     384             :     {
     385          82 :         char *pszTagName = XMLString::transcode(boundaryElem->getTagName());
     386          82 :         if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0)
     387             :         {
     388          82 :             OGRCompoundCurve *poCC = getBoundary(boundaryElem);
     389          82 :             if (pg->addRingDirectly(poCC) != OGRERR_NONE)
     390             :             {
     391           0 :                 delete poCC;
     392             :             }
     393             :         }
     394          82 :         XMLString::release(&pszTagName);
     395          82 :         boundaryElem = dynamic_cast<DOMElement *>(
     396          82 :             boundaryElem->getNextSibling());  // inner boundaries
     397             :     }
     398             : 
     399          72 :     return pg;
     400             : }
     401             : 
     402         117 : OGRGeometry *ILI2Reader::getGeometry(DOMElement *elem, int type)
     403             : {
     404         117 :     OGRGeometryCollection *gm = new OGRGeometryCollection();
     405             : 
     406         117 :     DOMElement *childElem = elem;
     407         117 :     while (childElem != nullptr)
     408             :     {
     409         117 :         char *pszTagName = XMLString::transcode(childElem->getTagName());
     410         117 :         switch (type)
     411             :         {
     412          24 :             case ILI2_COORD_TYPE:
     413          24 :                 if (cmpStr(ILI2_COORD, pszTagName) == 0)
     414             :                 {
     415          24 :                     delete gm;
     416          24 :                     XMLString::release(&pszTagName);
     417         117 :                     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          21 :             case ILI2_POLYLINE_TYPE:
     431          21 :                 if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
     432             :                 {
     433          21 :                     delete gm;
     434          21 :                     XMLString::release(&pszTagName);
     435          21 :                     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          72 :             case ILI2_AREA_TYPE:
     447         216 :                 if ((cmpStr(ILI2_AREA, pszTagName) == 0) ||
     448         144 :                     (cmpStr(ILI2_SURFACE, pszTagName) == 0))
     449             :                 {
     450          72 :                     delete gm;
     451          72 :                     XMLString::release(&pszTagName);
     452          72 :                     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           3 : int ILI2Reader::ReadModel(OGRILI2DataSource *poDS, ImdReader *poImdReader,
     475             :                           const char *modelFilename)
     476             : {
     477           3 :     poImdReader->ReadModel(modelFilename);
     478          38 :     for (FeatureDefnInfos::const_iterator it =
     479           3 :              poImdReader->featureDefnInfos.begin();
     480          79 :          it != poImdReader->featureDefnInfos.end(); ++it)
     481             :     {
     482             :         OGRLayer *layer =
     483          38 :             new OGRILI2Layer(it->GetTableDefnRef(), it->poGeomFieldInfos, poDS);
     484          38 :         m_listLayer.push_back(layer);
     485             :     }
     486           3 :     return 0;
     487             : }
     488             : 
     489             : // Detect field name of value element
     490        1728 : static char *fieldName(DOMElement *elem)
     491             : {
     492        1728 :     DOMNode *node = elem;
     493        1728 :     if (getGeometryTypeOfElem(elem))
     494             :     {
     495         117 :         int depth = 0;  // Depth of value elem node
     496         702 :         for (node = elem; node; node = node->getParentNode())
     497         585 :             ++depth;
     498             :         // Field name is on level 4
     499         117 :         node = elem;
     500         234 :         for (int d = 0; d < depth - 4; ++d)
     501         117 :             node = node->getParentNode();
     502             :     }
     503        1728 :     if (node == nullptr)
     504             :     {
     505           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "node == NULL");
     506           0 :         return CPLStrdup("***bug***");
     507             :     }
     508        1728 :     return CPLStrdup(transcode(node->getNodeName()));
     509             : }
     510             : 
     511          14 : void ILI2Reader::setFieldDefn(OGRFeatureDefn *featureDef, DOMElement *elem)
     512             : {
     513          14 :     int type = 0;
     514             :     // recursively search children
     515          14 :     for (DOMNode *childNode = elem->getFirstChild();
     516          64 :          type == 0 && childNode &&
     517          25 :          childNode->getNodeType() == DOMNode::ELEMENT_NODE;
     518          25 :          childNode = childNode->getNextSibling())
     519             :     {
     520          25 :         DOMElement *childElem = dynamic_cast<DOMElement *>(childNode);
     521          25 :         CPLAssert(childElem);
     522          25 :         type = getGeometryTypeOfElem(childElem);
     523          25 :         if (type == 0)
     524             :         {
     525          39 :             if (childElem->getFirstChild() &&
     526          18 :                 childElem->getFirstChild()->getNodeType() ==
     527             :                     DOMNode::ELEMENT_NODE)
     528             :             {
     529           8 :                 setFieldDefn(featureDef, childElem);
     530             :             }
     531             :             else
     532             :             {
     533          13 :                 char *fName = fieldName(childElem);
     534          13 :                 if (featureDef->GetFieldIndex(fName) == -1)
     535             :                 {
     536          13 :                     CPLDebug("OGR_ILI", "AddFieldDefn: %s", fName);
     537          26 :                     OGRFieldDefn oFieldDefn(fName, OFTString);
     538          13 :                     featureDef->AddFieldDefn(&oFieldDefn);
     539             :                 }
     540          13 :                 CPLFree(fName);
     541             :             }
     542             :         }
     543             :     }
     544          14 : }
     545             : 
     546        1095 : void ILI2Reader::SetFieldValues(OGRFeature *feature, DOMElement *elem)
     547             : {
     548        1095 :     int type = 0;
     549             :     // recursively search children
     550        1095 :     for (DOMNode *childNode = elem->getFirstChild();
     551        5671 :          type == 0 && childNode &&
     552        2288 :          childNode->getNodeType() == DOMNode::ELEMENT_NODE;
     553        2288 :          childNode = childNode->getNextSibling())
     554             :     {
     555        2288 :         DOMElement *childElem = dynamic_cast<DOMElement *>(childNode);
     556        2288 :         CPLAssert(childElem);
     557        2288 :         type = getGeometryTypeOfElem(childElem);
     558        2288 :         if (type == 0)
     559             :         {
     560        3542 :             if (childElem->getFirstChild() &&
     561        1371 :                 childElem->getFirstChild()->getNodeType() ==
     562             :                     DOMNode::ELEMENT_NODE)
     563             :             {
     564         573 :                 SetFieldValues(feature, childElem);
     565             :             }
     566             :             else
     567             :             {
     568        1598 :                 char *fName = fieldName(childElem);
     569        1598 :                 int fIndex = feature->GetFieldIndex(fName);
     570        1598 :                 if (fIndex != -1)
     571             :                 {
     572        1360 :                     char *objVal = getObjValue(childElem);
     573        1360 :                     if (objVal == nullptr)
     574         800 :                         objVal = getREFValue(childElem);  // only to try
     575        1360 :                     feature->SetField(fIndex, objVal);
     576        1360 :                     CPLFree(objVal);
     577             :                 }
     578             :                 else
     579             :                 {
     580         238 :                     CPLDebug("OGR_ILI", "Attribute '%s' not found", fName);
     581         238 :                     m_missAttrs.push_back(fName);
     582             :                 }
     583        1598 :                 CPLFree(fName);
     584             :             }
     585             :         }
     586             :         else
     587             :         {
     588         117 :             char *fName = fieldName(childElem);
     589         117 :             int fIndex = feature->GetGeomFieldIndex(fName);
     590         117 :             OGRGeometry *geom = getGeometry(childElem, type);
     591         117 :             if (geom)
     592             :             {
     593         117 :                 if (fIndex == -1)
     594             :                 {  // Unknown model
     595          27 :                     feature->SetGeometryDirectly(geom);
     596             :                 }
     597             :                 else
     598             :                 {
     599             :                     OGRwkbGeometryType geomType =
     600          90 :                         feature->GetGeomFieldDefnRef(fIndex)->GetType();
     601          90 :                     if (geomType == wkbMultiLineString ||
     602             :                         geomType == wkbPolygon)
     603             :                     {
     604          38 :                         feature->SetGeomFieldDirectly(
     605          38 :                             fIndex, geom->getLinearGeometry());
     606          38 :                         delete geom;
     607             :                     }
     608             :                     else
     609             :                     {
     610          52 :                         feature->SetGeomFieldDirectly(fIndex, geom);
     611             :                     }
     612             :                 }
     613             :             }
     614         117 :             CPLFree(fName);
     615             :         }
     616             :     }
     617        1095 : }
     618             : 
     619             : //
     620             : // ILI2Reader
     621             : //
     622           4 : IILI2Reader::~IILI2Reader()
     623             : {
     624           4 : }
     625             : 
     626           4 : ILI2Reader::ILI2Reader()
     627             :     : m_pszFilename(nullptr), m_poILI2Handler(nullptr), m_poSAXReader(nullptr),
     628           4 :       m_bReadStarted(FALSE), m_bXercesInitialized(false)
     629             : {
     630           4 :     SetupParser();
     631           4 : }
     632             : 
     633           8 : ILI2Reader::~ILI2Reader()
     634             : {
     635           4 :     CPLFree(m_pszFilename);
     636             : 
     637           4 :     CleanupParser();
     638             : 
     639           4 :     if (m_bXercesInitialized)
     640           4 :         OGRDeinitializeXerces();
     641             : 
     642           4 :     list<OGRLayer *>::const_iterator layerIt = m_listLayer.begin();
     643          48 :     while (layerIt != m_listLayer.end())
     644             :     {
     645          44 :         OGRILI2Layer *tmpLayer = (OGRILI2Layer *)*layerIt;
     646          44 :         delete tmpLayer;
     647          44 :         ++layerIt;
     648             :     }
     649           8 : }
     650             : 
     651           4 : void ILI2Reader::SetSourceFile(const char *pszFilename)
     652             : {
     653           4 :     CPLFree(m_pszFilename);
     654           4 :     m_pszFilename = CPLStrdup(pszFilename);
     655           4 : }
     656             : 
     657           4 : int ILI2Reader::SetupParser()
     658             : {
     659             : 
     660           4 :     if (!m_bXercesInitialized)
     661             :     {
     662           4 :         if (!OGRInitializeXerces())
     663           0 :             return FALSE;
     664           4 :         m_bXercesInitialized = true;
     665             :     }
     666             : 
     667             :     // Cleanup any old parser.
     668           4 :     if (m_poSAXReader != nullptr)
     669           0 :         CleanupParser();
     670             : 
     671             :     // Create and initialize parser.
     672           4 :     m_poSAXReader = XMLReaderFactory::createXMLReader();
     673             : 
     674           4 :     m_poILI2Handler = new ILI2Handler(this);
     675             : 
     676           4 :     m_poSAXReader->setContentHandler(m_poILI2Handler);
     677           4 :     m_poSAXReader->setErrorHandler(m_poILI2Handler);
     678           4 :     m_poSAXReader->setLexicalHandler(m_poILI2Handler);
     679           4 :     m_poSAXReader->setEntityResolver(m_poILI2Handler);
     680           4 :     m_poSAXReader->setDTDHandler(m_poILI2Handler);
     681           4 :     m_poSAXReader->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution,
     682           4 :                               true);
     683             : 
     684             :     /* No Validation
     685             :     #if (OGR_ILI2_VALIDATION)
     686             :         m_poSAXReader->setFeature(
     687             :             XMLString::transcode("http://xml.org/sax/features/validation"),
     688             :     true); m_poSAXReader->setFeature(
     689             :             XMLString::transcode("http://xml.org/sax/features/namespaces"),
     690             :     true);
     691             : 
     692             :         m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
     693             :         m_poSAXReader->setFeature( XMLUni::fgXercesSchema, true );
     694             : 
     695             :     //    m_poSAXReader->setDoSchema(true);
     696             :     //    m_poSAXReader->setValidationSchemaFullChecking(true);
     697             :     #else
     698             :     */
     699             :     XMLCh *tmpCh =
     700           4 :         XMLString::transcode("http://xml.org/sax/features/validation");
     701           4 :     m_poSAXReader->setFeature(tmpCh, false);
     702           4 :     XMLString::release(&tmpCh);
     703           4 :     tmpCh = XMLString::transcode("http://xml.org/sax/features/namespaces");
     704           4 :     m_poSAXReader->setFeature(tmpCh, false);
     705           4 :     XMLString::release(&tmpCh);
     706             :     // #endif
     707             : 
     708           4 :     m_bReadStarted = FALSE;
     709             : 
     710           4 :     return TRUE;
     711             : }
     712             : 
     713           4 : void ILI2Reader::CleanupParser()
     714             : {
     715           4 :     if (m_poSAXReader == nullptr)
     716           0 :         return;
     717             : 
     718           4 :     delete m_poSAXReader;
     719           4 :     m_poSAXReader = nullptr;
     720             : 
     721           4 :     delete m_poILI2Handler;
     722           4 :     m_poILI2Handler = nullptr;
     723             : 
     724           4 :     m_bReadStarted = FALSE;
     725             : }
     726             : 
     727           4 : int ILI2Reader::SaveClasses(const char *pszFile = nullptr)
     728             : {
     729             : 
     730             :     // Add logic later to determine reasonable default schema file.
     731           4 :     if (pszFile == nullptr)
     732           0 :         return FALSE;
     733             : 
     734           4 :     VSILFILE *fp = VSIFOpenL(pszFile, "rb");
     735           4 :     if (fp == nullptr)
     736           0 :         return FALSE;
     737             : 
     738           4 :     InputSource *is = OGRCreateXercesInputSource(fp);
     739             : 
     740             :     // parse and create layers and features
     741             :     try
     742             :     {
     743           4 :         CPLDebug("OGR_ILI", "Parsing %s", pszFile);
     744           4 :         m_poSAXReader->parse(*is);
     745           4 :         VSIFCloseL(fp);
     746           4 :         OGRDestroyXercesInputSource(is);
     747             :     }
     748           0 :     catch (const DOMException &toCatch)
     749             :     {
     750             :         // Can happen with createElement() in ILI2Handler::startElement()
     751           0 :         CPLError(CE_Failure, CPLE_AppDefined, "DOMException: %s\n",
     752           0 :                  transcode(toCatch.getMessage()).c_str());
     753           0 :         VSIFCloseL(fp);
     754           0 :         OGRDestroyXercesInputSource(is);
     755           0 :         return FALSE;
     756             :     }
     757           0 :     catch (const SAXException &toCatch)
     758             :     {
     759           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Parsing failed: %s\n",
     760           0 :                  transcode(toCatch.getMessage()).c_str());
     761           0 :         VSIFCloseL(fp);
     762           0 :         OGRDestroyXercesInputSource(is);
     763           0 :         return FALSE;
     764             :     }
     765             : 
     766           4 :     if (!m_missAttrs.empty())
     767             :     {
     768           1 :         m_missAttrs.sort();
     769           1 :         m_missAttrs.unique();
     770           2 :         string attrs = "";
     771           1 :         list<string>::const_iterator it;
     772           3 :         for (it = m_missAttrs.begin(); it != m_missAttrs.end(); ++it)
     773           2 :             attrs += *it + ", ";
     774             : 
     775           1 :         CPLError(CE_Warning, CPLE_NotSupported,
     776             :                  "Failed to add new definition to existing layers, attributes "
     777             :                  "not saved: %s",
     778             :                  attrs.c_str());
     779             :     }
     780             : 
     781           4 :     return TRUE;
     782             : }
     783             : 
     784           4 : list<OGRLayer *> ILI2Reader::GetLayers()
     785             : {
     786           4 :     return m_listLayer;
     787             : }
     788             : 
     789           0 : int ILI2Reader::GetLayerCount()
     790             : {
     791           0 :     return static_cast<int>(m_listLayer.size());
     792             : }
     793             : 
     794         522 : OGRLayer *ILI2Reader::GetLayer(const char *pszName)
     795             : {
     796        6681 :     for (list<OGRLayer *>::reverse_iterator layerIt = m_listLayer.rbegin();
     797       12840 :          layerIt != m_listLayer.rend(); ++layerIt)
     798             :     {
     799        6675 :         OGRFeatureDefn *fDef = (*layerIt)->GetLayerDefn();
     800        6675 :         if (cmpStr(fDef->GetName(), pszName) == 0)
     801             :         {
     802         516 :             return *layerIt;
     803             :         }
     804             :     }
     805           6 :     return nullptr;
     806             : }
     807             : 
     808         522 : int ILI2Reader::AddFeature(DOMElement *elem)
     809             : {
     810         522 :     CPLString osName(transcode(elem->getTagName()));
     811             :     // CPLDebug( "OGR_ILI", "Reading layer: %s", osName.c_str() );
     812             : 
     813             :     // test if this layer exist
     814         522 :     OGRILI2Layer *curLayer = dynamic_cast<OGRILI2Layer *>(GetLayer(osName));
     815         522 :     bool newLayer = (curLayer == nullptr);
     816             : 
     817             :     // add a layer
     818         522 :     if (newLayer)
     819             :     {
     820           6 :         CPLDebug("OGR_ILI", "Adding layer: %s", osName.c_str());
     821           6 :         OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(osName);
     822           6 :         poFeatureDefn->SetGeomType(wkbUnknown);
     823           6 :         GeomFieldInfos oGeomFieldInfos;
     824           6 :         curLayer = new OGRILI2Layer(poFeatureDefn, oGeomFieldInfos, nullptr);
     825           6 :         m_listLayer.push_back(curLayer);
     826             :     }
     827             : 
     828             :     // the feature and field definition
     829         522 :     OGRFeatureDefn *featureDef = curLayer->GetLayerDefn();
     830         522 :     if (newLayer)
     831             :     {
     832             :         // add TID field
     833          12 :         OGRFieldDefn ofieldDefn(ILI2_TID, OFTString);
     834           6 :         featureDef->AddFieldDefn(&ofieldDefn);
     835             : 
     836           6 :         setFieldDefn(featureDef, elem);
     837             :     }
     838             : 
     839             :     // add the features
     840         522 :     OGRFeature *feature = new OGRFeature(featureDef);
     841             : 
     842             :     // assign TID
     843         522 :     int fIndex = feature->GetFieldIndex(ILI2_TID);
     844         522 :     if (fIndex != -1)
     845             :     {
     846         522 :         feature->SetField(
     847        1044 :             fIndex, transcode(elem->getAttribute(xmlch_ILI2_TID)).c_str());
     848             :     }
     849             :     else
     850             :     {
     851           0 :         CPLDebug("OGR_ILI", "'%s' not found", ILI2_TID);
     852             :     }
     853             : 
     854         522 :     SetFieldValues(feature, elem);
     855         522 :     curLayer->AddFeature(feature);
     856             : 
     857        1044 :     return 0;
     858             : }
     859             : 
     860           4 : IILI2Reader *CreateILI2Reader()
     861             : {
     862           4 :     return new ILI2Reader();
     863             : }
     864             : 
     865          81 : void DestroyILI2Reader(IILI2Reader *reader)
     866             : {
     867          81 :     if (reader)
     868           4 :         delete reader;
     869          81 : }

Generated by: LCOV version 1.14