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