1 : /******************************************************************************
2 : * $Id: ogrsvgdatasource.cpp 23557 2011-12-12 22:08:17Z rouault $
3 : *
4 : * Project: SVG Translator
5 : * Purpose: Implements OGRSVGDataSource class
6 : * Author: Even Rouault, even dot rouault at mines dash paris dot org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2011, Even Rouault
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_svg.h"
31 : #include "cpl_conv.h"
32 :
33 : CPL_CVSID("$Id: ogrsvgdatasource.cpp 23557 2011-12-12 22:08:17Z rouault $");
34 :
35 : /************************************************************************/
36 : /* OGRSVGDataSource() */
37 : /************************************************************************/
38 :
39 48 : OGRSVGDataSource::OGRSVGDataSource()
40 :
41 : {
42 48 : papoLayers = NULL;
43 48 : nLayers = 0;
44 :
45 48 : bIsCloudmade = FALSE;
46 :
47 48 : pszName = NULL;
48 48 : }
49 :
50 : /************************************************************************/
51 : /* ~OGRSVGDataSource() */
52 : /************************************************************************/
53 :
54 48 : OGRSVGDataSource::~OGRSVGDataSource()
55 :
56 : {
57 51 : for( int i = 0; i < nLayers; i++ )
58 3 : delete papoLayers[i];
59 48 : CPLFree( papoLayers );
60 48 : CPLFree( pszName );
61 48 : }
62 :
63 : /************************************************************************/
64 : /* GetLayer() */
65 : /************************************************************************/
66 :
67 12 : OGRLayer *OGRSVGDataSource::GetLayer( int iLayer )
68 :
69 : {
70 12 : if( iLayer < 0 || iLayer >= nLayers )
71 0 : return NULL;
72 : else
73 12 : return papoLayers[iLayer];
74 : }
75 :
76 : #ifdef HAVE_EXPAT
77 :
78 : /************************************************************************/
79 : /* startElementValidateCbk() */
80 : /************************************************************************/
81 :
82 378 : void OGRSVGDataSource::startElementValidateCbk(const char *pszName,
83 : const char **ppszAttr)
84 : {
85 378 : if (eValidity == SVG_VALIDITY_UNKNOWN)
86 : {
87 6 : if (strcmp(pszName, "svg") == 0)
88 : {
89 : int i;
90 1 : eValidity = SVG_VALIDITY_VALID;
91 2 : for(i=0; ppszAttr[i] != NULL; i+= 2)
92 : {
93 2 : if (strcmp(ppszAttr[i], "xmlns:cm") == 0 &&
94 : strcmp(ppszAttr[i+1], "http://cloudmade.com/") == 0)
95 : {
96 1 : bIsCloudmade = TRUE;
97 1 : break;
98 : }
99 : }
100 : }
101 : else
102 : {
103 5 : eValidity = SVG_VALIDITY_INVALID;
104 : }
105 : }
106 378 : }
107 :
108 :
109 : /************************************************************************/
110 : /* dataHandlerValidateCbk() */
111 : /************************************************************************/
112 :
113 967 : void OGRSVGDataSource::dataHandlerValidateCbk(const char *data, int nLen)
114 : {
115 967 : nDataHandlerCounter ++;
116 967 : if (nDataHandlerCounter >= BUFSIZ)
117 : {
118 : CPLError(CE_Failure, CPLE_AppDefined,
119 0 : "File probably corrupted (million laugh pattern)");
120 0 : XML_StopParser(oCurrentParser, XML_FALSE);
121 : }
122 967 : }
123 :
124 :
125 378 : static void XMLCALL startElementValidateCbk(void *pUserData,
126 : const char *pszName, const char **ppszAttr)
127 : {
128 378 : OGRSVGDataSource* poDS = (OGRSVGDataSource*) pUserData;
129 378 : poDS->startElementValidateCbk(pszName, ppszAttr);
130 378 : }
131 :
132 967 : static void XMLCALL dataHandlerValidateCbk(void *pUserData, const char *data, int nLen)
133 : {
134 967 : OGRSVGDataSource* poDS = (OGRSVGDataSource*) pUserData;
135 967 : poDS->dataHandlerValidateCbk(data, nLen);
136 967 : }
137 : #endif
138 :
139 : /************************************************************************/
140 : /* Open() */
141 : /************************************************************************/
142 :
143 48 : int OGRSVGDataSource::Open( const char * pszFilename, int bUpdateIn)
144 :
145 : {
146 48 : if (bUpdateIn)
147 : {
148 : CPLError(CE_Failure, CPLE_NotSupported,
149 0 : "OGR/SVG driver does not support opening a file in update mode");
150 0 : return FALSE;
151 : }
152 : #ifdef HAVE_EXPAT
153 48 : pszName = CPLStrdup( pszFilename );
154 :
155 : /* -------------------------------------------------------------------- */
156 : /* Try to open the file. */
157 : /* -------------------------------------------------------------------- */
158 48 : CPLString osFilename(pszFilename);
159 48 : if (EQUAL(CPLGetExtension(pszFilename), "svgz") &&
160 : strstr(pszFilename, "/vsigzip/") == NULL)
161 : {
162 0 : osFilename = CPLString("/vsigzip/") + pszFilename;
163 0 : pszFilename = osFilename.c_str();
164 : }
165 :
166 48 : VSILFILE* fp = VSIFOpenL(pszFilename, "r");
167 48 : if (fp == NULL)
168 21 : return FALSE;
169 :
170 27 : eValidity = SVG_VALIDITY_UNKNOWN;
171 :
172 27 : XML_Parser oParser = OGRCreateExpatXMLParser();
173 27 : oCurrentParser = oParser;
174 27 : XML_SetUserData(oParser, this);
175 27 : XML_SetElementHandler(oParser, ::startElementValidateCbk, NULL);
176 27 : XML_SetCharacterDataHandler(oParser, ::dataHandlerValidateCbk);
177 :
178 : char aBuf[BUFSIZ];
179 : int nDone;
180 : unsigned int nLen;
181 27 : int nCount = 0;
182 :
183 : /* Begin to parse the file and look for the <svg> element */
184 : /* It *MUST* be the first element of an XML file */
185 : /* So once we have read the first element, we know if we can */
186 : /* handle the file or not with that driver */
187 0 : do
188 : {
189 27 : nDataHandlerCounter = 0;
190 27 : nLen = (unsigned int) VSIFReadL( aBuf, 1, sizeof(aBuf), fp );
191 27 : nDone = VSIFEofL(fp);
192 27 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
193 : {
194 21 : if (nLen <= BUFSIZ-1)
195 19 : aBuf[nLen] = 0;
196 : else
197 2 : aBuf[BUFSIZ-1] = 0;
198 21 : if (strstr(aBuf, "<?xml") && strstr(aBuf, "<svg"))
199 : {
200 : CPLError(CE_Failure, CPLE_AppDefined,
201 : "XML parsing of SVG file failed : %s at line %d, column %d",
202 : XML_ErrorString(XML_GetErrorCode(oParser)),
203 : (int)XML_GetCurrentLineNumber(oParser),
204 0 : (int)XML_GetCurrentColumnNumber(oParser));
205 : }
206 21 : eValidity = SVG_VALIDITY_INVALID;
207 21 : break;
208 : }
209 6 : if (eValidity == SVG_VALIDITY_INVALID)
210 : {
211 5 : break;
212 : }
213 1 : else if (eValidity == SVG_VALIDITY_VALID)
214 : {
215 1 : break;
216 : }
217 : else
218 : {
219 : /* After reading 50 * BUFSIZE bytes, and not finding whether the file */
220 : /* is SVG or not, we give up and fail silently */
221 0 : nCount ++;
222 0 : if (nCount == 50)
223 0 : break;
224 : }
225 : } while (!nDone && nLen > 0 );
226 :
227 27 : XML_ParserFree(oParser);
228 :
229 27 : VSIFCloseL(fp);
230 :
231 27 : if (eValidity == SVG_VALIDITY_VALID)
232 : {
233 1 : if (bIsCloudmade)
234 : {
235 1 : nLayers = 3;
236 : papoLayers =(OGRSVGLayer **) CPLRealloc(papoLayers,
237 1 : nLayers * sizeof(OGRSVGLayer*));
238 1 : papoLayers[0] = new OGRSVGLayer( pszFilename, "points", SVG_POINTS, this );
239 2 : papoLayers[1] = new OGRSVGLayer( pszFilename, "lines", SVG_LINES, this );
240 2 : papoLayers[2] = new OGRSVGLayer( pszFilename, "polygons", SVG_POLYGONS, this );
241 : }
242 : else
243 : {
244 : CPLDebug("SVG",
245 : "%s seems to be a SVG file, but not a Cloudmade vector one.",
246 0 : pszFilename);
247 : }
248 : }
249 :
250 27 : return (nLayers > 0);
251 : #else
252 : char aBuf[256];
253 : VSILFILE* fp = VSIFOpenL(pszFilename, "r");
254 : if (fp)
255 : {
256 : unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, 255, fp );
257 : aBuf[nLen] = 0;
258 : if (strstr(aBuf, "<?xml") && strstr(aBuf, "<svg") &&
259 : strstr(aBuf, "http://cloudmade.com/"))
260 : {
261 : CPLError(CE_Failure, CPLE_NotSupported,
262 : "OGR/SVG driver has not been built with read support. "
263 : "Expat library required");
264 : }
265 : VSIFCloseL(fp);
266 : }
267 : return FALSE;
268 : #endif
269 : }
270 :
271 : /************************************************************************/
272 : /* TestCapability() */
273 : /************************************************************************/
274 :
275 0 : int OGRSVGDataSource::TestCapability( const char *pszCap )
276 : {
277 0 : return FALSE;
278 : }
|