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