LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/kml - kmlnode.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 354 425 83.3 %
Date: 2026-06-27 16:33:51 Functions: 30 34 88.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  KML Driver
       4             :  * Purpose:  Class for building up the node structure of the kml file.
       5             :  * Author:   Jens Oberender, j.obi@troja.net
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Jens Oberender
       9             :  * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "kmlnode.h"
      16             : 
      17             : #include <cstring>
      18             : #include <limits>
      19             : #include <memory>
      20             : #include <string>
      21             : #include <vector>
      22             : 
      23             : #include "cpl_conv.h"
      24             : #include "cpl_error.h"
      25             : #include "ogr_geometry.h"
      26             : 
      27             : /************************************************************************/
      28             : /*                            Help functions                            */
      29             : /************************************************************************/
      30             : 
      31         817 : std::string Nodetype2String(Nodetype const &type)
      32             : {
      33         817 :     if (type == Empty)
      34           0 :         return "Empty";
      35         817 :     else if (type == Rest)
      36           0 :         return "Rest";
      37         817 :     else if (type == Mixed)
      38           3 :         return "Mixed";
      39         814 :     else if (type == Point)
      40         195 :         return "Point";
      41         619 :     else if (type == LineString)
      42         250 :         return "LineString";
      43         369 :     else if (type == Polygon)
      44         369 :         return "Polygon";
      45           0 :     else if (type == MultiGeometry)
      46           0 :         return "MultiGeometry";
      47           0 :     else if (type == MultiPoint)
      48           0 :         return "MultiPoint";
      49           0 :     else if (type == MultiLineString)
      50           0 :         return "MultiLineString";
      51           0 :     else if (type == MultiPolygon)
      52           0 :         return "MultiPolygon";
      53             :     else
      54           0 :         return "Unknown";
      55             : }
      56             : 
      57      242754 : static bool isNumberDigit(const char cIn)
      58             : {
      59      236154 :     return (cIn == '-' || cIn == '+' || (cIn >= '0' && cIn <= '9') ||
      60      478908 :             cIn == '.' || cIn == 'e' || cIn == 'E');
      61             : }
      62             : 
      63        6695 : static Coordinate *ParseCoordinate(std::string const &text)
      64             : {
      65        6695 :     int pos = 0;
      66        6695 :     const char *pszStr = text.c_str();
      67        6695 :     Coordinate *psTmp = new Coordinate();
      68             : 
      69             :     // X coordinate
      70        6695 :     psTmp->dfLongitude = CPLAtof(pszStr);
      71      124651 :     while (isNumberDigit(pszStr[pos++]))
      72             :         ;
      73             : 
      74             :     // Y coordinate
      75        6695 :     if (pszStr[pos - 1] != ',')
      76             :     {
      77           0 :         delete psTmp;
      78           0 :         return nullptr;
      79             :     }
      80             : 
      81        6695 :     psTmp->dfLatitude = CPLAtof(pszStr + pos);
      82      118103 :     while (isNumberDigit(pszStr[pos++]))
      83             :         ;
      84             : 
      85             :     // Z coordinate
      86        6695 :     if (pszStr[pos - 1] != ',')
      87             :     {
      88          88 :         psTmp->bHasZ = false;
      89          88 :         psTmp->dfAltitude = 0;
      90          88 :         return psTmp;
      91             :     }
      92             : 
      93        6607 :     psTmp->bHasZ = true;
      94        6607 :     psTmp->dfAltitude = CPLAtof(pszStr + pos);
      95             : 
      96        6607 :     return psTmp;
      97             : }
      98             : 
      99             : /************************************************************************/
     100             : /*                           KMLNode methods                            */
     101             : /************************************************************************/
     102             : 
     103        5675 : KMLNode::KMLNode()
     104        5675 :     : pvpoChildren_(new std::vector<KMLNode *>),
     105        5675 :       pvsContent_(new std::vector<std::string>)
     106             : {
     107        5675 : }
     108             : 
     109        5675 : KMLNode::~KMLNode()
     110             : {
     111        5675 :     CPLAssert(nullptr != pvpoChildren_);
     112             : 
     113        5675 :     kml_nodes_t::iterator itChild;
     114        7730 :     for (itChild = pvpoChildren_->begin(); itChild != pvpoChildren_->end();
     115        2055 :          ++itChild)
     116             :     {
     117        2055 :         delete (*itChild);
     118             :     }
     119        5675 :     delete pvpoChildren_;
     120             : 
     121        5675 :     kml_attributes_t::iterator itAttr;
     122        7126 :     for (itAttr = voAttributes_.begin(); itAttr != voAttributes_.end();
     123        1451 :          ++itAttr)
     124             :     {
     125        1451 :         delete (*itAttr);
     126             :     }
     127             : 
     128        5675 :     delete pvsContent_;
     129        5675 : }
     130             : 
     131           0 : void KMLNode::print(unsigned int what)
     132             : {
     133           0 :     std::string indent;
     134           0 :     for (std::size_t l = 0; l < nLevel_; l++)
     135           0 :         indent += " ";
     136             : 
     137           0 :     if (nLevel_ > 0)
     138             :     {
     139           0 :         if (nLayerNumber_ > -1)
     140             :         {
     141           0 :             CPLDebug("KML",
     142             :                      "%s%s (nLevel: %d Type: %s poParent: %s "
     143             :                      "pvpoChildren_: %d pvsContent_: %d pvoAttributes_: %d) "
     144             :                      "<--- Layer #%d",
     145           0 :                      indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
     146           0 :                      Nodetype2String(eType_).c_str(), poParent_->sName_.c_str(),
     147           0 :                      static_cast<int>(pvpoChildren_->size()),
     148           0 :                      static_cast<int>(pvsContent_->size()),
     149           0 :                      static_cast<int>(voAttributes_.size()), nLayerNumber_);
     150             :         }
     151             :         else
     152             :         {
     153           0 :             CPLDebug("KML",
     154             :                      "%s%s (nLevel: %d Type: %s poParent: %s "
     155             :                      "pvpoChildren_: %d pvsContent_: %d pvoAttributes_: %d)",
     156           0 :                      indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
     157           0 :                      Nodetype2String(eType_).c_str(), poParent_->sName_.c_str(),
     158           0 :                      static_cast<int>(pvpoChildren_->size()),
     159           0 :                      static_cast<int>(pvsContent_->size()),
     160           0 :                      static_cast<int>(voAttributes_.size()));
     161             :         }
     162             :     }
     163             :     else
     164             :     {
     165           0 :         CPLDebug("KML",
     166             :                  "%s%s (nLevel: %d Type: %s pvpoChildren_: %d "
     167             :                  "pvsContent_: %d pvoAttributes_: %d)",
     168           0 :                  indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
     169           0 :                  Nodetype2String(eType_).c_str(),
     170           0 :                  static_cast<int>(pvpoChildren_->size()),
     171           0 :                  static_cast<int>(pvsContent_->size()),
     172           0 :                  static_cast<int>(voAttributes_.size()));
     173             :     }
     174             : 
     175           0 :     if (what == 1 || what == 3)
     176             :     {
     177           0 :         for (kml_content_t::size_type z = 0; z < pvsContent_->size(); z++)
     178           0 :             CPLDebug("KML", "%s|->pvsContent_: '%s'", indent.c_str(),
     179           0 :                      (*pvsContent_)[z].c_str());
     180             :     }
     181             : 
     182           0 :     if (what == 2 || what == 3)
     183             :     {
     184           0 :         for (kml_attributes_t::size_type z = 0; z < voAttributes_.size(); z++)
     185           0 :             CPLDebug("KML", "%s|->pvoAttributes_: %s = '%s'", indent.c_str(),
     186           0 :                      voAttributes_[z]->sName.c_str(),
     187           0 :                      voAttributes_[z]->sValue.c_str());
     188             :     }
     189             : 
     190           0 :     for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
     191           0 :         (*pvpoChildren_)[z]->print(what);
     192           0 : }
     193             : 
     194        2011 : int KMLNode::classify(KML *poKML, int nRecLevel)
     195             : {
     196        2011 :     Nodetype all = Empty;
     197             : 
     198             :     /* Arbitrary value, but certainly large enough for reasonable usages ! */
     199        2011 :     if (nRecLevel == 32)
     200             :     {
     201           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     202             :                  "Too many recursion levels (%d) while parsing KML geometry.",
     203             :                  nRecLevel);
     204           0 :         return FALSE;
     205             :     }
     206             : 
     207        2011 :     if (sName_.compare("Point") == 0)
     208          64 :         eType_ = Point;
     209        1947 :     else if (sName_.compare("LineString") == 0)
     210          78 :         eType_ = LineString;
     211        1869 :     else if (sName_.compare("Polygon") == 0)
     212         113 :         eType_ = Polygon;
     213        1756 :     else if (poKML->isRest(sName_))
     214         261 :         eType_ = Empty;
     215        1495 :     else if (sName_.compare("coordinates") == 0)
     216             :     {
     217        2374 :         for (unsigned int nCountP = 0; nCountP < pvsContent_->size(); nCountP++)
     218             :         {
     219        2106 :             const char *pszCoord = (*pvsContent_)[nCountP].c_str();
     220        2106 :             int nComma = 0;
     221             :             while (true)
     222             :             {
     223        4117 :                 pszCoord = strchr(pszCoord, ',');
     224        6223 :                 if (pszCoord)
     225             :                 {
     226        4117 :                     nComma++;
     227        4117 :                     pszCoord++;
     228             :                 }
     229             :                 else
     230        2106 :                     break;
     231             :             }
     232        2106 :             if (nComma == 2)
     233        2011 :                 b25D_ = true;
     234             :         }
     235             :     }
     236        1227 :     else if (sName_.compare("Schema") == 0)
     237           1 :         eType_ = Schema;
     238        1226 :     else if (sName_.compare("SimpleField") == 0)
     239           3 :         eType_ = SimpleField;
     240        1223 :     else if (sName_.compare("SchemaData") == 0)
     241           1 :         eType_ = SchemaData;
     242        1222 :     else if (sName_.compare("SimpleData") == 0)
     243           3 :         eType_ = SimpleData;
     244             : 
     245        2011 :     const kml_nodes_t::size_type size = pvpoChildren_->size();
     246        3998 :     for (kml_nodes_t::size_type z = 0; z < size; z++)
     247             :     {
     248             :         // Classify pvpoChildren_
     249        1987 :         if (!(*pvpoChildren_)[z]->classify(poKML, nRecLevel + 1))
     250           0 :             return FALSE;
     251             : 
     252        1987 :         Nodetype curr = (*pvpoChildren_)[z]->eType_;
     253        1987 :         if (curr == SchemaData || curr == SimpleData)
     254           4 :             continue;
     255        1983 :         b25D_ |= (*pvpoChildren_)[z]->b25D_;
     256             : 
     257             :         // Compare and return if it is mixed
     258        1983 :         if (curr != all && all != Empty && curr != Empty)
     259             :         {
     260          92 :             if (sName_.compare("MultiGeometry") == 0 ||
     261          90 :                 sName_.compare("MultiPolygon") == 0 ||
     262         137 :                 sName_.compare("MultiLineString") == 0 ||
     263          45 :                 sName_.compare("MultiPoint") == 0)
     264           2 :                 eType_ = MultiGeometry;
     265             :             else
     266          45 :                 eType_ = Mixed;
     267             :         }
     268        1936 :         else if (curr != Empty)
     269             :         {
     270         589 :             all = curr;
     271             :         }
     272             :     }
     273             : 
     274        2011 :     if (eType_ == Unknown)
     275             :     {
     276        2929 :         if (sName_.compare("MultiGeometry") == 0 ||
     277        2919 :             sName_.compare("MultiPolygon") == 0 ||
     278        4388 :             sName_.compare("MultiLineString") == 0 ||
     279        1458 :             sName_.compare("MultiPoint") == 0)
     280             :         {
     281          12 :             if (all == Point)
     282           4 :                 eType_ = MultiPoint;
     283           8 :             else if (all == LineString)
     284           3 :                 eType_ = MultiLineString;
     285           5 :             else if (all == Polygon)
     286           3 :                 eType_ = MultiPolygon;
     287             :             else
     288           2 :                 eType_ = MultiGeometry;
     289             :         }
     290             :         else
     291        1457 :             eType_ = all;
     292             :     }
     293             : 
     294        2011 :     return TRUE;
     295             : }
     296             : 
     297         116 : void KMLNode::unregisterLayerIfMatchingThisNode(KML *poKML)
     298             : {
     299         190 :     for (std::size_t z = 0; z < countChildren(); z++)
     300             :     {
     301          74 :         getChild(z)->unregisterLayerIfMatchingThisNode(poKML);
     302             :     }
     303         116 :     poKML->unregisterLayerIfMatchingThisNode(this);
     304         116 : }
     305             : 
     306        1884 : void KMLNode::eliminateEmpty(KML *poKML)
     307             : {
     308        3787 :     for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size();)
     309             :     {
     310        3166 :         if ((*pvpoChildren_)[z]->eType_ == Empty &&
     311        1263 :             (poKML->isContainer((*pvpoChildren_)[z]->sName_) ||
     312        1239 :              poKML->isFeatureContainer((*pvpoChildren_)[z]->sName_)))
     313             :         {
     314          42 :             (*pvpoChildren_)[z]->unregisterLayerIfMatchingThisNode(poKML);
     315          42 :             delete (*pvpoChildren_)[z];
     316          42 :             pvpoChildren_->erase(pvpoChildren_->begin() + z);
     317             :         }
     318             :         else
     319             :         {
     320        1861 :             (*pvpoChildren_)[z]->eliminateEmpty(poKML);
     321        1861 :             ++z;
     322             :         }
     323             :     }
     324        1884 : }
     325             : 
     326          44 : bool KMLNode::hasOnlyEmpty() const
     327             : {
     328          64 :     for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
     329             :     {
     330          40 :         if ((*pvpoChildren_)[z]->eType_ != Empty)
     331             :         {
     332          20 :             return false;
     333             :         }
     334             :         else
     335             :         {
     336          20 :             if (!(*pvpoChildren_)[z]->hasOnlyEmpty())
     337           0 :                 return false;
     338             :         }
     339             :     }
     340             : 
     341          24 :     return true;
     342             : }
     343             : 
     344           0 : void KMLNode::setType(Nodetype oNotet)
     345             : {
     346           0 :     eType_ = oNotet;
     347           0 : }
     348             : 
     349        2182 : Nodetype KMLNode::getType() const
     350             : {
     351        2182 :     return eType_;
     352             : }
     353             : 
     354        5675 : void KMLNode::setName(std::string const &sIn)
     355             : {
     356        5675 :     sName_ = sIn;
     357        5675 : }
     358             : 
     359       18672 : const std::string &KMLNode::getName() const
     360             : {
     361       18672 :     return sName_;
     362             : }
     363             : 
     364        5675 : void KMLNode::setLevel(std::size_t nLev)
     365             : {
     366        5675 :     nLevel_ = nLev;
     367        5675 : }
     368             : 
     369           0 : std::size_t KMLNode::getLevel() const
     370             : {
     371           0 :     return nLevel_;
     372             : }
     373             : 
     374        1451 : void KMLNode::addAttribute(Attribute *poAttr)
     375             : {
     376        1451 :     voAttributes_.push_back(poAttr);
     377        1451 : }
     378             : 
     379        5650 : void KMLNode::setParent(KMLNode *poPar)
     380             : {
     381        5650 :     poParent_ = poPar;
     382        5650 : }
     383             : 
     384       11325 : KMLNode *KMLNode::getParent() const
     385             : {
     386       11325 :     return poParent_;
     387             : }
     388             : 
     389        2097 : void KMLNode::addChildren(KMLNode *poChil)
     390             : {
     391        2097 :     pvpoChildren_->push_back(poChil);
     392        2097 : }
     393             : 
     394        4691 : std::size_t KMLNode::countChildren() const
     395             : {
     396        4691 :     return pvpoChildren_->size();
     397             : }
     398             : 
     399        3127 : KMLNode *KMLNode::getChild(std::size_t index) const
     400             : {
     401        3127 :     return (*pvpoChildren_)[index];
     402             : }
     403             : 
     404        9210 : void KMLNode::addContent(std::string const &text)
     405             : {
     406        9210 :     pvsContent_->push_back(text);
     407        9210 : }
     408             : 
     409       19046 : void KMLNode::appendContent(std::string const &text)
     410             : {
     411       19046 :     pvsContent_->back() += text;
     412       19046 : }
     413             : 
     414        5246 : const std::string &KMLNode::getContent(std::size_t index) const
     415             : {
     416        5246 :     return (*pvsContent_)[index];
     417             : }
     418             : 
     419        2124 : void KMLNode::deleteContent(std::size_t index)
     420             : {
     421        2124 :     if (index < pvsContent_->size())
     422             :     {
     423        2124 :         pvsContent_->erase(pvsContent_->begin() + index);
     424             :     }
     425        2124 : }
     426             : 
     427       30235 : std::size_t KMLNode::numContent() const
     428             : {
     429       30235 :     return pvsContent_->size();
     430             : }
     431             : 
     432          84 : void KMLNode::setLayerNumber(int nNum)
     433             : {
     434          84 :     nLayerNumber_ = nNum;
     435          84 : }
     436             : 
     437           0 : int KMLNode::getLayerNumber() const
     438             : {
     439           0 :     return nLayerNumber_;
     440             : }
     441             : 
     442         836 : std::string KMLNode::getNameElement() const
     443             : {
     444         836 :     const kml_nodes_t::size_type size = pvpoChildren_->size();
     445             : 
     446         873 :     for (kml_nodes_t::size_type i = 0; i < size; ++i)
     447             :     {
     448         836 :         if ((*pvpoChildren_)[i]->sName_.compare("name") == 0)
     449             :         {
     450         799 :             const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
     451         799 :             if (subsize > 0)
     452             :             {
     453         799 :                 return (*(*pvpoChildren_)[i]->pvsContent_)[0];
     454             :             }
     455           0 :             break;
     456             :         }
     457             :     }
     458          37 :     return "";
     459             : }
     460             : 
     461         753 : std::string KMLNode::getDescriptionElement() const
     462             : {
     463         753 :     const kml_nodes_t::size_type size = pvpoChildren_->size();
     464        1879 :     for (kml_nodes_t::size_type i = 0; i < size; ++i)
     465             :     {
     466        1474 :         if ((*pvpoChildren_)[i]->sName_.compare("description") == 0)
     467             :         {
     468         348 :             const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
     469         348 :             if (subsize > 0)
     470             :             {
     471         348 :                 return (*(*pvpoChildren_)[i]->pvsContent_)[0];
     472             :             }
     473           0 :             break;
     474             :         }
     475             :     }
     476         405 :     return "";
     477             : }
     478             : 
     479        1021 : std::size_t KMLNode::getNumFeatures()
     480             : {
     481        1021 :     if (nNumFeatures_ == std::numeric_limits<size_t>::max())
     482             :     {
     483          28 :         nNumFeatures_ = 0;
     484          28 :         kml_nodes_t::size_type size = pvpoChildren_->size();
     485             : 
     486         157 :         for (kml_nodes_t::size_type i = 0; i < size; ++i)
     487             :         {
     488         129 :             if ((*pvpoChildren_)[i]->sName_ == "Placemark")
     489          89 :                 nNumFeatures_++;
     490             :         }
     491             :     }
     492        1021 :     return nNumFeatures_;
     493             : }
     494             : 
     495         771 : OGRGeometry *KMLNode::getGeometry(Nodetype eType)
     496             : {
     497         771 :     OGRGeometry *poGeom = nullptr;
     498         771 :     KMLNode *poCoor = nullptr;
     499         771 :     Coordinate *psCoord = nullptr;
     500             : 
     501         771 :     if (sName_.compare("Point") == 0)
     502             :     {
     503             :         // Search coordinate Element
     504         241 :         for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
     505             :         {
     506         239 :             if ((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
     507             :             {
     508         173 :                 poCoor = (*pvpoChildren_)[nCount];
     509         173 :                 for (unsigned int nCountP = 0;
     510         173 :                      nCountP < poCoor->pvsContent_->size(); nCountP++)
     511             :                 {
     512         172 :                     psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
     513         172 :                     if (psCoord != nullptr)
     514             :                     {
     515         172 :                         if (psCoord->bHasZ)
     516         162 :                             poGeom = new OGRPoint(psCoord->dfLongitude,
     517             :                                                   psCoord->dfLatitude,
     518         162 :                                                   psCoord->dfAltitude);
     519             :                         else
     520          10 :                             poGeom = new OGRPoint(psCoord->dfLongitude,
     521          10 :                                                   psCoord->dfLatitude);
     522         172 :                         delete psCoord;
     523         172 :                         return poGeom;
     524             :                     }
     525             :                 }
     526             :             }
     527             :         }
     528           2 :         poGeom = new OGRPoint();
     529             :     }
     530         597 :     else if (sName_.compare("LineString") == 0)
     531             :     {
     532             :         // Search coordinate Element
     533         243 :         poGeom = new OGRLineString();
     534         625 :         for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
     535             :         {
     536         382 :             if ((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
     537             :             {
     538         242 :                 poCoor = (*pvpoChildren_)[nCount];
     539        1984 :                 for (unsigned int nCountP = 0;
     540        1984 :                      nCountP < poCoor->pvsContent_->size(); nCountP++)
     541             :                 {
     542        1742 :                     psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
     543        1742 :                     if (psCoord != nullptr)
     544             :                     {
     545        1742 :                         if (psCoord->bHasZ)
     546        1728 :                             poGeom->toLineString()->addPoint(
     547             :                                 psCoord->dfLongitude, psCoord->dfLatitude,
     548             :                                 psCoord->dfAltitude);
     549             :                         else
     550          14 :                             poGeom->toLineString()->addPoint(
     551             :                                 psCoord->dfLongitude, psCoord->dfLatitude);
     552        1742 :                         delete psCoord;
     553             :                     }
     554             :                 }
     555             :             }
     556             :         }
     557             :     }
     558         354 :     else if (sName_.compare("Polygon") == 0)
     559             :     {
     560             :         //*********************************
     561             :         // Search outerBoundaryIs Element
     562             :         //*********************************
     563         340 :         poGeom = new OGRPolygon();
     564        1056 :         for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
     565             :         {
     566         716 :             if ((*pvpoChildren_)[nCount]->sName_.compare("outerBoundaryIs") ==
     567        1055 :                     0 &&
     568         339 :                 !(*pvpoChildren_)[nCount]->pvpoChildren_->empty())
     569             :             {
     570         338 :                 poCoor = (*(*pvpoChildren_)[nCount]->pvpoChildren_)[0];
     571             :             }
     572             :         }
     573             :         // No outer boundary found
     574         340 :         if (poCoor == nullptr)
     575             :         {
     576           2 :             return poGeom;
     577             :         }
     578             :         // Search coordinate Element
     579         338 :         OGRLinearRing *poLinearRing = nullptr;
     580         675 :         for (unsigned int nCount = 0; nCount < poCoor->pvpoChildren_->size();
     581             :              nCount++)
     582             :         {
     583         337 :             if ((*poCoor->pvpoChildren_)[nCount]->sName_.compare(
     584         337 :                     "coordinates") == 0)
     585             :             {
     586        4837 :                 for (unsigned int nCountP = 0;
     587        4837 :                      nCountP <
     588        4837 :                      (*poCoor->pvpoChildren_)[nCount]->pvsContent_->size();
     589             :                      nCountP++)
     590             :                 {
     591        9000 :                     psCoord = ParseCoordinate((*(*poCoor->pvpoChildren_)[nCount]
     592        4500 :                                                     ->pvsContent_)[nCountP]);
     593        4500 :                     if (psCoord != nullptr)
     594             :                     {
     595        4500 :                         if (poLinearRing == nullptr)
     596             :                         {
     597         336 :                             poLinearRing = new OGRLinearRing();
     598             :                         }
     599        4500 :                         if (psCoord->bHasZ)
     600        4453 :                             poLinearRing->addPoint(psCoord->dfLongitude,
     601             :                                                    psCoord->dfLatitude,
     602             :                                                    psCoord->dfAltitude);
     603             :                         else
     604          47 :                             poLinearRing->addPoint(psCoord->dfLongitude,
     605             :                                                    psCoord->dfLatitude);
     606        4500 :                         delete psCoord;
     607             :                     }
     608             :                 }
     609             :             }
     610             :         }
     611             :         // No outer boundary coordinates found
     612         338 :         if (poLinearRing == nullptr)
     613             :         {
     614           2 :             return poGeom;
     615             :         }
     616             : 
     617         336 :         poGeom->toPolygon()->addRingDirectly(poLinearRing);
     618         336 :         poLinearRing = nullptr;
     619             : 
     620             :         //*********************************
     621             :         // Search innerBoundaryIs Elements
     622             :         //*********************************
     623             : 
     624        1049 :         for (unsigned int nCount2 = 0; nCount2 < pvpoChildren_->size();
     625             :              nCount2++)
     626             :         {
     627         713 :             if ((*pvpoChildren_)[nCount2]->sName_.compare("innerBoundaryIs") ==
     628             :                 0)
     629             :             {
     630          51 :                 if (poLinearRing)
     631           0 :                     poGeom->toPolygon()->addRingDirectly(poLinearRing);
     632          51 :                 poLinearRing = nullptr;
     633             : 
     634          51 :                 if ((*pvpoChildren_)[nCount2]->pvpoChildren_->empty())
     635           1 :                     continue;
     636             : 
     637          50 :                 poLinearRing = new OGRLinearRing();
     638             : 
     639          50 :                 poCoor = (*(*pvpoChildren_)[nCount2]->pvpoChildren_)[0];
     640             :                 // Search coordinate Element
     641          99 :                 for (unsigned int nCount = 0;
     642          99 :                      nCount < poCoor->pvpoChildren_->size(); nCount++)
     643             :                 {
     644          49 :                     if ((*poCoor->pvpoChildren_)[nCount]->sName_.compare(
     645          49 :                             "coordinates") == 0)
     646             :                     {
     647         330 :                         for (unsigned int nCountP = 0;
     648         660 :                              nCountP < (*poCoor->pvpoChildren_)[nCount]
     649         330 :                                            ->pvsContent_->size();
     650             :                              nCountP++)
     651             :                         {
     652         281 :                             psCoord = ParseCoordinate(
     653         281 :                                 (*(*poCoor->pvpoChildren_)[nCount]
     654         281 :                                       ->pvsContent_)[nCountP]);
     655         281 :                             if (psCoord != nullptr)
     656             :                             {
     657         281 :                                 if (psCoord->bHasZ)
     658         264 :                                     poLinearRing->addPoint(psCoord->dfLongitude,
     659             :                                                            psCoord->dfLatitude,
     660             :                                                            psCoord->dfAltitude);
     661             :                                 else
     662          17 :                                     poLinearRing->addPoint(psCoord->dfLongitude,
     663             :                                                            psCoord->dfLatitude);
     664         281 :                                 delete psCoord;
     665             :                             }
     666             :                         }
     667             :                     }
     668             :                 }
     669             :             }
     670             :         }
     671             : 
     672         336 :         if (poLinearRing)
     673          50 :             poGeom->toPolygon()->addRingDirectly(poLinearRing);
     674             :     }
     675          17 :     else if (sName_.compare("MultiGeometry") == 0 ||
     676           5 :              sName_.compare("MultiPolygon") == 0 ||
     677          19 :              sName_.compare("MultiLineString") == 0 ||
     678           1 :              sName_.compare("MultiPoint") == 0)
     679             :     {
     680          14 :         if (eType == MultiPoint)
     681           4 :             poGeom = new OGRMultiPoint();
     682          10 :         else if (eType == MultiLineString)
     683           3 :             poGeom = new OGRMultiLineString();
     684           7 :         else if (eType == MultiPolygon)
     685           3 :             poGeom = new OGRMultiPolygon();
     686             :         else
     687           4 :             poGeom = new OGRGeometryCollection();
     688          32 :         for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
     689             :         {
     690          18 :             OGRGeometry *poSubGeom = (*pvpoChildren_)[nCount]->getGeometry();
     691          18 :             if (poSubGeom)
     692          18 :                 poGeom->toGeometryCollection()->addGeometryDirectly(poSubGeom);
     693             :         }
     694             :     }
     695             : 
     696         595 :     return poGeom;
     697             : }
     698             : 
     699         960 : Feature *KMLNode::getFeature(std::size_t nNum, int &nLastAsked, int &nLastCount)
     700             : {
     701         960 :     if (nNum >= getNumFeatures())
     702         207 :         return nullptr;
     703             : 
     704         753 :     unsigned int nCount = 0;
     705         753 :     unsigned int nCountP = 0;
     706         753 :     KMLNode *poFeat = nullptr;
     707         753 :     KMLNode *poTemp = nullptr;
     708             : 
     709         753 :     if (nLastAsked + 1 != static_cast<int>(nNum))
     710             :     {
     711             :         // nCount = 0;
     712             :         // nCountP = 0;
     713             :     }
     714             :     else
     715             :     {
     716         753 :         nCount = nLastCount + 1;
     717         753 :         nCountP = nLastAsked + 1;
     718             :     }
     719             : 
     720        1313 :     for (; nCount < pvpoChildren_->size(); nCount++)
     721             :     {
     722        1313 :         if ((*pvpoChildren_)[nCount]->sName_.compare("Placemark") == 0)
     723             :         {
     724         753 :             if (nCountP == nNum)
     725             :             {
     726         753 :                 poFeat = (*pvpoChildren_)[nCount];
     727         753 :                 break;
     728             :             }
     729           0 :             nCountP++;
     730             :         }
     731             :     }
     732             : 
     733         753 :     nLastAsked = static_cast<int>(nNum);
     734         753 :     nLastCount = nCount;
     735             : 
     736         753 :     if (poFeat == nullptr)
     737           0 :         return nullptr;
     738             : 
     739             :     // Create a feature structure
     740         753 :     Feature *psReturn = new Feature;
     741             :     // Build up the name
     742         753 :     psReturn->sName = poFeat->getNameElement();
     743             :     // Build up the description
     744         753 :     psReturn->sDescription = poFeat->getDescriptionElement();
     745             :     // the type
     746         753 :     psReturn->eType = poFeat->eType_;
     747             : 
     748        2575 :     for (nCount = 0; nCount < poFeat->pvpoChildren_->size(); nCount++)
     749             :     {
     750        1822 :         const auto poChild = (*poFeat->pvpoChildren_)[nCount];
     751        1822 :         const auto &sName = poChild->sName_;
     752        1823 :         if (sName == "ExtendedData" && poChild->pvpoChildren_->size() == 1 &&
     753           1 :             (*poChild->pvpoChildren_)[0]->sName_ == "SchemaData")
     754             :         {
     755           1 :             const auto poChild2 = (*poChild->pvpoChildren_)[0];
     756           4 :             for (size_t j = 0; j < poChild2->pvpoChildren_->size(); ++j)
     757             :             {
     758           3 :                 const auto poChild3 = (*poChild2->pvpoChildren_)[j];
     759           6 :                 if (poChild3->sName_ == "SimpleData" &&
     760           3 :                     poChild3->numContent() == 1)
     761             :                 {
     762           6 :                     std::string osAttrName;
     763           6 :                     for (const auto *poAttr : poChild3->getAttributes())
     764             :                     {
     765           3 :                         if (poAttr->sName == "name")
     766           3 :                             osAttrName = poAttr->sValue;
     767             :                     }
     768           3 :                     if (!osAttrName.empty())
     769             :                     {
     770           3 :                         psReturn->oFields[osAttrName] = poChild3->getContent(0);
     771             :                     }
     772             :                 }
     773             :             }
     774             :         }
     775             :     }
     776             : 
     777        1506 :     std::string sElementName;
     778         753 :     if (poFeat->eType_ == Point || poFeat->eType_ == LineString ||
     779         350 :         poFeat->eType_ == Polygon)
     780         739 :         sElementName = Nodetype2String(poFeat->eType_);
     781          14 :     else if (poFeat->eType_ == MultiGeometry || poFeat->eType_ == MultiPoint ||
     782           6 :              poFeat->eType_ == MultiLineString ||
     783           3 :              poFeat->eType_ == MultiPolygon)
     784          14 :         sElementName = "MultiGeometry";
     785             :     else
     786             :     {
     787           0 :         delete psReturn;
     788           0 :         return nullptr;
     789             :     }
     790             : 
     791        1822 :     for (nCount = 0; nCount < poFeat->pvpoChildren_->size(); nCount++)
     792             :     {
     793        1822 :         const auto &sName = (*poFeat->pvpoChildren_)[nCount]->sName_;
     794        2897 :         if (sName.compare(sElementName) == 0 ||
     795        1075 :             (sElementName == "MultiGeometry" &&
     796           6 :              (sName == "MultiPolygon" || sName == "MultiLineString" ||
     797           1 :               sName == "MultiPoint")))
     798             :         {
     799         753 :             poTemp = (*poFeat->pvpoChildren_)[nCount];
     800         753 :             psReturn->poGeom.reset(poTemp->getGeometry(poFeat->eType_));
     801         753 :             if (psReturn->poGeom)
     802         753 :                 return psReturn;
     803             :             else
     804             :             {
     805           0 :                 delete psReturn;
     806           0 :                 return nullptr;
     807             :             }
     808             :         }
     809             :     }
     810             : 
     811           0 :     delete psReturn;
     812           0 :     return nullptr;
     813             : }

Generated by: LCOV version 1.14