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