Coverage Report

Created: 2026-11-12 08:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/kml/kmlnode.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  KML Driver
4
 * Purpose:  Class for building up the node structure of the kml file.
5
 * Author:   Jens Oberender, j.obi@troja.net
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2007, Jens Oberender
9
 * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "kmlnode.h"
16
17
#include <cstring>
18
#include <limits>
19
#include <memory>
20
#include <string>
21
#include <vector>
22
23
#include "cpl_conv.h"
24
#include "cpl_error.h"
25
#include "ogr_geometry.h"
26
27
/************************************************************************/
28
/*                            Help functions                            */
29
/************************************************************************/
30
31
std::string Nodetype2String(Nodetype const &type)
32
399
{
33
399
    if (type == Empty)
34
0
        return "Empty";
35
399
    else if (type == Rest)
36
0
        return "Rest";
37
399
    else if (type == Mixed)
38
142
        return "Mixed";
39
257
    else if (type == Point)
40
136
        return "Point";
41
121
    else if (type == LineString)
42
48
        return "LineString";
43
73
    else if (type == Polygon)
44
46
        return "Polygon";
45
27
    else if (type == MultiGeometry)
46
12
        return "MultiGeometry";
47
15
    else if (type == MultiPoint)
48
0
        return "MultiPoint";
49
15
    else if (type == MultiLineString)
50
15
        return "MultiLineString";
51
0
    else if (type == MultiPolygon)
52
0
        return "MultiPolygon";
53
0
    else
54
0
        return "Unknown";
55
399
}
56
57
static bool isNumberDigit(const char cIn)
58
312k
{
59
312k
    return (cIn == '-' || cIn == '+' || (cIn >= '0' && cIn <= '9') ||
60
218k
            cIn == '.' || cIn == 'e' || cIn == 'E');
61
312k
}
62
63
static Coordinate *ParseCoordinate(std::string const &text)
64
180k
{
65
180k
    int pos = 0;
66
180k
    const char *pszStr = text.c_str();
67
180k
    Coordinate *psTmp = new Coordinate();
68
69
    // X coordinate
70
180k
    psTmp->dfLongitude = CPLAtof(pszStr);
71
284k
    while (isNumberDigit(pszStr[pos++]))
72
103k
        ;
73
74
    // Y coordinate
75
180k
    if (pszStr[pos - 1] != ',')
76
171k
    {
77
171k
        delete psTmp;
78
171k
        return nullptr;
79
171k
    }
80
81
9.01k
    psTmp->dfLatitude = CPLAtof(pszStr + pos);
82
28.5k
    while (isNumberDigit(pszStr[pos++]))
83
19.5k
        ;
84
85
    // Z coordinate
86
9.01k
    if (pszStr[pos - 1] != ',')
87
8.03k
    {
88
8.03k
        psTmp->bHasZ = false;
89
8.03k
        psTmp->dfAltitude = 0;
90
8.03k
        return psTmp;
91
8.03k
    }
92
93
985
    psTmp->bHasZ = true;
94
985
    psTmp->dfAltitude = CPLAtof(pszStr + pos);
95
96
985
    return psTmp;
97
9.01k
}
98
99
/************************************************************************/
100
/*                           KMLNode methods                            */
101
/************************************************************************/
102
103
KMLNode::KMLNode()
104
3.45M
    : pvpoChildren_(new std::vector<KMLNode *>),
105
3.45M
      pvsContent_(new std::vector<std::string>)
106
3.45M
{
107
3.45M
}
108
109
KMLNode::~KMLNode()
110
3.45M
{
111
3.45M
    CPLAssert(nullptr != pvpoChildren_);
112
113
3.45M
    kml_nodes_t::iterator itChild;
114
6.16M
    for (itChild = pvpoChildren_->begin(); itChild != pvpoChildren_->end();
115
3.45M
         ++itChild)
116
2.70M
    {
117
2.70M
        delete (*itChild);
118
2.70M
    }
119
3.45M
    delete pvpoChildren_;
120
121
3.45M
    kml_attributes_t::iterator itAttr;
122
6.05M
    for (itAttr = voAttributes_.begin(); itAttr != voAttributes_.end();
123
3.45M
         ++itAttr)
124
2.59M
    {
125
2.59M
        delete (*itAttr);
126
2.59M
    }
127
128
3.45M
    delete pvsContent_;
129
3.45M
}
130
131
void KMLNode::print(unsigned int what)
132
0
{
133
0
    std::string indent;
134
0
    for (std::size_t l = 0; l < nLevel_; l++)
135
0
        indent += " ";
136
137
0
    if (nLevel_ > 0)
138
0
    {
139
0
        if (nLayerNumber_ > -1)
140
0
        {
141
0
            CPLDebug("KML",
142
0
                     "%s%s (nLevel: %d Type: %s poParent: %s "
143
0
                     "pvpoChildren_: %d pvsContent_: %d pvoAttributes_: %d) "
144
0
                     "<--- Layer #%d",
145
0
                     indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
146
0
                     Nodetype2String(eType_).c_str(), poParent_->sName_.c_str(),
147
0
                     static_cast<int>(pvpoChildren_->size()),
148
0
                     static_cast<int>(pvsContent_->size()),
149
0
                     static_cast<int>(voAttributes_.size()), nLayerNumber_);
150
0
        }
151
0
        else
152
0
        {
153
0
            CPLDebug("KML",
154
0
                     "%s%s (nLevel: %d Type: %s poParent: %s "
155
0
                     "pvpoChildren_: %d pvsContent_: %d pvoAttributes_: %d)",
156
0
                     indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
157
0
                     Nodetype2String(eType_).c_str(), poParent_->sName_.c_str(),
158
0
                     static_cast<int>(pvpoChildren_->size()),
159
0
                     static_cast<int>(pvsContent_->size()),
160
0
                     static_cast<int>(voAttributes_.size()));
161
0
        }
162
0
    }
163
0
    else
164
0
    {
165
0
        CPLDebug("KML",
166
0
                 "%s%s (nLevel: %d Type: %s pvpoChildren_: %d "
167
0
                 "pvsContent_: %d pvoAttributes_: %d)",
168
0
                 indent.c_str(), sName_.c_str(), static_cast<int>(nLevel_),
169
0
                 Nodetype2String(eType_).c_str(),
170
0
                 static_cast<int>(pvpoChildren_->size()),
171
0
                 static_cast<int>(pvsContent_->size()),
172
0
                 static_cast<int>(voAttributes_.size()));
173
0
    }
174
175
0
    if (what == 1 || what == 3)
176
0
    {
177
0
        for (kml_content_t::size_type z = 0; z < pvsContent_->size(); z++)
178
0
            CPLDebug("KML", "%s|->pvsContent_: '%s'", indent.c_str(),
179
0
                     (*pvsContent_)[z].c_str());
180
0
    }
181
182
0
    if (what == 2 || what == 3)
183
0
    {
184
0
        for (kml_attributes_t::size_type z = 0; z < voAttributes_.size(); z++)
185
0
            CPLDebug("KML", "%s|->pvoAttributes_: %s = '%s'", indent.c_str(),
186
0
                     voAttributes_[z]->sName.c_str(),
187
0
                     voAttributes_[z]->sValue.c_str());
188
0
    }
189
190
0
    for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
191
0
        (*pvpoChildren_)[z]->print(what);
192
0
}
193
194
int KMLNode::classify(KML *poKML, int nRecLevel)
195
3.29M
{
196
3.29M
    Nodetype all = Empty;
197
198
    /* Arbitrary value, but certainly large enough for reasonable usages ! */
199
3.29M
    if (nRecLevel == 32)
200
4
    {
201
4
        CPLError(CE_Failure, CPLE_AppDefined,
202
4
                 "Too many recursion levels (%d) while parsing KML geometry.",
203
4
                 nRecLevel);
204
4
        return FALSE;
205
4
    }
206
207
3.29M
    if (sName_.compare("Point") == 0)
208
7.11k
        eType_ = Point;
209
3.28M
    else if (sName_.compare("LineString") == 0)
210
11.0k
        eType_ = LineString;
211
3.27M
    else if (sName_.compare("Polygon") == 0)
212
1.20k
        eType_ = Polygon;
213
3.27M
    else if (poKML->isRest(sName_))
214
1.68k
        eType_ = Empty;
215
3.27M
    else if (sName_.compare("coordinates") == 0)
216
20.9k
    {
217
217k
        for (unsigned int nCountP = 0; nCountP < pvsContent_->size(); nCountP++)
218
196k
        {
219
196k
            const char *pszCoord = (*pvsContent_)[nCountP].c_str();
220
196k
            int nComma = 0;
221
276k
            while (true)
222
276k
            {
223
276k
                pszCoord = strchr(pszCoord, ',');
224
276k
                if (pszCoord)
225
80.6k
                {
226
80.6k
                    nComma++;
227
80.6k
                    pszCoord++;
228
80.6k
                }
229
196k
                else
230
196k
                    break;
231
276k
            }
232
196k
            if (nComma == 2)
233
2.96k
                b25D_ = true;
234
196k
        }
235
20.9k
    }
236
3.25M
    else if (sName_.compare("Schema") == 0)
237
418
        eType_ = Schema;
238
3.24M
    else if (sName_.compare("SimpleField") == 0)
239
2.28k
        eType_ = SimpleField;
240
3.24M
    else if (sName_.compare("SchemaData") == 0)
241
711k
        eType_ = SchemaData;
242
2.53M
    else if (sName_.compare("SimpleData") == 0)
243
908k
        eType_ = SimpleData;
244
245
3.29M
    const kml_nodes_t::size_type size = pvpoChildren_->size();
246
6.58M
    for (kml_nodes_t::size_type z = 0; z < size; z++)
247
3.29M
    {
248
        // Classify pvpoChildren_
249
3.29M
        if (!(*pvpoChildren_)[z]->classify(poKML, nRecLevel + 1))
250
128
            return FALSE;
251
252
3.29M
        Nodetype curr = (*pvpoChildren_)[z]->eType_;
253
3.29M
        if (curr == SchemaData || curr == SimpleData)
254
1.62M
            continue;
255
1.67M
        b25D_ |= (*pvpoChildren_)[z]->b25D_;
256
257
        // Compare and return if it is mixed
258
1.67M
        if (curr != all && all != Empty && curr != Empty)
259
12.9k
        {
260
12.9k
            if (sName_.compare("MultiGeometry") == 0 ||
261
12.6k
                sName_.compare("MultiPolygon") == 0 ||
262
12.6k
                sName_.compare("MultiLineString") == 0 ||
263
12.6k
                sName_.compare("MultiPoint") == 0)
264
221
                eType_ = MultiGeometry;
265
12.6k
            else
266
12.6k
                eType_ = Mixed;
267
12.9k
        }
268
1.65M
        else if (curr != Empty)
269
37.0k
        {
270
37.0k
            all = curr;
271
37.0k
        }
272
1.67M
    }
273
274
3.29M
    if (eType_ == Unknown)
275
1.64M
    {
276
1.64M
        if (sName_.compare("MultiGeometry") == 0 ||
277
1.64M
            sName_.compare("MultiPolygon") == 0 ||
278
1.64M
            sName_.compare("MultiLineString") == 0 ||
279
1.64M
            sName_.compare("MultiPoint") == 0)
280
5.85k
        {
281
5.85k
            if (all == Point)
282
54
                eType_ = MultiPoint;
283
5.80k
            else if (all == LineString)
284
584
                eType_ = MultiLineString;
285
5.21k
            else if (all == Polygon)
286
180
                eType_ = MultiPolygon;
287
5.03k
            else
288
5.03k
                eType_ = MultiGeometry;
289
5.85k
        }
290
1.64M
        else
291
1.64M
            eType_ = all;
292
1.64M
    }
293
294
3.29M
    return TRUE;
295
3.29M
}
296
297
void KMLNode::unregisterLayerIfMatchingThisNode(KML *poKML)
298
3.13M
{
299
5.59M
    for (std::size_t z = 0; z < countChildren(); z++)
300
2.45M
    {
301
2.45M
        getChild(z)->unregisterLayerIfMatchingThisNode(poKML);
302
2.45M
    }
303
3.13M
    poKML->unregisterLayerIfMatchingThisNode(this);
304
3.13M
}
305
306
void KMLNode::eliminateEmpty(KML *poKML)
307
154k
{
308
986k
    for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size();)
309
831k
    {
310
831k
        if ((*pvpoChildren_)[z]->eType_ == Empty &&
311
721k
            (poKML->isContainer((*pvpoChildren_)[z]->sName_) ||
312
720k
             poKML->isFeatureContainer((*pvpoChildren_)[z]->sName_)))
313
677k
        {
314
677k
            (*pvpoChildren_)[z]->unregisterLayerIfMatchingThisNode(poKML);
315
677k
            delete (*pvpoChildren_)[z];
316
677k
            pvpoChildren_->erase(pvpoChildren_->begin() + z);
317
677k
        }
318
153k
        else
319
153k
        {
320
153k
            (*pvpoChildren_)[z]->eliminateEmpty(poKML);
321
153k
            ++z;
322
153k
        }
323
831k
    }
324
154k
}
325
326
bool KMLNode::hasOnlyEmpty() const
327
703
{
328
919
    for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
329
634
    {
330
634
        if ((*pvpoChildren_)[z]->eType_ != Empty)
331
418
        {
332
418
            return false;
333
418
        }
334
216
        else
335
216
        {
336
216
            if (!(*pvpoChildren_)[z]->hasOnlyEmpty())
337
0
                return false;
338
216
        }
339
634
    }
340
341
285
    return true;
342
703
}
343
344
void KMLNode::setType(Nodetype oNotet)
345
0
{
346
0
    eType_ = oNotet;
347
0
}
348
349
Nodetype KMLNode::getType() const
350
154k
{
351
154k
    return eType_;
352
154k
}
353
354
void KMLNode::setName(std::string const &sIn)
355
3.45M
{
356
3.45M
    sName_ = sIn;
357
3.45M
}
358
359
const std::string &KMLNode::getName() const
360
10.4M
{
361
10.4M
    return sName_;
362
10.4M
}
363
364
void KMLNode::setLevel(std::size_t nLev)
365
3.45M
{
366
3.45M
    nLevel_ = nLev;
367
3.45M
}
368
369
std::size_t KMLNode::getLevel() const
370
0
{
371
0
    return nLevel_;
372
0
}
373
374
void KMLNode::addAttribute(Attribute *poAttr)
375
2.59M
{
376
2.59M
    voAttributes_.push_back(poAttr);
377
2.59M
}
378
379
void KMLNode::setParent(KMLNode *poPar)
380
3.45M
{
381
3.45M
    poParent_ = poPar;
382
3.45M
}
383
384
KMLNode *KMLNode::getParent() const
385
6.91M
{
386
6.91M
    return poParent_;
387
6.91M
}
388
389
void KMLNode::addChildren(KMLNode *poChil)
390
3.38M
{
391
3.38M
    pvpoChildren_->push_back(poChil);
392
3.38M
}
393
394
std::size_t KMLNode::countChildren() const
395
5.92M
{
396
5.92M
    return pvpoChildren_->size();
397
5.92M
}
398
399
KMLNode *KMLNode::getChild(std::size_t index) const
400
2.65M
{
401
2.65M
    return (*pvpoChildren_)[index];
402
2.65M
}
403
404
void KMLNode::addContent(std::string const &text)
405
4.62M
{
406
4.62M
    pvsContent_->push_back(text);
407
4.62M
}
408
409
void KMLNode::appendContent(std::string const &text)
410
8.29M
{
411
8.29M
    pvsContent_->back() += text;
412
8.29M
}
413
414
const std::string &KMLNode::getContent(std::size_t index) const
415
2.53M
{
416
2.53M
    return (*pvsContent_)[index];
417
2.53M
}
418
419
void KMLNode::deleteContent(std::size_t index)
420
1.74M
{
421
1.74M
    if (index < pvsContent_->size())
422
1.74M
    {
423
1.74M
        pvsContent_->erase(pvsContent_->begin() + index);
424
1.74M
    }
425
1.74M
}
426
427
std::size_t KMLNode::numContent() const
428
14.3M
{
429
14.3M
    return pvsContent_->size();
430
14.3M
}
431
432
void KMLNode::setLayerNumber(int nNum)
433
364
{
434
364
    nLayerNumber_ = nNum;
435
364
}
436
437
int KMLNode::getLayerNumber() const
438
0
{
439
0
    return nLayerNumber_;
440
0
}
441
442
std::string KMLNode::getNameElement() const
443
929
{
444
929
    const kml_nodes_t::size_type size = pvpoChildren_->size();
445
446
1.44k
    for (kml_nodes_t::size_type i = 0; i < size; ++i)
447
963
    {
448
963
        if ((*pvpoChildren_)[i]->sName_.compare("name") == 0)
449
445
        {
450
445
            const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
451
445
            if (subsize > 0)
452
445
            {
453
445
                return (*(*pvpoChildren_)[i]->pvsContent_)[0];
454
445
            }
455
0
            break;
456
445
        }
457
963
    }
458
484
    return "";
459
929
}
460
461
std::string KMLNode::getDescriptionElement() const
462
559
{
463
559
    const kml_nodes_t::size_type size = pvpoChildren_->size();
464
1.16k
    for (kml_nodes_t::size_type i = 0; i < size; ++i)
465
659
    {
466
659
        if ((*pvpoChildren_)[i]->sName_.compare("description") == 0)
467
52
        {
468
52
            const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
469
52
            if (subsize > 0)
470
52
            {
471
52
                return (*(*pvpoChildren_)[i]->pvsContent_)[0];
472
52
            }
473
0
            break;
474
52
        }
475
659
    }
476
507
    return "";
477
559
}
478
479
std::size_t KMLNode::getNumFeatures()
480
711
{
481
711
    if (nNumFeatures_ == std::numeric_limits<size_t>::max())
482
162
    {
483
162
        nNumFeatures_ = 0;
484
162
        kml_nodes_t::size_type size = pvpoChildren_->size();
485
486
1.04k
        for (kml_nodes_t::size_type i = 0; i < size; ++i)
487
880
        {
488
880
            if ((*pvpoChildren_)[i]->sName_ == "Placemark")
489
582
                nNumFeatures_++;
490
880
        }
491
162
    }
492
711
    return nNumFeatures_;
493
711
}
494
495
OGRGeometry *KMLNode::getGeometry(Nodetype eType)
496
3.97k
{
497
3.97k
    OGRGeometry *poGeom = nullptr;
498
3.97k
    KMLNode *poCoor = nullptr;
499
3.97k
    Coordinate *psCoord = nullptr;
500
501
3.97k
    if (sName_.compare("Point") == 0)
502
24
    {
503
        // Search coordinate Element
504
36
        for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
505
36
        {
506
36
            if ((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
507
24
            {
508
24
                poCoor = (*pvpoChildren_)[nCount];
509
24
                for (unsigned int nCountP = 0;
510
24
                     nCountP < poCoor->pvsContent_->size(); nCountP++)
511
24
                {
512
24
                    psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
513
24
                    if (psCoord != nullptr)
514
24
                    {
515
24
                        if (psCoord->bHasZ)
516
23
                            poGeom = new OGRPoint(psCoord->dfLongitude,
517
23
                                                  psCoord->dfLatitude,
518
23
                                                  psCoord->dfAltitude);
519
1
                        else
520
1
                            poGeom = new OGRPoint(psCoord->dfLongitude,
521
1
                                                  psCoord->dfLatitude);
522
24
                        delete psCoord;
523
24
                        return poGeom;
524
24
                    }
525
24
                }
526
24
            }
527
36
        }
528
0
        poGeom = new OGRPoint();
529
0
    }
530
3.95k
    else if (sName_.compare("LineString") == 0)
531
3.43k
    {
532
        // Search coordinate Element
533
3.43k
        poGeom = new OGRLineString();
534
8.70k
        for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
535
5.27k
        {
536
5.27k
            if ((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
537
5.23k
            {
538
5.23k
                poCoor = (*pvpoChildren_)[nCount];
539
5.23k
                for (unsigned int nCountP = 0;
540
185k
                     nCountP < poCoor->pvsContent_->size(); nCountP++)
541
179k
                {
542
179k
                    psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
543
179k
                    if (psCoord != nullptr)
544
8.49k
                    {
545
8.49k
                        if (psCoord->bHasZ)
546
466
                            poGeom->toLineString()->addPoint(
547
466
                                psCoord->dfLongitude, psCoord->dfLatitude,
548
466
                                psCoord->dfAltitude);
549
8.02k
                        else
550
8.02k
                            poGeom->toLineString()->addPoint(
551
8.02k
                                psCoord->dfLongitude, psCoord->dfLatitude);
552
8.49k
                        delete psCoord;
553
8.49k
                    }
554
179k
                }
555
5.23k
            }
556
5.27k
        }
557
3.43k
    }
558
518
    else if (sName_.compare("Polygon") == 0)
559
32
    {
560
        //*********************************
561
        // Search outerBoundaryIs Element
562
        //*********************************
563
32
        poGeom = new OGRPolygon();
564
98
        for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
565
66
        {
566
66
            if ((*pvpoChildren_)[nCount]->sName_.compare("outerBoundaryIs") ==
567
66
                    0 &&
568
32
                !(*pvpoChildren_)[nCount]->pvpoChildren_->empty())
569
32
            {
570
32
                poCoor = (*(*pvpoChildren_)[nCount]->pvpoChildren_)[0];
571
32
            }
572
66
        }
573
        // No outer boundary found
574
32
        if (poCoor == nullptr)
575
0
        {
576
0
            return poGeom;
577
0
        }
578
        // Search coordinate Element
579
32
        OGRLinearRing *poLinearRing = nullptr;
580
64
        for (unsigned int nCount = 0; nCount < poCoor->pvpoChildren_->size();
581
32
             nCount++)
582
32
        {
583
32
            if ((*poCoor->pvpoChildren_)[nCount]->sName_.compare(
584
32
                    "coordinates") == 0)
585
32
            {
586
32
                for (unsigned int nCountP = 0;
587
532
                     nCountP <
588
532
                     (*poCoor->pvpoChildren_)[nCount]->pvsContent_->size();
589
500
                     nCountP++)
590
500
                {
591
500
                    psCoord = ParseCoordinate((*(*poCoor->pvpoChildren_)[nCount]
592
500
                                                    ->pvsContent_)[nCountP]);
593
500
                    if (psCoord != nullptr)
594
490
                    {
595
490
                        if (poLinearRing == nullptr)
596
32
                        {
597
32
                            poLinearRing = new OGRLinearRing();
598
32
                        }
599
490
                        if (psCoord->bHasZ)
600
484
                            poLinearRing->addPoint(psCoord->dfLongitude,
601
484
                                                   psCoord->dfLatitude,
602
484
                                                   psCoord->dfAltitude);
603
6
                        else
604
6
                            poLinearRing->addPoint(psCoord->dfLongitude,
605
6
                                                   psCoord->dfLatitude);
606
490
                        delete psCoord;
607
490
                    }
608
500
                }
609
32
            }
610
32
        }
611
        // No outer boundary coordinates found
612
32
        if (poLinearRing == nullptr)
613
0
        {
614
0
            return poGeom;
615
0
        }
616
617
32
        poGeom->toPolygon()->addRingDirectly(poLinearRing);
618
32
        poLinearRing = nullptr;
619
620
        //*********************************
621
        // Search innerBoundaryIs Elements
622
        //*********************************
623
624
98
        for (unsigned int nCount2 = 0; nCount2 < pvpoChildren_->size();
625
66
             nCount2++)
626
66
        {
627
66
            if ((*pvpoChildren_)[nCount2]->sName_.compare("innerBoundaryIs") ==
628
66
                0)
629
2
            {
630
2
                if (poLinearRing)
631
0
                    poGeom->toPolygon()->addRingDirectly(poLinearRing);
632
2
                poLinearRing = nullptr;
633
634
2
                if ((*pvpoChildren_)[nCount2]->pvpoChildren_->empty())
635
0
                    continue;
636
637
2
                poLinearRing = new OGRLinearRing();
638
639
2
                poCoor = (*(*pvpoChildren_)[nCount2]->pvpoChildren_)[0];
640
                // Search coordinate Element
641
2
                for (unsigned int nCount = 0;
642
4
                     nCount < poCoor->pvpoChildren_->size(); nCount++)
643
2
                {
644
2
                    if ((*poCoor->pvpoChildren_)[nCount]->sName_.compare(
645
2
                            "coordinates") == 0)
646
2
                    {
647
2
                        for (unsigned int nCountP = 0;
648
14
                             nCountP < (*poCoor->pvpoChildren_)[nCount]
649
14
                                           ->pvsContent_->size();
650
12
                             nCountP++)
651
12
                        {
652
12
                            psCoord = ParseCoordinate(
653
12
                                (*(*poCoor->pvpoChildren_)[nCount]
654
12
                                      ->pvsContent_)[nCountP]);
655
12
                            if (psCoord != nullptr)
656
12
                            {
657
12
                                if (psCoord->bHasZ)
658
12
                                    poLinearRing->addPoint(psCoord->dfLongitude,
659
12
                                                           psCoord->dfLatitude,
660
12
                                                           psCoord->dfAltitude);
661
0
                                else
662
0
                                    poLinearRing->addPoint(psCoord->dfLongitude,
663
0
                                                           psCoord->dfLatitude);
664
12
                                delete psCoord;
665
12
                            }
666
12
                        }
667
2
                    }
668
2
                }
669
2
            }
670
66
        }
671
672
32
        if (poLinearRing)
673
2
            poGeom->toPolygon()->addRingDirectly(poLinearRing);
674
32
    }
675
486
    else if (sName_.compare("MultiGeometry") == 0 ||
676
27
             sName_.compare("MultiPolygon") == 0 ||
677
27
             sName_.compare("MultiLineString") == 0 ||
678
27
             sName_.compare("MultiPoint") == 0)
679
459
    {
680
459
        if (eType == MultiPoint)
681
0
            poGeom = new OGRMultiPoint();
682
459
        else if (eType == MultiLineString)
683
458
            poGeom = new OGRMultiLineString();
684
1
        else if (eType == MultiPolygon)
685
0
            poGeom = new OGRMultiPolygon();
686
1
        else
687
1
            poGeom = new OGRGeometryCollection();
688
3.88k
        for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
689
3.42k
        {
690
3.42k
            OGRGeometry *poSubGeom = (*pvpoChildren_)[nCount]->getGeometry();
691
3.42k
            if (poSubGeom)
692
3.40k
                poGeom->toGeometryCollection()->addGeometryDirectly(poSubGeom);
693
3.42k
        }
694
459
    }
695
696
3.95k
    return poGeom;
697
3.97k
}
698
699
Feature *KMLNode::getFeature(std::size_t nNum, int &nLastAsked, int &nLastCount)
700
711
{
701
711
    if (nNum >= getNumFeatures())
702
152
        return nullptr;
703
704
559
    unsigned int nCount = 0;
705
559
    unsigned int nCountP = 0;
706
559
    KMLNode *poFeat = nullptr;
707
559
    KMLNode *poTemp = nullptr;
708
709
559
    if (nLastAsked + 1 != static_cast<int>(nNum))
710
0
    {
711
        // nCount = 0;
712
        // nCountP = 0;
713
0
    }
714
559
    else
715
559
    {
716
559
        nCount = nLastCount + 1;
717
559
        nCountP = nLastAsked + 1;
718
559
    }
719
720
841
    for (; nCount < pvpoChildren_->size(); nCount++)
721
841
    {
722
841
        if ((*pvpoChildren_)[nCount]->sName_.compare("Placemark") == 0)
723
559
        {
724
559
            if (nCountP == nNum)
725
559
            {
726
559
                poFeat = (*pvpoChildren_)[nCount];
727
559
                break;
728
559
            }
729
0
            nCountP++;
730
0
        }
731
841
    }
732
733
559
    nLastAsked = static_cast<int>(nNum);
734
559
    nLastCount = nCount;
735
736
559
    if (poFeat == nullptr)
737
0
        return nullptr;
738
739
    // Create a feature structure
740
559
    Feature *psReturn = new Feature;
741
    // Build up the name
742
559
    psReturn->sName = poFeat->getNameElement();
743
    // Build up the description
744
559
    psReturn->sDescription = poFeat->getDescriptionElement();
745
    // the type
746
559
    psReturn->eType = poFeat->eType_;
747
748
1.27k
    for (nCount = 0; nCount < poFeat->pvpoChildren_->size(); nCount++)
749
711
    {
750
711
        const auto poChild = (*poFeat->pvpoChildren_)[nCount];
751
711
        const auto &sName = poChild->sName_;
752
711
        if (sName == "ExtendedData" && poChild->pvpoChildren_->size() == 1 &&
753
0
            (*poChild->pvpoChildren_)[0]->sName_ == "SchemaData")
754
0
        {
755
0
            const auto poChild2 = (*poChild->pvpoChildren_)[0];
756
0
            for (size_t j = 0; j < poChild2->pvpoChildren_->size(); ++j)
757
0
            {
758
0
                const auto poChild3 = (*poChild2->pvpoChildren_)[j];
759
0
                if (poChild3->sName_ == "SimpleData" &&
760
0
                    poChild3->numContent() == 1)
761
0
                {
762
0
                    std::string osAttrName;
763
0
                    for (const auto *poAttr : poChild3->getAttributes())
764
0
                    {
765
0
                        if (poAttr->sName == "name")
766
0
                            osAttrName = poAttr->sValue;
767
0
                    }
768
0
                    if (!osAttrName.empty())
769
0
                    {
770
0
                        psReturn->oFields[osAttrName] = poChild3->getContent(0);
771
0
                    }
772
0
                }
773
0
            }
774
0
        }
775
711
    }
776
777
559
    std::string sElementName;
778
559
    if (poFeat->eType_ == Point || poFeat->eType_ == LineString ||
779
501
        poFeat->eType_ == Polygon)
780
90
        sElementName = Nodetype2String(poFeat->eType_);
781
469
    else if (poFeat->eType_ == MultiGeometry || poFeat->eType_ == MultiPoint ||
782
467
             poFeat->eType_ == MultiLineString ||
783
9
             poFeat->eType_ == MultiPolygon)
784
460
        sElementName = "MultiGeometry";
785
9
    else
786
9
    {
787
9
        delete psReturn;
788
9
        return nullptr;
789
9
    }
790
791
693
    for (nCount = 0; nCount < poFeat->pvpoChildren_->size(); nCount++)
792
692
    {
793
692
        const auto &sName = (*poFeat->pvpoChildren_)[nCount]->sName_;
794
692
        if (sName.compare(sElementName) == 0 ||
795
143
            (sElementName == "MultiGeometry" &&
796
1
             (sName == "MultiPolygon" || sName == "MultiLineString" ||
797
1
              sName == "MultiPoint")))
798
549
        {
799
549
            poTemp = (*poFeat->pvpoChildren_)[nCount];
800
549
            psReturn->poGeom.reset(poTemp->getGeometry(poFeat->eType_));
801
549
            if (psReturn->poGeom)
802
549
                return psReturn;
803
0
            else
804
0
            {
805
0
                delete psReturn;
806
0
                return nullptr;
807
0
            }
808
549
        }
809
692
    }
810
811
1
    delete psReturn;
812
1
    return nullptr;
813
550
}