Coverage Report

Created: 2026-08-14 09:29

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
339
{
33
339
    if (type == Empty)
34
0
        return "Empty";
35
339
    else if (type == Rest)
36
0
        return "Rest";
37
339
    else if (type == Mixed)
38
125
        return "Mixed";
39
214
    else if (type == Point)
40
86
        return "Point";
41
128
    else if (type == LineString)
42
57
        return "LineString";
43
71
    else if (type == Polygon)
44
51
        return "Polygon";
45
20
    else if (type == MultiGeometry)
46
6
        return "MultiGeometry";
47
14
    else if (type == MultiPoint)
48
0
        return "MultiPoint";
49
14
    else if (type == MultiLineString)
50
14
        return "MultiLineString";
51
0
    else if (type == MultiPolygon)
52
0
        return "MultiPolygon";
53
0
    else
54
0
        return "Unknown";
55
339
}
56
57
static bool isNumberDigit(const char cIn)
58
354k
{
59
354k
    return (cIn == '-' || cIn == '+' || (cIn >= '0' && cIn <= '9') ||
60
251k
            cIn == '.' || cIn == 'e' || cIn == 'E');
61
354k
}
62
63
static Coordinate *ParseCoordinate(std::string const &text)
64
207k
{
65
207k
    int pos = 0;
66
207k
    const char *pszStr = text.c_str();
67
207k
    Coordinate *psTmp = new Coordinate();
68
69
    // X coordinate
70
207k
    psTmp->dfLongitude = CPLAtof(pszStr);
71
323k
    while (isNumberDigit(pszStr[pos++]))
72
115k
        ;
73
74
    // Y coordinate
75
207k
    if (pszStr[pos - 1] != ',')
76
197k
    {
77
197k
        delete psTmp;
78
197k
        return nullptr;
79
197k
    }
80
81
9.98k
    psTmp->dfLatitude = CPLAtof(pszStr + pos);
82
31.6k
    while (isNumberDigit(pszStr[pos++]))
83
21.6k
        ;
84
85
    // Z coordinate
86
9.98k
    if (pszStr[pos - 1] != ',')
87
8.87k
    {
88
8.87k
        psTmp->bHasZ = false;
89
8.87k
        psTmp->dfAltitude = 0;
90
8.87k
        return psTmp;
91
8.87k
    }
92
93
1.11k
    psTmp->bHasZ = true;
94
1.11k
    psTmp->dfAltitude = CPLAtof(pszStr + pos);
95
96
1.11k
    return psTmp;
97
9.98k
}
98
99
/************************************************************************/
100
/*                           KMLNode methods                            */
101
/************************************************************************/
102
103
KMLNode::KMLNode()
104
2.30M
    : pvpoChildren_(new std::vector<KMLNode *>),
105
2.30M
      pvsContent_(new std::vector<std::string>)
106
2.30M
{
107
2.30M
}
108
109
KMLNode::~KMLNode()
110
2.30M
{
111
2.30M
    CPLAssert(nullptr != pvpoChildren_);
112
113
2.30M
    kml_nodes_t::iterator itChild;
114
4.22M
    for (itChild = pvpoChildren_->begin(); itChild != pvpoChildren_->end();
115
2.30M
         ++itChild)
116
1.91M
    {
117
1.91M
        delete (*itChild);
118
1.91M
    }
119
2.30M
    delete pvpoChildren_;
120
121
2.30M
    kml_attributes_t::iterator itAttr;
122
3.98M
    for (itAttr = voAttributes_.begin(); itAttr != voAttributes_.end();
123
2.30M
         ++itAttr)
124
1.67M
    {
125
1.67M
        delete (*itAttr);
126
1.67M
    }
127
128
2.30M
    delete pvsContent_;
129
2.30M
}
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
2.13M
{
196
2.13M
    Nodetype all = Empty;
197
198
    /* Arbitrary value, but certainly large enough for reasonable usages ! */
199
2.13M
    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
2.13M
    if (sName_.compare("Point") == 0)
208
6.21k
        eType_ = Point;
209
2.12M
    else if (sName_.compare("LineString") == 0)
210
11.6k
        eType_ = LineString;
211
2.11M
    else if (sName_.compare("Polygon") == 0)
212
1.20k
        eType_ = Polygon;
213
2.11M
    else if (poKML->isRest(sName_))
214
1.69k
        eType_ = Empty;
215
2.11M
    else if (sName_.compare("coordinates") == 0)
216
20.8k
    {
217
242k
        for (unsigned int nCountP = 0; nCountP < pvsContent_->size(); nCountP++)
218
222k
        {
219
222k
            const char *pszCoord = (*pvsContent_)[nCountP].c_str();
220
222k
            int nComma = 0;
221
310k
            while (true)
222
310k
            {
223
310k
                pszCoord = strchr(pszCoord, ',');
224
310k
                if (pszCoord)
225
88.0k
                {
226
88.0k
                    nComma++;
227
88.0k
                    pszCoord++;
228
88.0k
                }
229
222k
                else
230
222k
                    break;
231
310k
            }
232
222k
            if (nComma == 2)
233
3.04k
                b25D_ = true;
234
222k
        }
235
20.8k
    }
236
2.09M
    else if (sName_.compare("Schema") == 0)
237
348
        eType_ = Schema;
238
2.09M
    else if (sName_.compare("SimpleField") == 0)
239
1.79k
        eType_ = SimpleField;
240
2.09M
    else if (sName_.compare("SchemaData") == 0)
241
472k
        eType_ = SchemaData;
242
1.61M
    else if (sName_.compare("SimpleData") == 0)
243
600k
        eType_ = SimpleData;
244
245
2.13M
    const kml_nodes_t::size_type size = pvpoChildren_->size();
246
4.27M
    for (kml_nodes_t::size_type z = 0; z < size; z++)
247
2.13M
    {
248
        // Classify pvpoChildren_
249
2.13M
        if (!(*pvpoChildren_)[z]->classify(poKML, nRecLevel + 1))
250
128
            return FALSE;
251
252
2.13M
        Nodetype curr = (*pvpoChildren_)[z]->eType_;
253
2.13M
        if (curr == SchemaData || curr == SimpleData)
254
1.07M
            continue;
255
1.06M
        b25D_ |= (*pvpoChildren_)[z]->b25D_;
256
257
        // Compare and return if it is mixed
258
1.06M
        if (curr != all && all != Empty && curr != Empty)
259
12.8k
        {
260
12.8k
            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.8k
        }
268
1.04M
        else if (curr != Empty)
269
35.2k
        {
270
35.2k
            all = curr;
271
35.2k
        }
272
1.06M
    }
273
274
2.13M
    if (eType_ == Unknown)
275
1.03M
    {
276
1.03M
        if (sName_.compare("MultiGeometry") == 0 ||
277
1.03M
            sName_.compare("MultiPolygon") == 0 ||
278
1.03M
            sName_.compare("MultiLineString") == 0 ||
279
1.03M
            sName_.compare("MultiPoint") == 0)
280
5.88k
        {
281
5.88k
            if (all == Point)
282
54
                eType_ = MultiPoint;
283
5.83k
            else if (all == LineString)
284
643
                eType_ = MultiLineString;
285
5.19k
            else if (all == Polygon)
286
180
                eType_ = MultiPolygon;
287
5.01k
            else
288
5.01k
                eType_ = MultiGeometry;
289
5.88k
        }
290
1.03M
        else
291
1.03M
            eType_ = all;
292
1.03M
    }
293
294
2.13M
    return TRUE;
295
2.13M
}
296
297
void KMLNode::unregisterLayerIfMatchingThisNode(KML *poKML)
298
1.98M
{
299
3.66M
    for (std::size_t z = 0; z < countChildren(); z++)
300
1.67M
    {
301
1.67M
        getChild(z)->unregisterLayerIfMatchingThisNode(poKML);
302
1.67M
    }
303
1.98M
    poKML->unregisterLayerIfMatchingThisNode(this);
304
1.98M
}
305
306
void KMLNode::eliminateEmpty(KML *poKML)
307
149k
{
308
606k
    for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size();)
309
456k
    {
310
456k
        if ((*pvpoChildren_)[z]->eType_ == Empty &&
311
350k
            (poKML->isContainer((*pvpoChildren_)[z]->sName_) ||
312
349k
             poKML->isFeatureContainer((*pvpoChildren_)[z]->sName_)))
313
307k
        {
314
307k
            (*pvpoChildren_)[z]->unregisterLayerIfMatchingThisNode(poKML);
315
307k
            delete (*pvpoChildren_)[z];
316
307k
            pvpoChildren_->erase(pvpoChildren_->begin() + z);
317
307k
        }
318
148k
        else
319
148k
        {
320
148k
            (*pvpoChildren_)[z]->eliminateEmpty(poKML);
321
148k
            ++z;
322
148k
        }
323
456k
    }
324
149k
}
325
326
bool KMLNode::hasOnlyEmpty() const
327
695
{
328
945
    for (kml_nodes_t::size_type z = 0; z < pvpoChildren_->size(); z++)
329
624
    {
330
624
        if ((*pvpoChildren_)[z]->eType_ != Empty)
331
374
        {
332
374
            return false;
333
374
        }
334
250
        else
335
250
        {
336
250
            if (!(*pvpoChildren_)[z]->hasOnlyEmpty())
337
0
                return false;
338
250
        }
339
624
    }
340
341
321
    return true;
342
695
}
343
344
void KMLNode::setType(Nodetype oNotet)
345
0
{
346
0
    eType_ = oNotet;
347
0
}
348
349
Nodetype KMLNode::getType() const
350
149k
{
351
149k
    return eType_;
352
149k
}
353
354
void KMLNode::setName(std::string const &sIn)
355
2.30M
{
356
2.30M
    sName_ = sIn;
357
2.30M
}
358
359
const std::string &KMLNode::getName() const
360
6.95M
{
361
6.95M
    return sName_;
362
6.95M
}
363
364
void KMLNode::setLevel(std::size_t nLev)
365
2.30M
{
366
2.30M
    nLevel_ = nLev;
367
2.30M
}
368
369
std::size_t KMLNode::getLevel() const
370
0
{
371
0
    return nLevel_;
372
0
}
373
374
void KMLNode::addAttribute(Attribute *poAttr)
375
1.67M
{
376
1.67M
    voAttributes_.push_back(poAttr);
377
1.67M
}
378
379
void KMLNode::setParent(KMLNode *poPar)
380
2.30M
{
381
2.30M
    poParent_ = poPar;
382
2.30M
}
383
384
KMLNode *KMLNode::getParent() const
385
4.60M
{
386
4.60M
    return poParent_;
387
4.60M
}
388
389
void KMLNode::addChildren(KMLNode *poChil)
390
2.22M
{
391
2.22M
    pvpoChildren_->push_back(poChil);
392
2.22M
}
393
394
std::size_t KMLNode::countChildren() const
395
3.98M
{
396
3.98M
    return pvpoChildren_->size();
397
3.98M
}
398
399
KMLNode *KMLNode::getChild(std::size_t index) const
400
1.86M
{
401
1.86M
    return (*pvpoChildren_)[index];
402
1.86M
}
403
404
void KMLNode::addContent(std::string const &text)
405
3.15M
{
406
3.15M
    pvsContent_->push_back(text);
407
3.15M
}
408
409
void KMLNode::appendContent(std::string const &text)
410
5.42M
{
411
5.42M
    pvsContent_->back() += text;
412
5.42M
}
413
414
const std::string &KMLNode::getContent(std::size_t index) const
415
1.65M
{
416
1.65M
    return (*pvsContent_)[index];
417
1.65M
}
418
419
void KMLNode::deleteContent(std::size_t index)
420
1.11M
{
421
1.11M
    if (index < pvsContent_->size())
422
1.11M
    {
423
1.11M
        pvsContent_->erase(pvsContent_->begin() + index);
424
1.11M
    }
425
1.11M
}
426
427
std::size_t KMLNode::numContent() const
428
9.40M
{
429
9.40M
    return pvsContent_->size();
430
9.40M
}
431
432
void KMLNode::setLayerNumber(int nNum)
433
295
{
434
295
    nLayerNumber_ = nNum;
435
295
}
436
437
int KMLNode::getLayerNumber() const
438
0
{
439
0
    return nLayerNumber_;
440
0
}
441
442
std::string KMLNode::getNameElement() const
443
939
{
444
939
    const kml_nodes_t::size_type size = pvpoChildren_->size();
445
446
1.51k
    for (kml_nodes_t::size_type i = 0; i < size; ++i)
447
967
    {
448
967
        if ((*pvpoChildren_)[i]->sName_.compare("name") == 0)
449
396
        {
450
396
            const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
451
396
            if (subsize > 0)
452
396
            {
453
396
                return (*(*pvpoChildren_)[i]->pvsContent_)[0];
454
396
            }
455
0
            break;
456
396
        }
457
967
    }
458
543
    return "";
459
939
}
460
461
std::string KMLNode::getDescriptionElement() const
462
638
{
463
638
    const kml_nodes_t::size_type size = pvpoChildren_->size();
464
1.32k
    for (kml_nodes_t::size_type i = 0; i < size; ++i)
465
749
    {
466
749
        if ((*pvpoChildren_)[i]->sName_.compare("description") == 0)
467
61
        {
468
61
            const auto subsize = (*pvpoChildren_)[i]->pvsContent_->size();
469
61
            if (subsize > 0)
470
61
            {
471
61
                return (*(*pvpoChildren_)[i]->pvsContent_)[0];
472
61
            }
473
0
            break;
474
61
        }
475
749
    }
476
577
    return "";
477
638
}
478
479
std::size_t KMLNode::getNumFeatures()
480
773
{
481
773
    if (nNumFeatures_ == std::numeric_limits<size_t>::max())
482
145
    {
483
145
        nNumFeatures_ = 0;
484
145
        kml_nodes_t::size_type size = pvpoChildren_->size();
485
486
1.07k
        for (kml_nodes_t::size_type i = 0; i < size; ++i)
487
928
        {
488
928
            if ((*pvpoChildren_)[i]->sName_ == "Placemark")
489
658
                nNumFeatures_++;
490
928
        }
491
145
    }
492
773
    return nNumFeatures_;
493
773
}
494
495
OGRGeometry *KMLNode::getGeometry(Nodetype eType)
496
4.64k
{
497
4.64k
    OGRGeometry *poGeom = nullptr;
498
4.64k
    KMLNode *poCoor = nullptr;
499
4.64k
    Coordinate *psCoord = nullptr;
500
501
4.64k
    if (sName_.compare("Point") == 0)
502
28
    {
503
        // Search coordinate Element
504
42
        for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
505
42
        {
506
42
            if ((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
507
28
            {
508
28
                poCoor = (*pvpoChildren_)[nCount];
509
28
                for (unsigned int nCountP = 0;
510
28
                     nCountP < poCoor->pvsContent_->size(); nCountP++)
511
28
                {
512
28
                    psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
513
28
                    if (psCoord != nullptr)
514
28
                    {
515
28
                        if (psCoord->bHasZ)
516
28
                            poGeom = new OGRPoint(psCoord->dfLongitude,
517
28
                                                  psCoord->dfLatitude,
518
28
                                                  psCoord->dfAltitude);
519
0
                        else
520
0
                            poGeom = new OGRPoint(psCoord->dfLongitude,
521
0
                                                  psCoord->dfLatitude);
522
28
                        delete psCoord;
523
28
                        return poGeom;
524
28
                    }
525
28
                }
526
28
            }
527
42
        }
528
0
        poGeom = new OGRPoint();
529
0
    }
530
4.61k
    else if (sName_.compare("LineString") == 0)
531
4.03k
    {
532
        // Search coordinate Element
533
4.03k
        poGeom = new OGRLineString();
534
10.1k
        for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
535
6.10k
        {
536
6.10k
            if ((*pvpoChildren_)[nCount]->sName_.compare("coordinates") == 0)
537
6.06k
            {
538
6.06k
                poCoor = (*pvpoChildren_)[nCount];
539
6.06k
                for (unsigned int nCountP = 0;
540
213k
                     nCountP < poCoor->pvsContent_->size(); nCountP++)
541
207k
                {
542
207k
                    psCoord = ParseCoordinate((*poCoor->pvsContent_)[nCountP]);
543
207k
                    if (psCoord != nullptr)
544
9.38k
                    {
545
9.38k
                        if (psCoord->bHasZ)
546
518
                            poGeom->toLineString()->addPoint(
547
518
                                psCoord->dfLongitude, psCoord->dfLatitude,
548
518
                                psCoord->dfAltitude);
549
8.86k
                        else
550
8.86k
                            poGeom->toLineString()->addPoint(
551
8.86k
                                psCoord->dfLongitude, psCoord->dfLatitude);
552
9.38k
                        delete psCoord;
553
9.38k
                    }
554
207k
                }
555
6.06k
            }
556
6.10k
        }
557
4.03k
    }
558
585
    else if (sName_.compare("Polygon") == 0)
559
36
    {
560
        //*********************************
561
        // Search outerBoundaryIs Element
562
        //*********************************
563
36
        poGeom = new OGRPolygon();
564
110
        for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
565
74
        {
566
74
            if ((*pvpoChildren_)[nCount]->sName_.compare("outerBoundaryIs") ==
567
74
                    0 &&
568
36
                !(*pvpoChildren_)[nCount]->pvpoChildren_->empty())
569
36
            {
570
36
                poCoor = (*(*pvpoChildren_)[nCount]->pvpoChildren_)[0];
571
36
            }
572
74
        }
573
        // No outer boundary found
574
36
        if (poCoor == nullptr)
575
0
        {
576
0
            return poGeom;
577
0
        }
578
        // Search coordinate Element
579
36
        OGRLinearRing *poLinearRing = nullptr;
580
72
        for (unsigned int nCount = 0; nCount < poCoor->pvpoChildren_->size();
581
36
             nCount++)
582
36
        {
583
36
            if ((*poCoor->pvpoChildren_)[nCount]->sName_.compare(
584
36
                    "coordinates") == 0)
585
36
            {
586
36
                for (unsigned int nCountP = 0;
587
614
                     nCountP <
588
614
                     (*poCoor->pvpoChildren_)[nCount]->pvsContent_->size();
589
578
                     nCountP++)
590
578
                {
591
578
                    psCoord = ParseCoordinate((*(*poCoor->pvpoChildren_)[nCount]
592
578
                                                    ->pvsContent_)[nCountP]);
593
578
                    if (psCoord != nullptr)
594
567
                    {
595
567
                        if (poLinearRing == nullptr)
596
36
                        {
597
36
                            poLinearRing = new OGRLinearRing();
598
36
                        }
599
567
                        if (psCoord->bHasZ)
600
559
                            poLinearRing->addPoint(psCoord->dfLongitude,
601
559
                                                   psCoord->dfLatitude,
602
559
                                                   psCoord->dfAltitude);
603
8
                        else
604
8
                            poLinearRing->addPoint(psCoord->dfLongitude,
605
8
                                                   psCoord->dfLatitude);
606
567
                        delete psCoord;
607
567
                    }
608
578
                }
609
36
            }
610
36
        }
611
        // No outer boundary coordinates found
612
36
        if (poLinearRing == nullptr)
613
0
        {
614
0
            return poGeom;
615
0
        }
616
617
36
        poGeom->toPolygon()->addRingDirectly(poLinearRing);
618
36
        poLinearRing = nullptr;
619
620
        //*********************************
621
        // Search innerBoundaryIs Elements
622
        //*********************************
623
624
110
        for (unsigned int nCount2 = 0; nCount2 < pvpoChildren_->size();
625
74
             nCount2++)
626
74
        {
627
74
            if ((*pvpoChildren_)[nCount2]->sName_.compare("innerBoundaryIs") ==
628
74
                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
74
        }
671
672
36
        if (poLinearRing)
673
2
            poGeom->toPolygon()->addRingDirectly(poLinearRing);
674
36
    }
675
549
    else if (sName_.compare("MultiGeometry") == 0 ||
676
25
             sName_.compare("MultiPolygon") == 0 ||
677
25
             sName_.compare("MultiLineString") == 0 ||
678
25
             sName_.compare("MultiPoint") == 0)
679
524
    {
680
524
        if (eType == MultiPoint)
681
0
            poGeom = new OGRMultiPoint();
682
524
        else if (eType == MultiLineString)
683
523
            poGeom = new OGRMultiLineString();
684
1
        else if (eType == MultiPolygon)
685
0
            poGeom = new OGRMultiPolygon();
686
1
        else
687
1
            poGeom = new OGRGeometryCollection();
688
4.54k
        for (unsigned int nCount = 0; nCount < pvpoChildren_->size(); nCount++)
689
4.01k
        {
690
4.01k
            OGRGeometry *poSubGeom = (*pvpoChildren_)[nCount]->getGeometry();
691
4.01k
            if (poSubGeom)
692
3.99k
                poGeom->toGeometryCollection()->addGeometryDirectly(poSubGeom);
693
4.01k
        }
694
524
    }
695
696
4.61k
    return poGeom;
697
4.64k
}
698
699
Feature *KMLNode::getFeature(std::size_t nNum, int &nLastAsked, int &nLastCount)
700
773
{
701
773
    if (nNum >= getNumFeatures())
702
135
        return nullptr;
703
704
638
    unsigned int nCount = 0;
705
638
    unsigned int nCountP = 0;
706
638
    KMLNode *poFeat = nullptr;
707
638
    KMLNode *poTemp = nullptr;
708
709
638
    if (nLastAsked + 1 != static_cast<int>(nNum))
710
0
    {
711
        // nCount = 0;
712
        // nCountP = 0;
713
0
    }
714
638
    else
715
638
    {
716
638
        nCount = nLastCount + 1;
717
638
        nCountP = nLastAsked + 1;
718
638
    }
719
720
898
    for (; nCount < pvpoChildren_->size(); nCount++)
721
898
    {
722
898
        if ((*pvpoChildren_)[nCount]->sName_.compare("Placemark") == 0)
723
638
        {
724
638
            if (nCountP == nNum)
725
638
            {
726
638
                poFeat = (*pvpoChildren_)[nCount];
727
638
                break;
728
638
            }
729
0
            nCountP++;
730
0
        }
731
898
    }
732
733
638
    nLastAsked = static_cast<int>(nNum);
734
638
    nLastCount = nCount;
735
736
638
    if (poFeat == nullptr)
737
0
        return nullptr;
738
739
    // Create a feature structure
740
638
    Feature *psReturn = new Feature;
741
    // Build up the name
742
638
    psReturn->sName = poFeat->getNameElement();
743
    // Build up the description
744
638
    psReturn->sDescription = poFeat->getDescriptionElement();
745
    // the type
746
638
    psReturn->eType = poFeat->eType_;
747
748
1.44k
    for (nCount = 0; nCount < poFeat->pvpoChildren_->size(); nCount++)
749
810
    {
750
810
        const auto poChild = (*poFeat->pvpoChildren_)[nCount];
751
810
        const auto &sName = poChild->sName_;
752
810
        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
810
    }
776
777
638
    std::string sElementName;
778
638
    if (poFeat->eType_ == Point || poFeat->eType_ == LineString ||
779
570
        poFeat->eType_ == Polygon)
780
104
        sElementName = Nodetype2String(poFeat->eType_);
781
534
    else if (poFeat->eType_ == MultiGeometry || poFeat->eType_ == MultiPoint ||
782
532
             poFeat->eType_ == MultiLineString ||
783
9
             poFeat->eType_ == MultiPolygon)
784
525
        sElementName = "MultiGeometry";
785
9
    else
786
9
    {
787
9
        delete psReturn;
788
9
        return nullptr;
789
9
    }
790
791
795
    for (nCount = 0; nCount < poFeat->pvpoChildren_->size(); nCount++)
792
794
    {
793
794
        const auto &sName = (*poFeat->pvpoChildren_)[nCount]->sName_;
794
794
        if (sName.compare(sElementName) == 0 ||
795
166
            (sElementName == "MultiGeometry" &&
796
1
             (sName == "MultiPolygon" || sName == "MultiLineString" ||
797
1
              sName == "MultiPoint")))
798
628
        {
799
628
            poTemp = (*poFeat->pvpoChildren_)[nCount];
800
628
            psReturn->poGeom.reset(poTemp->getGeometry(poFeat->eType_));
801
628
            if (psReturn->poGeom)
802
628
                return psReturn;
803
0
            else
804
0
            {
805
0
                delete psReturn;
806
0
                return nullptr;
807
0
            }
808
628
        }
809
794
    }
810
811
1
    delete psReturn;
812
1
    return nullptr;
813
629
}