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 61 : KML::KML()
40 : {
41 61 : nDepth_ = 0;
42 61 : validity = KML_VALIDITY_UNKNOWN;
43 61 : pKMLFile_ = NULL;
44 61 : sError_ = "";
45 61 : poTrunk_ = NULL;
46 61 : poCurrent_ = NULL;
47 61 : nNumLayers_ = -1;
48 61 : papoLayers_ = NULL;
49 61 : }
50 :
51 61 : KML::~KML()
52 : {
53 61 : if( NULL != pKMLFile_ )
54 56 : VSIFCloseL(pKMLFile_);
55 61 : CPLFree(papoLayers_);
56 :
57 61 : delete poTrunk_;
58 61 : }
59 :
60 61 : bool KML::open(const char * pszFilename)
61 : {
62 61 : if( NULL != pKMLFile_ )
63 0 : VSIFCloseL( pKMLFile_ );
64 :
65 61 : pKMLFile_ = VSIFOpenL( pszFilename, "r" );
66 61 : if( NULL == pKMLFile_ )
67 : {
68 5 : return FALSE;
69 : }
70 :
71 56 : return TRUE;
72 : }
73 :
74 3 : void KML::parse()
75 : {
76 3 : std::size_t nDone = 0;
77 3 : std::size_t nLen = 0;
78 3 : char aBuf[BUFSIZ] = { 0 };
79 :
80 3 : if( NULL == pKMLFile_ )
81 : {
82 0 : sError_ = "No file given";
83 0 : return;
84 : }
85 :
86 3 : if(poTrunk_ != NULL) {
87 0 : delete poTrunk_;
88 0 : poTrunk_ = NULL;
89 : }
90 :
91 3 : if(poCurrent_ != NULL)
92 : {
93 0 : delete poCurrent_;
94 0 : poCurrent_ = NULL;
95 : }
96 :
97 3 : XML_Parser oParser = OGRCreateExpatXMLParser();
98 3 : XML_SetUserData(oParser, this);
99 3 : XML_SetElementHandler(oParser, startElement, endElement);
100 3 : XML_SetCharacterDataHandler(oParser, dataHandler);
101 3 : oCurrentParser = oParser;
102 3 : nWithoutEventCounter = 0;
103 :
104 7 : do
105 : {
106 7 : nDataHandlerCounter = 0;
107 7 : nLen = (int)VSIFReadL( aBuf, 1, sizeof(aBuf), pKMLFile_ );
108 7 : nDone = VSIFEofL(pKMLFile_);
109 7 : 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 7 : nWithoutEventCounter ++;
121 : } while (!nDone && nLen > 0 && nWithoutEventCounter < 10);
122 :
123 3 : XML_ParserFree(oParser);
124 3 : VSIRewindL(pKMLFile_);
125 3 : poCurrent_ = NULL;
126 :
127 3 : 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 56 : void KML::checkValidity()
135 : {
136 56 : std::size_t nDone = 0;
137 56 : std::size_t nLen = 0;
138 56 : char aBuf[BUFSIZ] = { 0 };
139 :
140 56 : if(poTrunk_ != NULL)
141 : {
142 0 : delete poTrunk_;
143 0 : poTrunk_ = NULL;
144 : }
145 :
146 56 : if(poCurrent_ != NULL)
147 : {
148 0 : delete poCurrent_;
149 0 : poCurrent_ = NULL;
150 : }
151 :
152 56 : if(pKMLFile_ == NULL)
153 : {
154 0 : this->sError_ = "No file given";
155 0 : return;
156 : }
157 :
158 56 : XML_Parser oParser = OGRCreateExpatXMLParser();
159 56 : XML_SetUserData(oParser, this);
160 56 : XML_SetElementHandler(oParser, startElementValidate, NULL);
161 56 : XML_SetCharacterDataHandler(oParser, dataHandlerValidate);
162 56 : int nCount = 0;
163 :
164 56 : oCurrentParser = oParser;
165 :
166 : /* Parses the file until we find the first element */
167 17 : do
168 : {
169 56 : nDataHandlerCounter = 0;
170 56 : nLen = (int)VSIFReadL( aBuf, 1, sizeof(aBuf), pKMLFile_ );
171 56 : nDone = VSIFEofL(pKMLFile_);
172 56 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
173 : {
174 39 : if (nLen <= BUFSIZ-1)
175 29 : aBuf[nLen] = 0;
176 : else
177 10 : aBuf[BUFSIZ-1] = 0;
178 39 : 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 39 : validity = KML_VALIDITY_INVALID;
188 39 : XML_ParserFree(oParser);
189 39 : VSIRewindL(pKMLFile_);
190 39 : return;
191 : }
192 :
193 17 : 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 17 : XML_ParserFree(oParser);
199 17 : VSIRewindL(pKMLFile_);
200 17 : poCurrent_ = NULL;
201 : }
202 :
203 570 : void XMLCALL KML::startElement(void* pUserData, const char* pszName, const char** ppszAttr)
204 : {
205 570 : int i = 0;
206 570 : KMLNode* poMynew = NULL;
207 570 : Attribute* poAtt = NULL;
208 :
209 570 : KML* poKML = (KML*) pUserData;
210 :
211 570 : poKML->nWithoutEventCounter = 0;
212 :
213 570 : if(poKML->poTrunk_ == NULL
214 : || (poKML->poCurrent_->getName()).compare("description") != 0)
215 : {
216 567 : poMynew = new KMLNode();
217 1134 : poMynew->setName(pszName);
218 567 : poMynew->setLevel(poKML->nDepth_);
219 :
220 1424 : for (i = 0; ppszAttr[i]; i += 2)
221 : {
222 145 : poAtt = new Attribute();
223 145 : poAtt->sName = ppszAttr[i];
224 145 : poAtt->sValue = ppszAttr[i + 1];
225 145 : poMynew->addAttribute(poAtt);
226 : }
227 :
228 567 : if(poKML->poTrunk_ == NULL)
229 3 : poKML->poTrunk_ = poMynew;
230 567 : if(poKML->poCurrent_ != NULL)
231 564 : poMynew->setParent(poKML->poCurrent_);
232 567 : poKML->poCurrent_ = poMynew;
233 :
234 567 : 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 570 : }
255 :
256 546 : void XMLCALL KML::startElementValidate(void* pUserData, const char* pszName, const char** ppszAttr)
257 : {
258 546 : int i = 0;
259 :
260 546 : KML* poKML = (KML*) pUserData;
261 :
262 546 : if (poKML->validity != KML_VALIDITY_UNKNOWN)
263 529 : return;
264 :
265 17 : poKML->validity = KML_VALIDITY_INVALID;
266 :
267 17 : if(strcmp(pszName, "kml") == 0)
268 : {
269 : // Check all Attributes
270 6 : for (i = 0; ppszAttr[i]; i += 2)
271 : {
272 : // Find the namespace and determine the KML version
273 3 : if(strcmp(ppszAttr[i], "xmlns") == 0)
274 : {
275 : // Is it KML 2.2?
276 4 : 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 1 : poKML->validity = KML_VALIDITY_VALID;
280 1 : 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 3 : 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 1643 : void XMLCALL KML::dataHandlerValidate(void * pUserData, const char * pszData, int nLen)
311 : {
312 1643 : KML* poKML = (KML*) pUserData;
313 :
314 1643 : poKML->nDataHandlerCounter ++;
315 1643 : 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 1643 : }
321 :
322 570 : void XMLCALL KML::endElement(void* pUserData, const char* pszName)
323 : {
324 570 : KMLNode* poTmp = NULL;
325 :
326 570 : KML* poKML = (KML*) pUserData;
327 :
328 570 : poKML->nWithoutEventCounter = 0;
329 :
330 570 : if(poKML->poCurrent_ != NULL &&
331 : poKML->poCurrent_->getName().compare(pszName) == 0)
332 : {
333 567 : poKML->nDepth_--;
334 567 : poTmp = poKML->poCurrent_;
335 : // Split the coordinates
336 567 : if(poKML->poCurrent_->getName().compare("coordinates") == 0 &&
337 : poKML->poCurrent_->numContent() == 1)
338 : {
339 37 : std::string sData = poKML->poCurrent_->getContent(0);
340 37 : std::size_t nPos = 0;
341 37 : std::size_t nLength = sData.length();
342 37 : const char* pszData = sData.c_str();
343 221 : while(TRUE)
344 : {
345 : // Cut off whitespaces
346 7322 : while(nPos < nLength &&
347 3484 : (pszData[nPos] == ' ' || pszData[nPos] == '\n'
348 442 : || pszData[nPos] == '\r' || pszData[nPos] == '\t' ))
349 2880 : nPos ++;
350 :
351 258 : if (nPos == nLength)
352 : break;
353 :
354 221 : std::size_t nPosBegin = nPos;
355 :
356 : // Get content
357 37394 : while(nPos < nLength &&
358 22316 : pszData[nPos] != ' ' && pszData[nPos] != '\n' && pszData[nPos] != '\r' &&
359 7318 : pszData[nPos] != '\t')
360 7318 : nPos++;
361 :
362 221 : if(nPos - nPosBegin > 0)
363 : {
364 221 : std::string sTmp(pszData + nPosBegin, nPos - nPosBegin);
365 442 : poKML->poCurrent_->addContent(sTmp);
366 : }
367 : }
368 74 : if(poKML->poCurrent_->numContent() > 1)
369 37 : poKML->poCurrent_->deleteContent(0);
370 : }
371 530 : else if (poKML->poCurrent_->numContent() == 1)
372 : {
373 468 : std::string sData = poKML->poCurrent_->getContent(0);
374 468 : std::string sDataWithoutNL;
375 468 : std::size_t nPos = 0;
376 468 : std::size_t nLength = sData.length();
377 468 : const char* pszData = sData.c_str();
378 468 : std::size_t nLineStartPos = 0;
379 468 : 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 15575 : while(nPos < nLength)
384 : {
385 14639 : char ch = pszData[nPos];
386 21137 : if (bLineStart && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'))
387 6498 : nLineStartPos ++;
388 8255 : 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 8027 : bLineStart = FALSE;
403 : }
404 14639 : nPos ++;
405 : }
406 :
407 468 : if (nLineStartPos > 0)
408 : {
409 181 : 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 181 : poKML->poCurrent_->deleteContent(0);
418 181 : poKML->poCurrent_->addContent(sDataWithoutNL);
419 468 : }
420 : }
421 :
422 567 : if(poKML->poCurrent_->getParent() != NULL)
423 564 : poKML->poCurrent_ = poKML->poCurrent_->getParent();
424 : else
425 3 : poKML->poCurrent_ = NULL;
426 :
427 567 : if(!poKML->isHandled(pszName))
428 : {
429 331 : CPLDebug("KML", "Not handled: %s", pszName);
430 331 : delete poTmp;
431 : }
432 : else
433 : {
434 236 : if(poKML->poCurrent_ != NULL)
435 233 : 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 570 : }
449 :
450 2270 : void XMLCALL KML::dataHandler(void* pUserData, const char* pszData, int nLen)
451 : {
452 2270 : KML* poKML = (KML*) pUserData;
453 :
454 2270 : poKML->nWithoutEventCounter = 0;
455 :
456 2270 : if(nLen < 1 || poKML->poCurrent_ == NULL)
457 0 : return;
458 :
459 2270 : poKML->nDataHandlerCounter ++;
460 2270 : 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 2270 : std::string sData(pszData, nLen);
467 :
468 4540 : if(poKML->poCurrent_->numContent() == 0)
469 505 : poKML->poCurrent_->addContent(sData);
470 : else
471 1765 : poKML->poCurrent_->appendContent(sData);
472 : }
473 :
474 56 : bool KML::isValid()
475 : {
476 56 : checkValidity();
477 :
478 56 : if( validity == KML_VALIDITY_VALID )
479 : CPLDebug("KML", "Valid: %d Version: %s",
480 3 : validity == KML_VALIDITY_VALID, sVersion_.c_str());
481 :
482 56 : return validity == KML_VALIDITY_VALID;
483 : }
484 :
485 0 : std::string KML::getError() const
486 : {
487 0 : return sError_;
488 : }
489 :
490 3 : void KML::classifyNodes()
491 : {
492 3 : poTrunk_->classify(this);
493 3 : }
494 :
495 3 : void KML::eliminateEmpty()
496 : {
497 3 : poTrunk_->eliminateEmpty(this);
498 3 : }
499 :
500 0 : void KML::print(unsigned short nNum)
501 : {
502 0 : if( poTrunk_ != NULL )
503 0 : poTrunk_->print(nNum);
504 0 : }
505 :
506 567 : bool KML::isHandled(std::string const& elem) const
507 : {
508 1310 : if( isLeaf(elem) || isFeature(elem) || isFeatureContainer(elem)
509 743 : || isContainer(elem) || isRest(elem) )
510 : {
511 236 : 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 3 : int KML::getNumLayers() const
547 : {
548 3 : return nNumLayers_;
549 : }
550 :
551 42 : bool KML::selectLayer(int nNum) {
552 42 : if(this->nNumLayers_ < 1 || nNum >= this->nNumLayers_)
553 0 : return FALSE;
554 42 : poCurrent_ = papoLayers_[nNum];
555 42 : return TRUE;
556 : }
557 :
558 9 : std::string KML::getCurrentName() const
559 : {
560 9 : std::string tmp;
561 9 : if( poCurrent_ != NULL )
562 : {
563 9 : tmp = poCurrent_->getNameElement();
564 : }
565 0 : return tmp;
566 : }
567 :
568 22 : Nodetype KML::getCurrentType() const
569 : {
570 22 : if(poCurrent_ != NULL)
571 22 : 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 32 : Feature* KML::getFeature(std::size_t nNum, int& nLastAsked, int &nLastCount)
593 : {
594 32 : if(poCurrent_ != NULL)
595 32 : return poCurrent_->getFeature(nNum, nLastAsked, nLastCount);
596 : else
597 0 : return NULL;
598 1140 : }
|