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

Generated by: LCOV version 1.14