LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/kml - kml.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 286 366 78.1 %
Date: 2024-04-27 17:22:41 Functions: 23 32 71.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  KML Driver
       4             :  * Purpose:  Class for reading, parsing and handling a kmlfile.
       5             :  * Author:   Jens Oberender, j.obi@troja.net
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Jens Oberender
       9             :  * Copyright (c) 2008-2013, 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             : #include "kmlnode.h"
      30             : #include "kml.h"
      31             : 
      32             : #include <cstring>
      33             : #include <cstdio>
      34             : #include <exception>
      35             : #include <iostream>
      36             : #include <string>
      37             : 
      38             : #include "cpl_conv.h"
      39             : #include "cpl_error.h"
      40             : #ifdef HAVE_EXPAT
      41             : #include "expat.h"
      42             : #endif
      43             : 
      44             : constexpr int PARSER_BUF_SIZE = 8192;
      45             : 
      46          25 : KML::KML()
      47             :     : poTrunk_(nullptr), nNumLayers_(-1), papoLayers_(nullptr), nDepth_(0),
      48             :       validity(KML_VALIDITY_UNKNOWN), pKMLFile_(nullptr), poCurrent_(nullptr),
      49          25 :       oCurrentParser(nullptr), nDataHandlerCounter(0), nWithoutEventCounter(0)
      50             : {
      51          25 : }
      52             : 
      53          25 : KML::~KML()
      54             : {
      55          25 :     if (nullptr != pKMLFile_)
      56          25 :         VSIFCloseL(pKMLFile_);
      57          25 :     CPLFree(papoLayers_);
      58             : 
      59          25 :     delete poTrunk_;
      60          25 : }
      61             : 
      62          25 : bool KML::open(const char *pszFilename)
      63             : {
      64          25 :     if (nullptr != pKMLFile_)
      65           0 :         VSIFCloseL(pKMLFile_);
      66             : 
      67          25 :     pKMLFile_ = VSIFOpenL(pszFilename, "r");
      68          25 :     return pKMLFile_ != nullptr;
      69             : }
      70             : 
      71          24 : bool KML::parse()
      72             : {
      73          24 :     if (nullptr == pKMLFile_)
      74             :     {
      75           0 :         sError_ = "No file given";
      76           0 :         return false;
      77             :     }
      78             : 
      79          24 :     if (poTrunk_ != nullptr)
      80             :     {
      81           0 :         delete poTrunk_;
      82           0 :         poTrunk_ = nullptr;
      83             :     }
      84             : 
      85          24 :     if (poCurrent_ != nullptr)
      86             :     {
      87           0 :         delete poCurrent_;
      88           0 :         poCurrent_ = nullptr;
      89             :     }
      90             : 
      91          24 :     XML_Parser oParser = OGRCreateExpatXMLParser();
      92          24 :     XML_SetUserData(oParser, this);
      93          24 :     XML_SetElementHandler(oParser, startElement, endElement);
      94          24 :     XML_SetCharacterDataHandler(oParser, dataHandler);
      95          24 :     oCurrentParser = oParser;
      96          24 :     nWithoutEventCounter = 0;
      97             : 
      98          24 :     int nDone = 0;
      99          24 :     int nLen = 0;
     100          48 :     std::vector<char> aBuf(PARSER_BUF_SIZE);
     101          24 :     bool bError = false;
     102             : 
     103          45 :     do
     104             :     {
     105          69 :         nDataHandlerCounter = 0;
     106          69 :         nLen = (int)VSIFReadL(aBuf.data(), 1, aBuf.size(), pKMLFile_);
     107          69 :         nDone = VSIFEofL(pKMLFile_);
     108          69 :         if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR)
     109             :         {
     110           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     111             :                      "XML parsing of KML file failed : %s at line %d, "
     112             :                      "column %d",
     113             :                      XML_ErrorString(XML_GetErrorCode(oParser)),
     114           1 :                      static_cast<int>(XML_GetCurrentLineNumber(oParser)),
     115           1 :                      static_cast<int>(XML_GetCurrentColumnNumber(oParser)));
     116           1 :             bError = true;
     117           1 :             break;
     118             :         }
     119          68 :         nWithoutEventCounter++;
     120          68 :     } while (!nDone && nLen > 0 && nWithoutEventCounter < 10);
     121             : 
     122          24 :     XML_ParserFree(oParser);
     123          24 :     VSIRewindL(pKMLFile_);
     124             : 
     125          24 :     if (nWithoutEventCounter == 10)
     126             :     {
     127           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     128             :                  "Too much data inside one element. File probably corrupted");
     129           0 :         bError = true;
     130             :     }
     131             : 
     132          24 :     if (bError)
     133             :     {
     134           1 :         if (poCurrent_ != nullptr)
     135             :         {
     136           0 :             while (poCurrent_)
     137             :             {
     138           0 :                 KMLNode *poTemp = poCurrent_->getParent();
     139           0 :                 delete poCurrent_;
     140           0 :                 poCurrent_ = poTemp;
     141             :             }
     142             :             // No need to destroy poTrunk_ : it has been destroyed in
     143             :             // the last iteration
     144             :         }
     145             :         else
     146             :         {
     147             :             // Case of invalid content after closing element matching
     148             :             // first <kml> element
     149           1 :             delete poTrunk_;
     150             :         }
     151           1 :         poTrunk_ = nullptr;
     152           1 :         return false;
     153             :     }
     154             : 
     155          23 :     poCurrent_ = nullptr;
     156          23 :     return true;
     157             : }
     158             : 
     159          25 : void KML::checkValidity()
     160             : {
     161          25 :     if (poTrunk_ != nullptr)
     162             :     {
     163           0 :         delete poTrunk_;
     164           0 :         poTrunk_ = nullptr;
     165             :     }
     166             : 
     167          25 :     if (poCurrent_ != nullptr)
     168             :     {
     169           0 :         delete poCurrent_;
     170           0 :         poCurrent_ = nullptr;
     171             :     }
     172             : 
     173          25 :     if (pKMLFile_ == nullptr)
     174             :     {
     175           0 :         sError_ = "No file given";
     176           1 :         return;
     177             :     }
     178             : 
     179          25 :     XML_Parser oParser = OGRCreateExpatXMLParser();
     180          25 :     XML_SetUserData(oParser, this);
     181          25 :     XML_SetElementHandler(oParser, startElementValidate, nullptr);
     182          25 :     XML_SetCharacterDataHandler(oParser, dataHandlerValidate);
     183          25 :     int nCount = 0;
     184             : 
     185          25 :     oCurrentParser = oParser;
     186             : 
     187          25 :     int nDone = 0;
     188          25 :     int nLen = 0;
     189          50 :     std::vector<char> aBuf(PARSER_BUF_SIZE);
     190             : 
     191             :     // Parses the file until we find the first element.
     192           0 :     do
     193             :     {
     194          25 :         nDataHandlerCounter = 0;
     195          25 :         nLen =
     196          25 :             static_cast<int>(VSIFReadL(aBuf.data(), 1, aBuf.size(), pKMLFile_));
     197          25 :         nDone = VSIFEofL(pKMLFile_);
     198          25 :         if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR)
     199             :         {
     200           1 :             if (nLen <= PARSER_BUF_SIZE - 1)
     201           1 :                 aBuf[nLen] = 0;
     202             :             else
     203           0 :                 aBuf[PARSER_BUF_SIZE - 1] = 0;
     204           2 :             if (strstr(aBuf.data(), "<?xml") &&
     205           1 :                 (strstr(aBuf.data(), "<kml") ||
     206           0 :                  (strstr(aBuf.data(), "<Document") &&
     207           0 :                   strstr(aBuf.data(), "/kml/2."))))
     208             :             {
     209           1 :                 CPLError(
     210             :                     CE_Failure, CPLE_AppDefined,
     211             :                     "XML parsing of KML file failed : %s at line %d, column %d",
     212             :                     XML_ErrorString(XML_GetErrorCode(oParser)),
     213           1 :                     (int)XML_GetCurrentLineNumber(oParser),
     214           1 :                     (int)XML_GetCurrentColumnNumber(oParser));
     215             :             }
     216             : 
     217           1 :             validity = KML_VALIDITY_INVALID;
     218           1 :             XML_ParserFree(oParser);
     219           1 :             VSIRewindL(pKMLFile_);
     220           1 :             return;
     221             :         }
     222             : 
     223          24 :         nCount++;
     224             :         /* After reading 50 * PARSER_BUF_SIZE bytes, and not finding whether the file */
     225             :         /* is KML or not, we give up and fail silently */
     226          24 :     } while (!nDone && nLen > 0 && validity == KML_VALIDITY_UNKNOWN &&
     227             :              nCount < 50);
     228             : 
     229          24 :     XML_ParserFree(oParser);
     230          24 :     VSIRewindL(pKMLFile_);
     231          24 :     poCurrent_ = nullptr;
     232             : }
     233             : 
     234        5664 : void XMLCALL KML::startElement(void *pUserData, const char *pszName,
     235             :                                const char **ppszAttr)
     236             : {
     237        5664 :     KML *poKML = static_cast<KML *>(pUserData);
     238             :     try
     239             :     {
     240        5664 :         poKML->nWithoutEventCounter = 0;
     241             : 
     242        5664 :         const char *pszColumn = strchr(pszName, ':');
     243        5664 :         if (pszColumn)
     244           5 :             pszName = pszColumn + 1;
     245             : 
     246       11304 :         if (poKML->poTrunk_ == nullptr ||
     247       11280 :             (poKML->poCurrent_ != nullptr &&
     248        5640 :              poKML->poCurrent_->getName().compare("description") != 0))
     249             :         {
     250        5659 :             if (poKML->nDepth_ == 1024)
     251             :             {
     252           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     253             :                          "Too big depth level (%d) while parsing KML.",
     254             :                          poKML->nDepth_);
     255           0 :                 XML_StopParser(poKML->oCurrentParser, XML_FALSE);
     256           0 :                 return;
     257             :             }
     258             : 
     259        5659 :             KMLNode *poMynew = new KMLNode();
     260        5659 :             poMynew->setName(pszName);
     261        5659 :             poMynew->setLevel(poKML->nDepth_);
     262             : 
     263        7086 :             for (int i = 0; ppszAttr[i]; i += 2)
     264             :             {
     265        1427 :                 Attribute *poAtt = new Attribute();
     266        1427 :                 poAtt->sName = ppszAttr[i];
     267        1427 :                 poAtt->sValue = ppszAttr[i + 1];
     268        1427 :                 poMynew->addAttribute(poAtt);
     269             :             }
     270             : 
     271        5659 :             if (poKML->poTrunk_ == nullptr)
     272          24 :                 poKML->poTrunk_ = poMynew;
     273        5659 :             if (poKML->poCurrent_ != nullptr)
     274        5635 :                 poMynew->setParent(poKML->poCurrent_);
     275        5659 :             poKML->poCurrent_ = poMynew;
     276             : 
     277        5659 :             poKML->nDepth_++;
     278             :         }
     279           5 :         else if (poKML->poCurrent_ != nullptr)
     280             :         {
     281          10 :             std::string sNewContent = "<";
     282           5 :             sNewContent += pszName;
     283           6 :             for (int i = 0; ppszAttr[i]; i += 2)
     284             :             {
     285           1 :                 sNewContent += " ";
     286           1 :                 sNewContent += ppszAttr[i];
     287           1 :                 sNewContent += "=\"";
     288           1 :                 sNewContent += ppszAttr[i + 1];
     289           1 :                 sNewContent += "\"";
     290             :             }
     291           5 :             sNewContent += ">";
     292           5 :             if (poKML->poCurrent_->numContent() == 0)
     293           0 :                 poKML->poCurrent_->addContent(sNewContent);
     294             :             else
     295           5 :                 poKML->poCurrent_->appendContent(sNewContent);
     296             :         }
     297             :     }
     298           0 :     catch (const std::exception &ex)
     299             :     {
     300           0 :         CPLError(CE_Failure, CPLE_AppDefined, "KML: libstdc++ exception : %s",
     301           0 :                  ex.what());
     302           0 :         XML_StopParser(poKML->oCurrentParser, XML_FALSE);
     303             :     }
     304             : }
     305             : 
     306        2053 : void XMLCALL KML::startElementValidate(void *pUserData, const char *pszName,
     307             :                                        const char **ppszAttr)
     308             : {
     309        2053 :     KML *poKML = static_cast<KML *>(pUserData);
     310             : 
     311        2053 :     if (poKML->validity != KML_VALIDITY_UNKNOWN)
     312        2028 :         return;
     313             : 
     314          25 :     poKML->validity = KML_VALIDITY_INVALID;
     315             : 
     316          25 :     const char *pszColumn = strchr(pszName, ':');
     317          25 :     if (pszColumn)
     318           1 :         pszName = pszColumn + 1;
     319             : 
     320          25 :     if (strcmp(pszName, "kml") == 0 || strcmp(pszName, "Document") == 0)
     321             :     {
     322             :         // Check all Attributes
     323          53 :         for (int i = 0; ppszAttr[i]; i += 2)
     324             :         {
     325             :             // Find the namespace and determine the KML version
     326          28 :             if (strcmp(ppszAttr[i], "xmlns") == 0)
     327             :             {
     328             :                 // Is it KML 2.2?
     329          23 :                 if ((strcmp(ppszAttr[i + 1],
     330          23 :                             "http://earth.google.com/kml/2.2") == 0) ||
     331          23 :                     (strcmp(ppszAttr[i + 1],
     332             :                             "http://www.opengis.net/kml/2.2") == 0))
     333             :                 {
     334           9 :                     poKML->validity = KML_VALIDITY_VALID;
     335           9 :                     poKML->sVersion_ = "2.2";
     336             :                 }
     337          14 :                 else if (strcmp(ppszAttr[i + 1],
     338             :                                 "http://earth.google.com/kml/2.1") == 0)
     339             :                 {
     340          14 :                     poKML->validity = KML_VALIDITY_VALID;
     341          14 :                     poKML->sVersion_ = "2.1";
     342             :                 }
     343           0 :                 else if (strcmp(ppszAttr[i + 1],
     344             :                                 "http://earth.google.com/kml/2.0") == 0)
     345             :                 {
     346           0 :                     poKML->validity = KML_VALIDITY_VALID;
     347           0 :                     poKML->sVersion_ = "2.0";
     348             :                 }
     349             :                 else
     350             :                 {
     351           0 :                     CPLDebug("KML",
     352             :                              "Unhandled xmlns value : %s. Going on though...",
     353           0 :                              ppszAttr[i]);
     354           0 :                     poKML->validity = KML_VALIDITY_VALID;
     355           0 :                     poKML->sVersion_ = "?";
     356             :                 }
     357             :             }
     358             :         }
     359             : 
     360          25 :         if (poKML->validity == KML_VALIDITY_INVALID)
     361             :         {
     362           2 :             CPLDebug("KML", "Did not find xmlns attribute in <kml> element. "
     363             :                             "Going on though...");
     364           2 :             poKML->validity = KML_VALIDITY_VALID;
     365           2 :             poKML->sVersion_ = "?";
     366             :         }
     367             :     }
     368             : }
     369             : 
     370        7634 : void XMLCALL KML::dataHandlerValidate(void *pUserData,
     371             :                                       const char * /* pszData */,
     372             :                                       int /* nLen */)
     373             : {
     374        7634 :     KML *poKML = static_cast<KML *>(pUserData);
     375             : 
     376        7634 :     poKML->nDataHandlerCounter++;
     377        7634 :     if (poKML->nDataHandlerCounter >= PARSER_BUF_SIZE)
     378             :     {
     379           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     380             :                  "File probably corrupted (million laugh pattern)");
     381           0 :         XML_StopParser(poKML->oCurrentParser, XML_FALSE);
     382             :     }
     383        7634 : }
     384             : 
     385        5664 : void XMLCALL KML::endElement(void *pUserData, const char *pszName)
     386             : {
     387        5664 :     KML *poKML = static_cast<KML *>(pUserData);
     388             : 
     389             :     try
     390             :     {
     391        5664 :         poKML->nWithoutEventCounter = 0;
     392             : 
     393        5664 :         const char *pszColumn = strchr(pszName, ':');
     394        5664 :         if (pszColumn)
     395           5 :             pszName = pszColumn + 1;
     396             : 
     397       11328 :         if (poKML->poCurrent_ != nullptr &&
     398        5664 :             poKML->poCurrent_->getName().compare(pszName) == 0)
     399             :         {
     400        5659 :             poKML->nDepth_--;
     401        5659 :             KMLNode *poTmp = poKML->poCurrent_;
     402             :             // Split the coordinates
     403        5926 :             if (poKML->poCurrent_->getName().compare("coordinates") == 0 &&
     404         267 :                 poKML->poCurrent_->numContent() == 1)
     405             :             {
     406         524 :                 const std::string sData = poKML->poCurrent_->getContent(0);
     407         262 :                 std::size_t nPos = 0;
     408         262 :                 const std::size_t nLength = sData.length();
     409         262 :                 const char *pszData = sData.c_str();
     410             :                 while (true)
     411             :                 {
     412             :                     // Cut off whitespaces
     413       33866 :                     while (nPos < nLength &&
     414       33604 :                            (pszData[nPos] == ' ' || pszData[nPos] == '\n' ||
     415        2105 :                             pszData[nPos] == '\r' || pszData[nPos] == '\t'))
     416       31499 :                         nPos++;
     417             : 
     418        2367 :                     if (nPos == nLength)
     419         262 :                         break;
     420             : 
     421        2105 :                     const std::size_t nPosBegin = nPos;
     422             : 
     423             :                     // Get content
     424       81106 :                     while (nPos < nLength && pszData[nPos] != ' ' &&
     425      162061 :                            pszData[nPos] != '\n' && pszData[nPos] != '\r' &&
     426       79087 :                            pszData[nPos] != '\t')
     427       79087 :                         nPos++;
     428             : 
     429        2105 :                     if (nPos - nPosBegin > 0)
     430             :                     {
     431        4210 :                         std::string sTmp(pszData + nPosBegin, nPos - nPosBegin);
     432        2105 :                         poKML->poCurrent_->addContent(sTmp);
     433             :                     }
     434        2105 :                 }
     435         262 :                 if (poKML->poCurrent_->numContent() > 1)
     436         262 :                     poKML->poCurrent_->deleteContent(0);
     437             :             }
     438        5397 :             else if (poKML->poCurrent_->numContent() == 1)
     439             :             {
     440        9940 :                 const std::string sData = poKML->poCurrent_->getContent(0);
     441        9940 :                 std::string sDataWithoutNL;
     442        4970 :                 std::size_t nPos = 0;
     443        4970 :                 const std::size_t nLength = sData.length();
     444        4970 :                 const char *pszData = sData.c_str();
     445        4970 :                 std::size_t nLineStartPos = 0;
     446        4970 :                 bool bLineStart = true;
     447             : 
     448             :                 // Re-assemble multi-line content by removing leading spaces for
     449             :                 // each line.  I am not sure why we do that. Should we preserve
     450             :                 // content as such?
     451      173819 :                 while (nPos < nLength)
     452             :                 {
     453      168849 :                     const char ch = pszData[nPos];
     454      168849 :                     if (bLineStart &&
     455       11797 :                         (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'))
     456       80456 :                         nLineStartPos++;
     457       88393 :                     else if (ch == '\n' || ch == '\r')
     458             :                     {
     459        1244 :                         if (!bLineStart)
     460             :                         {
     461             :                             std::string sTmp(pszData + nLineStartPos,
     462        1244 :                                              nPos - nLineStartPos);
     463        1244 :                             if (!sDataWithoutNL.empty())
     464        1111 :                                 sDataWithoutNL += " ";
     465        1244 :                             sDataWithoutNL += sTmp;
     466        1244 :                             bLineStart = true;
     467             :                         }
     468        1244 :                         nLineStartPos = nPos + 1;
     469             :                     }
     470             :                     else
     471             :                     {
     472       87149 :                         bLineStart = false;
     473             :                     }
     474      168849 :                     nPos++;
     475             :                 }
     476             : 
     477        4970 :                 if (nLineStartPos > 0)
     478             :                 {
     479        1855 :                     if (nLineStartPos < nPos)
     480             :                     {
     481             :                         std::string sTmp(pszData + nLineStartPos,
     482         242 :                                          nPos - nLineStartPos);
     483         121 :                         if (!sDataWithoutNL.empty())
     484         121 :                             sDataWithoutNL += " ";
     485         121 :                         sDataWithoutNL += sTmp;
     486             :                     }
     487             : 
     488        1855 :                     poKML->poCurrent_->deleteContent(0);
     489        1855 :                     poKML->poCurrent_->addContent(sDataWithoutNL);
     490             :                 }
     491             :             }
     492             : 
     493        5659 :             if (poKML->poCurrent_->getParent() != nullptr)
     494        5635 :                 poKML->poCurrent_ = poKML->poCurrent_->getParent();
     495             :             else
     496          24 :                 poKML->poCurrent_ = nullptr;
     497             : 
     498        5659 :             if (!poKML->isHandled(pszName))
     499             :             {
     500        3553 :                 CPLDebug("KML", "Not handled: %s", pszName);
     501        3553 :                 delete poTmp;
     502        3553 :                 if (poKML->poCurrent_ == poTmp)
     503           0 :                     poKML->poCurrent_ = nullptr;
     504        3553 :                 if (poKML->poTrunk_ == poTmp)
     505           0 :                     poKML->poTrunk_ = nullptr;
     506             :             }
     507             :             else
     508             :             {
     509        2106 :                 if (poKML->poCurrent_ != nullptr)
     510        2082 :                     poKML->poCurrent_->addChildren(poTmp);
     511             :             }
     512             :         }
     513           5 :         else if (poKML->poCurrent_ != nullptr)
     514             :         {
     515          10 :             std::string sNewContent = "</";
     516           5 :             sNewContent += pszName;
     517           5 :             sNewContent += ">";
     518           5 :             if (poKML->poCurrent_->numContent() == 0)
     519           0 :                 poKML->poCurrent_->addContent(sNewContent);
     520             :             else
     521           5 :                 poKML->poCurrent_->appendContent(sNewContent);
     522             :         }
     523             :     }
     524           0 :     catch (const std::exception &ex)
     525             :     {
     526           0 :         CPLError(CE_Failure, CPLE_AppDefined, "KML: libstdc++ exception : %s",
     527           0 :                  ex.what());
     528           0 :         XML_StopParser(poKML->oCurrentParser, XML_FALSE);
     529             :     }
     530        5664 : }
     531             : 
     532       24246 : void XMLCALL KML::dataHandler(void *pUserData, const char *pszData, int nLen)
     533             : {
     534       24246 :     KML *poKML = static_cast<KML *>(pUserData);
     535             : 
     536       24246 :     poKML->nWithoutEventCounter = 0;
     537             : 
     538       24246 :     if (nLen < 1 || poKML->poCurrent_ == nullptr)
     539           0 :         return;
     540             : 
     541       24246 :     poKML->nDataHandlerCounter++;
     542       24246 :     if (poKML->nDataHandlerCounter >= PARSER_BUF_SIZE)
     543             :     {
     544           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     545             :                  "File probably corrupted (million laugh pattern)");
     546           0 :         XML_StopParser(poKML->oCurrentParser, XML_FALSE);
     547             :     }
     548             : 
     549             :     try
     550             :     {
     551       48492 :         std::string sData(pszData, nLen);
     552             : 
     553       24246 :         if (poKML->poCurrent_->numContent() == 0)
     554        5232 :             poKML->poCurrent_->addContent(sData);
     555             :         else
     556       19014 :             poKML->poCurrent_->appendContent(sData);
     557             :     }
     558           0 :     catch (const std::exception &ex)
     559             :     {
     560           0 :         CPLError(CE_Failure, CPLE_AppDefined, "KML: libstdc++ exception : %s",
     561           0 :                  ex.what());
     562           0 :         XML_StopParser(poKML->oCurrentParser, XML_FALSE);
     563             :     }
     564             : }
     565             : 
     566          25 : bool KML::isValid()
     567             : {
     568          25 :     checkValidity();
     569             : 
     570          25 :     if (validity == KML_VALIDITY_VALID)
     571          24 :         CPLDebug("KML", "Valid: 1 Version: %s", sVersion_.c_str());
     572             : 
     573          25 :     return validity == KML_VALIDITY_VALID;
     574             : }
     575             : 
     576           0 : std::string KML::getError() const
     577             : {
     578           0 :     return sError_;
     579             : }
     580             : 
     581          23 : int KML::classifyNodes()
     582             : {
     583          23 :     if (poTrunk_ == nullptr)
     584           0 :         return false;
     585          23 :     return poTrunk_->classify(this);
     586             : }
     587             : 
     588          19 : void KML::eliminateEmpty()
     589             : {
     590          19 :     if (poTrunk_ != nullptr)
     591          19 :         poTrunk_->eliminateEmpty(this);
     592          19 : }
     593             : 
     594           0 : void KML::print(unsigned short nNum)
     595             : {
     596           0 :     if (poTrunk_ != nullptr)
     597           0 :         poTrunk_->print(nNum);
     598           0 : }
     599             : 
     600        5659 : bool KML::isHandled(std::string const &elem) const
     601             : {
     602       10176 :     return isLeaf(elem) || isFeature(elem) || isFeatureContainer(elem) ||
     603       10176 :            isContainer(elem) || isRest(elem);
     604             : }
     605             : 
     606           0 : bool KML::isLeaf(std::string const & /* elem */) const
     607             : {
     608           0 :     return false;
     609             : }
     610             : 
     611           0 : bool KML::isFeature(std::string const & /* elem */) const
     612             : {
     613           0 :     return false;
     614             : }
     615             : 
     616           0 : bool KML::isFeatureContainer(std::string const & /* elem */) const
     617             : {
     618           0 :     return false;
     619             : }
     620             : 
     621           0 : bool KML::isContainer(std::string const & /* elem */) const
     622             : {
     623           0 :     return false;
     624             : }
     625             : 
     626           0 : bool KML::isRest(std::string const & /* elem */) const
     627             : {
     628           0 :     return false;
     629             : }
     630             : 
     631           0 : void KML::findLayers(KMLNode * /* poNode */, int /* bKeepEmptyContainers */)
     632             : {
     633             :     // idle
     634           0 : }
     635             : 
     636          23 : bool KML::hasOnlyEmpty() const
     637             : {
     638          23 :     return poTrunk_->hasOnlyEmpty();
     639             : }
     640             : 
     641          23 : int KML::getNumLayers() const
     642             : {
     643          23 :     return nNumLayers_;
     644             : }
     645             : 
     646         875 : bool KML::selectLayer(int nNum)
     647             : {
     648         875 :     if (nNumLayers_ < 1 || nNum >= nNumLayers_)
     649           0 :         return false;
     650         875 :     poCurrent_ = papoLayers_[nNum];
     651         875 :     return true;
     652             : }
     653             : 
     654          82 : std::string KML::getCurrentName() const
     655             : {
     656          82 :     std::string tmp;
     657          82 :     if (poCurrent_ != nullptr)
     658             :     {
     659          82 :         tmp = poCurrent_->getNameElement();
     660             :     }
     661          82 :     return tmp;
     662             : }
     663             : 
     664         202 : Nodetype KML::getCurrentType() const
     665             : {
     666         202 :     if (poCurrent_ != nullptr)
     667         202 :         return poCurrent_->getType();
     668             : 
     669           0 :     return Unknown;
     670             : }
     671             : 
     672          74 : int KML::is25D() const
     673             : {
     674          74 :     if (poCurrent_ != nullptr)
     675          74 :         return poCurrent_->is25D();
     676             : 
     677           0 :     return Unknown;
     678             : }
     679             : 
     680          61 : int KML::getNumFeatures()
     681             : {
     682          61 :     if (poCurrent_ == nullptr)
     683           0 :         return -1;
     684             : 
     685          61 :     return static_cast<int>(poCurrent_->getNumFeatures());
     686             : }
     687             : 
     688         916 : Feature *KML::getFeature(std::size_t nNum, int &nLastAsked, int &nLastCount)
     689             : {
     690         916 :     if (poCurrent_ == nullptr)
     691           0 :         return nullptr;
     692             : 
     693         916 :     return poCurrent_->getFeature(nNum, nLastAsked, nLastCount);
     694             : }
     695             : 
     696         116 : void KML::unregisterLayerIfMatchingThisNode(KMLNode *poNode)
     697             : {
     698         116 :     for (int i = 0; i < nNumLayers_;)
     699             :     {
     700           2 :         if (papoLayers_[i] == poNode)
     701             :         {
     702           2 :             if (i < nNumLayers_ - 1)
     703             :             {
     704           0 :                 memmove(papoLayers_ + i, papoLayers_ + i + 1,
     705           0 :                         (nNumLayers_ - 1 - i) * sizeof(KMLNode *));
     706             :             }
     707           2 :             nNumLayers_--;
     708           2 :             break;
     709             :         }
     710           0 :         i++;
     711             :     }
     712         116 : }

Generated by: LCOV version 1.14