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

Generated by: LCOV version 1.14