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

OSGeo / gdal / 13836648005

13 Mar 2025 02:09PM UTC coverage: 70.436% (-0.01%) from 70.446%
13836648005

push

github

web-flow
New Transform type: Homography (#11949)

Add new transform type, Homography.
Add functions to compute homography from a list of GCPs.
Add functions to serialize and deserialize a homography
Automatically select homography transfrom when there are 4 or 5 GCPs present.

Fixes #11940

231 of 274 new or added lines in 2 files covered. (84.31%)

16257 existing lines in 42 files now uncovered.

553736 of 786159 relevant lines covered (70.44%)

221595.72 hits per line

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

91.27
/port/cplstringlist.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  CPLStringList implementation.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2011, Frank Warmerdam <warmerdam@pobox.com>
9
 * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

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

17
#include <cstddef>
18
#include <cstdio>
19
#include <cstdlib>
20
#include <cstring>
21

22
#include <algorithm>
23
#include <limits>
24
#include <string>
25

26
#include "cpl_conv.h"
27
#include "cpl_error.h"
28

29
/************************************************************************/
30
/*                           CPLStringList()                            */
31
/************************************************************************/
32

33
CPLStringList::CPLStringList() = default;
34

35
/************************************************************************/
36
/*                           CPLStringList()                            */
37
/************************************************************************/
38

39
/**
40
 * CPLStringList constructor.
41
 *
42
 * @param papszListIn the NULL terminated list of strings to consume.
43
 * @param bTakeOwnership TRUE if the CPLStringList should take ownership
44
 * of the list of strings which implies responsibility to free them.
45
 */
46

47
CPLStringList::CPLStringList(char **papszListIn, int bTakeOwnership)
1,775,590✔
48
    : CPLStringList()
1,775,590✔
49

50
{
51
    Assign(papszListIn, bTakeOwnership);
1,694,620✔
52
}
1,646,030✔
53

54
/************************************************************************/
55
/*                           CPLStringList()                            */
56
/************************************************************************/
57

58
/**
59
 * CPLStringList constructor.
60
 *
61
 * The input list is copied.
62
 *
63
 * @param papszListIn the NULL terminated list of strings to ingest.
64
 */
65

66
CPLStringList::CPLStringList(CSLConstList papszListIn) : CPLStringList()
3,906✔
67

68
{
69
    Assign(CSLDuplicate(papszListIn));
3,906✔
70
}
3,906✔
71

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

76
/**
77
 * CPLStringList constructor.
78
 *
79
 * The input list is copied.
80
 *
81
 * @param aosList input list.
82
 *
83
 * @since GDAL 3.9
84
 */
85
CPLStringList::CPLStringList(const std::vector<std::string> &aosList)
639✔
86
{
87
    if (!aosList.empty())
639✔
88
    {
89
        bOwnList = true;
272✔
90
        papszList = static_cast<char **>(
272✔
91
            VSI_CALLOC_VERBOSE(aosList.size() + 1, sizeof(char *)));
272✔
92
        nCount = static_cast<int>(aosList.size());
272✔
93
        for (int i = 0; i < nCount; ++i)
1,218✔
94
        {
95
            papszList[i] = VSI_STRDUP_VERBOSE(aosList[i].c_str());
946✔
96
        }
97
    }
98
}
639✔
99

100
/************************************************************************/
101
/*                           CPLStringList()                            */
102
/************************************************************************/
103

104
/**
105
 * CPLStringList constructor.
106
 *
107
 * The input list is copied.
108
 *
109
 * @param oInitList input list.
110
 *
111
 * @since GDAL 3.9
112
 */
113
CPLStringList::CPLStringList(std::initializer_list<const char *> oInitList)
3✔
114
{
115
    for (const char *pszStr : oInitList)
9✔
116
    {
117
        AddString(pszStr);
6✔
118
    }
119
}
3✔
120

121
/************************************************************************/
122
/*                           CPLStringList()                            */
123
/************************************************************************/
124

125
//! Copy constructor
126
CPLStringList::CPLStringList(const CPLStringList &oOther) : CPLStringList()
21,279✔
127

128
{
129
    operator=(oOther);
21,280✔
130
}
21,280✔
131

132
/************************************************************************/
133
/*                           CPLStringList()                            */
134
/************************************************************************/
135

136
//! Move constructor
137
CPLStringList::CPLStringList(CPLStringList &&oOther) : CPLStringList()
2,932,010✔
138

139
{
140
    operator=(std::move(oOther));
2,859,160✔
141
}
2,928,260✔
142

143
/************************************************************************/
144
/*                           BoundToConstList()                         */
145
/************************************************************************/
146

147
/**
148
 * Return a CPLStringList that wraps the passed list.
149
 *
150
 * The input list is *NOT* copied and must be kept alive while the
151
 * return CPLStringList is used.
152
 *
153
 * @param papszListIn a NULL terminated list of strings to wrap into the CPLStringList
154
 * @since GDAL 3.9
155
 */
156

157
/* static */
158
const CPLStringList CPLStringList::BoundToConstList(CSLConstList papszListIn)
94✔
159
{
160
    return CPLStringList(const_cast<char **>(papszListIn),
161
                         /* bTakeOwnership= */ false);
94✔
162
}
163

164
/************************************************************************/
165
/*                             operator=()                              */
166
/************************************************************************/
167

168
CPLStringList &CPLStringList::operator=(const CPLStringList &oOther)
36,917✔
169
{
170
    if (this != &oOther)
36,917✔
171
    {
172
        char **l_papszList = CSLDuplicate(oOther.papszList);
36,916✔
173
        if (l_papszList)
36,913✔
174
        {
175
            Assign(l_papszList, TRUE);
5,668✔
176
            nAllocation = oOther.nCount > 0 ? oOther.nCount + 1 : 0;
5,670✔
177
            nCount = oOther.nCount;
5,670✔
178
            bIsSorted = oOther.bIsSorted;
5,670✔
179
        }
180
    }
181

182
    return *this;
36,916✔
183
}
184

185
/************************************************************************/
186
/*                             operator=()                              */
187
/************************************************************************/
188

189
CPLStringList &CPLStringList::operator=(CPLStringList &&oOther)
2,909,180✔
190
{
191
    if (this != &oOther)
2,909,180✔
192
    {
193
        Clear();
2,921,620✔
194
        papszList = oOther.papszList;
2,896,120✔
195
        oOther.papszList = nullptr;
2,896,120✔
196
        nCount = oOther.nCount;
2,896,120✔
197
        oOther.nCount = 0;
2,896,120✔
198
        nAllocation = oOther.nAllocation;
2,896,120✔
199
        oOther.nAllocation = 0;
2,896,120✔
200
        bOwnList = oOther.bOwnList;
2,896,120✔
201
        oOther.bOwnList = false;
2,896,120✔
202
        bIsSorted = oOther.bIsSorted;
2,896,120✔
203
        oOther.bIsSorted = true;
2,896,120✔
204
    }
205

206
    return *this;
2,883,680✔
207
}
208

209
/************************************************************************/
210
/*                             operator=()                              */
211
/************************************************************************/
212

213
CPLStringList &CPLStringList::operator=(CSLConstList papszListIn)
30,966✔
214
{
215
    if (papszListIn != papszList)
30,966✔
216
    {
217
        Assign(CSLDuplicate(papszListIn));
13,036✔
218
        bIsSorted = false;
13,036✔
219
    }
220

221
    return *this;
30,966✔
222
}
223

224
/************************************************************************/
225
/*                           ~CPLStringList()                           */
226
/************************************************************************/
227

228
CPLStringList::~CPLStringList()
17,726,300✔
229

230
{
231
    Clear();
8,923,070✔
232
}
8,803,230✔
233

234
/************************************************************************/
235
/*                               Clear()                                */
236
/************************************************************************/
237

238
/**
239
 * Clear the string list.
240
 */
241
CPLStringList &CPLStringList::Clear()
13,732,500✔
242

243
{
244
    if (bOwnList)
13,732,500✔
245
    {
246
        CSLDestroy(papszList);
2,424,130✔
247
        papszList = nullptr;
2,447,010✔
248

249
        bOwnList = FALSE;
2,447,010✔
250
        nAllocation = 0;
2,447,010✔
251
        nCount = 0;
2,447,010✔
252
    }
253

254
    return *this;
13,755,400✔
255
}
256

257
/************************************************************************/
258
/*                               Assign()                               */
259
/************************************************************************/
260

261
/**
262
 * Assign a list of strings.
263
 *
264
 *
265
 * @param papszListIn the NULL terminated list of strings to consume.
266
 * @param bTakeOwnership TRUE if the CPLStringList should take ownership
267
 * of the list of strings which implies responsibility to free them.
268
 *
269
 * @return a reference to the CPLStringList on which it was invoked.
270
 */
271

272
CPLStringList &CPLStringList::Assign(char **papszListIn, int bTakeOwnership)
1,814,210✔
273

274
{
275
    Clear();
1,814,210✔
276

277
    papszList = papszListIn;
1,785,600✔
278
    bOwnList = CPL_TO_BOOL(bTakeOwnership);
1,785,600✔
279

280
    if (papszList == nullptr || *papszList == nullptr)
1,751,030✔
281
        nCount = 0;
1,390,600✔
282
    else
283
        nCount = -1;  // unknown
360,434✔
284

285
    nAllocation = 0;
1,751,030✔
286
    bIsSorted = FALSE;
1,751,030✔
287

288
    return *this;
1,751,030✔
289
}
290

291
/************************************************************************/
292
/*                               Count()                                */
293
/************************************************************************/
294

295
/**
296
 * @return count of strings in the list, zero if empty.
297
 */
298

299
int CPLStringList::Count() const
2,306,480✔
300

301
{
302
    if (nCount == -1)
2,306,480✔
303
    {
304
        if (papszList == nullptr)
347,790✔
305
        {
306
            nCount = 0;
×
307
            nAllocation = 0;
×
308
        }
309
        else
310
        {
311
            nCount = CSLCount(papszList);
347,790✔
312
            nAllocation = std::max(nCount + 1, nAllocation);
347,790✔
313
        }
314
    }
315

316
    return nCount;
2,306,480✔
317
}
318

319
/************************************************************************/
320
/*                           MakeOurOwnCopy()                           */
321
/*                                                                      */
322
/*      If we don't own the list, a copy is made which we own.          */
323
/*      Necessary if we are going to modify the list.                   */
324
/************************************************************************/
325

326
bool CPLStringList::MakeOurOwnCopy()
6,008,680✔
327

328
{
329
    if (bOwnList)
6,008,680✔
330
        return true;
3,371,840✔
331

332
    if (papszList == nullptr)
2,636,840✔
333
        return true;
2,636,660✔
334

335
    Count();
184✔
336
    char **papszListNew = CSLDuplicate(papszList);
83✔
337
    if (papszListNew == nullptr)
83✔
338
    {
339
        return false;
×
340
    }
341
    papszList = papszListNew;
83✔
342
    bOwnList = true;
83✔
343
    nAllocation = nCount + 1;
83✔
344
    return true;
83✔
345
}
346

347
/************************************************************************/
348
/*                          EnsureAllocation()                          */
349
/*                                                                      */
350
/*      Ensure we have enough room allocated for at least the           */
351
/*      requested number of strings (so nAllocation will be at least    */
352
/*      one more than the target)                                       */
353
/************************************************************************/
354

355
bool CPLStringList::EnsureAllocation(int nMaxList)
8,913,530✔
356

357
{
358
    if (!bOwnList)
8,913,530✔
359
    {
360
        if (!MakeOurOwnCopy())
2,157,410✔
361
            return false;
×
362
    }
363

364
    if (papszList == nullptr || nAllocation <= nMaxList)
8,913,520✔
365
    {
366
        // we need to be able to store nMaxList+1 as an int,
367
        // and allocate (nMaxList+1) * sizeof(char*) bytes
368
        if (nMaxList < 0 || nMaxList > std::numeric_limits<int>::max() - 1 ||
4,445,990✔
369
            static_cast<size_t>(nMaxList) >
2,223,060✔
370
                std::numeric_limits<size_t>::max() / sizeof(char *) - 1)
2,223,060✔
371
        {
372
            return false;
×
373
        }
374
        int nNewAllocation = nMaxList + 1;
2,222,930✔
375
        if (nNewAllocation <= (std::numeric_limits<int>::max() - 20) / 2 /
2,222,930✔
376
                                  static_cast<int>(sizeof(char *)))
377
            nNewAllocation = std::max(nNewAllocation * 2 + 20, nMaxList + 1);
2,223,000✔
378
        if (papszList == nullptr)
2,222,970✔
379
        {
380
            papszList = static_cast<char **>(
2,159,650✔
381
                VSI_CALLOC_VERBOSE(nNewAllocation, sizeof(char *)));
2,159,610✔
382
            bOwnList = true;
2,159,650✔
383
            nCount = 0;
2,159,650✔
384
            if (papszList == nullptr)
2,159,650✔
385
                return false;
×
386
        }
387
        else
388
        {
389
            char **papszListNew = static_cast<char **>(VSI_REALLOC_VERBOSE(
63,365✔
390
                papszList, nNewAllocation * sizeof(char *)));
391
            if (papszListNew == nullptr)
63,365✔
392
                return false;
×
393
            papszList = papszListNew;
63,365✔
394
        }
395
        nAllocation = nNewAllocation;
2,223,010✔
396
    }
397
    return true;
8,913,530✔
398
}
399

400
/************************************************************************/
401
/*                         AddStringDirectly()                          */
402
/************************************************************************/
403

404
/**
405
 * Add a string to the list.
406
 *
407
 * This method is similar to AddString(), but ownership of the
408
 * pszNewString is transferred to the CPLStringList class.
409
 *
410
 * @param pszNewString the string to add to the list.
411
 */
412

413
CPLStringList &CPLStringList::AddStringDirectly(char *pszNewString)
8,906,790✔
414

415
{
416
    if (nCount == -1)
8,906,790✔
417
        Count();
214✔
418

419
    if (!EnsureAllocation(nCount + 1))
8,906,790✔
420
    {
UNCOV
421
        VSIFree(pszNewString);
×
422
        return *this;
×
423
    }
424

425
    papszList[nCount++] = pszNewString;
8,906,760✔
426
    papszList[nCount] = nullptr;
8,906,760✔
427

428
    bIsSorted = false;
8,906,760✔
429

430
    return *this;
8,906,760✔
431
}
432

433
/************************************************************************/
434
/*                             AddString()                              */
435
/************************************************************************/
436

437
/**
438
 * Add a string to the list.
439
 *
440
 * A copy of the passed in string is made and inserted in the list.
441
 *
442
 * @param pszNewString the string to add to the list.
443
 */
444

445
CPLStringList &CPLStringList::AddString(const char *pszNewString)
5,170,720✔
446

447
{
448
    char *pszDupString = VSI_STRDUP_VERBOSE(pszNewString);
5,170,720✔
449
    if (pszDupString == nullptr)
5,170,720✔
450
        return *this;
×
451
    return AddStringDirectly(pszDupString);
5,170,720✔
452
}
453

454
/************************************************************************/
455
/*                             AddString()                              */
456
/************************************************************************/
457
/**
458
 * Add a string to the list.
459
 *
460
 * A copy of the passed in string is made and inserted in the list.
461
 *
462
 * @param newString the string to add to the list.
463
 * @return a reference to the CPLStringList on which it was invoked.
464
 */
465

466
CPLStringList &CPLStringList::AddString(const std::string &newString)
24,938✔
467
{
468
    return AddString(newString.c_str());
24,938✔
469
}
470

471
/************************************************************************/
472
/*                            AddNameValue()                            */
473
/************************************************************************/
474

475
/**
476
 * Add a name=value entry to the list.
477
 *
478
 * A key=value string is prepared and appended to the list.  There is no
479
 * check for other values for the same key in the list.
480
 *
481
 * @param pszKey the key name to add.
482
 * @param pszValue the key value to add.
483
 */
484

485
CPLStringList &CPLStringList::AddNameValue(const char *pszKey,
3,745,410✔
486
                                           const char *pszValue)
487

488
{
489
    if (pszKey == nullptr || pszValue == nullptr)
3,745,410✔
490
        return *this;
3,155✔
491

492
    if (!MakeOurOwnCopy())
3,742,250✔
493
        return *this;
×
494

495
    /* -------------------------------------------------------------------- */
496
    /*      Format the line.                                                */
497
    /* -------------------------------------------------------------------- */
498
    if (strlen(pszKey) >
7,484,650✔
499
            std::numeric_limits<size_t>::max() - strlen(pszValue) ||
7,484,630✔
500
        strlen(pszKey) + strlen(pszValue) >
3,742,290✔
501
            std::numeric_limits<size_t>::max() - 2)
3,742,290✔
502
    {
503
        CPLError(CE_Failure, CPLE_OutOfMemory,
×
504
                 "Too big strings in AddNameValue()");
505
        return *this;
×
506
    }
507
    const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
3,742,330✔
508
    char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
3,742,330✔
509
    if (pszLine == nullptr)
3,742,330✔
510
        return *this;
×
511
    snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
3,742,330✔
512

513
    /* -------------------------------------------------------------------- */
514
    /*      If we don't need to keep the sort order things are pretty       */
515
    /*      straight forward.                                               */
516
    /* -------------------------------------------------------------------- */
517
    if (!IsSorted())
3,742,330✔
518
        return AddStringDirectly(pszLine);
3,735,720✔
519

520
    /* -------------------------------------------------------------------- */
521
    /*      Find the proper insertion point.                                */
522
    /* -------------------------------------------------------------------- */
523
    CPLAssert(IsSorted());
6,575✔
524
    const int iKey = FindSortedInsertionPoint(pszLine);
6,550✔
525
    InsertStringDirectly(iKey, pszLine);
6,550✔
526
    bIsSorted = true;  // We have actually preserved sort order.
6,550✔
527

528
    return *this;
6,550✔
529
}
530

531
/************************************************************************/
532
/*                            SetNameValue()                            */
533
/************************************************************************/
534

535
/**
536
 * Set name=value entry in the list.
537
 *
538
 * Similar to AddNameValue(), except if there is already a value for
539
 * the key in the list it is replaced instead of adding a new entry to
540
 * the list.  If pszValue is NULL any existing key entry is removed.
541
 *
542
 * @param pszKey the key name to add.
543
 * @param pszValue the key value to add.
544
 */
545

546
CPLStringList &CPLStringList::SetNameValue(const char *pszKey,
3,792,720✔
547
                                           const char *pszValue)
548

549
{
550
    int iKey = FindName(pszKey);
3,792,720✔
551

552
    if (iKey == -1)
3,792,710✔
553
        return AddNameValue(pszKey, pszValue);
3,712,630✔
554

555
    Count();
80,076✔
556
    if (!MakeOurOwnCopy())
79,983✔
557
        return *this;
×
558

559
    CPLFree(papszList[iKey]);
79,983✔
560
    if (pszValue == nullptr)  // delete entry
79,983✔
561
    {
562

563
        // shift everything down by one.
564
        do
117✔
565
        {
566
            papszList[iKey] = papszList[iKey + 1];
221✔
567
        } while (papszList[iKey++] != nullptr);
221✔
568

569
        nCount--;
104✔
570
    }
571
    else
572
    {
573
        if (strlen(pszKey) >
159,758✔
574
                std::numeric_limits<size_t>::max() - strlen(pszValue) ||
159,758✔
575
            strlen(pszKey) + strlen(pszValue) >
79,879✔
576
                std::numeric_limits<size_t>::max() - 2)
79,879✔
577
        {
578
            CPLError(CE_Failure, CPLE_OutOfMemory,
×
579
                     "Too big strings in AddNameValue()");
580
            return *this;
×
581
        }
582
        const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
79,879✔
583
        char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
79,879✔
584
        if (pszLine == nullptr)
79,879✔
585
            return *this;
×
586
        snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
79,879✔
587

588
        papszList[iKey] = pszLine;
79,879✔
589
    }
590

591
    return *this;
79,983✔
592
}
593

594
/************************************************************************/
595
/*                              operator[]                              */
596
/************************************************************************/
597

598
/**
599
 * Fetch entry "i".
600
 *
601
 * Fetches the requested item in the list.  Note that the returned string
602
 * remains owned by the CPLStringList.  If "i" is out of range NULL is
603
 * returned.
604
 *
605
 * @param i the index of the list item to return.
606
 * @return selected entry in the list.
607
 */
608
char *CPLStringList::operator[](int i)
1,087,840✔
609

610
{
611
    if (nCount == -1)
1,087,840✔
612
        Count();
181✔
613

614
    if (i < 0 || i >= nCount)
1,087,840✔
615
        return nullptr;
52✔
616

617
    return papszList[i];
1,087,780✔
618
}
619

620
const char *CPLStringList::operator[](int i) const
293,590✔
621

622
{
623
    if (nCount == -1)
293,590✔
624
        Count();
6✔
625

626
    if (i < 0 || i >= nCount)
293,590✔
627
        return nullptr;
2✔
628

629
    return papszList[i];
293,588✔
630
}
631

632
/************************************************************************/
633
/*                             StealList()                              */
634
/************************************************************************/
635

636
/**
637
 * Seize ownership of underlying string array.
638
 *
639
 * This method is similar to List(), except that the returned list is
640
 * now owned by the caller and the CPLStringList is emptied.
641
 *
642
 * @return the C style string list.
643
 */
644
char **CPLStringList::StealList()
1,310,060✔
645

646
{
647
    char **papszRetList = papszList;
1,310,060✔
648

649
    bOwnList = false;
1,310,060✔
650
    papszList = nullptr;
1,310,060✔
651
    nCount = 0;
1,310,060✔
652
    nAllocation = 0;
1,310,060✔
653

654
    return papszRetList;
1,310,060✔
655
}
656

657
/* Case insensitive comparison function */
658
static int CPLCompareKeyValueString(const char *pszKVa, const char *pszKVb)
489,390✔
659
{
660
    const char *pszItera = pszKVa;
489,390✔
661
    const char *pszIterb = pszKVb;
489,390✔
662
    while (true)
663
    {
664
        char cha = *pszItera;
3,737,120✔
665
        char chb = *pszIterb;
3,737,120✔
666
        if (cha == '=' || cha == '\0')
3,737,120✔
667
        {
668
            if (chb == '=' || chb == '\0')
2,335✔
669
                return 0;
2✔
670
            else
671
                return -1;
2,333✔
672
        }
673
        if (chb == '=' || chb == '\0')
3,734,780✔
674
        {
675
            return 1;
2,865✔
676
        }
677
        if (cha >= 'a' && cha <= 'z')
3,731,920✔
678
            cha -= ('a' - 'A');
489,904✔
679
        if (chb >= 'a' && chb <= 'z')
3,731,920✔
680
            chb -= ('a' - 'A');
490,641✔
681
        if (cha < chb)
3,731,920✔
682
            return -1;
286,459✔
683
        else if (cha > chb)
3,445,460✔
684
            return 1;
197,731✔
685
        pszItera++;
3,247,730✔
686
        pszIterb++;
3,247,730✔
687
    }
3,247,730✔
688
}
689

690
/************************************************************************/
691
/*                                Sort()                                */
692
/************************************************************************/
693

694
/**
695
 * Sort the entries in the list and mark list sorted.
696
 *
697
 * Note that once put into "sorted" mode, the CPLStringList will attempt to
698
 * keep things in sorted order through calls to AddString(),
699
 * AddStringDirectly(), AddNameValue(), SetNameValue(). Complete list
700
 * assignments (via Assign() and operator= will clear the sorting state.
701
 * When in sorted order FindName(), FetchNameValue() and FetchNameValueDef()
702
 * will do a binary search to find the key, substantially improve lookup
703
 * performance in large lists.
704
 */
705

706
CPLStringList &CPLStringList::Sort()
28,893✔
707

708
{
709
    Count();
28,893✔
710
    if (!MakeOurOwnCopy())
28,893✔
711
        return *this;
×
712

713
    if (nCount > 1)
28,893✔
714
    {
715
        std::sort(papszList, papszList + nCount,
3,828✔
716
                  [](const char *a, const char *b)
440,695✔
717
                  { return CPLCompareKeyValueString(a, b) < 0; });
440,695✔
718
    }
719
    bIsSorted = true;
28,892✔
720

721
    return *this;
28,892✔
722
}
723

724
/************************************************************************/
725
/*                              FindName()                              */
726
/************************************************************************/
727

728
/**
729
 * Get index of given name/value keyword.
730
 *
731
 * Note that this search is for a line in the form name=value or name:value.
732
 * Use FindString() or PartialFindString() for searches not based on name=value
733
 * pairs.
734
 *
735
 * @param pszKey the name to search for.
736
 *
737
 * @return the string list index of this name, or -1 on failure.
738
 */
739

740
int CPLStringList::FindName(const char *pszKey) const
14,556,300✔
741

742
{
743
    if (!IsSorted())
14,556,300✔
744
        return CSLFindName(papszList, pszKey);
14,532,600✔
745

746
    // If we are sorted, we can do an optimized binary search.
747
    int iStart = 0;
25,908✔
748
    int iEnd = nCount - 1;
25,908✔
749
    size_t nKeyLen = strlen(pszKey);
25,908✔
750

751
    while (iStart <= iEnd)
56,405✔
752
    {
753
        const int iMiddle = (iEnd + iStart) / 2;
37,394✔
754
        const char *pszMiddle = papszList[iMiddle];
37,394✔
755

756
        if (EQUALN(pszMiddle, pszKey, nKeyLen) &&
37,394✔
757
            (pszMiddle[nKeyLen] == '=' || pszMiddle[nKeyLen] == ':'))
7,249✔
758
            return iMiddle;
6,897✔
759

760
        if (CPLCompareKeyValueString(pszKey, pszMiddle) < 0)
30,497✔
761
            iEnd = iMiddle - 1;
8,642✔
762
        else
763
            iStart = iMiddle + 1;
21,855✔
764
    }
765

766
    return -1;
19,011✔
767
}
768

769
/************************************************************************/
770
/*                            FetchBool()                               */
771
/************************************************************************/
772
/**
773
 *
774
 * Check for boolean key value.
775
 *
776
 * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
777
 * with the given name, and if it can be interpreted as being TRUE.  If
778
 * the key appears without any "=Value" portion it will be considered true.
779
 * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
780
 * if the key appears in the list it will be considered TRUE.  If the key
781
 * doesn't appear at all, the indicated default value will be returned.
782
 *
783
 * @param pszKey the key value to look for (case insensitive).
784
 * @param bDefault the value to return if the key isn't found at all.
785
 *
786
 * @return true or false
787
 */
788

789
bool CPLStringList::FetchBool(const char *pszKey, bool bDefault) const
12,731✔
790

791
{
792
    const char *pszValue = FetchNameValue(pszKey);
12,731✔
793

794
    if (pszValue == nullptr)
12,733✔
795
        return bDefault;
12,523✔
796

797
    return CPLTestBool(pszValue);
210✔
798
}
799

800
/************************************************************************/
801
/*                            FetchBoolean()                            */
802
/************************************************************************/
803
/**
804
 *
805
 * DEPRECATED: Check for boolean key value.
806
 *
807
 * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
808
 * with the given name, and if it can be interpreted as being TRUE.  If
809
 * the key appears without any "=Value" portion it will be considered true.
810
 * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
811
 * if the key appears in the list it will be considered TRUE.  If the key
812
 * doesn't appear at all, the indicated default value will be returned.
813
 *
814
 * @param pszKey the key value to look for (case insensitive).
815
 * @param bDefault the value to return if the key isn't found at all.
816
 *
817
 * @return TRUE or FALSE
818
 */
819

820
int CPLStringList::FetchBoolean(const char *pszKey, int bDefault) const
3,132✔
821

822
{
823
    return FetchBool(pszKey, CPL_TO_BOOL(bDefault)) ? TRUE : FALSE;
3,132✔
824
}
825

826
/************************************************************************/
827
/*                           FetchNameValue()                           */
828
/************************************************************************/
829

830
/**
831
 * Fetch value associated with this key name.
832
 *
833
 * If this list sorted, a fast binary search is done, otherwise a linear
834
 * scan is done.  Name lookup is case insensitive.
835
 *
836
 * @param pszName the key name to search for.
837
 *
838
 * @return the corresponding value or NULL if not found.  The returned string
839
 * should not be modified and points into internal object state that may
840
 * change on future calls.
841
 */
842

843
const char *CPLStringList::FetchNameValue(const char *pszName) const
10,747,600✔
844

845
{
846
    const int iKey = FindName(pszName);
10,747,600✔
847

848
    if (iKey == -1)
10,764,000✔
849
        return nullptr;
3,734,200✔
850

851
    CPLAssert(papszList[iKey][strlen(pszName)] == '=' ||
7,029,780✔
852
              papszList[iKey][strlen(pszName)] == ':');
853

854
    return papszList[iKey] + strlen(pszName) + 1;
7,029,780✔
855
}
856

857
/************************************************************************/
858
/*                         FetchNameValueDef()                          */
859
/************************************************************************/
860

861
/**
862
 * Fetch value associated with this key name.
863
 *
864
 * If this list sorted, a fast binary search is done, otherwise a linear
865
 * scan is done.  Name lookup is case insensitive.
866
 *
867
 * @param pszName the key name to search for.
868
 * @param pszDefault the default value returned if the named entry isn't found.
869
 *
870
 * @return the corresponding value or the passed default if not found.
871
 */
872

873
const char *CPLStringList::FetchNameValueDef(const char *pszName,
30,803✔
874
                                             const char *pszDefault) const
875

876
{
877
    const char *pszValue = FetchNameValue(pszName);
30,803✔
878
    if (pszValue == nullptr)
30,803✔
879
        return pszDefault;
22,887✔
880

881
    return pszValue;
7,916✔
882
}
883

884
/************************************************************************/
885
/*                            InsertString()                            */
886
/************************************************************************/
887

888
/**
889
 * \fn CPLStringList *CPLStringList::InsertString( int nInsertAtLineNo,
890
 *                                                 const char *pszNewLine );
891
 *
892
 * \brief Insert into the list at identified location.
893
 *
894
 * This method will insert a string into the list at the identified
895
 * location.  The insertion point must be within or at the end of the list.
896
 * The following entries are pushed down to make space.
897
 *
898
 * @param nInsertAtLineNo the line to insert at, zero to insert at front.
899
 * @param pszNewLine to the line to insert.  This string will be copied.
900
 */
901

902
/************************************************************************/
903
/*                        InsertStringDirectly()                        */
904
/************************************************************************/
905

906
/**
907
 * Insert into the list at identified location.
908
 *
909
 * This method will insert a string into the list at the identified
910
 * location.  The insertion point must be within or at the end of the list.
911
 * The following entries are pushed down to make space.
912
 *
913
 * @param nInsertAtLineNo the line to insert at, zero to insert at front.
914
 * @param pszNewLine to the line to insert, the ownership of this string
915
 * will be taken over the by the object.  It must have been allocated on the
916
 * heap.
917
 */
918

919
CPLStringList &CPLStringList::InsertStringDirectly(int nInsertAtLineNo,
6,768✔
920
                                                   char *pszNewLine)
921

922
{
923
    if (nCount == -1)
6,768✔
924
        Count();
27✔
925

926
    if (!EnsureAllocation(nCount + 1))
6,768✔
927
    {
928
        VSIFree(pszNewLine);
×
929
        return *this;
×
930
    }
931

932
    if (nInsertAtLineNo < 0 || nInsertAtLineNo > nCount)
6,768✔
933
    {
934
        CPLError(CE_Failure, CPLE_AppDefined,
×
935
                 "CPLStringList::InsertString() requested beyond list end.");
936
        return *this;
×
937
    }
938

939
    bIsSorted = false;
6,768✔
940

941
    for (int i = nCount; i > nInsertAtLineNo; i--)
23,178✔
942
        papszList[i] = papszList[i - 1];
16,410✔
943

944
    papszList[nInsertAtLineNo] = pszNewLine;
6,768✔
945
    papszList[++nCount] = nullptr;
6,768✔
946

947
    return *this;
6,768✔
948
}
949

950
/************************************************************************/
951
/*                      FindSortedInsertionPoint()                      */
952
/*                                                                      */
953
/*      Find the location at which the indicated line should be         */
954
/*      inserted in order to keep things in sorted order.               */
955
/************************************************************************/
956

957
int CPLStringList::FindSortedInsertionPoint(const char *pszLine)
6,550✔
958

959
{
960
    CPLAssert(IsSorted());
6,550✔
961

962
    int iStart = 0;
6,550✔
963
    int iEnd = nCount - 1;
6,550✔
964

965
    while (iStart <= iEnd)
19,612✔
966
    {
967
        const int iMiddle = (iEnd + iStart) / 2;
13,062✔
968
        const char *pszMiddle = papszList[iMiddle];
13,062✔
969

970
        if (CPLCompareKeyValueString(pszLine, pszMiddle) < 0)
13,062✔
971
            iEnd = iMiddle - 1;
2,252✔
972
        else
973
            iStart = iMiddle + 1;
10,810✔
974
    }
975

976
    iEnd++;
6,550✔
977
    CPLAssert(iEnd >= 0 && iEnd <= nCount);
6,550✔
978
    CPLAssert(iEnd == 0 ||
6,550✔
979
              CPLCompareKeyValueString(pszLine, papszList[iEnd - 1]) >= 0);
980
    CPLAssert(iEnd == nCount ||
6,550✔
981
              CPLCompareKeyValueString(pszLine, papszList[iEnd]) <= 0);
982

983
    return iEnd;
6,550✔
984
}
985

986
namespace cpl
987
{
988

989
/************************************************************************/
990
/*             CSLIterator::operator==(const CSLIterator &other)        */
991
/************************************************************************/
992

993
/*! @cond Doxygen_Suppress */
994
bool CSLIterator::operator==(const CSLIterator &other) const
252,493✔
995
{
996
    if (!m_bAtEnd && other.m_bAtEnd)
252,493✔
997
    {
998
        return m_papszList == nullptr || *m_papszList == nullptr;
252,498✔
999
    }
1000
    if (!m_bAtEnd && !other.m_bAtEnd)
×
1001
    {
1002
        return m_papszList == other.m_papszList;
×
1003
    }
1004
    if (m_bAtEnd && other.m_bAtEnd)
×
1005
    {
1006
        return true;
×
1007
    }
1008
    return false;
×
1009
}
1010

1011
/*! @endcond */
1012

1013
/************************************************************************/
1014
/*                      CSLNameValueIterator::operator*()               */
1015
/************************************************************************/
1016

1017
/*! @cond Doxygen_Suppress */
1018
CSLNameValueIterator::value_type CSLNameValueIterator::operator*()
1,291✔
1019
{
1020
    if (m_papszList)
1,291✔
1021
    {
1022
        while (*m_papszList)
1,292✔
1023
        {
1024
            char *pszKey = nullptr;
1,292✔
1025
            const char *pszValue = CPLParseNameValue(*m_papszList, &pszKey);
1,292✔
1026
            if (pszKey)
1,292✔
1027
            {
1028
                m_osKey = pszKey;
1,289✔
1029
                CPLFree(pszKey);
1,289✔
1030
                return {m_osKey.c_str(), pszValue};
1,289✔
1031
            }
1032
            else if (m_bReturnNullKeyIfNotNameValue)
3✔
1033
            {
1034
                return {nullptr, *m_papszList};
2✔
1035
            }
1036
            // Skip entries that are not name=value pairs.
1037
            ++m_papszList;
1✔
1038
        }
1039
    }
1040
    // Should not happen
1041
    CPLAssert(false);
×
1042
    return {"", ""};
1043
}
1044

1045
/*! @endcond */
1046

1047
/************************************************************************/
1048
/*                   CSLNameValueIteratorWrapper::end()                 */
1049
/************************************************************************/
1050

1051
/*! @cond Doxygen_Suppress */
1052
CSLNameValueIterator CSLNameValueIteratorWrapper::end() const
3,891✔
1053
{
1054
    int nCount = CSLCount(m_papszList);
3,891✔
1055
    if (!m_bReturnNullKeyIfNotNameValue)
3,891✔
1056
    {
1057
        while (nCount > 0 && strchr(m_papszList[nCount - 1], '=') == nullptr)
3,829✔
1058
            --nCount;
12✔
1059
    }
1060
    return CSLNameValueIterator{m_papszList + nCount,
3,891✔
1061
                                m_bReturnNullKeyIfNotNameValue};
3,891✔
1062
}
1063

1064
/*! @endcond */
1065

1066
}  // namespace cpl
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