LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/svg - ogrsvglayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 333 406 82.0 %
Date: 2024-11-21 22:18:42 Functions: 23 24 95.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  SVG Translator
       4             :  * Purpose:  Implements OGRSVGLayer class.
       5             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogr_svg.h"
      14             : #include "cpl_conv.h"
      15             : 
      16             : /************************************************************************/
      17             : /*                            OGRSVGLayer()                             */
      18             : /************************************************************************/
      19             : 
      20           3 : OGRSVGLayer::OGRSVGLayer(const char *pszFilename, const char *pszLayerName,
      21             :                          SVGGeometryType svgGeomTypeIn,
      22             : #ifndef HAVE_EXPAT
      23             :                          CPL_UNUSED
      24             : #endif
      25           3 :                              OGRSVGDataSource *poDSIn)
      26             :     : poFeatureDefn(nullptr), poSRS(nullptr),
      27             : #ifdef HAVE_EXPAT
      28             :       poDS(poDSIn),
      29             : #endif
      30             :       osLayerName(pszLayerName), svgGeomType(svgGeomTypeIn), nTotalFeatures(0),
      31             :       nNextFID(0), fpSVG(nullptr),
      32             : #ifdef HAVE_EXPAT
      33             :       oParser(nullptr), oSchemaParser(nullptr),
      34             : #endif
      35             :       pszSubElementValue(nullptr), nSubElementValueLen(0), iCurrentField(0),
      36             :       poFeature(nullptr), ppoFeatureTab(nullptr), nFeatureTabLength(0),
      37             :       nFeatureTabIndex(0), depthLevel(0), interestingDepthLevel(0),
      38             :       inInterestingElement(false), bStopParsing(false)
      39             : #ifdef HAVE_EXPAT
      40             :       ,
      41           3 :       nWithoutEventCounter(0), nDataHandlerCounter(0), poCurLayer(nullptr)
      42             : #endif
      43             : 
      44             : {
      45           3 :     SetDescription(pszLayerName);
      46             : 
      47           3 :     poSRS = new OGRSpatialReference(
      48             :         "PROJCS[\"WGS 84 / Pseudo-Mercator\","
      49             :         "GEOGCS[\"WGS 84\","
      50             :         "    DATUM[\"WGS_1984\","
      51             :         "        SPHEROID[\"WGS 84\",6378137,298.257223563,"
      52             :         "            AUTHORITY[\"EPSG\",\"7030\"]],"
      53             :         "        AUTHORITY[\"EPSG\",\"6326\"]],"
      54             :         "    PRIMEM[\"Greenwich\",0,"
      55             :         "        AUTHORITY[\"EPSG\",\"8901\"]],"
      56             :         "    UNIT[\"degree\",0.0174532925199433,"
      57             :         "        AUTHORITY[\"EPSG\",\"9122\"]],"
      58             :         "    AUTHORITY[\"EPSG\",\"4326\"]],"
      59             :         "UNIT[\"metre\",1,"
      60             :         "    AUTHORITY[\"EPSG\",\"9001\"]],"
      61             :         "PROJECTION[\"Mercator_1SP\"],"
      62             :         "PARAMETER[\"central_meridian\",0],"
      63             :         "PARAMETER[\"scale_factor\",1],"
      64             :         "PARAMETER[\"false_easting\",0],"
      65             :         "PARAMETER[\"false_northing\",0],"
      66             :         "EXTENSION[\"PROJ4\",\"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 "
      67             :         "+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  "
      68             :         "+no_defs\"],"
      69             :         "AUTHORITY[\"EPSG\",\"3857\"],"
      70             :         "AXIS[\"X\",EAST],"
      71           3 :         "AXIS[\"Y\",NORTH]]");
      72           3 :     poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      73             : 
      74           3 :     fpSVG = VSIFOpenL(pszFilename, "r");
      75           3 :     if (fpSVG == nullptr)
      76             :     {
      77           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s", pszFilename);
      78           0 :         return;
      79             :     }
      80             : 
      81           3 :     OGRSVGLayer::ResetReading();
      82             : }
      83             : 
      84             : /************************************************************************/
      85             : /*                            ~OGRSVGLayer()                            */
      86             : /************************************************************************/
      87             : 
      88           6 : OGRSVGLayer::~OGRSVGLayer()
      89             : 
      90             : {
      91             : #ifdef HAVE_EXPAT
      92           3 :     if (oParser)
      93           3 :         XML_ParserFree(oParser);
      94             : #endif
      95           3 :     if (poFeatureDefn)
      96           3 :         poFeatureDefn->Release();
      97             : 
      98           3 :     if (poSRS != nullptr)
      99           3 :         poSRS->Release();
     100             : 
     101           3 :     CPLFree(pszSubElementValue);
     102             : 
     103           3 :     for (int i = nFeatureTabIndex; i < nFeatureTabLength; i++)
     104           0 :         delete ppoFeatureTab[i];
     105           3 :     CPLFree(ppoFeatureTab);
     106             : 
     107           3 :     if (poFeature)
     108           0 :         delete poFeature;
     109             : 
     110           3 :     if (fpSVG)
     111           3 :         VSIFCloseL(fpSVG);
     112           6 : }
     113             : 
     114             : #ifdef HAVE_EXPAT
     115             : 
     116          54 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
     117             :                                     const char **ppszAttr)
     118             : {
     119          54 :     ((OGRSVGLayer *)pUserData)->startElementCbk(pszName, ppszAttr);
     120          54 : }
     121             : 
     122          54 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
     123             : {
     124          54 :     ((OGRSVGLayer *)pUserData)->endElementCbk(pszName);
     125          54 : }
     126             : 
     127         168 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
     128             : {
     129         168 :     ((OGRSVGLayer *)pUserData)->dataHandlerCbk(data, nLen);
     130         168 : }
     131             : 
     132             : #endif
     133             : 
     134             : /************************************************************************/
     135             : /*                            ResetReading()                            */
     136             : /************************************************************************/
     137             : 
     138           3 : void OGRSVGLayer::ResetReading()
     139             : 
     140             : {
     141           3 :     nNextFID = 0;
     142           3 :     if (fpSVG)
     143             :     {
     144           3 :         VSIFSeekL(fpSVG, 0, SEEK_SET);
     145           3 :         VSIFClearErrL(fpSVG);
     146             : #ifdef HAVE_EXPAT
     147           3 :         if (oParser)
     148           0 :             XML_ParserFree(oParser);
     149             : 
     150           3 :         oParser = OGRCreateExpatXMLParser();
     151           3 :         XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
     152           3 :         XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
     153           3 :         XML_SetUserData(oParser, this);
     154             : #endif
     155             :     }
     156             : 
     157           3 :     CPLFree(pszSubElementValue);
     158           3 :     pszSubElementValue = nullptr;
     159           3 :     nSubElementValueLen = 0;
     160           3 :     iCurrentField = -1;
     161             : 
     162           3 :     for (int i = nFeatureTabIndex; i < nFeatureTabLength; i++)
     163           0 :         delete ppoFeatureTab[i];
     164           3 :     CPLFree(ppoFeatureTab);
     165           3 :     nFeatureTabIndex = 0;
     166           3 :     nFeatureTabLength = 0;
     167           3 :     ppoFeatureTab = nullptr;
     168           3 :     if (poFeature)
     169           0 :         delete poFeature;
     170           3 :     poFeature = nullptr;
     171             : 
     172           3 :     depthLevel = 0;
     173           3 :     interestingDepthLevel = 0;
     174           3 :     inInterestingElement = false;
     175           3 : }
     176             : 
     177             : #ifdef HAVE_EXPAT
     178             : 
     179             : /************************************************************************/
     180             : /*                         OGRSVGGetClass()                             */
     181             : /************************************************************************/
     182             : 
     183           9 : static const char *OGRSVGGetClass(const char **ppszAttr)
     184             : {
     185           9 :     const char **ppszIter = ppszAttr;
     186          19 :     while (*ppszIter)
     187             :     {
     188          19 :         if (strcmp(ppszIter[0], "class") == 0)
     189           9 :             return ppszIter[1];
     190          10 :         ppszIter += 2;
     191             :     }
     192           0 :     return "";
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                          OGRSVGParseD()                              */
     197             : /************************************************************************/
     198             : 
     199           2 : static void OGRSVGParseD(OGRLineString *poLS, const char *pszD)
     200             : {
     201             :     char szBuffer[32];
     202           2 :     int iBuffer = 0;
     203           2 :     const char *pszIter = pszD;
     204           2 :     int iNumber = 0;
     205           2 :     double dfPrevNumber = 0.0;
     206           2 :     bool bRelativeLineto = false;
     207           2 :     double dfX = 0.0;
     208           2 :     double dfY = 0.0;
     209           2 :     int nPointCount = 0;
     210             :     while (true)
     211             :     {
     212        9001 :         const char ch = *(pszIter++);
     213             : 
     214        9001 :         if (ch == 'M' || ch == 'm')
     215             :         {
     216           2 :             if (nPointCount != 0)
     217             :             {
     218           0 :                 CPLDebug("SVG", "Not ready to handle M/m not at the beginning");
     219           1 :                 return;
     220             :             }
     221             :         }
     222        8999 :         else if (ch == 'L')
     223             :         {
     224           2 :             bRelativeLineto = false;
     225             :         }
     226        8997 :         else if (ch == 'l')
     227             :         {
     228           0 :             if (nPointCount == 0)
     229             :             {
     230           0 :                 CPLDebug("SVG", "Relative lineto at the beginning of the line");
     231           0 :                 return;
     232             :             }
     233           0 :             bRelativeLineto = true;
     234             :         }
     235        8997 :         else if (ch == 'z' || ch == 'Z')
     236             :         {
     237           1 :             poLS->closeRings();
     238           1 :             return;
     239             :         }
     240        8996 :         else if (ch == '+' || ch == '-' || ch == '.' ||
     241        7915 :                  (ch >= '0' && ch <= '9'))
     242             :         {
     243        8632 :             if (iBuffer == 30)
     244             :             {
     245           0 :                 CPLDebug("SVG", "Too big number");
     246           0 :                 return;
     247             :             }
     248        8632 :             szBuffer[iBuffer++] = ch;
     249             :         }
     250         364 :         else if (ch == ' ' || ch == 0)
     251             :         {
     252         364 :             if (iBuffer > 0)
     253             :             {
     254         360 :                 szBuffer[iBuffer] = 0;
     255         360 :                 if (iNumber == 1)
     256             :                 {
     257             :                     // Cloudmade --> negate y.
     258         180 :                     const double dfNumber = -CPLAtof(szBuffer);
     259             : 
     260         180 :                     if (bRelativeLineto)
     261             :                     {
     262           0 :                         dfX += dfPrevNumber;
     263           0 :                         dfY += dfNumber;
     264             :                     }
     265             :                     else
     266             :                     {
     267         180 :                         dfX = dfPrevNumber;
     268         180 :                         dfY = dfNumber;
     269             :                     }
     270         180 :                     poLS->addPoint(dfX, dfY);
     271         180 :                     nPointCount++;
     272             : 
     273         180 :                     iNumber = 0;
     274             :                 }
     275             :                 else
     276             :                 {
     277         180 :                     iNumber = 1;
     278         180 :                     dfPrevNumber = CPLAtof(szBuffer);
     279             :                 }
     280             : 
     281         360 :                 iBuffer = 0;
     282             :             }
     283         364 :             if (ch == 0)
     284           1 :                 break;
     285             :         }
     286        8999 :     }
     287             : }
     288             : 
     289             : /************************************************************************/
     290             : /*                        startElementCbk()                            */
     291             : /************************************************************************/
     292             : 
     293          54 : void OGRSVGLayer::startElementCbk(const char *pszName, const char **ppszAttr)
     294             : {
     295          54 :     if (bStopParsing)
     296           0 :         return;
     297             : 
     298          54 :     nWithoutEventCounter = 0;
     299             : 
     300          55 :     if (svgGeomType == SVG_POINTS && strcmp(pszName, "circle") == 0 &&
     301           1 :         strcmp(OGRSVGGetClass(ppszAttr), "point") == 0)
     302             :     {
     303           1 :         bool bHasFoundX = false;
     304           1 :         bool bHasFoundY = false;
     305           1 :         double dfX = 0.0;
     306           1 :         double dfY = 0.0;
     307           6 :         for (int i = 0; ppszAttr[i]; i += 2)
     308             :         {
     309           5 :             if (strcmp(ppszAttr[i], "cx") == 0)
     310             :             {
     311           1 :                 bHasFoundX = true;
     312           1 :                 dfX = CPLAtof(ppszAttr[i + 1]);
     313             :             }
     314           4 :             else if (strcmp(ppszAttr[i], "cy") == 0)
     315             :             {
     316           1 :                 bHasFoundY = true;
     317             :                 /* Cloudmade --> negate y */
     318           1 :                 dfY = -CPLAtof(ppszAttr[i + 1]);
     319             :             }
     320             :         }
     321           1 :         if (bHasFoundX && bHasFoundY)
     322             :         {
     323           1 :             interestingDepthLevel = depthLevel;
     324           1 :             inInterestingElement = true;
     325             : 
     326           1 :             if (poFeature)
     327           0 :                 delete poFeature;
     328             : 
     329           1 :             poFeature = new OGRFeature(poFeatureDefn);
     330             : 
     331           1 :             poFeature->SetFID(nNextFID++);
     332           1 :             OGRPoint *poPoint = new OGRPoint(dfX, dfY);
     333           1 :             poPoint->assignSpatialReference(poSRS);
     334           1 :             poFeature->SetGeometryDirectly(poPoint);
     335             :         }
     336             :     }
     337          55 :     else if (svgGeomType == SVG_LINES && strcmp(pszName, "path") == 0 &&
     338           2 :              strcmp(OGRSVGGetClass(ppszAttr), "line") == 0)
     339             :     {
     340           1 :         const char *pszD = nullptr;
     341           1 :         for (int i = 0; ppszAttr[i]; i += 2)
     342             :         {
     343           1 :             if (strcmp(ppszAttr[i], "d") == 0)
     344             :             {
     345           1 :                 pszD = ppszAttr[i + 1];
     346           1 :                 break;
     347             :             }
     348             :         }
     349           1 :         if (pszD)
     350             :         {
     351           1 :             interestingDepthLevel = depthLevel;
     352           1 :             inInterestingElement = true;
     353             : 
     354           1 :             if (poFeature)
     355           0 :                 delete poFeature;
     356             : 
     357           1 :             poFeature = new OGRFeature(poFeatureDefn);
     358             : 
     359           1 :             poFeature->SetFID(nNextFID++);
     360           1 :             OGRLineString *poLS = new OGRLineString();
     361           1 :             OGRSVGParseD(poLS, pszD);
     362           1 :             poLS->assignSpatialReference(poSRS);
     363           1 :             poFeature->SetGeometryDirectly(poLS);
     364             :         }
     365             :     }
     366          54 :     else if (svgGeomType == SVG_POLYGONS && strcmp(pszName, "path") == 0 &&
     367           2 :              strcmp(OGRSVGGetClass(ppszAttr), "polygon") == 0)
     368             :     {
     369           1 :         const char *pszD = nullptr;
     370           1 :         for (int i = 0; ppszAttr[i]; i += 2)
     371             :         {
     372           1 :             if (strcmp(ppszAttr[i], "d") == 0)
     373             :             {
     374           1 :                 pszD = ppszAttr[i + 1];
     375           1 :                 break;
     376             :             }
     377             :         }
     378           1 :         if (pszD)
     379             :         {
     380           1 :             interestingDepthLevel = depthLevel;
     381           1 :             inInterestingElement = true;
     382             : 
     383           1 :             if (poFeature)
     384           0 :                 delete poFeature;
     385             : 
     386           1 :             poFeature = new OGRFeature(poFeatureDefn);
     387             : 
     388           1 :             poFeature->SetFID(nNextFID++);
     389           1 :             OGRPolygon *poPolygon = new OGRPolygon();
     390           1 :             OGRLinearRing *poLS = new OGRLinearRing();
     391           1 :             OGRSVGParseD(poLS, pszD);
     392           1 :             poPolygon->addRingDirectly(poLS);
     393           1 :             poPolygon->assignSpatialReference(poSRS);
     394           1 :             poFeature->SetGeometryDirectly(poPolygon);
     395             :         }
     396             :     }
     397          51 :     else if (inInterestingElement && depthLevel == interestingDepthLevel + 1 &&
     398          11 :              STARTS_WITH(pszName, "cm:"))
     399             :     {
     400          11 :         iCurrentField = poFeatureDefn->GetFieldIndex(pszName + 3);
     401             :     }
     402             : 
     403          54 :     depthLevel++;
     404             : }
     405             : 
     406             : /************************************************************************/
     407             : /*                           endElementCbk()                            */
     408             : /************************************************************************/
     409             : 
     410          54 : void OGRSVGLayer::endElementCbk(CPL_UNUSED const char *pszName)
     411             : {
     412          54 :     if (bStopParsing)
     413           0 :         return;
     414             : 
     415          54 :     nWithoutEventCounter = 0;
     416             : 
     417          54 :     depthLevel--;
     418             : 
     419          54 :     if (inInterestingElement)
     420             :     {
     421          14 :         if (depthLevel == interestingDepthLevel)
     422             :         {
     423           3 :             inInterestingElement = false;
     424             : 
     425           6 :             if ((m_poFilterGeom == nullptr ||
     426           6 :                  FilterGeometry(poFeature->GetGeometryRef())) &&
     427           3 :                 (m_poAttrQuery == nullptr ||
     428           0 :                  m_poAttrQuery->Evaluate(poFeature)))
     429             :             {
     430           6 :                 ppoFeatureTab = (OGRFeature **)CPLRealloc(
     431           3 :                     ppoFeatureTab,
     432           3 :                     sizeof(OGRFeature *) * (nFeatureTabLength + 1));
     433           3 :                 ppoFeatureTab[nFeatureTabLength] = poFeature;
     434           3 :                 nFeatureTabLength++;
     435             :             }
     436             :             else
     437             :             {
     438           0 :                 delete poFeature;
     439             :             }
     440           3 :             poFeature = nullptr;
     441             :         }
     442          11 :         else if (depthLevel == interestingDepthLevel + 1)
     443             :         {
     444          11 :             if (poFeature && iCurrentField >= 0 && nSubElementValueLen)
     445             :             {
     446          11 :                 pszSubElementValue[nSubElementValueLen] = 0;
     447          11 :                 poFeature->SetField(iCurrentField, pszSubElementValue);
     448             :             }
     449             : 
     450          11 :             CPLFree(pszSubElementValue);
     451          11 :             pszSubElementValue = nullptr;
     452          11 :             nSubElementValueLen = 0;
     453          11 :             iCurrentField = -1;
     454             :         }
     455             :     }
     456             : }
     457             : 
     458             : /************************************************************************/
     459             : /*                          dataHandlerCbk()                            */
     460             : /************************************************************************/
     461             : 
     462         168 : void OGRSVGLayer::dataHandlerCbk(const char *data, int nLen)
     463             : {
     464         168 :     if (bStopParsing)
     465           0 :         return;
     466             : 
     467         168 :     nDataHandlerCounter++;
     468         168 :     if (nDataHandlerCounter >= PARSER_BUF_SIZE)
     469             :     {
     470           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     471             :                  "File probably corrupted (million laugh pattern)");
     472           0 :         XML_StopParser(oParser, XML_FALSE);
     473           0 :         bStopParsing = true;
     474           0 :         return;
     475             :     }
     476             : 
     477         168 :     nWithoutEventCounter = 0;
     478             : 
     479         168 :     if (iCurrentField >= 0)
     480             :     {
     481          11 :         char *pszNewSubElementValue = (char *)VSI_REALLOC_VERBOSE(
     482             :             pszSubElementValue, nSubElementValueLen + nLen + 1);
     483          11 :         if (pszNewSubElementValue == nullptr)
     484             :         {
     485           0 :             XML_StopParser(oParser, XML_FALSE);
     486           0 :             bStopParsing = true;
     487           0 :             return;
     488             :         }
     489          11 :         pszSubElementValue = pszNewSubElementValue;
     490          11 :         memcpy(pszSubElementValue + nSubElementValueLen, data, nLen);
     491          11 :         nSubElementValueLen += nLen;
     492          11 :         if (nSubElementValueLen > 100000)
     493             :         {
     494           0 :             CPLError(
     495             :                 CE_Failure, CPLE_AppDefined,
     496             :                 "Too much data inside one element. File probably corrupted");
     497           0 :             XML_StopParser(oParser, XML_FALSE);
     498           0 :             bStopParsing = true;
     499             :         }
     500             :     }
     501             : }
     502             : #endif
     503             : 
     504             : /************************************************************************/
     505             : /*                           GetNextFeature()                           */
     506             : /************************************************************************/
     507             : 
     508           3 : OGRFeature *OGRSVGLayer::GetNextFeature()
     509             : {
     510           3 :     GetLayerDefn();
     511             : 
     512           3 :     if (fpSVG == nullptr)
     513           0 :         return nullptr;
     514             : 
     515           3 :     if (bStopParsing)
     516           0 :         return nullptr;
     517             : 
     518             : #ifdef HAVE_EXPAT
     519           3 :     if (nFeatureTabIndex < nFeatureTabLength)
     520             :     {
     521           0 :         return ppoFeatureTab[nFeatureTabIndex++];
     522             :     }
     523             : 
     524           3 :     if (VSIFEofL(fpSVG) || VSIFErrorL(fpSVG))
     525           0 :         return nullptr;
     526             : 
     527           3 :     std::vector<char> aBuf(PARSER_BUF_SIZE);
     528             : 
     529           3 :     CPLFree(ppoFeatureTab);
     530           3 :     ppoFeatureTab = nullptr;
     531           3 :     nFeatureTabLength = 0;
     532           3 :     nFeatureTabIndex = 0;
     533           3 :     nWithoutEventCounter = 0;
     534           3 :     iCurrentField = -1;
     535             : 
     536           3 :     int nDone = 0;
     537           3 :     do
     538             :     {
     539           6 :         nDataHandlerCounter = 0;
     540             :         unsigned int nLen =
     541           6 :             (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fpSVG);
     542           6 :         nDone = nLen < aBuf.size();
     543           6 :         if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR)
     544             :         {
     545           0 :             CPLError(
     546             :                 CE_Failure, CPLE_AppDefined,
     547             :                 "XML parsing of SVG file failed : %s at line %d, column %d",
     548             :                 XML_ErrorString(XML_GetErrorCode(oParser)),
     549           0 :                 (int)XML_GetCurrentLineNumber(oParser),
     550           0 :                 (int)XML_GetCurrentColumnNumber(oParser));
     551           0 :             bStopParsing = true;
     552           0 :             break;
     553             :         }
     554           6 :         nWithoutEventCounter++;
     555           6 :     } while (!nDone && nFeatureTabLength == 0 && !bStopParsing &&
     556           3 :              nWithoutEventCounter < 1000);
     557             : 
     558           3 :     if (nWithoutEventCounter == 1000)
     559             :     {
     560           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     561             :                  "Too much data inside one element. File probably corrupted");
     562           0 :         bStopParsing = true;
     563             :     }
     564             : 
     565           3 :     return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : nullptr;
     566             : #else
     567             :     return nullptr;
     568             : #endif
     569             : }
     570             : 
     571             : /************************************************************************/
     572             : /*                           TestCapability()                           */
     573             : /************************************************************************/
     574             : 
     575           0 : int OGRSVGLayer::TestCapability(const char *pszCap)
     576             : 
     577             : {
     578           0 :     if (EQUAL(pszCap, OLCFastFeatureCount))
     579           0 :         return m_poAttrQuery == nullptr && m_poFilterGeom == nullptr &&
     580           0 :                nTotalFeatures > 0;
     581             : 
     582           0 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
     583           0 :         return TRUE;
     584             : 
     585             :     else
     586           0 :         return FALSE;
     587             : }
     588             : 
     589             : /************************************************************************/
     590             : /*                       LoadSchema()                         */
     591             : /************************************************************************/
     592             : 
     593             : #ifdef HAVE_EXPAT
     594             : 
     595          18 : static void XMLCALL startElementLoadSchemaCbk(void *pUserData,
     596             :                                               const char *pszName,
     597             :                                               const char **ppszAttr)
     598             : {
     599          18 :     ((OGRSVGLayer *)pUserData)->startElementLoadSchemaCbk(pszName, ppszAttr);
     600          18 : }
     601             : 
     602          18 : static void XMLCALL endElementLoadSchemaCbk(void *pUserData,
     603             :                                             const char *pszName)
     604             : {
     605          18 :     ((OGRSVGLayer *)pUserData)->endElementLoadSchemaCbk(pszName);
     606          18 : }
     607             : 
     608          56 : static void XMLCALL dataHandlerLoadSchemaCbk(void *pUserData, const char *data,
     609             :                                              int nLen)
     610             : {
     611          56 :     ((OGRSVGLayer *)pUserData)->dataHandlerLoadSchemaCbk(data, nLen);
     612          56 : }
     613             : 
     614             : /** This function parses the whole file to build the schema */
     615           1 : void OGRSVGLayer::LoadSchema()
     616             : {
     617           1 :     CPLAssert(poFeatureDefn == nullptr);
     618             : 
     619           4 :     for (int i = 0; i < poDS->GetLayerCount(); i++)
     620             :     {
     621           3 :         OGRSVGLayer *poLayer = (OGRSVGLayer *)poDS->GetLayer(i);
     622           3 :         poLayer->poFeatureDefn = new OGRFeatureDefn(poLayer->osLayerName);
     623           3 :         poLayer->poFeatureDefn->Reference();
     624           3 :         poLayer->poFeatureDefn->SetGeomType(poLayer->GetGeomType());
     625           3 :         poLayer->poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(
     626           3 :             poLayer->poSRS);
     627             :     }
     628             : 
     629           1 :     oSchemaParser = OGRCreateExpatXMLParser();
     630           1 :     XML_SetElementHandler(oSchemaParser, ::startElementLoadSchemaCbk,
     631             :                           ::endElementLoadSchemaCbk);
     632           1 :     XML_SetCharacterDataHandler(oSchemaParser, ::dataHandlerLoadSchemaCbk);
     633           1 :     XML_SetUserData(oSchemaParser, this);
     634             : 
     635           1 :     if (fpSVG == nullptr)
     636           0 :         return;
     637             : 
     638           1 :     VSIFSeekL(fpSVG, 0, SEEK_SET);
     639             : 
     640           1 :     inInterestingElement = false;
     641           1 :     depthLevel = 0;
     642           1 :     nWithoutEventCounter = 0;
     643           1 :     bStopParsing = false;
     644             : 
     645           2 :     std::vector<char> aBuf(PARSER_BUF_SIZE);
     646           1 :     int nDone = 0;
     647           1 :     do
     648             :     {
     649           2 :         nDataHandlerCounter = 0;
     650             :         unsigned int nLen =
     651           2 :             (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fpSVG);
     652           2 :         nDone = nLen < aBuf.size();
     653           2 :         if (XML_Parse(oSchemaParser, aBuf.data(), nLen, nDone) ==
     654             :             XML_STATUS_ERROR)
     655             :         {
     656           0 :             CPLError(
     657             :                 CE_Failure, CPLE_AppDefined,
     658             :                 "XML parsing of SVG file failed : %s at line %d, column %d",
     659             :                 XML_ErrorString(XML_GetErrorCode(oSchemaParser)),
     660           0 :                 (int)XML_GetCurrentLineNumber(oSchemaParser),
     661           0 :                 (int)XML_GetCurrentColumnNumber(oSchemaParser));
     662           0 :             bStopParsing = true;
     663           0 :             break;
     664             :         }
     665           2 :         nWithoutEventCounter++;
     666           2 :     } while (!nDone && !bStopParsing && nWithoutEventCounter < 1000);
     667             : 
     668           1 :     if (nWithoutEventCounter == 1000)
     669             :     {
     670           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     671             :                  "Too much data inside one element. File probably corrupted");
     672           0 :         bStopParsing = true;
     673             :     }
     674             : 
     675           1 :     XML_ParserFree(oSchemaParser);
     676           1 :     oSchemaParser = nullptr;
     677             : 
     678           1 :     VSIFSeekL(fpSVG, 0, SEEK_SET);
     679             : }
     680             : 
     681             : /************************************************************************/
     682             : /*                  startElementLoadSchemaCbk()                         */
     683             : /************************************************************************/
     684             : 
     685          18 : void OGRSVGLayer::startElementLoadSchemaCbk(const char *pszName,
     686             :                                             const char **ppszAttr)
     687             : {
     688          18 :     if (bStopParsing)
     689           0 :         return;
     690             : 
     691          18 :     nWithoutEventCounter = 0;
     692             : 
     693          19 :     if (strcmp(pszName, "circle") == 0 &&
     694           1 :         strcmp(OGRSVGGetClass(ppszAttr), "point") == 0)
     695             :     {
     696           1 :         poCurLayer = cpl::down_cast<OGRSVGLayer *>(poDS->GetLayer(0));
     697           1 :         if (!poCurLayer)
     698             :         {
     699           0 :             CPLAssert(false);
     700             :             return;
     701             :         }
     702           1 :         poCurLayer->nTotalFeatures++;
     703           1 :         inInterestingElement = true;
     704           1 :         interestingDepthLevel = depthLevel;
     705             :     }
     706          19 :     else if (strcmp(pszName, "path") == 0 &&
     707           2 :              strcmp(OGRSVGGetClass(ppszAttr), "line") == 0)
     708             :     {
     709           1 :         poCurLayer = cpl::down_cast<OGRSVGLayer *>(poDS->GetLayer(1));
     710           1 :         if (!poCurLayer)
     711             :         {
     712           0 :             CPLAssert(false);
     713             :             return;
     714             :         }
     715           1 :         poCurLayer->nTotalFeatures++;
     716           1 :         inInterestingElement = true;
     717           1 :         interestingDepthLevel = depthLevel;
     718             :     }
     719          17 :     else if (strcmp(pszName, "path") == 0 &&
     720           1 :              strcmp(OGRSVGGetClass(ppszAttr), "polygon") == 0)
     721             :     {
     722           1 :         poCurLayer = cpl::down_cast<OGRSVGLayer *>(poDS->GetLayer(2));
     723           1 :         if (!poCurLayer)
     724             :         {
     725           0 :             CPLAssert(false);
     726             :             return;
     727             :         }
     728           1 :         poCurLayer->nTotalFeatures++;
     729           1 :         inInterestingElement = true;
     730           1 :         interestingDepthLevel = depthLevel;
     731             :     }
     732          15 :     else if (inInterestingElement)
     733             :     {
     734          11 :         if (depthLevel == interestingDepthLevel + 1 &&
     735          11 :             STARTS_WITH(pszName, "cm:"))
     736             :         {
     737          11 :             pszName += 3;
     738          11 :             if (poCurLayer->poFeatureDefn->GetFieldIndex(pszName) < 0)
     739             :             {
     740          22 :                 OGRFieldDefn oFieldDefn(pszName, OFTString);
     741          11 :                 if (strcmp(pszName, "timestamp") == 0)
     742           3 :                     oFieldDefn.SetType(OFTDateTime);
     743           8 :                 else if (strcmp(pszName, "way_area") == 0 ||
     744           7 :                          strcmp(pszName, "area") == 0)
     745           1 :                     oFieldDefn.SetType(OFTReal);
     746           7 :                 else if (strcmp(pszName, "z_order") == 0)
     747           0 :                     oFieldDefn.SetType(OFTInteger);
     748          11 :                 poCurLayer->poFeatureDefn->AddFieldDefn(&oFieldDefn);
     749             :             }
     750             :         }
     751             :     }
     752             : 
     753          18 :     depthLevel++;
     754             : }
     755             : 
     756             : /************************************************************************/
     757             : /*                   endElementLoadSchemaCbk()                           */
     758             : /************************************************************************/
     759             : 
     760          18 : void OGRSVGLayer::endElementLoadSchemaCbk(CPL_UNUSED const char *pszName)
     761             : {
     762          18 :     if (bStopParsing)
     763           0 :         return;
     764             : 
     765          18 :     nWithoutEventCounter = 0;
     766             : 
     767          18 :     depthLevel--;
     768             : 
     769          18 :     if (inInterestingElement && depthLevel == interestingDepthLevel)
     770             :     {
     771           3 :         inInterestingElement = false;
     772             :     }
     773             : }
     774             : 
     775             : /************************************************************************/
     776             : /*                   dataHandlerLoadSchemaCbk()                         */
     777             : /************************************************************************/
     778             : 
     779          56 : void OGRSVGLayer::dataHandlerLoadSchemaCbk(CPL_UNUSED const char *data,
     780             :                                            CPL_UNUSED int nLen)
     781             : {
     782          56 :     if (bStopParsing)
     783           0 :         return;
     784             : 
     785          56 :     nDataHandlerCounter++;
     786          56 :     if (nDataHandlerCounter >= PARSER_BUF_SIZE)
     787             :     {
     788           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     789             :                  "File probably corrupted (million laugh pattern)");
     790           0 :         XML_StopParser(oSchemaParser, XML_FALSE);
     791           0 :         bStopParsing = true;
     792           0 :         return;
     793             :     }
     794             : 
     795          56 :     nWithoutEventCounter = 0;
     796             : }
     797             : #else
     798             : void OGRSVGLayer::LoadSchema()
     799             : {
     800             : }
     801             : #endif
     802             : 
     803             : /************************************************************************/
     804             : /*                          GetLayerDefn()                              */
     805             : /************************************************************************/
     806             : 
     807           6 : OGRFeatureDefn *OGRSVGLayer::GetLayerDefn()
     808             : {
     809           6 :     if (poFeatureDefn == nullptr)
     810             :     {
     811           1 :         LoadSchema();
     812             :     }
     813             : 
     814           6 :     return poFeatureDefn;
     815             : }
     816             : 
     817             : /************************************************************************/
     818             : /*                           GetGeomType()                              */
     819             : /************************************************************************/
     820             : 
     821           3 : OGRwkbGeometryType OGRSVGLayer::GetGeomType()
     822             : {
     823           3 :     if (svgGeomType == SVG_POINTS)
     824           1 :         return wkbPoint;
     825           2 :     else if (svgGeomType == SVG_LINES)
     826           1 :         return wkbLineString;
     827             :     else
     828           1 :         return wkbPolygon;
     829             : }
     830             : 
     831             : /************************************************************************/
     832             : /*                           GetGeomType()                              */
     833             : /************************************************************************/
     834             : 
     835           3 : GIntBig OGRSVGLayer::GetFeatureCount(int bForce)
     836             : {
     837           3 :     if (m_poAttrQuery != nullptr || m_poFilterGeom != nullptr)
     838           0 :         return OGRLayer::GetFeatureCount(bForce);
     839             : 
     840           3 :     GetLayerDefn();
     841             : 
     842           3 :     return nTotalFeatures;
     843             : }

Generated by: LCOV version 1.14