LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/svg - ogrsvgdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 69 93 74.2 %
Date: 2024-11-21 22:18:42 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  SVG Translator
       4             :  * Purpose:  Implements OGRSVGDataSource class
       5             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2011, 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             : /*                          OGRSVGDataSource()                          */
      18             : /************************************************************************/
      19             : 
      20           1 : OGRSVGDataSource::OGRSVGDataSource()
      21             :     : papoLayers(nullptr), nLayers(0)
      22             : #ifdef HAVE_EXPAT
      23             :       ,
      24             :       eValidity(SVG_VALIDITY_UNKNOWN), bIsCloudmade(false),
      25           1 :       oCurrentParser(nullptr), nDataHandlerCounter(0)
      26             : #endif
      27             : {
      28           1 : }
      29             : 
      30             : /************************************************************************/
      31             : /*                         ~OGRSVGDataSource()                          */
      32             : /************************************************************************/
      33             : 
      34           2 : OGRSVGDataSource::~OGRSVGDataSource()
      35             : 
      36             : {
      37           4 :     for (int i = 0; i < nLayers; i++)
      38           3 :         delete papoLayers[i];
      39           1 :     CPLFree(papoLayers);
      40           2 : }
      41             : 
      42             : /************************************************************************/
      43             : /*                              GetLayer()                              */
      44             : /************************************************************************/
      45             : 
      46          12 : OGRLayer *OGRSVGDataSource::GetLayer(int iLayer)
      47             : 
      48             : {
      49          12 :     if (iLayer < 0 || iLayer >= nLayers)
      50           0 :         return nullptr;
      51             :     else
      52          12 :         return papoLayers[iLayer];
      53             : }
      54             : 
      55             : #ifdef HAVE_EXPAT
      56             : 
      57             : /************************************************************************/
      58             : /*                startElementValidateCbk()                             */
      59             : /************************************************************************/
      60             : 
      61           4 : void OGRSVGDataSource::startElementValidateCbk(const char *pszNameIn,
      62             :                                                const char **ppszAttr)
      63             : {
      64           4 :     if (eValidity == SVG_VALIDITY_UNKNOWN)
      65             :     {
      66           1 :         if (strcmp(pszNameIn, "svg") == 0)
      67             :         {
      68           1 :             eValidity = SVG_VALIDITY_VALID;
      69           2 :             for (int i = 0; ppszAttr[i] != nullptr; i += 2)
      70             :             {
      71           2 :                 if (strcmp(ppszAttr[i], "xmlns:cm") == 0 &&
      72           1 :                     strcmp(ppszAttr[i + 1], "http://cloudmade.com/") == 0)
      73             :                 {
      74           1 :                     bIsCloudmade = true;
      75           1 :                     break;
      76             :                 }
      77             :             }
      78             :         }
      79             :         else
      80             :         {
      81           0 :             eValidity = SVG_VALIDITY_INVALID;
      82             :         }
      83             :     }
      84           4 : }
      85             : 
      86             : /************************************************************************/
      87             : /*                      dataHandlerValidateCbk()                        */
      88             : /************************************************************************/
      89             : 
      90           8 : void OGRSVGDataSource::dataHandlerValidateCbk(CPL_UNUSED const char *data,
      91             :                                               CPL_UNUSED int nLen)
      92             : {
      93           8 :     nDataHandlerCounter++;
      94           8 :     if (nDataHandlerCounter >= PARSER_BUF_SIZE)
      95             :     {
      96           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      97             :                  "File probably corrupted (million laugh pattern)");
      98           0 :         XML_StopParser(oCurrentParser, XML_FALSE);
      99             :     }
     100           8 : }
     101             : 
     102           4 : static void XMLCALL startElementValidateCbk(void *pUserData,
     103             :                                             const char *pszName,
     104             :                                             const char **ppszAttr)
     105             : {
     106           4 :     OGRSVGDataSource *poDS = (OGRSVGDataSource *)pUserData;
     107           4 :     poDS->startElementValidateCbk(pszName, ppszAttr);
     108           4 : }
     109             : 
     110           8 : static void XMLCALL dataHandlerValidateCbk(void *pUserData, const char *data,
     111             :                                            int nLen)
     112             : {
     113           8 :     OGRSVGDataSource *poDS = (OGRSVGDataSource *)pUserData;
     114           8 :     poDS->dataHandlerValidateCbk(data, nLen);
     115           8 : }
     116             : #endif
     117             : 
     118             : /************************************************************************/
     119             : /*                                Open()                                */
     120             : /************************************************************************/
     121             : 
     122           1 : int OGRSVGDataSource::Open(const char *pszFilename)
     123             : 
     124             : {
     125             : #ifdef HAVE_EXPAT
     126             :     /* -------------------------------------------------------------------- */
     127             :     /*      Try to open the file.                                           */
     128             :     /* -------------------------------------------------------------------- */
     129           2 :     CPLString osFilename;  // keep in that scope
     130           1 :     if (EQUAL(CPLGetExtension(pszFilename), "svgz") &&
     131           0 :         strstr(pszFilename, "/vsigzip/") == nullptr)
     132             :     {
     133           0 :         osFilename = CPLString("/vsigzip/") + pszFilename;
     134           0 :         pszFilename = osFilename.c_str();
     135             :     }
     136             : 
     137           1 :     VSILFILE *fp = VSIFOpenL(pszFilename, "r");
     138           1 :     if (fp == nullptr)
     139           0 :         return FALSE;
     140             : 
     141           1 :     eValidity = SVG_VALIDITY_UNKNOWN;
     142             : 
     143           1 :     XML_Parser oParser = OGRCreateExpatXMLParser();
     144           1 :     oCurrentParser = oParser;
     145           1 :     XML_SetUserData(oParser, this);
     146           1 :     XML_SetElementHandler(oParser, ::startElementValidateCbk, nullptr);
     147           1 :     XML_SetCharacterDataHandler(oParser, ::dataHandlerValidateCbk);
     148             : 
     149           1 :     std::vector<char> aBuf(PARSER_BUF_SIZE);
     150           1 :     int nDone = 0;
     151           1 :     unsigned int nLen = 0;
     152           1 :     int nCount = 0;
     153             : 
     154             :     /* Begin to parse the file and look for the <svg> element */
     155             :     /* It *MUST* be the first element of an XML file */
     156             :     /* So once we have read the first element, we know if we can */
     157             :     /* handle the file or not with that driver */
     158           0 :     do
     159             :     {
     160           1 :         nDataHandlerCounter = 0;
     161           1 :         nLen = (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fp);
     162           1 :         nDone = nLen < aBuf.size();
     163           1 :         if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR)
     164             :         {
     165           0 :             if (nLen <= PARSER_BUF_SIZE - 1)
     166           0 :                 aBuf[nLen] = 0;
     167             :             else
     168           0 :                 aBuf[PARSER_BUF_SIZE - 1] = 0;
     169           0 :             if (strstr(aBuf.data(), "<?xml") && strstr(aBuf.data(), "<svg"))
     170             :             {
     171           0 :                 CPLError(
     172             :                     CE_Failure, CPLE_AppDefined,
     173             :                     "XML parsing of SVG file failed : %s at line %d, column %d",
     174             :                     XML_ErrorString(XML_GetErrorCode(oParser)),
     175           0 :                     (int)XML_GetCurrentLineNumber(oParser),
     176           0 :                     (int)XML_GetCurrentColumnNumber(oParser));
     177             :             }
     178           0 :             eValidity = SVG_VALIDITY_INVALID;
     179           0 :             break;
     180             :         }
     181           1 :         if (eValidity == SVG_VALIDITY_INVALID)
     182             :         {
     183           0 :             break;
     184             :         }
     185           1 :         else if (eValidity == SVG_VALIDITY_VALID)
     186             :         {
     187           1 :             break;
     188             :         }
     189             :         else
     190             :         {
     191             :             /* After reading 50 * PARSER_BUF_SIZE bytes, and not finding whether the
     192             :              * file */
     193             :             /* is SVG or not, we give up and fail silently */
     194           0 :             nCount++;
     195           0 :             if (nCount == 50)
     196           0 :                 break;
     197             :         }
     198           0 :     } while (!nDone && nLen > 0);
     199             : 
     200           1 :     XML_ParserFree(oParser);
     201             : 
     202           1 :     VSIFCloseL(fp);
     203             : 
     204           1 :     if (eValidity == SVG_VALIDITY_VALID)
     205             :     {
     206           1 :         if (bIsCloudmade)
     207             :         {
     208           1 :             nLayers = 3;
     209           2 :             papoLayers = (OGRSVGLayer **)CPLRealloc(
     210           1 :                 papoLayers, nLayers * sizeof(OGRSVGLayer *));
     211           1 :             papoLayers[0] =
     212           1 :                 new OGRSVGLayer(pszFilename, "points", SVG_POINTS, this);
     213           1 :             papoLayers[1] =
     214           1 :                 new OGRSVGLayer(pszFilename, "lines", SVG_LINES, this);
     215           1 :             papoLayers[2] =
     216           1 :                 new OGRSVGLayer(pszFilename, "polygons", SVG_POLYGONS, this);
     217             :         }
     218             :         else
     219             :         {
     220           0 :             CPLDebug(
     221             :                 "SVG",
     222             :                 "%s seems to be a SVG file, but not a Cloudmade vector one.",
     223             :                 pszFilename);
     224             :         }
     225             :     }
     226             : 
     227           1 :     return nLayers > 0;
     228             : #else
     229             :     char aBuf[256];
     230             :     VSILFILE *fp = VSIFOpenL(pszFilename, "r");
     231             :     if (fp)
     232             :     {
     233             :         unsigned int nLen = (unsigned int)VSIFReadL(aBuf, 1, 255, fp);
     234             :         aBuf[nLen] = 0;
     235             :         if (strstr(aBuf, "<?xml") && strstr(aBuf, "<svg") &&
     236             :             strstr(aBuf, "http://cloudmade.com/"))
     237             :         {
     238             :             CPLError(CE_Failure, CPLE_NotSupported,
     239             :                      "OGR/SVG driver has not been built with read support. "
     240             :                      "Expat library required");
     241             :         }
     242             :         VSIFCloseL(fp);
     243             :     }
     244             :     return FALSE;
     245             : #endif
     246             : }

Generated by: LCOV version 1.14