1 : /******************************************************************************
2 : * $Id: kml.cpp 17946 2009-11-01 18:31:43Z 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 82 : KML::KML()
40 : {
41 82 : nDepth_ = 0;
42 82 : validity = KML_VALIDITY_UNKNOWN;
43 82 : pKMLFile_ = NULL;
44 82 : sError_ = "";
45 82 : poTrunk_ = NULL;
46 82 : poCurrent_ = NULL;
47 82 : nNumLayers_ = -1;
48 82 : papoLayers_ = NULL;
49 82 : }
50 :
51 82 : KML::~KML()
52 : {
53 82 : if( NULL != pKMLFile_ )
54 78 : VSIFCloseL(pKMLFile_);
55 82 : CPLFree(papoLayers_);
56 :
57 82 : delete poTrunk_;
58 82 : }
59 :
60 82 : bool KML::open(const char * pszFilename)
61 : {
62 82 : if( NULL != pKMLFile_ )
63 0 : VSIFCloseL( pKMLFile_ );
64 :
65 82 : pKMLFile_ = VSIFOpenL( pszFilename, "r" );
66 82 : if( NULL == pKMLFile_ )
67 : {
68 4 : return FALSE;
69 : }
70 :
71 78 : return TRUE;
72 : }
73 :
74 4 : void KML::parse()
75 : {
76 4 : std::size_t nDone = 0;
77 4 : std::size_t nLen = 0;
78 4 : char aBuf[BUFSIZ] = { 0 };
79 :
80 4 : if( NULL == pKMLFile_ )
81 : {
82 0 : sError_ = "No file given";
83 0 : return;
84 : }
85 :
86 4 : if(poTrunk_ != NULL) {
87 0 : delete poTrunk_;
88 0 : poTrunk_ = NULL;
89 : }
90 :
91 4 : if(poCurrent_ != NULL)
92 : {
93 0 : delete poCurrent_;
94 0 : poCurrent_ = NULL;
95 : }
96 :
97 4 : XML_Parser oParser = OGRCreateExpatXMLParser();
98 4 : XML_SetUserData(oParser, this);
99 4 : XML_SetElementHandler(oParser, startElement, endElement);
100 4 : XML_SetCharacterDataHandler(oParser, dataHandler);
101 4 : oCurrentParser = oParser;
102 4 : nWithoutEventCounter = 0;
103 :
104 8 : do
105 : {
106 8 : nDataHandlerCounter = 0;
107 8 : nLen = (int)VSIFReadL( aBuf, 1, sizeof(aBuf), pKMLFile_ );
108 8 : nDone = VSIFEofL(pKMLFile_);
109 8 : 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 8 : nWithoutEventCounter ++;
121 : } while (!nDone && nLen > 0 && nWithoutEventCounter < 10);
122 :
123 4 : XML_ParserFree(oParser);
124 4 : VSIRewindL(pKMLFile_);
125 4 : poCurrent_ = NULL;
126 :
127 4 : 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 78 : void KML::checkValidity()
135 : {
136 78 : std::size_t nDone = 0;
137 78 : std::size_t nLen = 0;
138 78 : char aBuf[BUFSIZ] = { 0 };
139 :
140 78 : if(poTrunk_ != NULL)
141 : {
142 0 : delete poTrunk_;
143 0 : poTrunk_ = NULL;
144 : }
145 :
146 78 : if(poCurrent_ != NULL)
147 : {
148 0 : delete poCurrent_;
149 0 : poCurrent_ = NULL;
150 : }
151 :
152 78 : if(pKMLFile_ == NULL)
153 : {
154 0 : this->sError_ = "No file given";
155 0 : return;
156 : }
157 :
158 78 : XML_Parser oParser = OGRCreateExpatXMLParser();
159 78 : XML_SetUserData(oParser, this);
160 78 : XML_SetElementHandler(oParser, startElementValidate, NULL);
161 78 : XML_SetCharacterDataHandler(oParser, dataHandlerValidate);
162 78 : int nCount = 0;
163 :
164 78 : oCurrentParser = oParser;
165 :
166 : /* Parses the file until we find the first element */
167 18 : do
168 : {
169 78 : nDataHandlerCounter = 0;
170 78 : nLen = (int)VSIFReadL( aBuf, 1, sizeof(aBuf), pKMLFile_ );
171 78 : nDone = VSIFEofL(pKMLFile_);
172 78 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
173 : {
174 60 : if (nLen <= BUFSIZ-1)
175 37 : aBuf[nLen] = 0;
176 : else
177 23 : aBuf[BUFSIZ-1] = 0;
178 60 : 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 60 : validity = KML_VALIDITY_INVALID;
188 60 : XML_ParserFree(oParser);
189 60 : VSIRewindL(pKMLFile_);
190 60 : return;
191 : }
192 :
193 18 : 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 18 : XML_ParserFree(oParser);
199 18 : VSIRewindL(pKMLFile_);
200 18 : poCurrent_ = NULL;
201 : }
202 :
203 677 : void XMLCALL KML::startElement(void* pUserData, const char* pszName, const char** ppszAttr)
204 : {
205 677 : int i = 0;
206 677 : KMLNode* poMynew = NULL;
207 677 : Attribute* poAtt = NULL;
208 :
209 677 : KML* poKML = (KML*) pUserData;
210 :
211 677 : poKML->nWithoutEventCounter = 0;
212 :
213 677 : if(poKML->poTrunk_ == NULL
214 : || (poKML->poCurrent_->getName()).compare("description") != 0)
215 : {
216 674 : poMynew = new KMLNode();
217 1348 : poMynew->setName(pszName);
218 674 : poMynew->setLevel(poKML->nDepth_);
219 :
220 1640 : for (i = 0; ppszAttr[i]; i += 2)
221 : {
222 146 : poAtt = new Attribute();
223 146 : poAtt->sName = ppszAttr[i];
224 146 : poAtt->sValue = ppszAttr[i + 1];
225 146 : poMynew->addAttribute(poAtt);
226 : }
227 :
228 674 : if(poKML->poTrunk_ == NULL)
229 4 : poKML->poTrunk_ = poMynew;
230 674 : if(poKML->poCurrent_ != NULL)
231 670 : poMynew->setParent(poKML->poCurrent_);
232 674 : poKML->poCurrent_ = poMynew;
233 :
234 674 : poKML->nDepth_++;
235 : }
236 : else
237 : {
238 3 : std::string sNewContent = "<";
239 3 : sNewContent += pszName;
240 4 : for (i = 0; ppszAttr[i]; i += 2)
241 : {
242 1 : sNewContent += " ";
243 1 : sNewContent += ppszAttr[i];
244 1 : sNewContent += "=\"";
245 1 : sNewContent += ppszAttr[i + 1];
246 1 : sNewContent += "\"";
247 : }
248 3 : sNewContent += ">";
249 3 : if(poKML->poCurrent_->numContent() == 0)
250 0 : poKML->poCurrent_->addContent(sNewContent);
251 : else
252 3 : poKML->poCurrent_->appendContent(sNewContent);
253 : }
254 677 : }
255 :
256 653 : void XMLCALL KML::startElementValidate(void* pUserData, const char* pszName, const char** ppszAttr)
257 : {
258 653 : int i = 0;
259 :
260 653 : KML* poKML = (KML*) pUserData;
261 :
262 653 : if (poKML->validity != KML_VALIDITY_UNKNOWN)
263 635 : return;
264 :
265 18 : poKML->validity = KML_VALIDITY_INVALID;
266 :
267 18 : if(strcmp(pszName, "kml") == 0)
268 : {
269 : // Check all Attributes
270 8 : for (i = 0; ppszAttr[i]; i += 2)
271 : {
272 : // Find the namespace and determine the KML version
273 4 : if(strcmp(ppszAttr[i], "xmlns") == 0)
274 : {
275 : // Is it KML 2.2?
276 6 : if((strcmp(ppszAttr[i + 1], "http://earth.google.com/kml/2.2") == 0) ||
277 : (strcmp(ppszAttr[i + 1], "http://www.opengis.net/kml/2.2") == 0))
278 : {
279 2 : poKML->validity = KML_VALIDITY_VALID;
280 2 : poKML->sVersion_ = "2.2";
281 : }
282 2 : else if(strcmp(ppszAttr[i + 1], "http://earth.google.com/kml/2.1") == 0)
283 : {
284 2 : poKML->validity = KML_VALIDITY_VALID;
285 2 : poKML->sVersion_ = "2.1";
286 : }
287 0 : else if(strcmp(ppszAttr[i + 1], "http://earth.google.com/kml/2.0") == 0)
288 : {
289 0 : poKML->validity = KML_VALIDITY_VALID;
290 0 : poKML->sVersion_ = "2.0";
291 : }
292 : else
293 : {
294 0 : CPLDebug("KML", "Unhandled xmlns value : %s. Going on though...", ppszAttr[i]);
295 0 : poKML->validity = KML_VALIDITY_VALID;
296 0 : poKML->sVersion_ = "?";
297 : }
298 : }
299 : }
300 :
301 4 : if (poKML->validity == KML_VALIDITY_INVALID)
302 : {
303 0 : CPLDebug("KML", "Did not find xmlns attribute in <kml> element. Going on though...");
304 0 : poKML->validity = KML_VALIDITY_VALID;
305 0 : poKML->sVersion_ = "?";
306 : }
307 : }
308 : }
309 :
310 1812 : void XMLCALL KML::dataHandlerValidate(void * pUserData, const char * pszData, int nLen)
311 : {
312 1812 : KML* poKML = (KML*) pUserData;
313 :
314 1812 : poKML->nDataHandlerCounter ++;
315 1812 : if (poKML->nDataHandlerCounter >= BUFSIZ)
316 : {
317 0 : CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
318 0 : XML_StopParser(poKML->oCurrentParser, XML_FALSE);
319 : }
320 1812 : }
321 :
322 677 : void XMLCALL KML::endElement(void* pUserData, const char* pszName)
323 : {
324 677 : KMLNode* poTmp = NULL;
325 :
326 677 : KML* poKML = (KML*) pUserData;
327 :
328 677 : poKML->nWithoutEventCounter = 0;
329 :
330 677 : if(poKML->poCurrent_ != NULL &&
331 : poKML->poCurrent_->getName().compare(pszName) == 0)
332 : {
333 674 : poKML->nDepth_--;
334 674 : poTmp = poKML->poCurrent_;
335 : // Split the coordinates
336 674 : if(poKML->poCurrent_->getName().compare("coordinates") == 0 &&
337 : poKML->poCurrent_->numContent() == 1)
338 : {
339 53 : std::string sData = poKML->poCurrent_->getContent(0);
340 53 : std::size_t nPos = 0;
341 53 : std::size_t nLength = sData.length();
342 53 : const char* pszData = sData.c_str();
343 269 : while(TRUE)
344 : {
345 : // Cut off whitespaces
346 3556 : while(nPos < nLength &&
347 : (pszData[nPos] == ' ' || pszData[nPos] == '\n'
348 : || pszData[nPos] == '\r' || pszData[nPos] == '\t' ))
349 2912 : nPos ++;
350 :
351 322 : if (nPos == nLength)
352 53 : break;
353 :
354 269 : std::size_t nPosBegin = nPos;
355 :
356 : // Get content
357 8000 : while(nPos < nLength &&
358 : pszData[nPos] != ' ' && pszData[nPos] != '\n' && pszData[nPos] != '\r' &&
359 : pszData[nPos] != '\t')
360 7462 : nPos++;
361 :
362 269 : if(nPos - nPosBegin > 0)
363 : {
364 269 : std::string sTmp(pszData + nPosBegin, nPos - nPosBegin);
365 538 : poKML->poCurrent_->addContent(sTmp);
366 : }
367 : }
368 53 : if(poKML->poCurrent_->numContent() > 1)
369 53 : poKML->poCurrent_->deleteContent(0);
370 : }
371 621 : else if (poKML->poCurrent_->numContent() == 1)
372 : {
373 496 : std::string sData = poKML->poCurrent_->getContent(0);
374 496 : std::string sDataWithoutNL;
375 496 : std::size_t nPos = 0;
376 496 : std::size_t nLength = sData.length();
377 496 : const char* pszData = sData.c_str();
378 496 : std::size_t nLineStartPos = 0;
379 496 : int bLineStart = TRUE;
380 :
381 : /* Re-assemble multi-line content by removing leading spaces for each line */
382 : /* I'm not sure why we do that. Shouldn't we preserve content as such ? */
383 15969 : while(nPos < nLength)
384 : {
385 14977 : char ch = pszData[nPos];
386 21802 : if (bLineStart && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'))
387 6825 : nLineStartPos ++;
388 8266 : else if (ch == '\n' || ch == '\r')
389 : {
390 114 : if (!bLineStart)
391 : {
392 114 : std::string sTmp(pszData + nLineStartPos, nPos - nLineStartPos);
393 228 : if (sDataWithoutNL.size() > 0)
394 101 : sDataWithoutNL += " ";
395 114 : sDataWithoutNL += sTmp;
396 114 : bLineStart = TRUE;
397 : }
398 114 : nLineStartPos = nPos + 1;
399 : }
400 : else
401 : {
402 8038 : bLineStart = FALSE;
403 : }
404 14977 : nPos ++;
405 : }
406 :
407 496 : if (nLineStartPos > 0)
408 : {
409 208 : if (nLineStartPos < nPos)
410 : {
411 11 : std::string sTmp(pszData + nLineStartPos, nPos - nLineStartPos);
412 22 : if (sDataWithoutNL.size() > 0)
413 11 : sDataWithoutNL += " ";
414 11 : sDataWithoutNL += sTmp;
415 : }
416 :
417 208 : poKML->poCurrent_->deleteContent(0);
418 208 : poKML->poCurrent_->addContent(sDataWithoutNL);
419 496 : }
420 : }
421 :
422 674 : if(poKML->poCurrent_->getParent() != NULL)
423 670 : poKML->poCurrent_ = poKML->poCurrent_->getParent();
424 : else
425 4 : poKML->poCurrent_ = NULL;
426 :
427 674 : if(!poKML->isHandled(pszName))
428 : {
429 331 : CPLDebug("KML", "Not handled: %s", pszName);
430 331 : delete poTmp;
431 : }
432 : else
433 : {
434 343 : if(poKML->poCurrent_ != NULL)
435 339 : poKML->poCurrent_->addChildren(poTmp);
436 : }
437 : }
438 3 : else if(poKML->poCurrent_ != NULL)
439 : {
440 3 : std::string sNewContent = "</";
441 3 : sNewContent += pszName;
442 3 : sNewContent += ">";
443 3 : if(poKML->poCurrent_->numContent() == 0)
444 0 : poKML->poCurrent_->addContent(sNewContent);
445 : else
446 3 : poKML->poCurrent_->appendContent(sNewContent);
447 : }
448 677 : }
449 :
450 2439 : void XMLCALL KML::dataHandler(void* pUserData, const char* pszData, int nLen)
451 : {
452 2439 : KML* poKML = (KML*) pUserData;
453 :
454 2439 : poKML->nWithoutEventCounter = 0;
455 :
456 2439 : if(nLen < 1 || poKML->poCurrent_ == NULL)
457 0 : return;
458 :
459 2439 : poKML->nDataHandlerCounter ++;
460 2439 : if (poKML->nDataHandlerCounter >= BUFSIZ)
461 : {
462 0 : CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
463 0 : XML_StopParser(poKML->oCurrentParser, XML_FALSE);
464 : }
465 :
466 2439 : std::string sData(pszData, nLen);
467 :
468 4878 : if(poKML->poCurrent_->numContent() == 0)
469 549 : poKML->poCurrent_->addContent(sData);
470 : else
471 1890 : poKML->poCurrent_->appendContent(sData);
472 : }
473 :
474 78 : bool KML::isValid()
475 : {
476 78 : checkValidity();
477 :
478 78 : if( validity == KML_VALIDITY_VALID )
479 : CPLDebug("KML", "Valid: %d Version: %s",
480 4 : validity == KML_VALIDITY_VALID, sVersion_.c_str());
481 :
482 78 : return validity == KML_VALIDITY_VALID;
483 : }
484 :
485 0 : std::string KML::getError() const
486 : {
487 0 : return sError_;
488 : }
489 :
490 4 : void KML::classifyNodes()
491 : {
492 4 : poTrunk_->classify(this);
493 4 : }
494 :
495 4 : void KML::eliminateEmpty()
496 : {
497 4 : poTrunk_->eliminateEmpty(this);
498 4 : }
499 :
500 0 : void KML::print(unsigned short nNum)
501 : {
502 0 : if( poTrunk_ != NULL )
503 0 : poTrunk_->print(nNum);
504 0 : }
505 :
506 674 : bool KML::isHandled(std::string const& elem) const
507 : {
508 674 : if( isLeaf(elem) || isFeature(elem) || isFeatureContainer(elem)
509 : || isContainer(elem) || isRest(elem) )
510 : {
511 343 : return true;
512 : }
513 331 : return false;
514 : }
515 :
516 0 : bool KML::isLeaf(std::string const& elem) const
517 : {
518 0 : return false;
519 : };
520 :
521 0 : bool KML::isFeature(std::string const& elem) const
522 : {
523 0 : return false;
524 : };
525 :
526 0 : bool KML::isFeatureContainer(std::string const& elem) const
527 : {
528 0 : return false;
529 : };
530 :
531 0 : bool KML::isContainer(std::string const& elem) const
532 : {
533 0 : return false;
534 : };
535 :
536 0 : bool KML::isRest(std::string const& elem) const
537 : {
538 0 : return false;
539 : };
540 :
541 0 : void KML::findLayers(KMLNode* poNode)
542 : {
543 : // idle
544 0 : };
545 :
546 4 : int KML::getNumLayers() const
547 : {
548 4 : return nNumLayers_;
549 : }
550 :
551 66 : bool KML::selectLayer(int nNum) {
552 66 : if(this->nNumLayers_ < 1 || nNum >= this->nNumLayers_)
553 0 : return FALSE;
554 66 : poCurrent_ = papoLayers_[nNum];
555 66 : return TRUE;
556 : }
557 :
558 10 : std::string KML::getCurrentName() const
559 : {
560 10 : std::string tmp;
561 10 : if( poCurrent_ != NULL )
562 : {
563 10 : tmp = poCurrent_->getNameElement();
564 : }
565 0 : return tmp;
566 : }
567 :
568 29 : Nodetype KML::getCurrentType() const
569 : {
570 29 : if(poCurrent_ != NULL)
571 29 : return poCurrent_->getType();
572 : else
573 0 : return Unknown;
574 : }
575 :
576 8 : int KML::is25D() const
577 : {
578 8 : if(poCurrent_ != NULL)
579 8 : return poCurrent_->is25D();
580 : else
581 0 : return Unknown;
582 : }
583 :
584 1 : int KML::getNumFeatures()
585 : {
586 1 : if(poCurrent_ != NULL)
587 1 : return static_cast<int>(poCurrent_->getNumFeatures());
588 : else
589 0 : return -1;
590 : }
591 :
592 55 : Feature* KML::getFeature(std::size_t nNum, int& nLastAsked, int &nLastCount)
593 : {
594 55 : if(poCurrent_ != NULL)
595 55 : return poCurrent_->getFeature(nNum, nLastAsked, nLastCount);
596 : else
597 0 : return NULL;
598 896 : }
|