1 : /******************************************************************************
2 : * $Id: kml.cpp 23978 2012-02-14 20:42:34Z rouault $
3 : *
4 : * Project: KML Driver
5 : * Purpose: Class for reading, parsing and handling a kmlfile.
6 : * Author: Jens Oberender, j.obi@troja.net
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2007, Jens Oberender
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 : #include "kmlnode.h"
30 : #include "kml.h"
31 : #include "cpl_error.h"
32 : #include "cpl_conv.h"
33 : // std
34 : #include <cstdio>
35 : #include <cerrno>
36 : #include <string>
37 : #include <iostream>
38 :
39 164 : KML::KML()
40 : {
41 164 : nDepth_ = 0;
42 164 : validity = KML_VALIDITY_UNKNOWN;
43 164 : pKMLFile_ = NULL;
44 164 : sError_ = "";
45 164 : poTrunk_ = NULL;
46 164 : poCurrent_ = NULL;
47 164 : nNumLayers_ = -1;
48 164 : papoLayers_ = NULL;
49 164 : }
50 :
51 164 : KML::~KML()
52 : {
53 164 : if( NULL != pKMLFile_ )
54 98 : VSIFCloseL(pKMLFile_);
55 164 : CPLFree(papoLayers_);
56 :
57 164 : delete poTrunk_;
58 164 : }
59 :
60 164 : bool KML::open(const char * pszFilename)
61 : {
62 164 : if( NULL != pKMLFile_ )
63 0 : VSIFCloseL( pKMLFile_ );
64 :
65 164 : pKMLFile_ = VSIFOpenL( pszFilename, "r" );
66 164 : if( NULL == pKMLFile_ )
67 : {
68 66 : return FALSE;
69 : }
70 :
71 98 : return TRUE;
72 : }
73 :
74 18 : void KML::parse()
75 : {
76 18 : std::size_t nDone = 0;
77 18 : std::size_t nLen = 0;
78 18 : char aBuf[BUFSIZ] = { 0 };
79 :
80 18 : if( NULL == pKMLFile_ )
81 : {
82 0 : sError_ = "No file given";
83 0 : return;
84 : }
85 :
86 18 : if(poTrunk_ != NULL) {
87 0 : delete poTrunk_;
88 0 : poTrunk_ = NULL;
89 : }
90 :
91 18 : if(poCurrent_ != NULL)
92 : {
93 0 : delete poCurrent_;
94 0 : poCurrent_ = NULL;
95 : }
96 :
97 18 : XML_Parser oParser = OGRCreateExpatXMLParser();
98 18 : XML_SetUserData(oParser, this);
99 18 : XML_SetElementHandler(oParser, startElement, endElement);
100 18 : XML_SetCharacterDataHandler(oParser, dataHandler);
101 18 : oCurrentParser = oParser;
102 18 : nWithoutEventCounter = 0;
103 :
104 42 : do
105 : {
106 42 : nDataHandlerCounter = 0;
107 42 : nLen = (int)VSIFReadL( aBuf, 1, sizeof(aBuf), pKMLFile_ );
108 42 : nDone = VSIFEofL(pKMLFile_);
109 42 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
110 : {
111 : CPLError(CE_Failure, CPLE_AppDefined,
112 : "XML parsing of KML file failed : %s at line %d, column %d",
113 : XML_ErrorString(XML_GetErrorCode(oParser)),
114 : (int)XML_GetCurrentLineNumber(oParser),
115 0 : (int)XML_GetCurrentColumnNumber(oParser));
116 0 : XML_ParserFree(oParser);
117 0 : VSIRewindL(pKMLFile_);
118 0 : return;
119 : }
120 42 : nWithoutEventCounter ++;
121 : } while (!nDone && nLen > 0 && nWithoutEventCounter < 10);
122 :
123 18 : XML_ParserFree(oParser);
124 18 : VSIRewindL(pKMLFile_);
125 18 : poCurrent_ = NULL;
126 :
127 18 : if (nWithoutEventCounter == 10)
128 : {
129 : CPLError(CE_Failure, CPLE_AppDefined,
130 0 : "Too much data inside one element. File probably corrupted");
131 : }
132 : }
133 :
134 98 : void KML::checkValidity()
135 : {
136 98 : std::size_t nDone = 0;
137 98 : std::size_t nLen = 0;
138 98 : char aBuf[BUFSIZ] = { 0 };
139 :
140 98 : if(poTrunk_ != NULL)
141 : {
142 0 : delete poTrunk_;
143 0 : poTrunk_ = NULL;
144 : }
145 :
146 98 : if(poCurrent_ != NULL)
147 : {
148 0 : delete poCurrent_;
149 0 : poCurrent_ = NULL;
150 : }
151 :
152 98 : if(pKMLFile_ == NULL)
153 : {
154 0 : this->sError_ = "No file given";
155 0 : return;
156 : }
157 :
158 98 : XML_Parser oParser = OGRCreateExpatXMLParser();
159 98 : XML_SetUserData(oParser, this);
160 98 : XML_SetElementHandler(oParser, startElementValidate, NULL);
161 98 : XML_SetCharacterDataHandler(oParser, dataHandlerValidate);
162 98 : int nCount = 0;
163 :
164 98 : oCurrentParser = oParser;
165 :
166 : /* Parses the file until we find the first element */
167 28 : do
168 : {
169 98 : nDataHandlerCounter = 0;
170 98 : nLen = (int)VSIFReadL( aBuf, 1, sizeof(aBuf), pKMLFile_ );
171 98 : nDone = VSIFEofL(pKMLFile_);
172 98 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
173 : {
174 70 : if (nLen <= BUFSIZ-1)
175 26 : aBuf[nLen] = 0;
176 : else
177 44 : aBuf[BUFSIZ-1] = 0;
178 70 : if (strstr(aBuf, "<?xml") && strstr(aBuf, "<kml"))
179 : {
180 : CPLError(CE_Failure, CPLE_AppDefined,
181 : "XML parsing of KML file failed : %s at line %d, column %d",
182 : XML_ErrorString(XML_GetErrorCode(oParser)),
183 : (int)XML_GetCurrentLineNumber(oParser),
184 0 : (int)XML_GetCurrentColumnNumber(oParser));
185 : }
186 :
187 70 : validity = KML_VALIDITY_INVALID;
188 70 : XML_ParserFree(oParser);
189 70 : VSIRewindL(pKMLFile_);
190 70 : return;
191 : }
192 :
193 28 : nCount ++;
194 : /* After reading 50 * BUFSIZE bytes, and not finding whether the file */
195 : /* is KML or not, we give up and fail silently */
196 : } while (!nDone && nLen > 0 && validity == KML_VALIDITY_UNKNOWN && nCount < 50);
197 :
198 28 : XML_ParserFree(oParser);
199 28 : VSIRewindL(pKMLFile_);
200 28 : poCurrent_ = NULL;
201 : }
202 :
203 3390 : void XMLCALL KML::startElement(void* pUserData, const char* pszName, const char** ppszAttr)
204 : {
205 3390 : int i = 0;
206 3390 : KMLNode* poMynew = NULL;
207 3390 : Attribute* poAtt = NULL;
208 :
209 3390 : KML* poKML = (KML*) pUserData;
210 :
211 3390 : poKML->nWithoutEventCounter = 0;
212 :
213 3390 : if(poKML->poTrunk_ == NULL
214 : || (poKML->poCurrent_->getName()).compare("description") != 0)
215 : {
216 3380 : if (poKML->nDepth_ == 1024)
217 : {
218 : CPLError( CE_Failure, CPLE_AppDefined,
219 : "Too big depth level (%d) while parsing KML.",
220 0 : poKML->nDepth_ );
221 0 : XML_StopParser(poKML->oCurrentParser, XML_FALSE);
222 0 : return;
223 : }
224 :
225 3380 : poMynew = new KMLNode();
226 6760 : poMynew->setName(pszName);
227 3380 : poMynew->setLevel(poKML->nDepth_);
228 :
229 8396 : for (i = 0; ppszAttr[i]; i += 2)
230 : {
231 818 : poAtt = new Attribute();
232 818 : poAtt->sName = ppszAttr[i];
233 818 : poAtt->sValue = ppszAttr[i + 1];
234 818 : poMynew->addAttribute(poAtt);
235 : }
236 :
237 3380 : if(poKML->poTrunk_ == NULL)
238 18 : poKML->poTrunk_ = poMynew;
239 3380 : if(poKML->poCurrent_ != NULL)
240 3362 : poMynew->setParent(poKML->poCurrent_);
241 3380 : poKML->poCurrent_ = poMynew;
242 :
243 3380 : poKML->nDepth_++;
244 : }
245 : else
246 : {
247 10 : std::string sNewContent = "<";
248 10 : sNewContent += pszName;
249 12 : for (i = 0; ppszAttr[i]; i += 2)
250 : {
251 2 : sNewContent += " ";
252 2 : sNewContent += ppszAttr[i];
253 2 : sNewContent += "=\"";
254 2 : sNewContent += ppszAttr[i + 1];
255 2 : sNewContent += "\"";
256 : }
257 10 : sNewContent += ">";
258 10 : if(poKML->poCurrent_->numContent() == 0)
259 0 : poKML->poCurrent_->addContent(sNewContent);
260 : else
261 10 : poKML->poCurrent_->appendContent(sNewContent);
262 : }
263 : }
264 :
265 1412 : void XMLCALL KML::startElementValidate(void* pUserData, const char* pszName, const char** ppszAttr)
266 : {
267 1412 : int i = 0;
268 :
269 1412 : KML* poKML = (KML*) pUserData;
270 :
271 1412 : if (poKML->validity != KML_VALIDITY_UNKNOWN)
272 1392 : return;
273 :
274 20 : poKML->validity = KML_VALIDITY_INVALID;
275 :
276 20 : if(strcmp(pszName, "kml") == 0)
277 : {
278 : // Check all Attributes
279 40 : for (i = 0; ppszAttr[i]; i += 2)
280 : {
281 : // Find the namespace and determine the KML version
282 22 : if(strcmp(ppszAttr[i], "xmlns") == 0)
283 : {
284 : // Is it KML 2.2?
285 26 : if((strcmp(ppszAttr[i + 1], "http://earth.google.com/kml/2.2") == 0) ||
286 : (strcmp(ppszAttr[i + 1], "http://www.opengis.net/kml/2.2") == 0))
287 : {
288 8 : poKML->validity = KML_VALIDITY_VALID;
289 8 : poKML->sVersion_ = "2.2";
290 : }
291 10 : else if(strcmp(ppszAttr[i + 1], "http://earth.google.com/kml/2.1") == 0)
292 : {
293 10 : poKML->validity = KML_VALIDITY_VALID;
294 10 : poKML->sVersion_ = "2.1";
295 : }
296 0 : else if(strcmp(ppszAttr[i + 1], "http://earth.google.com/kml/2.0") == 0)
297 : {
298 0 : poKML->validity = KML_VALIDITY_VALID;
299 0 : poKML->sVersion_ = "2.0";
300 : }
301 : else
302 : {
303 0 : CPLDebug("KML", "Unhandled xmlns value : %s. Going on though...", ppszAttr[i]);
304 0 : poKML->validity = KML_VALIDITY_VALID;
305 0 : poKML->sVersion_ = "?";
306 : }
307 : }
308 : }
309 :
310 18 : if (poKML->validity == KML_VALIDITY_INVALID)
311 : {
312 0 : CPLDebug("KML", "Did not find xmlns attribute in <kml> element. Going on though...");
313 0 : poKML->validity = KML_VALIDITY_VALID;
314 0 : poKML->sVersion_ = "?";
315 : }
316 : }
317 : }
318 :
319 4528 : void XMLCALL KML::dataHandlerValidate(void * pUserData, const char * pszData, int nLen)
320 : {
321 4528 : KML* poKML = (KML*) pUserData;
322 :
323 4528 : poKML->nDataHandlerCounter ++;
324 4528 : if (poKML->nDataHandlerCounter >= BUFSIZ)
325 : {
326 0 : CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
327 0 : XML_StopParser(poKML->oCurrentParser, XML_FALSE);
328 : }
329 4528 : }
330 :
331 3390 : void XMLCALL KML::endElement(void* pUserData, const char* pszName)
332 : {
333 3390 : KMLNode* poTmp = NULL;
334 :
335 3390 : KML* poKML = (KML*) pUserData;
336 :
337 3390 : poKML->nWithoutEventCounter = 0;
338 :
339 3390 : if(poKML->poCurrent_ != NULL &&
340 : poKML->poCurrent_->getName().compare(pszName) == 0)
341 : {
342 3380 : poKML->nDepth_--;
343 3380 : poTmp = poKML->poCurrent_;
344 : // Split the coordinates
345 3380 : if(poKML->poCurrent_->getName().compare("coordinates") == 0 &&
346 : poKML->poCurrent_->numContent() == 1)
347 : {
348 188 : std::string sData = poKML->poCurrent_->getContent(0);
349 188 : std::size_t nPos = 0;
350 188 : std::size_t nLength = sData.length();
351 188 : const char* pszData = sData.c_str();
352 1268 : while(TRUE)
353 : {
354 : // Cut off whitespaces
355 43468 : while(nPos < nLength &&
356 20764 : (pszData[nPos] == ' ' || pszData[nPos] == '\n'
357 2536 : || pszData[nPos] == '\r' || pszData[nPos] == '\t' ))
358 17256 : nPos ++;
359 :
360 1456 : if (nPos == nLength)
361 : break;
362 :
363 1268 : std::size_t nPosBegin = nPos;
364 :
365 : // Get content
366 222484 : while(nPos < nLength &&
367 132828 : pszData[nPos] != ' ' && pszData[nPos] != '\n' && pszData[nPos] != '\r' &&
368 43560 : pszData[nPos] != '\t')
369 43560 : nPos++;
370 :
371 1268 : if(nPos - nPosBegin > 0)
372 : {
373 1268 : std::string sTmp(pszData + nPosBegin, nPos - nPosBegin);
374 2536 : poKML->poCurrent_->addContent(sTmp);
375 : }
376 : }
377 376 : if(poKML->poCurrent_->numContent() > 1)
378 188 : poKML->poCurrent_->deleteContent(0);
379 : }
380 3192 : else if (poKML->poCurrent_->numContent() == 1)
381 : {
382 2806 : std::string sData = poKML->poCurrent_->getContent(0);
383 2806 : std::string sDataWithoutNL;
384 2806 : std::size_t nPos = 0;
385 2806 : std::size_t nLength = sData.length();
386 2806 : const char* pszData = sData.c_str();
387 2806 : std::size_t nLineStartPos = 0;
388 2806 : int bLineStart = TRUE;
389 :
390 : /* Re-assemble multi-line content by removing leading spaces for each line */
391 : /* I'm not sure why we do that. Shouldn't we preserve content as such ? */
392 93442 : while(nPos < nLength)
393 : {
394 87830 : char ch = pszData[nPos];
395 127110 : if (bLineStart && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'))
396 39280 : nLineStartPos ++;
397 49230 : else if (ch == '\n' || ch == '\r')
398 : {
399 680 : if (!bLineStart)
400 : {
401 680 : std::string sTmp(pszData + nLineStartPos, nPos - nLineStartPos);
402 1360 : if (sDataWithoutNL.size() > 0)
403 606 : sDataWithoutNL += " ";
404 680 : sDataWithoutNL += sTmp;
405 680 : bLineStart = TRUE;
406 : }
407 680 : nLineStartPos = nPos + 1;
408 : }
409 : else
410 : {
411 47870 : bLineStart = FALSE;
412 : }
413 87830 : nPos ++;
414 : }
415 :
416 2806 : if (nLineStartPos > 0)
417 : {
418 1080 : if (nLineStartPos < nPos)
419 : {
420 66 : std::string sTmp(pszData + nLineStartPos, nPos - nLineStartPos);
421 132 : if (sDataWithoutNL.size() > 0)
422 66 : sDataWithoutNL += " ";
423 66 : sDataWithoutNL += sTmp;
424 : }
425 :
426 1080 : poKML->poCurrent_->deleteContent(0);
427 1080 : poKML->poCurrent_->addContent(sDataWithoutNL);
428 2806 : }
429 : }
430 :
431 3380 : if(poKML->poCurrent_->getParent() != NULL)
432 3362 : poKML->poCurrent_ = poKML->poCurrent_->getParent();
433 : else
434 18 : poKML->poCurrent_ = NULL;
435 :
436 3380 : if(!poKML->isHandled(pszName))
437 : {
438 1986 : CPLDebug("KML", "Not handled: %s", pszName);
439 1986 : delete poTmp;
440 : }
441 : else
442 : {
443 1394 : if(poKML->poCurrent_ != NULL)
444 1376 : poKML->poCurrent_->addChildren(poTmp);
445 : }
446 : }
447 10 : else if(poKML->poCurrent_ != NULL)
448 : {
449 10 : std::string sNewContent = "</";
450 10 : sNewContent += pszName;
451 10 : sNewContent += ">";
452 10 : if(poKML->poCurrent_->numContent() == 0)
453 0 : poKML->poCurrent_->addContent(sNewContent);
454 : else
455 10 : poKML->poCurrent_->appendContent(sNewContent);
456 : }
457 3390 : }
458 :
459 13608 : void XMLCALL KML::dataHandler(void* pUserData, const char* pszData, int nLen)
460 : {
461 13608 : KML* poKML = (KML*) pUserData;
462 :
463 13608 : poKML->nWithoutEventCounter = 0;
464 :
465 13608 : if(nLen < 1 || poKML->poCurrent_ == NULL)
466 0 : return;
467 :
468 13608 : poKML->nDataHandlerCounter ++;
469 13608 : if (poKML->nDataHandlerCounter >= BUFSIZ)
470 : {
471 0 : CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
472 0 : XML_StopParser(poKML->oCurrentParser, XML_FALSE);
473 : }
474 :
475 : try
476 : {
477 13608 : std::string sData(pszData, nLen);
478 :
479 27216 : if(poKML->poCurrent_->numContent() == 0)
480 2994 : poKML->poCurrent_->addContent(sData);
481 : else
482 10614 : poKML->poCurrent_->appendContent(sData);
483 : }
484 0 : catch(const std::exception& ex)
485 : {
486 0 : CPLError(CE_Failure, CPLE_AppDefined, "libstdc++ exception : %s", ex.what());
487 0 : XML_StopParser(poKML->oCurrentParser, XML_FALSE);
488 : }
489 : }
490 :
491 98 : bool KML::isValid()
492 : {
493 98 : checkValidity();
494 :
495 98 : if( validity == KML_VALIDITY_VALID )
496 : CPLDebug("KML", "Valid: %d Version: %s",
497 18 : validity == KML_VALIDITY_VALID, sVersion_.c_str());
498 :
499 98 : return validity == KML_VALIDITY_VALID;
500 : }
501 :
502 0 : std::string KML::getError() const
503 : {
504 0 : return sError_;
505 : }
506 :
507 18 : int KML::classifyNodes()
508 : {
509 18 : return poTrunk_->classify(this);
510 : }
511 :
512 14 : void KML::eliminateEmpty()
513 : {
514 14 : poTrunk_->eliminateEmpty(this);
515 14 : }
516 :
517 0 : void KML::print(unsigned short nNum)
518 : {
519 0 : if( poTrunk_ != NULL )
520 0 : poTrunk_->print(nNum);
521 0 : }
522 :
523 3380 : bool KML::isHandled(std::string const& elem) const
524 : {
525 7850 : if( isLeaf(elem) || isFeature(elem) || isFeatureContainer(elem)
526 4470 : || isContainer(elem) || isRest(elem) )
527 : {
528 1394 : return true;
529 : }
530 1986 : return false;
531 : }
532 :
533 0 : bool KML::isLeaf(std::string const& elem) const
534 : {
535 0 : return false;
536 : };
537 :
538 0 : bool KML::isFeature(std::string const& elem) const
539 : {
540 0 : return false;
541 : };
542 :
543 0 : bool KML::isFeatureContainer(std::string const& elem) const
544 : {
545 0 : return false;
546 : };
547 :
548 0 : bool KML::isContainer(std::string const& elem) const
549 : {
550 0 : return false;
551 : };
552 :
553 0 : bool KML::isRest(std::string const& elem) const
554 : {
555 0 : return false;
556 : };
557 :
558 0 : void KML::findLayers(KMLNode* poNode, int bKeepEmptyContainers)
559 : {
560 : // idle
561 0 : };
562 :
563 18 : bool KML::hasOnlyEmpty() const
564 : {
565 18 : return poTrunk_->hasOnlyEmpty();
566 : }
567 :
568 18 : int KML::getNumLayers() const
569 : {
570 18 : return nNumLayers_;
571 : }
572 :
573 642 : bool KML::selectLayer(int nNum) {
574 642 : if(this->nNumLayers_ < 1 || nNum >= this->nNumLayers_)
575 0 : return FALSE;
576 642 : poCurrent_ = papoLayers_[nNum];
577 642 : return TRUE;
578 : }
579 :
580 50 : std::string KML::getCurrentName() const
581 : {
582 50 : std::string tmp;
583 50 : if( poCurrent_ != NULL )
584 : {
585 50 : tmp = poCurrent_->getNameElement();
586 : }
587 0 : return tmp;
588 : }
589 :
590 140 : Nodetype KML::getCurrentType() const
591 : {
592 140 : if(poCurrent_ != NULL)
593 140 : return poCurrent_->getType();
594 : else
595 0 : return Unknown;
596 : }
597 :
598 42 : int KML::is25D() const
599 : {
600 42 : if(poCurrent_ != NULL)
601 42 : return poCurrent_->is25D();
602 : else
603 0 : return Unknown;
604 : }
605 :
606 58 : int KML::getNumFeatures()
607 : {
608 58 : if(poCurrent_ != NULL)
609 58 : return static_cast<int>(poCurrent_->getNumFeatures());
610 : else
611 0 : return -1;
612 : }
613 :
614 660 : Feature* KML::getFeature(std::size_t nNum, int& nLastAsked, int &nLastCount)
615 : {
616 660 : if(poCurrent_ != NULL)
617 660 : return poCurrent_->getFeature(nNum, nLastAsked, nLastCount);
618 : else
619 0 : return NULL;
620 4029 : }
|