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 : }
|