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