• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15992523769

01 Jul 2025 07:16AM UTC coverage: 71.09% (-0.004%) from 71.094%
15992523769

Pull #12682

github

web-flow
Merge 1383a7df3 into f6ed9706f
Pull Request #12682: Bump msys2/setup-msys2 from 2.27.0 to 2.28.0

574092 of 807557 relevant lines covered (71.09%)

250020.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.78
/ogr/ogr_srsnode.cpp
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  The OGR_SRSNode class.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999,  Les Technologies SoftMap Inc.
9
 * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "cpl_port.h"
15
#include "ogr_spatialref.h"
16

17
#include <cctype>
18
#include <cstddef>
19
#include <cstring>
20

21
#include "ogr_core.h"
22
#include "ogr_p.h"
23
#include "cpl_conv.h"
24
#include "cpl_error.h"
25
#include "cpl_string.h"
26

27
/************************************************************************/
28
/*                            OGR_SRSNode()                             */
29
/************************************************************************/
30

31
/**
32
 * Constructor.
33
 *
34
 * @param pszValueIn this optional parameter can be used to initialize
35
 * the value of the node upon creation.  If omitted the node will be created
36
 * with a value of "".  Newly created OGR_SRSNodes have no children.
37
 */
38

39
OGR_SRSNode::OGR_SRSNode(const char *pszValueIn)
1,050,920✔
40
    : pszValue(CPLStrdup(pszValueIn)), papoChildNodes(nullptr),
1,050,920✔
41
      poParent(nullptr), nChildren(0)
1,050,920✔
42
{
43
}
1,050,920✔
44

45
/************************************************************************/
46
/*                            ~OGR_SRSNode()                            */
47
/************************************************************************/
48

49
OGR_SRSNode::~OGR_SRSNode()
1,025,140✔
50

51
{
52
    CPLFree(pszValue);
1,025,140✔
53

54
    ClearChildren();
1,025,140✔
55
}
1,025,140✔
56

57
/************************************************************************/
58
/*                             ~Listener()                              */
59
/************************************************************************/
60

61
OGR_SRSNode::Listener::~Listener() = default;
62

63
/************************************************************************/
64
/*                           RegisterListener()                         */
65
/************************************************************************/
66

67
void OGR_SRSNode::RegisterListener(const std::shared_ptr<Listener> &listener)
25,445✔
68
{
69
    m_listener = listener;
25,445✔
70
}
25,445✔
71

72
/************************************************************************/
73
/*                             notifyChange()                           */
74
/************************************************************************/
75

76
void OGR_SRSNode::notifyChange()
2,049,670✔
77
{
78
    auto locked = m_listener.lock();
4,099,330✔
79
    if (locked)
2,049,670✔
80
    {
81
        locked->notifyChange(this);
2,021,440✔
82
    }
83
}
2,049,670✔
84

85
/************************************************************************/
86
/*                           ClearChildren()                            */
87
/************************************************************************/
88

89
/** Clear children nodes
90
 */
91
void OGR_SRSNode::ClearChildren()
2,048,780✔
92

93
{
94
    for (int i = 0; i < nChildren; i++)
3,048,220✔
95
    {
96
        delete papoChildNodes[i];
999,437✔
97
    }
98

99
    CPLFree(papoChildNodes);
2,048,780✔
100

101
    papoChildNodes = nullptr;
2,048,780✔
102
    nChildren = 0;
2,048,780✔
103
}
2,048,780✔
104

105
/************************************************************************/
106
/*                           GetChildCount()                            */
107
/************************************************************************/
108

109
/**
110
 * \fn int OGR_SRSNode::GetChildCount() const;
111
 *
112
 * Get number of children nodes.
113
 *
114
 * @return 0 for leaf nodes, or the number of children nodes.
115
 */
116

117
/************************************************************************/
118
/*                              GetChild()                              */
119
/************************************************************************/
120

121
/**
122
 * Fetch requested child.
123
 *
124
 * @param iChild the index of the child to fetch, from 0 to
125
 * GetChildCount() - 1.
126
 *
127
 * @return a pointer to the child OGR_SRSNode, or NULL if there is no such
128
 * child.
129
 */
130

131
OGR_SRSNode *OGR_SRSNode::GetChild(int iChild)
40,563✔
132

133
{
134
    if (iChild < 0 || iChild >= nChildren)
40,563✔
135
        return nullptr;
×
136

137
    return papoChildNodes[iChild];
40,563✔
138
}
139

140
/**
141
 * Fetch requested child.
142
 *
143
 * @param iChild the index of the child to fetch, from 0 to
144
 * GetChildCount() - 1.
145
 *
146
 * @return a pointer to the child OGR_SRSNode, or NULL if there is no such
147
 * child.
148
 */
149

150
const OGR_SRSNode *OGR_SRSNode::GetChild(int iChild) const
177,847✔
151

152
{
153
    if (iChild < 0 || iChild >= nChildren)
177,847✔
154
        return nullptr;
×
155

156
    return papoChildNodes[iChild];
177,847✔
157
}
158

159
/************************************************************************/
160
/*                              GetNode()                               */
161
/************************************************************************/
162

163
/**
164
 * Find named node in tree.
165
 *
166
 * This method does a pre-order traversal of the node tree searching for
167
 * a node with this exact value (case insensitive), and returns it.  Leaf
168
 * nodes are not considered, under the assumption that they are just
169
 * attribute value nodes.
170
 *
171
 * If a node appears more than once in the tree (such as UNIT for instance),
172
 * the first encountered will be returned.  Use GetNode() on a subtree to be
173
 * more specific.
174
 *
175
 * @param pszName the name of the node to search for.
176
 *
177
 * @return a pointer to the node found, or NULL if none.
178
 */
179

180
OGR_SRSNode *OGR_SRSNode::GetNode(const char *pszName)
874,878✔
181

182
{
183
    if (nChildren > 0 && EQUAL(pszName, pszValue))
874,878✔
184
        return this;
41,188✔
185

186
    /* -------------------------------------------------------------------- */
187
    /*      First we check the immediate children so we will get an         */
188
    /*      immediate child in preference to a subchild.                    */
189
    /* -------------------------------------------------------------------- */
190
    for (int i = 0; i < nChildren; i++)
1,726,360✔
191
    {
192
        if (EQUAL(papoChildNodes[i]->pszValue, pszName) &&
949,185✔
193
            papoChildNodes[i]->nChildren > 0)
56,514✔
194
            return papoChildNodes[i];
56,514✔
195
    }
196

197
    /* -------------------------------------------------------------------- */
198
    /*      Then get each child to check their children.                    */
199
    /* -------------------------------------------------------------------- */
200
    for (int i = 0; i < nChildren; i++)
1,520,100✔
201
    {
202
        OGR_SRSNode *poNode = papoChildNodes[i]->GetNode(pszName);
754,990✔
203
        if (poNode != nullptr)
754,990✔
204
            return poNode;
12,068✔
205
    }
206

207
    return nullptr;
765,108✔
208
}
209

210
/**
211
 * Find named node in tree.
212
 *
213
 * This method does a pre-order traversal of the node tree searching for
214
 * a node with this exact value (case insensitive), and returns it.  Leaf
215
 * nodes are not considered, under the assumption that they are just
216
 * attribute value nodes.
217
 *
218
 * If a node appears more than once in the tree (such as UNIT for instance),
219
 * the first encountered will be returned.  Use GetNode() on a subtree to be
220
 * more specific.
221
 *
222
 * @param pszName the name of the node to search for.
223
 *
224
 * @return a pointer to the node found, or NULL if none.
225
 */
226

227
const OGR_SRSNode *OGR_SRSNode::GetNode(const char *pszName) const
93✔
228

229
{
230
    return const_cast<OGR_SRSNode *>(this)->GetNode(pszName);
93✔
231
}
232

233
/************************************************************************/
234
/*                              AddChild()                              */
235
/************************************************************************/
236

237
/**
238
 * Add passed node as a child of target node.
239
 *
240
 * Note that ownership of the passed node is assumed by the node on which
241
 * the method is invoked ... use the Clone() method if the original is to
242
 * be preserved.  New children are always added at the end of the list.
243
 *
244
 * @param poNew the node to add as a child.
245
 */
246

247
void OGR_SRSNode::AddChild(OGR_SRSNode *poNew)
1,025,120✔
248

249
{
250
    InsertChild(poNew, nChildren);
1,025,120✔
251
}
1,025,120✔
252

253
/************************************************************************/
254
/*                            InsertChild()                             */
255
/************************************************************************/
256

257
/**
258
 * Insert the passed node as a child of target node, at the indicated
259
 * position.
260
 *
261
 * Note that ownership of the passed node is assumed by the node on which
262
 * the method is invoked ... use the Clone() method if the original is to
263
 * be preserved.  All existing children at location iChild and beyond are
264
 * push down one space to make space for the new child.
265
 *
266
 * @param poNew the node to add as a child.
267
 * @param iChild position to insert, use 0 to insert at the beginning.
268
 */
269

270
void OGR_SRSNode::InsertChild(OGR_SRSNode *poNew, int iChild)
1,025,120✔
271

272
{
273
    if (iChild > nChildren)
1,025,120✔
274
        iChild = nChildren;
×
275

276
    nChildren++;
1,025,120✔
277
    papoChildNodes = static_cast<OGR_SRSNode **>(
1,025,120✔
278
        CPLRealloc(papoChildNodes, sizeof(void *) * nChildren));
1,025,120✔
279

280
    memmove(papoChildNodes + iChild + 1, papoChildNodes + iChild,
1,025,120✔
281
            sizeof(void *) * (nChildren - iChild - 1));
1,025,120✔
282

283
    papoChildNodes[iChild] = poNew;
1,025,120✔
284
    poNew->poParent = this;
1,025,120✔
285

286
    poNew->m_listener = m_listener;
1,025,120✔
287
    notifyChange();
1,025,120✔
288
}
1,025,120✔
289

290
/************************************************************************/
291
/*                            DestroyChild()                            */
292
/************************************************************************/
293

294
/**
295
 * Remove a child node, and it's subtree.
296
 *
297
 * Note that removing a child node will result in children after it
298
 * being renumbered down one.
299
 *
300
 * @param iChild the index of the child.
301
 */
302

303
void OGR_SRSNode::DestroyChild(int iChild)
477✔
304

305
{
306
    if (iChild < 0 || iChild >= nChildren)
477✔
307
        return;
×
308

309
    delete papoChildNodes[iChild];
477✔
310
    while (iChild < nChildren - 1)
974✔
311
    {
312
        papoChildNodes[iChild] = papoChildNodes[iChild + 1];
497✔
313
        iChild++;
497✔
314
    }
315

316
    nChildren--;
477✔
317
    notifyChange();
477✔
318
}
319

320
/************************************************************************/
321
/*                             FindChild()                              */
322
/************************************************************************/
323

324
/**
325
 * Find the index of the child matching the given string.
326
 *
327
 * Note that the node value must match pszValue with the exception of
328
 * case.  The comparison is case insensitive.
329
 *
330
 * @param pszValueIn the node value being searched for.
331
 *
332
 * @return the child index, or -1 on failure.
333
 */
334

335
int OGR_SRSNode::FindChild(const char *pszValueIn) const
59,621✔
336

337
{
338
    for (int i = 0; i < nChildren; i++)
213,999✔
339
    {
340
        if (EQUAL(papoChildNodes[i]->pszValue, pszValueIn))
198,650✔
341
            return i;
44,272✔
342
    }
343

344
    return -1;
15,349✔
345
}
346

347
/************************************************************************/
348
/*                              GetValue()                              */
349
/************************************************************************/
350

351
/**
352
 * \fn const char *OGR_SRSNode::GetValue() const;
353
 *
354
 * Fetch value string for this node.
355
 *
356
 * @return A non-NULL string is always returned.  The returned pointer is to
357
 * the internal value of this node, and should not be modified, or freed.
358
 */
359

360
/************************************************************************/
361
/*                              SetValue()                              */
362
/************************************************************************/
363

364
/**
365
 * Set the node value.
366
 *
367
 * @param pszNewValue the new value to assign to this node.  The passed
368
 * string is duplicated and remains the responsibility of the caller.
369
 */
370

371
void OGR_SRSNode::SetValue(const char *pszNewValue)
1,024,060✔
372

373
{
374
    CPLFree(pszValue);
1,024,060✔
375
    pszValue = CPLStrdup(pszNewValue);
1,024,060✔
376
    notifyChange();
1,024,060✔
377
}
1,024,060✔
378

379
/************************************************************************/
380
/*                               Clone()                                */
381
/************************************************************************/
382

383
/**
384
 * Make a duplicate of this node, and it's children.
385
 *
386
 * @return a new node tree, which becomes the responsibility of the caller.
387
 */
388

389
OGR_SRSNode *OGR_SRSNode::Clone() const
2,690✔
390

391
{
392
    OGR_SRSNode *poNew = new OGR_SRSNode(pszValue);
2,690✔
393

394
    for (int i = 0; i < nChildren; i++)
5,315✔
395
    {
396
        poNew->AddChild(papoChildNodes[i]->Clone());
2,625✔
397
    }
398
    poNew->m_listener = m_listener;
2,690✔
399

400
    return poNew;
2,690✔
401
}
402

403
/************************************************************************/
404
/*                            NeedsQuoting()                            */
405
/*                                                                      */
406
/*      Does this node need to be quoted when it is exported to Wkt?    */
407
/************************************************************************/
408

409
int OGR_SRSNode::NeedsQuoting() const
311,397✔
410

411
{
412
    // Non-terminals are never quoted.
413
    if (GetChildCount() != 0)
311,397✔
414
        return FALSE;
111,932✔
415

416
    // As per bugzilla bug 201, the OGC spec says the authority code
417
    // needs to be quoted even though it appears well behaved.
418
    if (poParent != nullptr && EQUAL(poParent->GetValue(), "AUTHORITY"))
199,465✔
419
        return TRUE;
55,956✔
420

421
    // As per bugzilla bug 294, the OGC spec says the direction
422
    // values for the AXIS keywords should *not* be quoted.
423
    if (poParent != nullptr && EQUAL(poParent->GetValue(), "AXIS") &&
175,875✔
424
        this != poParent->GetChild(0))
32,366✔
425
        return FALSE;
16,183✔
426

427
    if (poParent != nullptr && EQUAL(poParent->GetValue(), "CS") &&
127,326✔
428
        this == poParent->GetChild(0))
×
429
        return FALSE;
×
430

431
    // Strings starting with e or E are not valid numeric values, so they
432
    // need quoting, like in AXIS["E",EAST]
433
    if ((pszValue[0] == 'e' || pszValue[0] == 'E'))
127,326✔
434
        return TRUE;
8,231✔
435

436
    // Non-numeric tokens are generally quoted while clean numeric values
437
    // are generally not.
438
    for (int i = 0; pszValue[i] != '\0'; i++)
494,903✔
439
    {
440
        if ((pszValue[i] < '0' || pszValue[i] > '9') && pszValue[i] != '.' &&
451,538✔
441
            pszValue[i] != '-' && pszValue[i] != '+' && pszValue[i] != 'e' &&
75,943✔
442
            pszValue[i] != 'E')
75,732✔
443
            return TRUE;
75,730✔
444
    }
445

446
    return FALSE;
43,365✔
447
}
448

449
/************************************************************************/
450
/*                            exportToWkt()                             */
451
/************************************************************************/
452

453
/**
454
 * Convert this tree of nodes into WKT format.
455
 *
456
 * Note that the returned WKT string should be freed with
457
 * CPLFree() when no longer needed.  It is the responsibility of the caller.
458
 *
459
 * @param ppszResult the resulting string is returned in this pointer.
460
 *
461
 * @return currently OGRERR_NONE is always returned, but the future it
462
 * is possible error conditions will develop.
463
 */
464

465
OGRErr OGR_SRSNode::exportToWkt(char **ppszResult) const
311,325✔
466

467
{
468
    /* -------------------------------------------------------------------- */
469
    /*      Build a list of the WKT format for the children.                */
470
    /* -------------------------------------------------------------------- */
471
    char **papszChildrenWkt =
472
        static_cast<char **>(CPLCalloc(sizeof(char *), nChildren + 1));
311,325✔
473
    size_t nLength = strlen(pszValue) + 4;
311,325✔
474

475
    for (int i = 0; i < nChildren; i++)
614,268✔
476
    {
477
        papoChildNodes[i]->exportToWkt(papszChildrenWkt + i);
302,943✔
478
        nLength += strlen(papszChildrenWkt[i]) + 1;
302,943✔
479
    }
480

481
    /* -------------------------------------------------------------------- */
482
    /*      Allocate the result string.                                     */
483
    /* -------------------------------------------------------------------- */
484
    *ppszResult = static_cast<char *>(CPLMalloc(nLength));
311,325✔
485
    *ppszResult[0] = '\0';
311,325✔
486

487
    /* -------------------------------------------------------------------- */
488
    /*      Capture this nodes value.  We put it in double quotes if        */
489
    /*      this is a leaf node, otherwise we assume it is a well formed    */
490
    /*      node name.                                                      */
491
    /* -------------------------------------------------------------------- */
492
    if (NeedsQuoting())
311,325✔
493
    {
494
        strcat(*ppszResult, "\"");
139,891✔
495
        strcat(*ppszResult, pszValue);  // Should we do quoting?
139,891✔
496
        strcat(*ppszResult, "\"");
139,891✔
497
    }
498
    else
499
        strcat(*ppszResult, pszValue);
171,434✔
500

501
    /* -------------------------------------------------------------------- */
502
    /*      Add the children strings with appropriate brackets and commas.  */
503
    /* -------------------------------------------------------------------- */
504
    if (nChildren > 0)
311,325✔
505
        strcat(*ppszResult, "[");
111,906✔
506

507
    for (int i = 0; i < nChildren; i++)
614,268✔
508
    {
509
        strcat(*ppszResult, papszChildrenWkt[i]);
302,943✔
510
        if (i == nChildren - 1)
302,943✔
511
            strcat(*ppszResult, "]");
111,906✔
512
        else
513
            strcat(*ppszResult, ",");
191,037✔
514
    }
515

516
    CSLDestroy(papszChildrenWkt);
311,325✔
517

518
    return OGRERR_NONE;
311,325✔
519
}
520

521
/************************************************************************/
522
/*                         exportToPrettyWkt()                          */
523
/************************************************************************/
524

525
/**
526
 * Convert this tree of nodes into pretty WKT format.
527
 *
528
 * Note that the returned WKT string should be freed with
529
 * CPLFree() when no longer needed.  It is the responsibility of the caller.
530
 *
531
 * @param ppszResult the resulting string is returned in this pointer.
532
 *
533
 * @param nDepth depth of the node
534
 *
535
 * @return currently OGRERR_NONE is always returned, but the future it
536
 * is possible error conditions will develop.
537
 */
538

539
OGRErr OGR_SRSNode::exportToPrettyWkt(char **ppszResult, int nDepth) const
72✔
540

541
{
542
    /* -------------------------------------------------------------------- */
543
    /*      Build a list of the WKT format for the children.                */
544
    /* -------------------------------------------------------------------- */
545
    char **papszChildrenWkt =
546
        static_cast<char **>(CPLCalloc(sizeof(char *), nChildren + 1));
72✔
547
    size_t nLength = strlen(pszValue) + 4;
72✔
548

549
    for (int i = 0; i < nChildren; i++)
142✔
550
    {
551
        papoChildNodes[i]->exportToPrettyWkt(papszChildrenWkt + i, nDepth + 1);
70✔
552
        nLength += strlen(papszChildrenWkt[i]) + 2 + nDepth * 4;
70✔
553
    }
554

555
    /* -------------------------------------------------------------------- */
556
    /*      Allocate the result string.                                     */
557
    /* -------------------------------------------------------------------- */
558
    *ppszResult = static_cast<char *>(CPLMalloc(nLength));
72✔
559
    *ppszResult[0] = '\0';
72✔
560

561
    /* -------------------------------------------------------------------- */
562
    /*      Capture this nodes value.  We put it in double quotes if        */
563
    /*      this is a leaf node, otherwise we assume it is a well formed    */
564
    /*      node name.                                                      */
565
    /* -------------------------------------------------------------------- */
566
    if (NeedsQuoting())
72✔
567
    {
568
        strcat(*ppszResult, "\"");
26✔
569
        strcat(*ppszResult, pszValue);  // Should we do quoting?
26✔
570
        strcat(*ppszResult, "\"");
26✔
571
    }
572
    else
573
    {
574
        strcat(*ppszResult, pszValue);
46✔
575
    }
576

577
    /* -------------------------------------------------------------------- */
578
    /*      Add the children strings with appropriate brackets and commas.  */
579
    /* -------------------------------------------------------------------- */
580
    if (nChildren > 0)
72✔
581
        strcat(*ppszResult, "[");
26✔
582

583
    for (int i = 0; i < nChildren; i++)
142✔
584
    {
585
        if (papoChildNodes[i]->GetChildCount() > 0)
70✔
586
        {
587
            strcat(*ppszResult, "\n");
24✔
588
            for (int j = 0; j < 4 * nDepth; j++)
160✔
589
                strcat(*ppszResult, " ");
136✔
590
        }
591
        strcat(*ppszResult, papszChildrenWkt[i]);
70✔
592
        if (i < nChildren - 1)
70✔
593
            strcat(*ppszResult, ",");
44✔
594
    }
595

596
    if (nChildren > 0)
72✔
597
    {
598
        if ((*ppszResult)[strlen(*ppszResult) - 1] == ',')
26✔
599
            (*ppszResult)[strlen(*ppszResult) - 1] = '\0';
×
600

601
        strcat(*ppszResult, "]");
26✔
602
    }
603

604
    CSLDestroy(papszChildrenWkt);
72✔
605

606
    return OGRERR_NONE;
72✔
607
}
608

609
/************************************************************************/
610
/*                           importFromWkt()                            */
611
/************************************************************************/
612

613
/**
614
 * Import from WKT string.
615
 *
616
 * This method will wipe the existing children and value of this node, and
617
 * reassign them based on the contents of the passed WKT string.  Only as
618
 * much of the input string as needed to construct this node, and its
619
 * children is consumed from the input string, and the input string pointer
620
 * is then updated to point to the remaining (unused) input.
621
 *
622
 * @param ppszInput Pointer to pointer to input.  The pointer is updated to
623
 * point to remaining unused input text.
624
 *
625
 * @return OGRERR_NONE if import succeeds, or OGRERR_CORRUPT_DATA if it
626
 * fails for any reason.
627
 * @deprecated GDAL 2.3. Use importFromWkt(const char**) instead.
628
 */
629

630
OGRErr OGR_SRSNode::importFromWkt(char **ppszInput)
×
631

632
{
633
    int nNodes = 0;
×
634
    return importFromWkt(const_cast<const char **>(ppszInput), 0, &nNodes);
×
635
}
636

637
/**
638
 * Import from WKT string.
639
 *
640
 * This method will wipe the existing children and value of this node, and
641
 * reassign them based on the contents of the passed WKT string.  Only as
642
 * much of the input string as needed to construct this node, and its
643
 * children is consumed from the input string, and the input string pointer
644
 * is then updated to point to the remaining (unused) input.
645
 *
646
 * @param ppszInput Pointer to pointer to input.  The pointer is updated to
647
 * point to remaining unused input text.
648
 *
649
 * @return OGRERR_NONE if import succeeds, or OGRERR_CORRUPT_DATA if it
650
 * fails for any reason.
651
 *
652
 * @since GDAL 2.3
653
 */
654

655
OGRErr OGR_SRSNode::importFromWkt(const char **ppszInput)
25,757✔
656

657
{
658
    int nNodes = 0;
25,757✔
659
    return importFromWkt(ppszInput, 0, &nNodes);
51,514✔
660
}
661

662
OGRErr OGR_SRSNode::importFromWkt(const char **ppszInput, int nRecLevel,
1,023,640✔
663
                                  int *pnNodes)
664

665
{
666
    // Sanity checks.
667
    if (nRecLevel == 10)
1,023,640✔
668
    {
669
        return OGRERR_CORRUPT_DATA;
×
670
    }
671
    if (*pnNodes == 1000)
1,023,640✔
672
    {
673
        return OGRERR_CORRUPT_DATA;
×
674
    }
675

676
    const char *pszInput = *ppszInput;
1,023,640✔
677
    bool bInQuotedString = false;
1,023,640✔
678

679
    /* -------------------------------------------------------------------- */
680
    /*      Clear any existing children of this node.                       */
681
    /* -------------------------------------------------------------------- */
682
    ClearChildren();
1,023,640✔
683

684
    /* -------------------------------------------------------------------- */
685
    /*      Read the ``value'' for this node.                               */
686
    /* -------------------------------------------------------------------- */
687
    {
688
        char szToken[512];  // do not initialize whole buffer. significant
689
                            // overhead
690
        size_t nTokenLen = 0;
1,023,640✔
691
        szToken[0] = '\0';
1,023,640✔
692

693
        while (*pszInput != '\0' && nTokenLen + 1 < sizeof(szToken))
9,408,550✔
694
        {
695
            if (*pszInput == '"')
9,408,550✔
696
            {
697
                bInQuotedString = !bInQuotedString;
911,528✔
698
            }
699
            else if (!bInQuotedString &&
8,497,020✔
700
                     (*pszInput == '[' || *pszInput == ']' ||
4,897,550✔
701
                      *pszInput == ',' || *pszInput == '(' || *pszInput == ')'))
4,302,010✔
702
            {
703
                break;
704
            }
705
            else if (!bInQuotedString &&
7,473,380✔
706
                     (*pszInput == ' ' || *pszInput == '\t' ||
3,873,910✔
707
                      *pszInput == 10 || *pszInput == 13))
3,873,410✔
708
            {
709
                // Skip over whitespace.
710
            }
711
            else
712
            {
713
                szToken[nTokenLen++] = *pszInput;
7,472,840✔
714
            }
715

716
            pszInput++;
8,384,910✔
717
        }
718

719
        if (*pszInput == '\0' || nTokenLen == sizeof(szToken) - 1)
1,023,640✔
720
            return OGRERR_CORRUPT_DATA;
×
721

722
        szToken[nTokenLen++] = '\0';
1,023,640✔
723
        SetValue(szToken);
1,023,640✔
724
    }
725

726
    /* -------------------------------------------------------------------- */
727
    /*      Read children, if we have a sublist.                            */
728
    /* -------------------------------------------------------------------- */
729
    if (*pszInput == '[' || *pszInput == '(')
1,023,640✔
730
    {
731
        do
637,363✔
732
        {
733
            pszInput++;  // Skip bracket or comma.
997,888✔
734

735
            OGR_SRSNode *poNewChild = new OGR_SRSNode();
997,888✔
736
            poNewChild->m_listener = m_listener;
997,888✔
737

738
            (*pnNodes)++;
997,888✔
739
            const OGRErr eErr =
740
                poNewChild->importFromWkt(&pszInput, nRecLevel + 1, pnNodes);
997,888✔
741
            if (eErr != OGRERR_NONE)
997,888✔
742
            {
743
                delete poNewChild;
×
744
                return eErr;
×
745
            }
746

747
            AddChild(poNewChild);
997,888✔
748

749
            // Swallow whitespace.
750
            while (isspace(static_cast<unsigned char>(*pszInput)))
997,888✔
751
                pszInput++;
×
752
        } while (*pszInput == ',');
997,888✔
753

754
        if (*pszInput != ')' && *pszInput != ']')
360,525✔
755
            return OGRERR_CORRUPT_DATA;
×
756

757
        pszInput++;
360,525✔
758
    }
759

760
    *ppszInput = pszInput;
1,023,640✔
761

762
    return OGRERR_NONE;
1,023,640✔
763
}
764

765
/************************************************************************/
766
/*                           MakeValueSafe()                            */
767
/************************************************************************/
768

769
/**
770
 * Massage value string, stripping special characters so it will be a
771
 * database safe string.
772
 *
773
 * The operation is also applies to all subnodes of the current node.
774
 */
775

776
void OGR_SRSNode::MakeValueSafe()
×
777

778
{
779
    /* -------------------------------------------------------------------- */
780
    /*      First process subnodes.                                         */
781
    /* -------------------------------------------------------------------- */
782
    for (int iChild = 0; iChild < GetChildCount(); iChild++)
×
783
    {
784
        GetChild(iChild)->MakeValueSafe();
×
785
    }
786

787
    /* -------------------------------------------------------------------- */
788
    /*      Skip numeric nodes.                                             */
789
    /* -------------------------------------------------------------------- */
790
    if ((pszValue[0] >= '0' && pszValue[0] <= '9') || pszValue[0] != '.')
×
791
        return;
×
792

793
    /* -------------------------------------------------------------------- */
794
    /*      Translate non-alphanumeric values to underscores.               */
795
    /* -------------------------------------------------------------------- */
796
    for (int i = 0; pszValue[i] != '\0'; i++)
×
797
    {
798
        if (!(pszValue[i] >= 'A' && pszValue[i] <= 'Z') &&
×
799
            !(pszValue[i] >= 'a' && pszValue[i] <= 'z') &&
×
800
            !(pszValue[i] >= '0' && pszValue[i] <= '9'))
×
801
        {
802
            pszValue[i] = '_';
×
803
        }
804
    }
805

806
    /* -------------------------------------------------------------------- */
807
    /*      Remove repeated and trailing underscores.                       */
808
    /* -------------------------------------------------------------------- */
809
    int j = 0;
×
810
    for (int i = 1; pszValue[i] != '\0'; i++)
×
811
    {
812
        if (pszValue[j] == '_' && pszValue[i] == '_')
×
813
            continue;
×
814

815
        pszValue[++j] = pszValue[i];
×
816
    }
817

818
    if (pszValue[j] == '_')
×
819
        pszValue[j] = '\0';
×
820
    else
821
        pszValue[j + 1] = '\0';
×
822
}
823

824
/************************************************************************/
825
/*                             StripNodes()                             */
826
/************************************************************************/
827

828
/**
829
 * Strip child nodes matching name.
830
 *
831
 * Removes any descendant nodes of this node that match the given name.
832
 * Of course children of removed nodes are also discarded.
833
 *
834
 * @param pszName the name for nodes that should be removed.
835
 */
836

837
void OGR_SRSNode::StripNodes(const char *pszName)
6,022✔
838

839
{
840
    /* -------------------------------------------------------------------- */
841
    /*      Strip any children matching this name.                          */
842
    /* -------------------------------------------------------------------- */
843
    while (FindChild(pszName) >= 0)
6,022✔
844
        DestroyChild(FindChild(pszName));
78✔
845

846
    /* -------------------------------------------------------------------- */
847
    /*      Recurse                                                         */
848
    /* -------------------------------------------------------------------- */
849
    for (int i = 0; i < GetChildCount(); i++)
11,549✔
850
        GetChild(i)->StripNodes(pszName);
5,605✔
851
}
5,944✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc