Coverage Report

Created: 2025-12-31 08:30

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