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 92 : KML::KML()
40 : {
41 92 : nDepth_ = 0;
42 92 : validity = KML_VALIDITY_UNKNOWN;
43 92 : pKMLFile_ = NULL;
44 92 : sError_ = "";
45 92 : poTrunk_ = NULL;
46 92 : poCurrent_ = NULL;
47 92 : nNumLayers_ = -1;
48 92 : papoLayers_ = NULL;
49 92 : }
50 :
51 92 : KML::~KML()
52 : {
53 92 : if( NULL != pKMLFile_ )
54 64 : VSIFCloseL(pKMLFile_);
55 92 : CPLFree(papoLayers_);
56 :
57 92 : delete poTrunk_;
58 92 : }
59 :
60 92 : bool KML::open(const char * pszFilename)
61 : {
62 92 : if( NULL != pKMLFile_ )
63 0 : VSIFCloseL( pKMLFile_ );
64 :
65 92 : pKMLFile_ = VSIFOpenL( pszFilename, "r" );
66 92 : if( NULL == pKMLFile_ )
67 : {
68 28 : return FALSE;
69 : }
70 :
71 64 : return TRUE;
72 : }
73 :
74 9 : void KML::parse()
75 : {
76 9 : std::size_t nDone = 0;
77 9 : std::size_t nLen = 0;
78 9 : char aBuf[BUFSIZ] = { 0 };
79 :
80 9 : if( NULL == pKMLFile_ )
81 : {
82 0 : sError_ = "No file given";
83 0 : return;
84 : }
85 :
86 9 : if(poTrunk_ != NULL) {
87 0 : delete poTrunk_;
88 0 : poTrunk_ = NULL;
89 : }
90 :
91 9 : if(poCurrent_ != NULL)
92 : {
93 0 : delete poCurrent_;
94 0 : poCurrent_ = NULL;
95 : }
96 :
97 9 : XML_Parser oParser = OGRCreateExpatXMLParser();
98 9 : XML_SetUserData(oParser, this);
99 9 : XML_SetElementHandler(oParser, startElement, endElement);
100 9 : XML_SetCharacterDataHandler(oParser, dataHandler);
101 9 : oCurrentParser = oParser;
102 9 : nWithoutEventCounter = 0;
103 :
104 21 : do
105 : {
106 21 : nDataHandlerCounter = 0;
107 21 : nLen = (int)VSIFReadL( aBuf, 1, sizeof(aBuf), pKMLFile_ );
108 21 : nDone = VSIFEofL(pKMLFile_);
109 21 : 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 21 : nWithoutEventCounter ++;
121 : } while (!nDone && nLen > 0 && nWithoutEventCounter < 10);
122 :
123 9 : XML_ParserFree(oParser);
124 9 : VSIRewindL(pKMLFile_);
125 9 : poCurrent_ = NULL;
126 :
127 9 : 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 64 : void KML::checkValidity()
135 : {
136 64 : std::size_t nDone = 0;
137 64 : std::size_t nLen = 0;
138 64 : char aBuf[BUFSIZ] = { 0 };
139 :
140 64 : if(poTrunk_ != NULL)
141 : {
142 0 : delete poTrunk_;
143 0 : poTrunk_ = NULL;
144 : }
145 :
146 64 : if(poCurrent_ != NULL)
147 : {
148 0 : delete poCurrent_;
149 0 : poCurrent_ = NULL;
150 : }
151 :
152 64 : if(pKMLFile_ == NULL)
153 : {
154 0 : this->sError_ = "No file given";
155 0 : return;
156 : }
157 :
158 64 : XML_Parser oParser = OGRCreateExpatXMLParser();
159 64 : XML_SetUserData(oParser, this);
160 64 : XML_SetElementHandler(oParser, startElementValidate, NULL);
161 64 : XML_SetCharacterDataHandler(oParser, dataHandlerValidate);
162 64 : int nCount = 0;
163 :
164 64 : oCurrentParser = oParser;
165 :
166 : /* Parses the file until we find the first element */
167 15 : do
168 : {
169 64 : nDataHandlerCounter = 0;
170 64 : nLen = (int)VSIFReadL( aBuf, 1, sizeof(aBuf), pKMLFile_ );
171 64 : nDone = VSIFEofL(pKMLFile_);
172 64 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
173 : {
174 49 : if (nLen <= BUFSIZ-1)
175 21 : aBuf[nLen] = 0;
176 : else
177 28 : aBuf[BUFSIZ-1] = 0;
178 49 : 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 49 : validity = KML_VALIDITY_INVALID;
188 49 : XML_ParserFree(oParser);
189 49 : VSIRewindL(pKMLFile_);
190 49 : return;
191 : }
192 :
193 15 : 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 15 : XML_ParserFree(oParser);
199 15 : VSIRewindL(pKMLFile_);
200 15 : poCurrent_ = NULL;
201 : }
202 :
203 1695 : void XMLCALL KML::startElement(void* pUserData, const char* pszName, const char** ppszAttr)
204 : {
205 1695 : int i = 0;
206 1695 : KMLNode* poMynew = NULL;
207 1695 : Attribute* poAtt = NULL;
208 :
209 1695 : KML* poKML = (KML*) pUserData;
210 :
211 1695 : poKML->nWithoutEventCounter = 0;
212 :
213 1695 : if(poKML->poTrunk_ == NULL
214 : || (poKML->poCurrent_->getName()).compare("description") != 0)
215 : {
216 1690 : 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 1690 : poMynew = new KMLNode();
226 3380 : poMynew->setName(pszName);
227 1690 : poMynew->setLevel(poKML->nDepth_);
228 :
229 4198 : for (i = 0; ppszAttr[i]; i += 2)
230 : {
231 409 : poAtt = new Attribute();
232 409 : poAtt->sName = ppszAttr[i];
233 409 : poAtt->sValue = ppszAttr[i + 1];
234 409 : poMynew->addAttribute(poAtt);
235 : }
236 :
237 1690 : if(poKML->poTrunk_ == NULL)
238 9 : poKML->poTrunk_ = poMynew;
239 1690 : if(poKML->poCurrent_ != NULL)
240 1681 : poMynew->setParent(poKML->poCurrent_);
241 1690 : poKML->poCurrent_ = poMynew;
242 :
243 1690 : poKML->nDepth_++;
244 : }
245 : else
246 : {
247 5 : std::string sNewContent = "<";
248 5 : sNewContent += pszName;
249 6 : for (i = 0; ppszAttr[i]; i += 2)
250 : {
251 1 : sNewContent += " ";
252 1 : sNewContent += ppszAttr[i];
253 1 : sNewContent += "=\"";
254 1 : sNewContent += ppszAttr[i + 1];
255 1 : sNewContent += "\"";
256 : }
257 5 : sNewContent += ">";
258 5 : if(poKML->poCurrent_->numContent() == 0)
259 0 : poKML->poCurrent_->addContent(sNewContent);
260 : else
261 5 : poKML->poCurrent_->appendContent(sNewContent);
262 : }
263 : }
264 :
265 707 : void XMLCALL KML::startElementValidate(void* pUserData, const char* pszName, const char** ppszAttr)
266 : {
267 707 : int i = 0;
268 :
269 707 : KML* poKML = (KML*) pUserData;
270 :
271 707 : if (poKML->validity != KML_VALIDITY_UNKNOWN)
272 696 : return;
273 :
274 11 : poKML->validity = KML_VALIDITY_INVALID;
275 :
276 11 : if(strcmp(pszName, "kml") == 0)
277 : {
278 : // Check all Attributes
279 20 : for (i = 0; ppszAttr[i]; i += 2)
280 : {
281 : // Find the namespace and determine the KML version
282 11 : if(strcmp(ppszAttr[i], "xmlns") == 0)
283 : {
284 : // Is it KML 2.2?
285 13 : 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 4 : poKML->validity = KML_VALIDITY_VALID;
289 4 : poKML->sVersion_ = "2.2";
290 : }
291 5 : else if(strcmp(ppszAttr[i + 1], "http://earth.google.com/kml/2.1") == 0)
292 : {
293 5 : poKML->validity = KML_VALIDITY_VALID;
294 5 : 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 9 : 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 2267 : void XMLCALL KML::dataHandlerValidate(void * pUserData, const char * pszData, int nLen)
320 : {
321 2267 : KML* poKML = (KML*) pUserData;
322 :
323 2267 : poKML->nDataHandlerCounter ++;
324 2267 : 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 2267 : }
330 :
331 1695 : void XMLCALL KML::endElement(void* pUserData, const char* pszName)
332 : {
333 1695 : KMLNode* poTmp = NULL;
334 :
335 1695 : KML* poKML = (KML*) pUserData;
336 :
337 1695 : poKML->nWithoutEventCounter = 0;
338 :
339 1695 : if(poKML->poCurrent_ != NULL &&
340 : poKML->poCurrent_->getName().compare(pszName) == 0)
341 : {
342 1690 : poKML->nDepth_--;
343 1690 : poTmp = poKML->poCurrent_;
344 : // Split the coordinates
345 1690 : if(poKML->poCurrent_->getName().compare("coordinates") == 0 &&
346 : poKML->poCurrent_->numContent() == 1)
347 : {
348 94 : std::string sData = poKML->poCurrent_->getContent(0);
349 94 : std::size_t nPos = 0;
350 94 : std::size_t nLength = sData.length();
351 94 : const char* pszData = sData.c_str();
352 634 : while(TRUE)
353 : {
354 : // Cut off whitespaces
355 21734 : while(nPos < nLength &&
356 10382 : (pszData[nPos] == ' ' || pszData[nPos] == '\n'
357 1268 : || pszData[nPos] == '\r' || pszData[nPos] == '\t' ))
358 8628 : nPos ++;
359 :
360 728 : if (nPos == nLength)
361 : break;
362 :
363 634 : std::size_t nPosBegin = nPos;
364 :
365 : // Get content
366 111242 : while(nPos < nLength &&
367 66414 : pszData[nPos] != ' ' && pszData[nPos] != '\n' && pszData[nPos] != '\r' &&
368 21780 : pszData[nPos] != '\t')
369 21780 : nPos++;
370 :
371 634 : if(nPos - nPosBegin > 0)
372 : {
373 634 : std::string sTmp(pszData + nPosBegin, nPos - nPosBegin);
374 1268 : poKML->poCurrent_->addContent(sTmp);
375 : }
376 : }
377 188 : if(poKML->poCurrent_->numContent() > 1)
378 94 : poKML->poCurrent_->deleteContent(0);
379 : }
380 1596 : else if (poKML->poCurrent_->numContent() == 1)
381 : {
382 1403 : std::string sData = poKML->poCurrent_->getContent(0);
383 1403 : std::string sDataWithoutNL;
384 1403 : std::size_t nPos = 0;
385 1403 : std::size_t nLength = sData.length();
386 1403 : const char* pszData = sData.c_str();
387 1403 : std::size_t nLineStartPos = 0;
388 1403 : 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 46721 : while(nPos < nLength)
393 : {
394 43915 : char ch = pszData[nPos];
395 63555 : if (bLineStart && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'))
396 19640 : nLineStartPos ++;
397 24615 : else if (ch == '\n' || ch == '\r')
398 : {
399 340 : if (!bLineStart)
400 : {
401 340 : std::string sTmp(pszData + nLineStartPos, nPos - nLineStartPos);
402 680 : if (sDataWithoutNL.size() > 0)
403 303 : sDataWithoutNL += " ";
404 340 : sDataWithoutNL += sTmp;
405 340 : bLineStart = TRUE;
406 : }
407 340 : nLineStartPos = nPos + 1;
408 : }
409 : else
410 : {
411 23935 : bLineStart = FALSE;
412 : }
413 43915 : nPos ++;
414 : }
415 :
416 1403 : if (nLineStartPos > 0)
417 : {
418 540 : if (nLineStartPos < nPos)
419 : {
420 33 : std::string sTmp(pszData + nLineStartPos, nPos - nLineStartPos);
421 66 : if (sDataWithoutNL.size() > 0)
422 33 : sDataWithoutNL += " ";
423 33 : sDataWithoutNL += sTmp;
424 : }
425 :
426 540 : poKML->poCurrent_->deleteContent(0);
427 540 : poKML->poCurrent_->addContent(sDataWithoutNL);
428 1403 : }
429 : }
430 :
431 1690 : if(poKML->poCurrent_->getParent() != NULL)
432 1681 : poKML->poCurrent_ = poKML->poCurrent_->getParent();
433 : else
434 9 : poKML->poCurrent_ = NULL;
435 :
436 1690 : if(!poKML->isHandled(pszName))
437 : {
438 993 : CPLDebug("KML", "Not handled: %s", pszName);
439 993 : delete poTmp;
440 : }
441 : else
442 : {
443 697 : if(poKML->poCurrent_ != NULL)
444 688 : poKML->poCurrent_->addChildren(poTmp);
445 : }
446 : }
447 5 : else if(poKML->poCurrent_ != NULL)
448 : {
449 5 : std::string sNewContent = "</";
450 5 : sNewContent += pszName;
451 5 : sNewContent += ">";
452 5 : if(poKML->poCurrent_->numContent() == 0)
453 0 : poKML->poCurrent_->addContent(sNewContent);
454 : else
455 5 : poKML->poCurrent_->appendContent(sNewContent);
456 : }
457 1695 : }
458 :
459 6804 : void XMLCALL KML::dataHandler(void* pUserData, const char* pszData, int nLen)
460 : {
461 6804 : KML* poKML = (KML*) pUserData;
462 :
463 6804 : poKML->nWithoutEventCounter = 0;
464 :
465 6804 : if(nLen < 1 || poKML->poCurrent_ == NULL)
466 0 : return;
467 :
468 6804 : poKML->nDataHandlerCounter ++;
469 6804 : 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 6804 : std::string sData(pszData, nLen);
478 :
479 13608 : if(poKML->poCurrent_->numContent() == 0)
480 1497 : poKML->poCurrent_->addContent(sData);
481 : else
482 5307 : 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 64 : bool KML::isValid()
492 : {
493 64 : checkValidity();
494 :
495 64 : if( validity == KML_VALIDITY_VALID )
496 : CPLDebug("KML", "Valid: %d Version: %s",
497 9 : validity == KML_VALIDITY_VALID, sVersion_.c_str());
498 :
499 64 : return validity == KML_VALIDITY_VALID;
500 : }
501 :
502 0 : std::string KML::getError() const
503 : {
504 0 : return sError_;
505 : }
506 :
507 9 : int KML::classifyNodes()
508 : {
509 9 : return poTrunk_->classify(this);
510 : }
511 :
512 7 : void KML::eliminateEmpty()
513 : {
514 7 : poTrunk_->eliminateEmpty(this);
515 7 : }
516 :
517 0 : void KML::print(unsigned short nNum)
518 : {
519 0 : if( poTrunk_ != NULL )
520 0 : poTrunk_->print(nNum);
521 0 : }
522 :
523 1690 : bool KML::isHandled(std::string const& elem) const
524 : {
525 3925 : if( isLeaf(elem) || isFeature(elem) || isFeatureContainer(elem)
526 2235 : || isContainer(elem) || isRest(elem) )
527 : {
528 697 : return true;
529 : }
530 993 : 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 9 : bool KML::hasOnlyEmpty() const
564 : {
565 9 : return poTrunk_->hasOnlyEmpty();
566 : }
567 :
568 9 : int KML::getNumLayers() const
569 : {
570 9 : return nNumLayers_;
571 : }
572 :
573 402 : bool KML::selectLayer(int nNum) {
574 402 : if(this->nNumLayers_ < 1 || nNum >= this->nNumLayers_)
575 0 : return FALSE;
576 402 : poCurrent_ = papoLayers_[nNum];
577 402 : return TRUE;
578 : }
579 :
580 25 : std::string KML::getCurrentName() const
581 : {
582 25 : std::string tmp;
583 25 : if( poCurrent_ != NULL )
584 : {
585 25 : tmp = poCurrent_->getNameElement();
586 : }
587 0 : return tmp;
588 : }
589 :
590 70 : Nodetype KML::getCurrentType() const
591 : {
592 70 : if(poCurrent_ != NULL)
593 70 : return poCurrent_->getType();
594 : else
595 0 : return Unknown;
596 : }
597 :
598 21 : int KML::is25D() const
599 : {
600 21 : if(poCurrent_ != NULL)
601 21 : return poCurrent_->is25D();
602 : else
603 0 : return Unknown;
604 : }
605 :
606 29 : int KML::getNumFeatures()
607 : {
608 29 : if(poCurrent_ != NULL)
609 29 : return static_cast<int>(poCurrent_->getNumFeatures());
610 : else
611 0 : return -1;
612 : }
613 :
614 430 : Feature* KML::getFeature(std::size_t nNum, int& nLastAsked, int &nLastCount)
615 : {
616 430 : if(poCurrent_ != NULL)
617 430 : return poCurrent_->getFeature(nNum, nLastAsked, nLastCount);
618 : else
619 0 : return NULL;
620 2139 : }
|