1 : /******************************************************************************
2 : * $Id: kml.cpp 23589 2011-12-17 14:21:01Z 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 44 : KML::KML()
40 : {
41 44 : nDepth_ = 0;
42 44 : validity = KML_VALIDITY_UNKNOWN;
43 44 : pKMLFile_ = NULL;
44 44 : sError_ = "";
45 44 : poTrunk_ = NULL;
46 44 : poCurrent_ = NULL;
47 44 : nNumLayers_ = -1;
48 44 : papoLayers_ = NULL;
49 44 : }
50 :
51 44 : KML::~KML()
52 : {
53 44 : if( NULL != pKMLFile_ )
54 28 : VSIFCloseL(pKMLFile_);
55 44 : CPLFree(papoLayers_);
56 :
57 44 : delete poTrunk_;
58 44 : }
59 :
60 44 : bool KML::open(const char * pszFilename)
61 : {
62 44 : if( NULL != pKMLFile_ )
63 0 : VSIFCloseL( pKMLFile_ );
64 :
65 44 : pKMLFile_ = VSIFOpenL( pszFilename, "r" );
66 44 : if( NULL == pKMLFile_ )
67 : {
68 16 : return FALSE;
69 : }
70 :
71 28 : return TRUE;
72 : }
73 :
74 7 : void KML::parse()
75 : {
76 7 : std::size_t nDone = 0;
77 7 : std::size_t nLen = 0;
78 7 : char aBuf[BUFSIZ] = { 0 };
79 :
80 7 : if( NULL == pKMLFile_ )
81 : {
82 0 : sError_ = "No file given";
83 0 : return;
84 : }
85 :
86 7 : if(poTrunk_ != NULL) {
87 0 : delete poTrunk_;
88 0 : poTrunk_ = NULL;
89 : }
90 :
91 7 : if(poCurrent_ != NULL)
92 : {
93 0 : delete poCurrent_;
94 0 : poCurrent_ = NULL;
95 : }
96 :
97 7 : XML_Parser oParser = OGRCreateExpatXMLParser();
98 7 : XML_SetUserData(oParser, this);
99 7 : XML_SetElementHandler(oParser, startElement, endElement);
100 7 : XML_SetCharacterDataHandler(oParser, dataHandler);
101 7 : oCurrentParser = oParser;
102 7 : nWithoutEventCounter = 0;
103 :
104 19 : do
105 : {
106 19 : nDataHandlerCounter = 0;
107 19 : nLen = (int)VSIFReadL( aBuf, 1, sizeof(aBuf), pKMLFile_ );
108 19 : nDone = VSIFEofL(pKMLFile_);
109 19 : 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 19 : nWithoutEventCounter ++;
121 : } while (!nDone && nLen > 0 && nWithoutEventCounter < 10);
122 :
123 7 : XML_ParserFree(oParser);
124 7 : VSIRewindL(pKMLFile_);
125 7 : poCurrent_ = NULL;
126 :
127 7 : 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 28 : void KML::checkValidity()
135 : {
136 28 : std::size_t nDone = 0;
137 28 : std::size_t nLen = 0;
138 28 : char aBuf[BUFSIZ] = { 0 };
139 :
140 28 : if(poTrunk_ != NULL)
141 : {
142 0 : delete poTrunk_;
143 0 : poTrunk_ = NULL;
144 : }
145 :
146 28 : if(poCurrent_ != NULL)
147 : {
148 0 : delete poCurrent_;
149 0 : poCurrent_ = NULL;
150 : }
151 :
152 28 : if(pKMLFile_ == NULL)
153 : {
154 0 : this->sError_ = "No file given";
155 0 : return;
156 : }
157 :
158 28 : XML_Parser oParser = OGRCreateExpatXMLParser();
159 28 : XML_SetUserData(oParser, this);
160 28 : XML_SetElementHandler(oParser, startElementValidate, NULL);
161 28 : XML_SetCharacterDataHandler(oParser, dataHandlerValidate);
162 28 : int nCount = 0;
163 :
164 28 : oCurrentParser = oParser;
165 :
166 : /* Parses the file until we find the first element */
167 10 : do
168 : {
169 28 : nDataHandlerCounter = 0;
170 28 : nLen = (int)VSIFReadL( aBuf, 1, sizeof(aBuf), pKMLFile_ );
171 28 : nDone = VSIFEofL(pKMLFile_);
172 28 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
173 : {
174 18 : if (nLen <= BUFSIZ-1)
175 10 : aBuf[nLen] = 0;
176 : else
177 8 : aBuf[BUFSIZ-1] = 0;
178 18 : 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 18 : validity = KML_VALIDITY_INVALID;
188 18 : XML_ParserFree(oParser);
189 18 : VSIRewindL(pKMLFile_);
190 18 : return;
191 : }
192 :
193 10 : 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 10 : XML_ParserFree(oParser);
199 10 : VSIRewindL(pKMLFile_);
200 10 : poCurrent_ = NULL;
201 : }
202 :
203 1683 : void XMLCALL KML::startElement(void* pUserData, const char* pszName, const char** ppszAttr)
204 : {
205 1683 : int i = 0;
206 1683 : KMLNode* poMynew = NULL;
207 1683 : Attribute* poAtt = NULL;
208 :
209 1683 : KML* poKML = (KML*) pUserData;
210 :
211 1683 : poKML->nWithoutEventCounter = 0;
212 :
213 1683 : if(poKML->poTrunk_ == NULL
214 : || (poKML->poCurrent_->getName()).compare("description") != 0)
215 : {
216 1678 : 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 1678 : poMynew = new KMLNode();
226 3356 : poMynew->setName(pszName);
227 1678 : poMynew->setLevel(poKML->nDepth_);
228 :
229 4162 : for (i = 0; ppszAttr[i]; i += 2)
230 : {
231 403 : poAtt = new Attribute();
232 403 : poAtt->sName = ppszAttr[i];
233 403 : poAtt->sValue = ppszAttr[i + 1];
234 403 : poMynew->addAttribute(poAtt);
235 : }
236 :
237 1678 : if(poKML->poTrunk_ == NULL)
238 7 : poKML->poTrunk_ = poMynew;
239 1678 : if(poKML->poCurrent_ != NULL)
240 1671 : poMynew->setParent(poKML->poCurrent_);
241 1678 : poKML->poCurrent_ = poMynew;
242 :
243 1678 : 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 694 : void XMLCALL KML::startElementValidate(void* pUserData, const char* pszName, const char** ppszAttr)
266 : {
267 694 : int i = 0;
268 :
269 694 : KML* poKML = (KML*) pUserData;
270 :
271 694 : if (poKML->validity != KML_VALIDITY_UNKNOWN)
272 686 : return;
273 :
274 8 : poKML->validity = KML_VALIDITY_INVALID;
275 :
276 8 : if(strcmp(pszName, "kml") == 0)
277 : {
278 : // Check all Attributes
279 14 : for (i = 0; ppszAttr[i]; i += 2)
280 : {
281 : // Find the namespace and determine the KML version
282 7 : if(strcmp(ppszAttr[i], "xmlns") == 0)
283 : {
284 : // Is it KML 2.2?
285 9 : 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 2 : poKML->validity = KML_VALIDITY_VALID;
289 2 : 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 7 : 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 2225 : void XMLCALL KML::dataHandlerValidate(void * pUserData, const char * pszData, int nLen)
320 : {
321 2225 : KML* poKML = (KML*) pUserData;
322 :
323 2225 : poKML->nDataHandlerCounter ++;
324 2225 : 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 2225 : }
330 :
331 1683 : void XMLCALL KML::endElement(void* pUserData, const char* pszName)
332 : {
333 1683 : KMLNode* poTmp = NULL;
334 :
335 1683 : KML* poKML = (KML*) pUserData;
336 :
337 1683 : poKML->nWithoutEventCounter = 0;
338 :
339 1683 : if(poKML->poCurrent_ != NULL &&
340 : poKML->poCurrent_->getName().compare(pszName) == 0)
341 : {
342 1678 : poKML->nDepth_--;
343 1678 : poTmp = poKML->poCurrent_;
344 : // Split the coordinates
345 1678 : 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 1584 : else if (poKML->poCurrent_->numContent() == 1)
381 : {
382 1391 : std::string sData = poKML->poCurrent_->getContent(0);
383 1391 : std::string sDataWithoutNL;
384 1391 : std::size_t nPos = 0;
385 1391 : std::size_t nLength = sData.length();
386 1391 : const char* pszData = sData.c_str();
387 1391 : std::size_t nLineStartPos = 0;
388 1391 : 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 46520 : while(nPos < nLength)
393 : {
394 43738 : char ch = pszData[nPos];
395 63231 : if (bLineStart && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'))
396 19493 : nLineStartPos ++;
397 24585 : 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 23905 : bLineStart = FALSE;
412 : }
413 43738 : nPos ++;
414 : }
415 :
416 1391 : if (nLineStartPos > 0)
417 : {
418 533 : 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 533 : poKML->poCurrent_->deleteContent(0);
427 533 : poKML->poCurrent_->addContent(sDataWithoutNL);
428 1391 : }
429 : }
430 :
431 1678 : if(poKML->poCurrent_->getParent() != NULL)
432 1671 : poKML->poCurrent_ = poKML->poCurrent_->getParent();
433 : else
434 7 : poKML->poCurrent_ = NULL;
435 :
436 1678 : if(!poKML->isHandled(pszName))
437 : {
438 993 : CPLDebug("KML", "Not handled: %s", pszName);
439 993 : delete poTmp;
440 : }
441 : else
442 : {
443 685 : if(poKML->poCurrent_ != NULL)
444 678 : 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 1683 : }
458 :
459 6765 : void XMLCALL KML::dataHandler(void* pUserData, const char* pszData, int nLen)
460 : {
461 6765 : KML* poKML = (KML*) pUserData;
462 :
463 6765 : poKML->nWithoutEventCounter = 0;
464 :
465 6765 : if(nLen < 1 || poKML->poCurrent_ == NULL)
466 0 : return;
467 :
468 6765 : poKML->nDataHandlerCounter ++;
469 6765 : 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 6765 : std::string sData(pszData, nLen);
478 :
479 13530 : if(poKML->poCurrent_->numContent() == 0)
480 1485 : poKML->poCurrent_->addContent(sData);
481 : else
482 5280 : 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 28 : bool KML::isValid()
492 : {
493 28 : checkValidity();
494 :
495 28 : if( validity == KML_VALIDITY_VALID )
496 : CPLDebug("KML", "Valid: %d Version: %s",
497 7 : validity == KML_VALIDITY_VALID, sVersion_.c_str());
498 :
499 28 : return validity == KML_VALIDITY_VALID;
500 : }
501 :
502 0 : std::string KML::getError() const
503 : {
504 0 : return sError_;
505 : }
506 :
507 7 : int KML::classifyNodes()
508 : {
509 7 : 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 1678 : bool KML::isHandled(std::string const& elem) const
524 : {
525 3907 : if( isLeaf(elem) || isFeature(elem) || isFeatureContainer(elem)
526 2229 : || isContainer(elem) || isRest(elem) )
527 : {
528 685 : 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)
559 : {
560 : // idle
561 0 : };
562 :
563 7 : int KML::getNumLayers() const
564 : {
565 7 : return nNumLayers_;
566 : }
567 :
568 317 : bool KML::selectLayer(int nNum) {
569 317 : if(this->nNumLayers_ < 1 || nNum >= this->nNumLayers_)
570 0 : return FALSE;
571 317 : poCurrent_ = papoLayers_[nNum];
572 317 : return TRUE;
573 : }
574 :
575 23 : std::string KML::getCurrentName() const
576 : {
577 23 : std::string tmp;
578 23 : if( poCurrent_ != NULL )
579 : {
580 23 : tmp = poCurrent_->getNameElement();
581 : }
582 0 : return tmp;
583 : }
584 :
585 56 : Nodetype KML::getCurrentType() const
586 : {
587 56 : if(poCurrent_ != NULL)
588 56 : return poCurrent_->getType();
589 : else
590 0 : return Unknown;
591 : }
592 :
593 21 : int KML::is25D() const
594 : {
595 21 : if(poCurrent_ != NULL)
596 21 : return poCurrent_->is25D();
597 : else
598 0 : return Unknown;
599 : }
600 :
601 27 : int KML::getNumFeatures()
602 : {
603 27 : if(poCurrent_ != NULL)
604 27 : return static_cast<int>(poCurrent_->getNumFeatures());
605 : else
606 0 : return -1;
607 : }
608 :
609 330 : Feature* KML::getFeature(std::size_t nNum, int& nLastAsked, int &nLastCount)
610 : {
611 330 : if(poCurrent_ != NULL)
612 330 : return poCurrent_->getFeature(nNum, nLastAsked, nLastCount);
613 : else
614 0 : return NULL;
615 1947 : }
|