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

OSGeo / gdal / 15899162844

26 Jun 2025 10:14AM UTC coverage: 71.088% (+0.004%) from 71.084%
15899162844

Pull #12623

github

web-flow
Merge c704a8392 into f5cb024d4
Pull Request #12623: gdal raster overview add: add a --overview-src option

209 of 244 new or added lines in 5 files covered. (85.66%)

96 existing lines in 44 files now uncovered.

574014 of 807474 relevant lines covered (71.09%)

250815.03 hits per line

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

89.42
/port/cpl_string.cpp
1
/**********************************************************************
2
 *
3
 * Name:     cpl_string.cpp
4
 * Project:  CPL - Common Portability Library
5
 * Purpose:  String and Stringlist manipulation functions.
6
 * Author:   Daniel Morissette, danmo@videotron.ca
7
 *
8
 **********************************************************************
9
 * Copyright (c) 1998, Daniel Morissette
10
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 **********************************************************************
14
 *
15
 * Independent Security Audit 2003/04/04 Andrey Kiselev:
16
 *   Completed audit of this module. All functions may be used without buffer
17
 *   overflows and stack corruptions with any kind of input data strings with
18
 *   except of CPLSPrintf() and CSLAppendPrintf() (see note below).
19
 *
20
 * Security Audit 2003/03/28 warmerda:
21
 *   Completed security audit.  I believe that this module may be safely used
22
 *   to parse tokenize arbitrary input strings, assemble arbitrary sets of
23
 *   names values into string lists, unescape and escape text even if provided
24
 *   by a potentially hostile source.
25
 *
26
 *   CPLSPrintf() and CSLAppendPrintf() may not be safely invoked on
27
 *   arbitrary length inputs since it has a fixed size output buffer on system
28
 *   without vsnprintf().
29
 *
30
 **********************************************************************/
31

32
#undef WARN_STANDARD_PRINTF
33

34
#include "cpl_port.h"
35
#include "cpl_string.h"
36

37
#include <cctype>
38
#include <climits>
39
#include <cmath>
40
#include <cstdlib>
41
#include <cstring>
42

43
#include <limits>
44

45
#include "cpl_config.h"
46
#include "cpl_multiproc.h"
47
#include "cpl_vsi.h"
48

49
#if !defined(va_copy) && defined(__va_copy)
50
#define va_copy __va_copy
51
#endif
52

53
/*=====================================================================
54
                    StringList manipulation functions.
55
 =====================================================================*/
56

57
/**********************************************************************
58
 *                       CSLAddString()
59
 **********************************************************************/
60

61
/** Append a string to a StringList and return a pointer to the modified
62
 * StringList.
63
 *
64
 * If the input StringList is NULL, then a new StringList is created.
65
 * Note that CSLAddString performance when building a list is in O(n^2)
66
 * which can cause noticeable slow down when n > 10000.
67
 */
68
char **CSLAddString(char **papszStrList, const char *pszNewString)
434,321✔
69
{
70
    char **papszRet = CSLAddStringMayFail(papszStrList, pszNewString);
434,321✔
71
    if (papszRet == nullptr && pszNewString != nullptr)
434,195✔
72
        abort();
×
73
    return papszRet;
434,195✔
74
}
75

76
/** Same as CSLAddString() but may return NULL in case of (memory) failure */
77
char **CSLAddStringMayFail(char **papszStrList, const char *pszNewString)
469,863✔
78
{
79
    if (pszNewString == nullptr)
469,863✔
80
        return papszStrList;  // Nothing to do!
131✔
81

82
    char *pszDup = VSI_STRDUP_VERBOSE(pszNewString);
469,732✔
83
    if (pszDup == nullptr)
469,627✔
84
        return nullptr;
×
85

86
    // Allocate room for the new string.
87
    char **papszStrListNew = nullptr;
469,627✔
88
    int nItems = 0;
469,627✔
89

90
    if (papszStrList == nullptr)
469,627✔
91
        papszStrListNew =
92
            static_cast<char **>(VSI_CALLOC_VERBOSE(2, sizeof(char *)));
66,319✔
93
    else
94
    {
95
        nItems = CSLCount(papszStrList);
403,308✔
96
        papszStrListNew = static_cast<char **>(
97
            VSI_REALLOC_VERBOSE(papszStrList, (nItems + 2) * sizeof(char *)));
403,320✔
98
    }
99
    if (papszStrListNew == nullptr)
469,654✔
100
    {
101
        VSIFree(pszDup);
×
102
        return nullptr;
×
103
    }
104

105
    // Copy the string in the list.
106
    papszStrListNew[nItems] = pszDup;
469,654✔
107
    papszStrListNew[nItems + 1] = nullptr;
469,654✔
108

109
    return papszStrListNew;
469,654✔
110
}
111

112
/************************************************************************/
113
/*                              CSLCount()                              */
114
/************************************************************************/
115

116
/**
117
 * Return number of items in a string list.
118
 *
119
 * Returns the number of items in a string list, not counting the
120
 * terminating NULL.  Passing in NULL is safe, and will result in a count
121
 * of zero.
122
 *
123
 * Lists are counted by iterating through them so long lists will
124
 * take more time than short lists.  Care should be taken to avoid using
125
 * CSLCount() as an end condition for loops as it will result in O(n^2)
126
 * behavior.
127
 *
128
 * @param papszStrList the string list to count.
129
 *
130
 * @return the number of entries.
131
 */
132
int CSLCount(CSLConstList papszStrList)
4,662,590✔
133
{
134
    if (!papszStrList)
4,662,590✔
135
        return 0;
3,345,660✔
136

137
    int nItems = 0;
1,316,930✔
138

139
    while (*papszStrList != nullptr)
13,020,500✔
140
    {
141
        ++nItems;
11,703,500✔
142
        ++papszStrList;
11,703,500✔
143
    }
144

145
    return nItems;
1,316,930✔
146
}
147

148
/************************************************************************/
149
/*                            CSLGetField()                             */
150
/************************************************************************/
151

152
/**
153
 * Fetches the indicated field, being careful not to crash if the field
154
 * doesn't exist within this string list.
155
 *
156
 * The returned pointer should not be freed, and doesn't necessarily last long.
157
 */
158
const char *CSLGetField(CSLConstList papszStrList, int iField)
1,239✔
159

160
{
161
    if (papszStrList == nullptr || iField < 0)
1,239✔
162
        return ("");
×
163

164
    for (int i = 0; i < iField + 1; i++)
2,681✔
165
    {
166
        if (papszStrList[i] == nullptr)
1,444✔
167
            return "";
2✔
168
    }
169

170
    return (papszStrList[iField]);
1,237✔
171
}
172

173
/************************************************************************/
174
/*                             CSLDestroy()                             */
175
/************************************************************************/
176

177
/**
178
 * Free string list.
179
 *
180
 * Frees the passed string list (null terminated array of strings).
181
 * It is safe to pass NULL.
182
 *
183
 * @param papszStrList the list to free.
184
 */
185
void CPL_STDCALL CSLDestroy(char **papszStrList)
12,651,500✔
186
{
187
    if (!papszStrList)
12,651,500✔
188
        return;
9,732,170✔
189

190
    for (char **papszPtr = papszStrList; *papszPtr != nullptr; ++papszPtr)
13,769,800✔
191
    {
192
        CPLFree(*papszPtr);
10,857,600✔
193
    }
194

195
    CPLFree(papszStrList);
2,912,250✔
196
}
197

198
/************************************************************************/
199
/*                            CSLDuplicate()                            */
200
/************************************************************************/
201

202
/**
203
 * Clone a string list.
204
 *
205
 * Efficiently allocates a copy of a string list.  The returned list is
206
 * owned by the caller and should be freed with CSLDestroy().
207
 *
208
 * @param papszStrList the input string list.
209
 *
210
 * @return newly allocated copy.
211
 */
212

213
char **CSLDuplicate(CSLConstList papszStrList)
3,415,650✔
214
{
215
    const int nLines = CSLCount(papszStrList);
3,415,650✔
216

217
    if (nLines == 0)
3,313,500✔
218
        return nullptr;
3,331,360✔
219

UNCOV
220
    CSLConstList papszSrc = papszStrList;
×
221

222
    char **papszNewList =
UNCOV
223
        static_cast<char **>(VSI_MALLOC2_VERBOSE(nLines + 1, sizeof(char *)));
×
224

225
    char **papszDst = papszNewList;
63,540✔
226

227
    for (; *papszSrc != nullptr; ++papszSrc, ++papszDst)
422,391✔
228
    {
229
        *papszDst = VSI_STRDUP_VERBOSE(*papszSrc);
358,851✔
230
        if (*papszDst == nullptr)
358,851✔
231
        {
UNCOV
232
            CSLDestroy(papszNewList);
×
233
            return nullptr;
×
234
        }
235
    }
236
    *papszDst = nullptr;
63,540✔
237

238
    return papszNewList;
63,540✔
239
}
240

241
/************************************************************************/
242
/*                               CSLMerge                               */
243
/************************************************************************/
244

245
/**
246
 * \brief Merge two lists.
247
 *
248
 * The two lists are merged, ensuring that if any keys appear in both
249
 * that the value from the second (papszOverride) list take precedence.
250
 *
251
 * @param papszOrig the original list, being modified.
252
 * @param papszOverride the list of items being merged in.  This list
253
 * is unaltered and remains owned by the caller.
254
 *
255
 * @return updated list.
256
 */
257

258
char **CSLMerge(char **papszOrig, CSLConstList papszOverride)
699,239✔
259

260
{
261
    if (papszOrig == nullptr && papszOverride != nullptr)
699,239✔
262
        return CSLDuplicate(papszOverride);
621✔
263

264
    if (papszOverride == nullptr)
698,618✔
265
        return papszOrig;
660,281✔
266

267
    for (int i = 0; papszOverride[i] != nullptr; ++i)
6,218✔
268
    {
269
        char *pszKey = nullptr;
4,393✔
270
        const char *pszValue = CPLParseNameValue(papszOverride[i], &pszKey);
4,393✔
271

272
        papszOrig = CSLSetNameValue(papszOrig, pszKey, pszValue);
4,393✔
273
        CPLFree(pszKey);
4,393✔
274
    }
275

276
    return papszOrig;
1,825✔
277
}
278

279
/************************************************************************/
280
/*                             CSLLoad2()                               */
281
/************************************************************************/
282

283
/**
284
 * Load a text file into a string list.
285
 *
286
 * The VSI*L API is used, so VSIFOpenL() supported objects that aren't
287
 * physical files can also be accessed.  Files are returned as a string list,
288
 * with one item in the string list per line.  End of line markers are
289
 * stripped (by CPLReadLineL()).
290
 *
291
 * If reading the file fails a CPLError() will be issued and NULL returned.
292
 *
293
 * @param pszFname the name of the file to read.
294
 * @param nMaxLines maximum number of lines to read before stopping, or -1 for
295
 * no limit.
296
 * @param nMaxCols maximum number of characters in a line before stopping, or -1
297
 * for no limit.
298
 * @param papszOptions NULL-terminated array of options. Unused for now.
299
 *
300
 * @return a string list with the files lines, now owned by caller. To be freed
301
 * with CSLDestroy()
302
 *
303
 * @since GDAL 1.7.0
304
 */
305

306
char **CSLLoad2(const char *pszFname, int nMaxLines, int nMaxCols,
3,403✔
307
                CSLConstList papszOptions)
308
{
309
    VSILFILE *fp = VSIFOpenL(pszFname, "rb");
3,403✔
310

311
    if (!fp)
3,403✔
312
    {
313
        if (CPLFetchBool(papszOptions, "EMIT_ERROR_IF_CANNOT_OPEN_FILE", true))
2,188✔
314
        {
315
            // Unable to open file.
316
            CPLError(CE_Failure, CPLE_OpenFailed,
1✔
317
                     "CSLLoad2(\"%s\") failed: unable to open file.", pszFname);
318
        }
319
        return nullptr;
2,188✔
320
    }
321

322
    char **papszStrList = nullptr;
1,215✔
323
    int nLines = 0;
1,215✔
324
    int nAllocatedLines = 0;
1,215✔
325

326
    while (!VSIFEofL(fp) && (nMaxLines == -1 || nLines < nMaxLines))
9,089✔
327
    {
328
        const char *pszLine = CPLReadLine2L(fp, nMaxCols, papszOptions);
7,880✔
329
        if (pszLine == nullptr)
7,880✔
330
            break;
6✔
331

332
        if (nLines + 1 >= nAllocatedLines)
7,874✔
333
        {
334
            nAllocatedLines = 16 + nAllocatedLines * 2;
1,341✔
335
            char **papszStrListNew = static_cast<char **>(
336
                VSIRealloc(papszStrList, nAllocatedLines * sizeof(char *)));
1,341✔
337
            if (papszStrListNew == nullptr)
1,341✔
338
            {
339
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
×
340
                CPLReadLineL(nullptr);
×
341
                CPLError(CE_Failure, CPLE_OutOfMemory,
×
342
                         "CSLLoad2(\"%s\") "
343
                         "failed: not enough memory to allocate lines.",
344
                         pszFname);
345
                return papszStrList;
×
346
            }
347
            papszStrList = papszStrListNew;
1,341✔
348
        }
349
        papszStrList[nLines] = CPLStrdup(pszLine);
7,874✔
350
        papszStrList[nLines + 1] = nullptr;
7,874✔
351
        ++nLines;
7,874✔
352
    }
353

354
    CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
1,215✔
355

356
    // Free the internal thread local line buffer.
357
    CPLReadLineL(nullptr);
1,215✔
358

359
    return papszStrList;
1,215✔
360
}
361

362
/************************************************************************/
363
/*                              CSLLoad()                               */
364
/************************************************************************/
365

366
/**
367
 * Load a text file into a string list.
368
 *
369
 * The VSI*L API is used, so VSIFOpenL() supported objects that aren't
370
 * physical files can also be accessed.  Files are returned as a string list,
371
 * with one item in the string list per line.  End of line markers are
372
 * stripped (by CPLReadLineL()).
373
 *
374
 * If reading the file fails a CPLError() will be issued and NULL returned.
375
 *
376
 * @param pszFname the name of the file to read.
377
 *
378
 * @return a string list with the files lines, now owned by caller. To be freed
379
 * with CSLDestroy()
380
 */
381

382
char **CSLLoad(const char *pszFname)
231✔
383
{
384
    return CSLLoad2(pszFname, -1, -1, nullptr);
231✔
385
}
386

387
/**********************************************************************
388
 *                       CSLSave()
389
 **********************************************************************/
390

391
/** Write a StringList to a text file.
392
 *
393
 * Returns the number of lines written, or 0 if the file could not
394
 * be written.
395
 */
396

397
int CSLSave(CSLConstList papszStrList, const char *pszFname)
2✔
398
{
399
    if (papszStrList == nullptr)
2✔
400
        return 0;
×
401

402
    VSILFILE *fp = VSIFOpenL(pszFname, "wt");
2✔
403
    if (fp == nullptr)
2✔
404
    {
405
        // Unable to open file.
406
        CPLError(CE_Failure, CPLE_OpenFailed,
1✔
407
                 "CSLSave(\"%s\") failed: unable to open output file.",
408
                 pszFname);
409
        return 0;
1✔
410
    }
411

412
    int nLines = 0;
1✔
413
    while (*papszStrList != nullptr)
2✔
414
    {
415
        if (VSIFPrintfL(fp, "%s\n", *papszStrList) < 1)
1✔
416
        {
417
            CPLError(CE_Failure, CPLE_FileIO,
×
418
                     "CSLSave(\"%s\") failed: unable to write to output file.",
419
                     pszFname);
420
            break;  // A Problem happened... abort.
×
421
        }
422

423
        ++nLines;
1✔
424
        ++papszStrList;
1✔
425
    }
426

427
    if (VSIFCloseL(fp) != 0)
1✔
428
    {
429
        CPLError(CE_Failure, CPLE_FileIO,
×
430
                 "CSLSave(\"%s\") failed: unable to write to output file.",
431
                 pszFname);
432
    }
433

434
    return nLines;
1✔
435
}
436

437
/**********************************************************************
438
 *                       CSLPrint()
439
 **********************************************************************/
440

441
/** Print a StringList to fpOut.  If fpOut==NULL, then output is sent
442
 * to stdout.
443
 *
444
 * Returns the number of lines printed.
445
 */
446
int CSLPrint(CSLConstList papszStrList, FILE *fpOut)
×
447
{
448
    if (!papszStrList)
×
449
        return 0;
×
450

451
    if (fpOut == nullptr)
×
452
        fpOut = stdout;
×
453

454
    int nLines = 0;
×
455

456
    while (*papszStrList != nullptr)
×
457
    {
458
        if (VSIFPrintf(fpOut, "%s\n", *papszStrList) < 0)
×
459
            return nLines;
×
460
        ++nLines;
×
461
        ++papszStrList;
×
462
    }
463

464
    return nLines;
×
465
}
466

467
/**********************************************************************
468
 *                       CSLInsertStrings()
469
 **********************************************************************/
470

471
/** Copies the contents of a StringList inside another StringList
472
 * before the specified line.
473
 *
474
 * nInsertAtLineNo is a 0-based line index before which the new strings
475
 * should be inserted.  If this value is -1 or is larger than the actual
476
 * number of strings in the list then the strings are added at the end
477
 * of the source StringList.
478
 *
479
 * Returns the modified StringList.
480
 */
481

482
char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo,
17,397✔
483
                        CSLConstList papszNewLines)
484
{
485
    if (papszNewLines == nullptr)
17,397✔
486
        return papszStrList;  // Nothing to do!
36✔
487

488
    const int nToInsert = CSLCount(papszNewLines);
17,361✔
489
    if (nToInsert == 0)
17,361✔
490
        return papszStrList;  // Nothing to do!
1,242✔
491

492
    const int nSrcLines = CSLCount(papszStrList);
16,119✔
493
    const int nDstLines = nSrcLines + nToInsert;
16,119✔
494

495
    // Allocate room for the new strings.
496
    papszStrList = static_cast<char **>(
497
        CPLRealloc(papszStrList, (nDstLines + 1) * sizeof(char *)));
16,119✔
498

499
    // Make sure the array is NULL-terminated.  It may not be if
500
    // papszStrList was NULL before Realloc().
501
    papszStrList[nSrcLines] = nullptr;
16,119✔
502

503
    // Make some room in the original list at the specified location.
504
    // Note that we also have to move the NULL pointer at the end of
505
    // the source StringList.
506
    if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
16,119✔
507
        nInsertAtLineNo = nSrcLines;
15,331✔
508

509
    {
510
        char **ppszSrc = papszStrList + nSrcLines;
16,119✔
511
        char **ppszDst = papszStrList + nDstLines;
16,119✔
512

513
        for (int i = nSrcLines; i >= nInsertAtLineNo; --i)
33,493✔
514
        {
515
            *ppszDst = *ppszSrc;
17,374✔
516
            --ppszDst;
17,374✔
517
            --ppszSrc;
17,374✔
518
        }
519
    }
520

521
    // Copy the strings to the list.
522
    CSLConstList ppszSrc = papszNewLines;
16,119✔
523
    char **ppszDst = papszStrList + nInsertAtLineNo;
16,119✔
524

525
    for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
145,475✔
526
    {
527
        *ppszDst = CPLStrdup(*ppszSrc);
129,356✔
528
    }
529

530
    return papszStrList;
16,119✔
531
}
532

533
/**********************************************************************
534
 *                       CSLInsertString()
535
 **********************************************************************/
536

537
/** Insert a string at a given line number inside a StringList
538
 *
539
 * nInsertAtLineNo is a 0-based line index before which the new string
540
 * should be inserted.  If this value is -1 or is larger than the actual
541
 * number of strings in the list then the string is added at the end
542
 * of the source StringList.
543
 *
544
 * Returns the modified StringList.
545
 */
546

547
char **CSLInsertString(char **papszStrList, int nInsertAtLineNo,
533✔
548
                       const char *pszNewLine)
549
{
550
    char *apszList[2] = {const_cast<char *>(pszNewLine), nullptr};
533✔
551

552
    return CSLInsertStrings(papszStrList, nInsertAtLineNo, apszList);
1,066✔
553
}
554

555
/**********************************************************************
556
 *                       CSLRemoveStrings()
557
 **********************************************************************/
558

559
/** Remove strings inside a StringList
560
 *
561
 * nFirstLineToDelete is the 0-based line index of the first line to
562
 * remove. If this value is -1 or is larger than the actual
563
 * number of strings in list then the nNumToRemove last strings are
564
 * removed.
565
 *
566
 * If ppapszRetStrings != NULL then the deleted strings won't be
567
 * free'd, they will be stored in a new StringList and the pointer to
568
 * this new list will be returned in *ppapszRetStrings.
569
 *
570
 * Returns the modified StringList.
571
 */
572

573
char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
6,514✔
574
                        int nNumToRemove, char ***ppapszRetStrings)
575
{
576
    const int nSrcLines = CSLCount(papszStrList);
6,514✔
577

578
    if (nNumToRemove < 1 || nSrcLines == 0)
6,514✔
579
        return papszStrList;  // Nothing to do!
×
580

581
    // If operation will result in an empty StringList, don't waste
582
    // time here.
583
    const int nDstLines = nSrcLines - nNumToRemove;
6,514✔
584
    if (nDstLines < 1)
6,514✔
585
    {
586
        CSLDestroy(papszStrList);
983✔
587
        return nullptr;
983✔
588
    }
589

590
    // Remove lines from the source StringList.
591
    // Either free() each line or store them to a new StringList depending on
592
    // the caller's choice.
593
    char **ppszDst = papszStrList + nFirstLineToDelete;
5,531✔
594

595
    if (ppapszRetStrings == nullptr)
5,531✔
596
    {
597
        // free() all the strings that will be removed.
598
        for (int i = 0; i < nNumToRemove; ++i)
11,062✔
599
        {
600
            CPLFree(*ppszDst);
5,531✔
601
            *ppszDst = nullptr;
5,531✔
602
        }
603
    }
604
    else
605
    {
606
        // Store the strings to remove in a new StringList.
607
        *ppapszRetStrings =
×
608
            static_cast<char **>(CPLCalloc(nNumToRemove + 1, sizeof(char *)));
×
609

610
        for (int i = 0; i < nNumToRemove; ++i)
×
611
        {
612
            (*ppapszRetStrings)[i] = *ppszDst;
×
613
            *ppszDst = nullptr;
×
614
            ++ppszDst;
×
615
        }
616
    }
617

618
    // Shift down all the lines that follow the lines to remove.
619
    if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines)
5,531✔
620
        nFirstLineToDelete = nDstLines;
×
621

622
    char **ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
5,531✔
623
    ppszDst = papszStrList + nFirstLineToDelete;
5,531✔
624

625
    for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
11,808✔
626
    {
627
        *ppszDst = *ppszSrc;
6,277✔
628
    }
629
    // Move the NULL pointer at the end of the StringList.
630
    *ppszDst = *ppszSrc;
5,531✔
631

632
    // At this point, we could realloc() papszStrList to a smaller size, but
633
    // since this array will likely grow again in further operations on the
634
    // StringList we'll leave it as it is.
635
    return papszStrList;
5,531✔
636
}
637

638
/************************************************************************/
639
/*                           CSLFindString()                            */
640
/************************************************************************/
641

642
/**
643
 * Find a string within a string list (case insensitive).
644
 *
645
 * Returns the index of the entry in the string list that contains the
646
 * target string.  The string in the string list must be a full match for
647
 * the target, but the search is case insensitive.
648
 *
649
 * @param papszList the string list to be searched.
650
 * @param pszTarget the string to be searched for.
651
 *
652
 * @return the index of the string within the list or -1 on failure.
653
 */
654

655
int CSLFindString(CSLConstList papszList, const char *pszTarget)
4,193,040✔
656

657
{
658
    if (papszList == nullptr)
4,193,040✔
659
        return -1;
280,009✔
660

661
    for (int i = 0; papszList[i] != nullptr; ++i)
31,615,800✔
662
    {
663
        if (EQUAL(papszList[i], pszTarget))
27,892,900✔
664
            return i;
190,127✔
665
    }
666

667
    return -1;
3,722,900✔
668
}
669

670
/************************************************************************/
671
/*                     CSLFindStringCaseSensitive()                     */
672
/************************************************************************/
673

674
/**
675
 * Find a string within a string list(case sensitive)
676
 *
677
 * Returns the index of the entry in the string list that contains the
678
 * target string.  The string in the string list must be a full match for
679
 * the target.
680
 *
681
 * @param papszList the string list to be searched.
682
 * @param pszTarget the string to be searched for.
683
 *
684
 * @return the index of the string within the list or -1 on failure.
685
 *
686
 * @since GDAL 2.0
687
 */
688

689
int CSLFindStringCaseSensitive(CSLConstList papszList, const char *pszTarget)
4,260✔
690

691
{
692
    if (papszList == nullptr)
4,260✔
693
        return -1;
617✔
694

695
    for (int i = 0; papszList[i] != nullptr; ++i)
76,111✔
696
    {
697
        if (strcmp(papszList[i], pszTarget) == 0)
72,482✔
698
            return i;
14✔
699
    }
700

701
    return -1;
3,629✔
702
}
703

704
/************************************************************************/
705
/*                           CSLPartialFindString()                     */
706
/************************************************************************/
707

708
/**
709
 * Find a substring within a string list.
710
 *
711
 * Returns the index of the entry in the string list that contains the
712
 * target string as a substring.  The search is case sensitive (unlike
713
 * CSLFindString()).
714
 *
715
 * @param papszHaystack the string list to be searched.
716
 * @param pszNeedle the substring to be searched for.
717
 *
718
 * @return the index of the string within the list or -1 on failure.
719
 */
720

721
int CSLPartialFindString(CSLConstList papszHaystack, const char *pszNeedle)
22,270✔
722
{
723
    if (papszHaystack == nullptr || pszNeedle == nullptr)
22,270✔
724
        return -1;
7,206✔
725

726
    for (int i = 0; papszHaystack[i] != nullptr; ++i)
34,343✔
727
    {
728
        if (strstr(papszHaystack[i], pszNeedle))
25,792✔
729
            return i;
6,513✔
730
    }
731

732
    return -1;
8,551✔
733
}
734

735
/**********************************************************************
736
 *                       CSLTokenizeString()
737
 **********************************************************************/
738

739
/** Tokenizes a string and returns a StringList with one string for
740
 * each token.
741
 */
742
char **CSLTokenizeString(const char *pszString)
170,194✔
743
{
744
    return CSLTokenizeString2(pszString, " ", CSLT_HONOURSTRINGS);
170,194✔
745
}
746

747
/************************************************************************/
748
/*                      CSLTokenizeStringComplex()                      */
749
/************************************************************************/
750

751
/** Obsolete tokenizing api. Use CSLTokenizeString2() */
752
char **CSLTokenizeStringComplex(const char *pszString,
566,423✔
753
                                const char *pszDelimiters, int bHonourStrings,
754
                                int bAllowEmptyTokens)
755
{
756
    int nFlags = 0;
566,423✔
757

758
    if (bHonourStrings)
566,423✔
759
        nFlags |= CSLT_HONOURSTRINGS;
124,681✔
760
    if (bAllowEmptyTokens)
566,423✔
761
        nFlags |= CSLT_ALLOWEMPTYTOKENS;
17,257✔
762

763
    return CSLTokenizeString2(pszString, pszDelimiters, nFlags);
566,423✔
764
}
765

766
/************************************************************************/
767
/*                         CSLTokenizeString2()                         */
768
/************************************************************************/
769

770
/**
771
 * Tokenize a string.
772
 *
773
 * This function will split a string into tokens based on specified'
774
 * delimiter(s) with a variety of options.  The returned result is a
775
 * string list that should be freed with CSLDestroy() when no longer
776
 * needed.
777
 *
778
 * The available parsing options are:
779
 *
780
 * - CSLT_ALLOWEMPTYTOKENS: allow the return of empty tokens when two
781
 * delimiters in a row occur with no other text between them.  If not set,
782
 * empty tokens will be discarded;
783
 * - CSLT_STRIPLEADSPACES: strip leading space characters from the token (as
784
 * reported by isspace());
785
 * - CSLT_STRIPENDSPACES: strip ending space characters from the token (as
786
 * reported by isspace());
787
 * - CSLT_HONOURSTRINGS: double quotes can be used to hold values that should
788
 * not be broken into multiple tokens;
789
 * - CSLT_PRESERVEQUOTES: string quotes are carried into the tokens when this
790
 * is set, otherwise they are removed;
791
 * - CSLT_PRESERVEESCAPES: if set backslash escapes (for backslash itself,
792
 * and for literal double quotes) will be preserved in the tokens, otherwise
793
 * the backslashes will be removed in processing.
794
 *
795
 * \b Example:
796
 *
797
 * Parse a string into tokens based on various white space (space, newline,
798
 * tab) and then print out results and cleanup.  Quotes may be used to hold
799
 * white space in tokens.
800

801
\code
802
    char **papszTokens =
803
        CSLTokenizeString2( pszCommand, " \t\n",
804
                            CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS );
805

806
    for( int i = 0; papszTokens != NULL && papszTokens[i] != NULL; ++i )
807
        printf( "arg %d: '%s'", papszTokens[i] );  // ok
808

809
    CSLDestroy( papszTokens );
810
\endcode
811

812
 * @param pszString the string to be split into tokens.
813
 * @param pszDelimiters one or more characters to be used as token delimiters.
814
 * @param nCSLTFlags an ORing of one or more of the CSLT_ flag values.
815
 *
816
 * @return a string list of tokens owned by the caller.
817
 */
818

819
char **CSLTokenizeString2(const char *pszString, const char *pszDelimiters,
1,272,100✔
820
                          int nCSLTFlags)
821
{
822
    if (pszString == nullptr)
1,272,100✔
823
        return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
4,126✔
824

825
    CPLStringList oRetList;
2,535,940✔
826
    const bool bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS) != 0;
1,267,970✔
827
    const bool bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS) != 0;
1,267,970✔
828
    const bool bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES) != 0;
1,267,970✔
829
    const bool bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES) != 0;
1,267,970✔
830

831
    char *pszToken = static_cast<char *>(CPLCalloc(10, 1));
1,267,970✔
832
    size_t nTokenMax = 10;
1,267,970✔
833

834
    while (*pszString != '\0')
4,063,310✔
835
    {
836
        bool bInString = false;
2,795,340✔
837
        bool bStartString = true;
2,795,340✔
838
        size_t nTokenLen = 0;
2,795,340✔
839

840
        // Try to find the next delimiter, marking end of token.
841
        for (; *pszString != '\0'; ++pszString)
36,882,400✔
842
        {
843
            // Extend token buffer if we are running close to its end.
844
            if (nTokenLen >= nTokenMax - 3)
35,670,500✔
845
            {
846
                if (nTokenMax > std::numeric_limits<size_t>::max() / 2)
1,067,400✔
847
                {
848
                    CPLFree(pszToken);
×
849
                    return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
×
850
                }
851
                nTokenMax = nTokenMax * 2;
1,067,400✔
852
                char *pszNewToken = static_cast<char *>(
853
                    VSI_REALLOC_VERBOSE(pszToken, nTokenMax));
1,067,400✔
854
                if (pszNewToken == nullptr)
1,067,400✔
855
                {
856
                    CPLFree(pszToken);
×
857
                    return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
×
858
                }
859
                pszToken = pszNewToken;
1,067,400✔
860
            }
861

862
            // End if this is a delimiter skip it and break.
863
            if (!bInString && strchr(pszDelimiters, *pszString) != nullptr)
35,670,500✔
864
            {
865
                ++pszString;
1,583,460✔
866
                break;
1,583,460✔
867
            }
868

869
            // If this is a quote, and we are honouring constant
870
            // strings, then process the constant strings, with out delim
871
            // but don't copy over the quotes.
872
            if (bHonourStrings && *pszString == '"')
34,087,000✔
873
            {
874
                if (nCSLTFlags & CSLT_PRESERVEQUOTES)
73,655✔
875
                {
876
                    pszToken[nTokenLen] = *pszString;
4,603✔
877
                    ++nTokenLen;
4,603✔
878
                }
879

880
                bInString = !bInString;
73,655✔
881
                continue;
73,655✔
882
            }
883

884
            /*
885
             * Within string constants we allow for escaped quotes, but in
886
             * processing them we will unescape the quotes and \\ sequence
887
             * reduces to \
888
             */
889
            if (bInString && pszString[0] == '\\')
34,013,400✔
890
            {
891
                if (pszString[1] == '"' || pszString[1] == '\\')
112✔
892
                {
893
                    if (nCSLTFlags & CSLT_PRESERVEESCAPES)
46✔
894
                    {
895
                        pszToken[nTokenLen] = *pszString;
6✔
896
                        ++nTokenLen;
6✔
897
                    }
898

899
                    ++pszString;
46✔
900
                }
901
            }
902

903
            // Strip spaces at the token start if requested.
904
            if (!bInString && bStripLeadSpaces && bStartString &&
34,013,400✔
905
                isspace(static_cast<unsigned char>(*pszString)))
31,716✔
906
                continue;
4,587✔
907

908
            bStartString = false;
34,008,800✔
909

910
            pszToken[nTokenLen] = *pszString;
34,008,800✔
911
            ++nTokenLen;
34,008,800✔
912
        }
913

914
        // Strip spaces at the token end if requested.
915
        if (!bInString && bStripEndSpaces)
2,795,340✔
916
        {
917
            while (nTokenLen &&
32,653✔
918
                   isspace(static_cast<unsigned char>(pszToken[nTokenLen - 1])))
27,513✔
919
                nTokenLen--;
38✔
920
        }
921

922
        pszToken[nTokenLen] = '\0';
2,795,340✔
923

924
        // Add the token.
925
        if (pszToken[0] != '\0' || bAllowEmptyTokens)
2,795,340✔
926
            oRetList.AddString(pszToken);
2,674,520✔
927
    }
928

929
    /*
930
     * If the last token was empty, then we need to capture
931
     * it now, as the loop would skip it.
932
     */
933
    if (*pszString == '\0' && bAllowEmptyTokens && oRetList.Count() > 0 &&
1,294,650✔
934
        strchr(pszDelimiters, *(pszString - 1)) != nullptr)
26,682✔
935
    {
936
        oRetList.AddString("");
1,250✔
937
    }
938

939
    CPLFree(pszToken);
1,267,970✔
940

941
    if (oRetList.List() == nullptr)
1,267,970✔
942
    {
943
        // Prefer to return empty lists as a pointer to
944
        // a null pointer since some client code might depend on this.
945
        oRetList.Assign(static_cast<char **>(CPLCalloc(sizeof(char *), 1)));
25,153✔
946
    }
947

948
    return oRetList.StealList();
1,267,970✔
949
}
950

951
/**********************************************************************
952
 *                       CPLSPrintf()
953
 *
954
 * NOTE: This function should move to cpl_conv.cpp.
955
 **********************************************************************/
956

957
// For now, assume that a 8000 chars buffer will be enough.
958
constexpr int CPLSPrintf_BUF_SIZE = 8000;
959
constexpr int CPLSPrintf_BUF_Count = 10;
960

961
/** CPLSPrintf() that works with 10 static buffer.
962
 *
963
 * It returns a ref. to a static buffer that should not be freed and
964
 * is valid only until the next call to CPLSPrintf().
965
 */
966

967
const char *CPLSPrintf(CPL_FORMAT_STRING(const char *fmt), ...)
1,520,970✔
968
{
969
    va_list args;
970

971
    /* -------------------------------------------------------------------- */
972
    /*      Get the thread local buffer ring data.                          */
973
    /* -------------------------------------------------------------------- */
974
    char *pachBufRingInfo = static_cast<char *>(CPLGetTLS(CTLS_CPLSPRINTF));
1,520,970✔
975

976
    if (pachBufRingInfo == nullptr)
1,520,960✔
977
    {
978
        pachBufRingInfo = static_cast<char *>(CPLCalloc(
2,719✔
979
            1, sizeof(int) + CPLSPrintf_BUF_Count * CPLSPrintf_BUF_SIZE));
980
        CPLSetTLS(CTLS_CPLSPRINTF, pachBufRingInfo, TRUE);
2,722✔
981
    }
982

983
    /* -------------------------------------------------------------------- */
984
    /*      Work out which string in the "ring" we want to use this         */
985
    /*      time.                                                           */
986
    /* -------------------------------------------------------------------- */
987
    int *pnBufIndex = reinterpret_cast<int *>(pachBufRingInfo);
1,520,970✔
988
    const size_t nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
1,520,970✔
989
    char *pachBuffer = pachBufRingInfo + nOffset;
1,520,970✔
990

991
    *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
1,520,970✔
992

993
    /* -------------------------------------------------------------------- */
994
    /*      Format the result.                                              */
995
    /* -------------------------------------------------------------------- */
996

997
    va_start(args, fmt);
1,520,970✔
998

999
    const int ret =
1000
        CPLvsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE - 1, fmt, args);
1,520,970✔
1001
    if (ret < 0 || ret >= CPLSPrintf_BUF_SIZE - 1)
1,520,960✔
1002
    {
1003
        CPLError(CE_Failure, CPLE_AppDefined,
4✔
1004
                 "CPLSPrintf() called with too "
1005
                 "big string. Output will be truncated !");
1006
    }
1007

1008
    va_end(args);
1,520,960✔
1009

1010
    return pachBuffer;
1,520,960✔
1011
}
1012

1013
/**********************************************************************
1014
 *                       CSLAppendPrintf()
1015
 **********************************************************************/
1016

1017
/** Use CPLSPrintf() to append a new line at the end of a StringList.
1018
 * Returns the modified StringList.
1019
 */
1020
char **CSLAppendPrintf(char **papszStrList, CPL_FORMAT_STRING(const char *fmt),
176✔
1021
                       ...)
1022
{
1023
    va_list args;
1024

1025
    va_start(args, fmt);
176✔
1026
    CPLString osWork;
352✔
1027
    osWork.vPrintf(fmt, args);
176✔
1028
    va_end(args);
176✔
1029

1030
    return CSLAddString(papszStrList, osWork);
352✔
1031
}
1032

1033
/************************************************************************/
1034
/*                            CPLVASPrintf()                            */
1035
/************************************************************************/
1036

1037
/** This is intended to serve as an easy to use C callable vasprintf()
1038
 * alternative.  Used in the GeoJSON library for instance */
1039
int CPLVASPrintf(char **buf, CPL_FORMAT_STRING(const char *fmt), va_list ap)
×
1040

1041
{
1042
    CPLString osWork;
×
1043

1044
    osWork.vPrintf(fmt, ap);
×
1045

1046
    if (buf)
×
1047
        *buf = CPLStrdup(osWork.c_str());
×
1048

1049
    return static_cast<int>(osWork.size());
×
1050
}
1051

1052
/************************************************************************/
1053
/*                  CPLvsnprintf_get_end_of_formatting()                */
1054
/************************************************************************/
1055

1056
static const char *CPLvsnprintf_get_end_of_formatting(const char *fmt)
4,274,820✔
1057
{
1058
    char ch = '\0';
4,274,820✔
1059
    // Flag.
1060
    for (; (ch = *fmt) != '\0'; ++fmt)
5,463,400✔
1061
    {
1062
        if (ch == '\'')
5,463,400✔
1063
            continue;  // Bad idea as this is locale specific.
×
1064
        if (ch == '-' || ch == '+' || ch == ' ' || ch == '#' || ch == '0')
5,463,400✔
1065
            continue;
1,188,580✔
1066
        break;
4,274,810✔
1067
    }
1068

1069
    // Field width.
1070
    for (; (ch = *fmt) != '\0'; ++fmt)
5,619,060✔
1071
    {
1072
        if (ch == '$')
5,619,060✔
1073
            return nullptr;  // Do not support this.
×
1074
        if (*fmt >= '0' && *fmt <= '9')
5,619,060✔
1075
            continue;
1,344,240✔
1076
        break;
4,274,820✔
1077
    }
1078

1079
    // Precision.
1080
    if (ch == '.')
4,274,820✔
1081
    {
1082
        ++fmt;
694,151✔
1083
        for (; (ch = *fmt) != '\0'; ++fmt)
1,964,800✔
1084
        {
1085
            if (ch == '$')
1,964,800✔
1086
                return nullptr;  // Do not support this.
×
1087
            if (*fmt >= '0' && *fmt <= '9')
1,964,800✔
1088
                continue;
1,270,650✔
1089
            break;
694,151✔
1090
        }
1091
    }
1092

1093
    // Length modifier.
1094
    for (; (ch = *fmt) != '\0'; ++fmt)
4,359,170✔
1095
    {
1096
        if (ch == 'h' || ch == 'l' || ch == 'j' || ch == 'z' || ch == 't' ||
4,359,170✔
1097
            ch == 'L')
1098
            continue;
84,360✔
1099
        else if (ch == 'I' && fmt[1] == '6' && fmt[2] == '4')
4,274,810✔
1100
            fmt += 2;
×
1101
        else
1102
            return fmt;
4,274,820✔
1103
    }
1104

1105
    return nullptr;
×
1106
}
1107

1108
/************************************************************************/
1109
/*                           CPLvsnprintf()                             */
1110
/************************************************************************/
1111

1112
#define call_native_snprintf(type)                                             \
1113
    local_ret = snprintf(str + offset_out, size - offset_out, localfmt,        \
1114
                         va_arg(wrk_args, type))
1115

1116
/** vsnprintf() wrapper that is not sensitive to LC_NUMERIC settings.
1117
 *
1118
 * This function has the same contract as standard vsnprintf(), except that
1119
 * formatting of floating-point numbers will use decimal point, whatever the
1120
 * current locale is set.
1121
 *
1122
 * @param str output buffer
1123
 * @param size size of the output buffer (including space for terminating nul)
1124
 * @param fmt formatting string
1125
 * @param args arguments
1126
 * @return the number of characters (excluding terminating nul) that would be
1127
 * written if size is big enough. Or potentially -1 with Microsoft C runtime
1128
 * for Visual Studio < 2015.
1129
 * @since GDAL 2.0
1130
 */
1131
int CPLvsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt),
2,430,590✔
1132
                 va_list args)
1133
{
1134
    if (size == 0)
2,430,590✔
1135
        return vsnprintf(str, size, fmt, args);
×
1136

1137
    va_list wrk_args;
1138

1139
#ifdef va_copy
1140
    va_copy(wrk_args, args);
2,430,590✔
1141
#else
1142
    wrk_args = args;
1143
#endif
1144

1145
    const char *fmt_ori = fmt;
2,430,590✔
1146
    size_t offset_out = 0;
2,430,590✔
1147
    char ch = '\0';
2,430,590✔
1148
    bool bFormatUnknown = false;
2,430,590✔
1149

1150
    for (; (ch = *fmt) != '\0'; ++fmt)
35,080,200✔
1151
    {
1152
        if (ch == '%')
32,651,100✔
1153
        {
1154
            if (strncmp(fmt, "%.*f", 4) == 0)
4,275,640✔
1155
            {
1156
                const int precision = va_arg(wrk_args, int);
830✔
1157
                const double val = va_arg(wrk_args, double);
830✔
1158
                const int local_ret =
1159
                    snprintf(str + offset_out, size - offset_out, "%.*f",
822✔
1160
                             precision, val);
1161
                // MSVC vsnprintf() returns -1.
1162
                if (local_ret < 0 || offset_out + local_ret >= size)
822✔
1163
                    break;
1164
                for (int j = 0; j < local_ret; ++j)
15,704✔
1165
                {
1166
                    if (str[offset_out + j] == ',')
14,874✔
1167
                    {
1168
                        str[offset_out + j] = '.';
×
1169
                        break;
×
1170
                    }
1171
                }
1172
                offset_out += local_ret;
830✔
1173
                fmt += strlen("%.*f") - 1;
830✔
1174
                continue;
830✔
1175
            }
1176

1177
            const char *ptrend = CPLvsnprintf_get_end_of_formatting(fmt + 1);
4,274,810✔
1178
            if (ptrend == nullptr || ptrend - fmt >= 20)
4,274,810✔
1179
            {
UNCOV
1180
                bFormatUnknown = true;
×
UNCOV
1181
                break;
×
1182
            }
1183
            char end = *ptrend;
4,274,820✔
1184
            char end_m1 = ptrend[-1];
4,274,820✔
1185

1186
            char localfmt[22] = {};
4,274,820✔
1187
            memcpy(localfmt, fmt, ptrend - fmt + 1);
4,274,820✔
1188
            localfmt[ptrend - fmt + 1] = '\0';
4,274,820✔
1189

1190
            int local_ret = 0;
4,274,820✔
1191
            if (end == '%')
4,274,820✔
1192
            {
1193
                if (offset_out == size - 1)
15,021✔
1194
                    break;
×
1195
                local_ret = 1;
15,021✔
1196
                str[offset_out] = '%';
15,021✔
1197
            }
1198
            else if (end == 'd' || end == 'i' || end == 'c')
4,259,800✔
1199
            {
1200
                if (end_m1 == 'h')
1,306,150✔
1201
                    call_native_snprintf(int);
×
1202
                else if (end_m1 == 'l' && ptrend[-2] != 'l')
1,306,150✔
1203
                    call_native_snprintf(long);
4,165✔
1204
                else if (end_m1 == 'l' && ptrend[-2] == 'l')
1,301,980✔
1205
                    call_native_snprintf(GIntBig);
22,188✔
1206
                else if (end_m1 == '4' && ptrend[-2] == '6' &&
1,279,790✔
1207
                         ptrend[-3] == 'I')
×
1208
                    // Microsoft I64 modifier.
1209
                    call_native_snprintf(GIntBig);
×
1210
                else if (end_m1 == 'z')
1,279,790✔
1211
                    call_native_snprintf(size_t);
×
1212
                else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
1,279,790✔
1213
                         (end_m1 >= 'A' && end_m1 <= 'Z'))
×
1214
                {
1215
                    bFormatUnknown = true;
×
1216
                    break;
×
1217
                }
1218
                else
1219
                    call_native_snprintf(int);
1,279,790✔
1220
            }
1221
            else if (end == 'o' || end == 'u' || end == 'x' || end == 'X')
2,953,650✔
1222
            {
1223
                if (end_m1 == 'h')
1,206,930✔
1224
                    call_native_snprintf(unsigned int);
×
1225
                else if (end_m1 == 'l' && ptrend[-2] != 'l')
1,206,930✔
1226
                    call_native_snprintf(unsigned long);
772✔
1227
                else if (end_m1 == 'l' && ptrend[-2] == 'l')
1,206,160✔
1228
                    call_native_snprintf(GUIntBig);
14,471✔
1229
                else if (end_m1 == '4' && ptrend[-2] == '6' &&
1,191,690✔
1230
                         ptrend[-3] == 'I')
×
1231
                    // Microsoft I64 modifier.
1232
                    call_native_snprintf(GUIntBig);
×
1233
                else if (end_m1 == 'z')
1,191,690✔
1234
                    call_native_snprintf(size_t);
×
1235
                else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
1,191,690✔
1236
                         (end_m1 >= 'A' && end_m1 <= 'Z'))
×
1237
                {
1238
                    bFormatUnknown = true;
×
1239
                    break;
×
1240
                }
1241
                else
1242
                    call_native_snprintf(unsigned int);
1,191,690✔
1243
            }
1244
            else if (end == 'e' || end == 'E' || end == 'f' || end == 'F' ||
1,746,720✔
1245
                     end == 'g' || end == 'G' || end == 'a' || end == 'A')
1,028,700✔
1246
            {
1247
                if (end_m1 == 'L')
718,036✔
1248
                    call_native_snprintf(long double);
×
1249
                else
1250
                    call_native_snprintf(double);
718,036✔
1251
                // MSVC vsnprintf() returns -1.
1252
                if (local_ret < 0 || offset_out + local_ret >= size)
718,028✔
1253
                    break;
1254
                for (int j = 0; j < local_ret; ++j)
10,072,600✔
1255
                {
1256
                    if (str[offset_out + j] == ',')
9,354,700✔
1257
                    {
1258
                        str[offset_out + j] = '.';
×
1259
                        break;
×
1260
                    }
1261
                }
717,940✔
1262
            }
1263
            else if (end == 's')
1,028,690✔
1264
            {
1265
                const char *pszPtr = va_arg(wrk_args, const char *);
1,023,310✔
1266
                CPLAssert(pszPtr);
1,023,310✔
1267
                local_ret = snprintf(str + offset_out, size - offset_out,
1,023,320✔
1268
                                     localfmt, pszPtr);
1269
            }
1270
            else if (end == 'p')
5,378✔
1271
            {
1272
                call_native_snprintf(void *);
5,387✔
1273
            }
1274
            else
1275
            {
1276
                bFormatUnknown = true;
×
1277
                break;
×
1278
            }
1279
            // MSVC vsnprintf() returns -1.
1280
            if (local_ret < 0 || offset_out + local_ret >= size)
4,274,730✔
1281
                break;
1282
            offset_out += local_ret;
4,273,900✔
1283
            fmt = ptrend;
4,273,900✔
1284
        }
1285
        else
1286
        {
1287
            if (offset_out == size - 1)
28,375,500✔
1288
                break;
589✔
1289
            str[offset_out++] = *fmt;
28,374,900✔
1290
        }
1291
    }
1292
    if (ch == '\0' && offset_out < size)
2,430,570✔
1293
        str[offset_out] = '\0';
2,429,090✔
1294
    else
1295
    {
1296
        if (bFormatUnknown)
1,482✔
1297
        {
1298
            CPLDebug("CPL",
×
1299
                     "CPLvsnprintf() called with unsupported "
1300
                     "formatting string: %s",
1301
                     fmt_ori);
1302
        }
1303
#ifdef va_copy
1304
        va_end(wrk_args);
1,482✔
1305
        va_copy(wrk_args, args);
1,482✔
1306
#else
1307
        wrk_args = args;
1308
#endif
1309
#if defined(HAVE_VSNPRINTF)
1310
        offset_out = vsnprintf(str, size, fmt_ori, wrk_args);
1,482✔
1311
#else
1312
        offset_out = vsprintf(str, fmt_ori, wrk_args);
1313
#endif
1314
    }
1315

1316
#ifdef va_copy
1317
    va_end(wrk_args);
2,430,570✔
1318
#endif
1319

1320
    return static_cast<int>(offset_out);
2,430,570✔
1321
}
1322

1323
/************************************************************************/
1324
/*                           CPLsnprintf()                              */
1325
/************************************************************************/
1326

1327
#if !defined(ALIAS_CPLSNPRINTF_AS_SNPRINTF)
1328

1329
#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ <= 2
1330
#pragma clang diagnostic push
1331
#pragma clang diagnostic ignored "-Wunknown-pragmas"
1332
#pragma clang diagnostic ignored "-Wdocumentation"
1333
#endif
1334

1335
/** snprintf() wrapper that is not sensitive to LC_NUMERIC settings.
1336
 *
1337
 * This function has the same contract as standard snprintf(), except that
1338
 * formatting of floating-point numbers will use decimal point, whatever the
1339
 * current locale is set.
1340
 *
1341
 * @param str output buffer
1342
 * @param size size of the output buffer (including space for terminating nul)
1343
 * @param fmt formatting string
1344
 * @param ... arguments
1345
 * @return the number of characters (excluding terminating nul) that would be
1346
 * written if size is big enough. Or potentially -1 with Microsoft C runtime
1347
 * for Visual Studio < 2015.
1348
 * @since GDAL 2.0
1349
 */
1350

1351
int CPLsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt), ...)
166,674✔
1352
{
1353
    va_list args;
1354

1355
    va_start(args, fmt);
166,674✔
1356
    const int ret = CPLvsnprintf(str, size, fmt, args);
166,674✔
1357
    va_end(args);
166,674✔
1358
    return ret;
166,674✔
1359
}
1360

1361
#endif  //  !defined(ALIAS_CPLSNPRINTF_AS_SNPRINTF)
1362

1363
/************************************************************************/
1364
/*                           CPLsprintf()                               */
1365
/************************************************************************/
1366

1367
/** sprintf() wrapper that is not sensitive to LC_NUMERIC settings.
1368
  *
1369
  * This function has the same contract as standard sprintf(), except that
1370
  * formatting of floating-point numbers will use decimal point, whatever the
1371
  * current locale is set.
1372
  *
1373
  * @param str output buffer (must be large enough to hold the result)
1374
  * @param fmt formatting string
1375
  * @param ... arguments
1376
  * @return the number of characters (excluding terminating nul) written in
1377
` * output buffer.
1378
  * @since GDAL 2.0
1379
  */
1380
int CPLsprintf(char *str, CPL_FORMAT_STRING(const char *fmt), ...)
×
1381
{
1382
    va_list args;
1383

1384
    va_start(args, fmt);
×
1385
    const int ret = CPLvsnprintf(str, INT_MAX, fmt, args);
×
1386
    va_end(args);
×
1387
    return ret;
×
1388
}
1389

1390
/************************************************************************/
1391
/*                           CPLprintf()                                */
1392
/************************************************************************/
1393

1394
/** printf() wrapper that is not sensitive to LC_NUMERIC settings.
1395
 *
1396
 * This function has the same contract as standard printf(), except that
1397
 * formatting of floating-point numbers will use decimal point, whatever the
1398
 * current locale is set.
1399
 *
1400
 * @param fmt formatting string
1401
 * @param ... arguments
1402
 * @return the number of characters (excluding terminating nul) written in
1403
 * output buffer.
1404
 * @since GDAL 2.0
1405
 */
1406
int CPLprintf(CPL_FORMAT_STRING(const char *fmt), ...)
157✔
1407
{
1408
    va_list wrk_args, args;
1409

1410
    va_start(args, fmt);
157✔
1411

1412
#ifdef va_copy
1413
    va_copy(wrk_args, args);
157✔
1414
#else
1415
    wrk_args = args;
1416
#endif
1417

1418
    char szBuffer[4096] = {};
157✔
1419
    // Quiet coverity by staring off nul terminated.
1420
    int ret = CPLvsnprintf(szBuffer, sizeof(szBuffer), fmt, wrk_args);
157✔
1421

1422
#ifdef va_copy
1423
    va_end(wrk_args);
157✔
1424
#endif
1425

1426
    if (ret < int(sizeof(szBuffer)) - 1)
157✔
1427
        ret = printf("%s", szBuffer); /*ok*/
157✔
1428
    else
1429
    {
1430
#ifdef va_copy
1431
        va_copy(wrk_args, args);
×
1432
#else
1433
        wrk_args = args;
1434
#endif
1435

1436
        ret = vfprintf(stdout, fmt, wrk_args);
×
1437

1438
#ifdef va_copy
1439
        va_end(wrk_args);
×
1440
#endif
1441
    }
1442

1443
    va_end(args);
157✔
1444

1445
    return ret;
157✔
1446
}
1447

1448
/************************************************************************/
1449
/*                           CPLsscanf()                                */
1450
/************************************************************************/
1451

1452
/** \brief sscanf() wrapper that is not sensitive to LC_NUMERIC settings.
1453
 *
1454
 * This function has the same contract as standard sscanf(), except that
1455
 * formatting of floating-point numbers will use decimal point, whatever the
1456
 * current locale is set.
1457
 *
1458
 * CAUTION: only works with a very limited number of formatting strings,
1459
 * consisting only of "%lf" and regular characters.
1460
 *
1461
 * @param str input string
1462
 * @param fmt formatting string
1463
 * @param ... arguments
1464
 * @return the number of matched patterns;
1465
 * @since GDAL 2.0
1466
 */
1467
#ifdef DOXYGEN_XML
1468
int CPLsscanf(const char *str, const char *fmt, ...)
1469
#else
1470
int CPLsscanf(const char *str, CPL_SCANF_FORMAT_STRING(const char *fmt), ...)
1,817✔
1471
#endif
1472
{
1473
    bool error = false;
1,817✔
1474
    int ret = 0;
1,817✔
1475
    const char *fmt_ori = fmt;
1,817✔
1476
    va_list args;
1477

1478
    va_start(args, fmt);
1,817✔
1479
    for (; *fmt != '\0' && *str != '\0'; ++fmt)
14,065✔
1480
    {
1481
        if (*fmt == '%')
12,248✔
1482
        {
1483
            if (fmt[1] == 'l' && fmt[2] == 'f')
7,014✔
1484
            {
1485
                fmt += 2;
7,014✔
1486
                char *end;
1487
                *(va_arg(args, double *)) = CPLStrtod(str, &end);
7,014✔
1488
                if (end > str)
7,014✔
1489
                {
1490
                    ++ret;
7,014✔
1491
                    str = end;
7,014✔
1492
                }
1493
                else
1494
                    break;
7,014✔
1495
            }
1496
            else
1497
            {
1498
                error = true;
×
1499
                break;
×
1500
            }
1501
        }
1502
        else if (isspace(static_cast<unsigned char>(*fmt)))
5,234✔
1503
        {
1504
            while (*str != '\0' && isspace(static_cast<unsigned char>(*str)))
1,754✔
1505
                ++str;
877✔
1506
        }
1507
        else if (*str != *fmt)
4,357✔
1508
            break;
×
1509
        else
1510
            ++str;
4,357✔
1511
    }
1512
    va_end(args);
1,817✔
1513

1514
    if (error)
1,817✔
1515
    {
1516
        CPLError(CE_Failure, CPLE_NotSupported,
×
1517
                 "Format %s not supported by CPLsscanf()", fmt_ori);
1518
    }
1519

1520
    return ret;
1,817✔
1521
}
1522

1523
#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ <= 2
1524
#pragma clang diagnostic pop
1525
#endif
1526

1527
/************************************************************************/
1528
/*                         CPLTestBool()                                */
1529
/************************************************************************/
1530

1531
/**
1532
 * Test what boolean value contained in the string.
1533
 *
1534
 * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned false.
1535
 * Otherwise, true will be returned.
1536
 *
1537
 * @param pszValue the string should be tested.
1538
 *
1539
 * @return true or false.
1540
 */
1541

1542
bool CPLTestBool(const char *pszValue)
3,337,190✔
1543
{
1544
    return !(EQUAL(pszValue, "NO") || EQUAL(pszValue, "FALSE") ||
4,166,370✔
1545
             EQUAL(pszValue, "OFF") || EQUAL(pszValue, "0"));
4,166,370✔
1546
}
1547

1548
/************************************************************************/
1549
/*                         CSLTestBoolean()                             */
1550
/************************************************************************/
1551

1552
/**
1553
 * Test what boolean value contained in the string.
1554
 *
1555
 * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned FALSE.
1556
 * Otherwise, TRUE will be returned.
1557
 *
1558
 * Deprecated.  Removed in GDAL 3.x.
1559
 *
1560
 * Use CPLTestBoolean() for C and CPLTestBool() for C++.
1561
 *
1562
 * @param pszValue the string should be tested.
1563
 *
1564
 * @return TRUE or FALSE.
1565
 */
1566

1567
int CSLTestBoolean(const char *pszValue)
660✔
1568
{
1569
    return CPLTestBool(pszValue) ? TRUE : FALSE;
660✔
1570
}
1571

1572
/************************************************************************/
1573
/*                         CPLTestBoolean()                             */
1574
/************************************************************************/
1575

1576
/**
1577
 * Test what boolean value contained in the string.
1578
 *
1579
 * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned FALSE.
1580
 * Otherwise, TRUE will be returned.
1581
 *
1582
 * Use this only in C code.  In C++, prefer CPLTestBool().
1583
 *
1584
 * @param pszValue the string should be tested.
1585
 *
1586
 * @return TRUE or FALSE.
1587
 */
1588

1589
int CPLTestBoolean(const char *pszValue)
43✔
1590
{
1591
    return CPLTestBool(pszValue) ? TRUE : FALSE;
43✔
1592
}
1593

1594
/**********************************************************************
1595
 *                       CPLFetchBool()
1596
 **********************************************************************/
1597

1598
/** Check for boolean key value.
1599
 *
1600
 * In a StringList of "Name=Value" pairs, look to see if there is a key
1601
 * with the given name, and if it can be interpreted as being TRUE.  If
1602
 * the key appears without any "=Value" portion it will be considered true.
1603
 * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
1604
 * if the key appears in the list it will be considered TRUE.  If the key
1605
 * doesn't appear at all, the indicated default value will be returned.
1606
 *
1607
 * @param papszStrList the string list to search.
1608
 * @param pszKey the key value to look for (case insensitive).
1609
 * @param bDefault the value to return if the key isn't found at all.
1610
 *
1611
 * @return true or false
1612
 */
1613

1614
bool CPLFetchBool(CSLConstList papszStrList, const char *pszKey, bool bDefault)
343,147✔
1615

1616
{
1617
    if (CSLFindString(papszStrList, pszKey) != -1)
343,147✔
1618
        return true;
2✔
1619

1620
    const char *const pszValue = CSLFetchNameValue(papszStrList, pszKey);
343,142✔
1621
    if (pszValue == nullptr)
343,142✔
1622
        return bDefault;
325,457✔
1623

1624
    return CPLTestBool(pszValue);
17,685✔
1625
}
1626

1627
/**********************************************************************
1628
 *                       CSLFetchBoolean()
1629
 **********************************************************************/
1630

1631
/** DEPRECATED.  Check for boolean key value.
1632
 *
1633
 * In a StringList of "Name=Value" pairs, look to see if there is a key
1634
 * with the given name, and if it can be interpreted as being TRUE.  If
1635
 * the key appears without any "=Value" portion it will be considered true.
1636
 * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
1637
 * if the key appears in the list it will be considered TRUE.  If the key
1638
 * doesn't appear at all, the indicated default value will be returned.
1639
 *
1640
 * @param papszStrList the string list to search.
1641
 * @param pszKey the key value to look for (case insensitive).
1642
 * @param bDefault the value to return if the key isn't found at all.
1643
 *
1644
 * @return TRUE or FALSE
1645
 */
1646

1647
int CSLFetchBoolean(CSLConstList papszStrList, const char *pszKey, int bDefault)
1,384✔
1648

1649
{
1650
    return CPLFetchBool(papszStrList, pszKey, CPL_TO_BOOL(bDefault));
1,384✔
1651
}
1652

1653
/************************************************************************/
1654
/*                     CSLFetchNameValueDefaulted()                     */
1655
/************************************************************************/
1656

1657
/** Same as CSLFetchNameValue() but return pszDefault in case of no match */
1658
const char *CSLFetchNameValueDef(CSLConstList papszStrList, const char *pszName,
839,533✔
1659
                                 const char *pszDefault)
1660

1661
{
1662
    const char *pszResult = CSLFetchNameValue(papszStrList, pszName);
839,533✔
1663
    if (pszResult != nullptr)
839,509✔
1664
        return pszResult;
178,805✔
1665

1666
    return pszDefault;
660,704✔
1667
}
1668

1669
/**********************************************************************
1670
 *                       CSLFetchNameValue()
1671
 **********************************************************************/
1672

1673
/** In a StringList of "Name=Value" pairs, look for the
1674
 * first value associated with the specified name.  The search is not
1675
 * case sensitive.
1676
 * ("Name:Value" pairs are also supported for backward compatibility
1677
 * with older stuff.)
1678
 *
1679
 * Returns a reference to the value in the StringList that the caller
1680
 * should not attempt to free.
1681
 *
1682
 * Returns NULL if the name is not found.
1683
 */
1684

1685
const char *CSLFetchNameValue(CSLConstList papszStrList, const char *pszName)
17,424,800✔
1686
{
1687
    if (papszStrList == nullptr || pszName == nullptr)
17,424,800✔
1688
        return nullptr;
4,634,330✔
1689

1690
    const size_t nLen = strlen(pszName);
12,790,500✔
1691
    while (*papszStrList != nullptr)
19,891,000✔
1692
    {
1693
        if (EQUALN(*papszStrList, pszName, nLen) &&
7,453,050✔
1694
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
359,862✔
1695
        {
1696
            return (*papszStrList) + nLen + 1;
352,503✔
1697
        }
1698
        ++papszStrList;
7,100,540✔
1699
    }
1700
    return nullptr;
12,438,000✔
1701
}
1702

1703
/************************************************************************/
1704
/*                            CSLFindName()                             */
1705
/************************************************************************/
1706

1707
/**
1708
 * Find StringList entry with given key name.
1709
 *
1710
 * @param papszStrList the string list to search.
1711
 * @param pszName the key value to look for (case insensitive).
1712
 *
1713
 * @return -1 on failure or the list index of the first occurrence
1714
 * matching the given key.
1715
 */
1716

1717
int CSLFindName(CSLConstList papszStrList, const char *pszName)
16,244,400✔
1718
{
1719
    if (papszStrList == nullptr || pszName == nullptr)
16,244,400✔
1720
        return -1;
784,773✔
1721

1722
    const size_t nLen = strlen(pszName);
15,459,600✔
1723
    int iIndex = 0;
15,459,600✔
1724
    while (*papszStrList != nullptr)
130,494,000✔
1725
    {
1726
        if (EQUALN(*papszStrList, pszName, nLen) &&
122,583,000✔
1727
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
8,288,750✔
1728
        {
1729
            return iIndex;
7,548,140✔
1730
        }
1731
        ++iIndex;
115,034,000✔
1732
        ++papszStrList;
115,034,000✔
1733
    }
1734
    return -1;
7,911,480✔
1735
}
1736

1737
/************************************************************************/
1738
/*                     CPLParseMemorySize()                             */
1739
/************************************************************************/
1740

1741
/** Parse a memory size from a string.
1742
 *
1743
 * The string may indicate the units of the memory (e.g., "230k", "500 MB"),
1744
 * using the prefixes "k", "m", or "g" in either lower or upper-case,
1745
 * optionally followed by a "b" or "B". The string may alternatively specify
1746
 * memory as a fraction of the usable RAM (e.g., "25%"). Spaces before the
1747
 * number, between the number and the units, or after the units are ignored,
1748
 * but other characters will cause a parsing failure. If the string cannot
1749
 * be understood, the function will return CE_Failure.
1750
 *
1751
 * @param pszValue the string to parse
1752
 * @param[out] pnValue the parsed size, converted to bytes (if unit was specified)
1753
 * @param[out] pbUnitSpecified whether the string indicated the units
1754
 *
1755
 * @return CE_None on success, CE_Failure otherwise
1756
 * @since 3.10
1757
 */
1758
CPLErr CPLParseMemorySize(const char *pszValue, GIntBig *pnValue,
6,319✔
1759
                          bool *pbUnitSpecified)
1760
{
1761
    const char *start = pszValue;
6,319✔
1762
    char *end = nullptr;
6,319✔
1763

1764
    // trim leading whitespace
1765
    while (*start == ' ')
6,323✔
1766
    {
1767
        start++;
4✔
1768
    }
1769

1770
    auto len = CPLStrnlen(start, 100);
6,319✔
1771
    double value = CPLStrtodM(start, &end);
6,319✔
1772
    const char *unit = nullptr;
6,319✔
1773
    bool unitIsNotPercent = false;
6,319✔
1774

1775
    if (end == start)
6,319✔
1776
    {
1777
        CPLError(CE_Failure, CPLE_IllegalArg, "Received non-numeric value: %s",
3✔
1778
                 pszValue);
1779
        return CE_Failure;
3✔
1780
    }
1781

1782
    if (value < 0 || !std::isfinite(value))
6,316✔
1783
    {
1784
        CPLError(CE_Failure, CPLE_IllegalArg,
2✔
1785
                 "Memory size must be a positive number or zero.");
1786
        return CE_Failure;
2✔
1787
    }
1788

1789
    for (const char *c = end; c < start + len; c++)
18,217✔
1790
    {
1791
        if (unit == nullptr)
11,908✔
1792
        {
1793
            // check various suffixes and convert number into bytes
1794
            if (*c == '%')
6,212✔
1795
            {
1796
                if (value < 0 || value > 100)
511✔
1797
                {
1798
                    CPLError(CE_Failure, CPLE_IllegalArg,
2✔
1799
                             "Memory percentage must be between 0 and 100.");
1800
                    return CE_Failure;
2✔
1801
                }
1802
                auto bytes = CPLGetUsablePhysicalRAM();
509✔
1803
                if (bytes == 0)
509✔
1804
                {
1805
                    CPLError(CE_Failure, CPLE_NotSupported,
×
1806
                             "Cannot determine usable physical RAM");
1807
                    return CE_Failure;
×
1808
                }
1809
                value *= static_cast<double>(bytes / 100);
509✔
1810
                unit = c;
509✔
1811
            }
1812
            else
1813
            {
1814
                switch (*c)
5,701✔
1815
                {
1816
                    case 'G':
32✔
1817
                    case 'g':
1818
                        value *= 1024;
32✔
1819
                        [[fallthrough]];
1820
                    case 'M':
5,692✔
1821
                    case 'm':
1822
                        value *= 1024;
5,692✔
1823
                        [[fallthrough]];
1824
                    case 'K':
5,696✔
1825
                    case 'k':
1826
                        value *= 1024;
5,696✔
1827
                        unit = c;
5,696✔
1828
                        unitIsNotPercent = true;
5,696✔
1829
                        break;
5,696✔
1830
                    case ' ':
3✔
1831
                        break;
3✔
1832
                    default:
2✔
1833
                        CPLError(CE_Failure, CPLE_IllegalArg,
2✔
1834
                                 "Unexpected value: %s", pszValue);
1835
                        return CE_Failure;
2✔
1836
                }
1837
            }
1838
        }
1839
        else if (unitIsNotPercent && c == unit + 1 && (*c == 'b' || *c == 'B'))
5,696✔
1840
        {
1841
            // ignore 'B' or 'b' as part of unit
1842
            continue;
5,695✔
1843
        }
1844
        else if (*c != ' ')
1✔
1845
        {
1846
            CPLError(CE_Failure, CPLE_IllegalArg, "Unexpected value: %s",
1✔
1847
                     pszValue);
1848
            return CE_Failure;
1✔
1849
        }
1850
    }
1851

1852
    *pnValue = static_cast<GIntBig>(value);
6,309✔
1853
    if (pbUnitSpecified)
6,309✔
1854
    {
1855
        *pbUnitSpecified = (unit != nullptr);
588✔
1856
    }
1857
    return CE_None;
6,309✔
1858
}
1859

1860
/**********************************************************************
1861
 *                       CPLParseNameValue()
1862
 **********************************************************************/
1863

1864
/**
1865
 * Parse NAME=VALUE string into name and value components.
1866
 *
1867
 * Note that if ppszKey is non-NULL, the key (or name) portion will be
1868
 * allocated using CPLMalloc(), and returned in that pointer.  It is the
1869
 * applications responsibility to free this string, but the application should
1870
 * not modify or free the returned value portion.
1871
 *
1872
 * This function also support "NAME:VALUE" strings and will strip white
1873
 * space from around the delimiter when forming name and value strings.
1874
 *
1875
 * Eventually CSLFetchNameValue() and friends may be modified to use
1876
 * CPLParseNameValue().
1877
 *
1878
 * @param pszNameValue string in "NAME=VALUE" format.
1879
 * @param ppszKey optional pointer though which to return the name
1880
 * portion.
1881
 *
1882
 * @return the value portion (pointing into original string).
1883
 */
1884

1885
const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey)
81,320✔
1886
{
1887
    for (int i = 0; pszNameValue[i] != '\0'; ++i)
1,162,610✔
1888
    {
1889
        if (pszNameValue[i] == '=' || pszNameValue[i] == ':')
1,159,500✔
1890
        {
1891
            const char *pszValue = pszNameValue + i + 1;
78,217✔
1892
            while (*pszValue == ' ' || *pszValue == '\t')
86,523✔
1893
                ++pszValue;
8,306✔
1894

1895
            if (ppszKey != nullptr)
78,217✔
1896
            {
1897
                *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
78,195✔
1898
                memcpy(*ppszKey, pszNameValue, i);
78,195✔
1899
                (*ppszKey)[i] = '\0';
78,195✔
1900
                while (i > 0 &&
78,466✔
1901
                       ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
78,466✔
1902
                {
1903
                    (*ppszKey)[i - 1] = '\0';
271✔
1904
                    i--;
271✔
1905
                }
1906
            }
1907

1908
            return pszValue;
78,217✔
1909
        }
1910
    }
1911

1912
    return nullptr;
3,103✔
1913
}
1914

1915
/**********************************************************************
1916
 *                       CPLParseNameValueSep()
1917
 **********************************************************************/
1918
/**
1919
 * Parse NAME<Sep>VALUE string into name and value components.
1920
 *
1921
 * This is derived directly from CPLParseNameValue() which will separate
1922
 * on '=' OR ':', here chSep is required for specifying the separator
1923
 * explicitly.
1924
 *
1925
 * @param pszNameValue string in "NAME=VALUE" format.
1926
 * @param ppszKey optional pointer though which to return the name
1927
 * portion.
1928
 * @param chSep required single char separator
1929
 * @return the value portion (pointing into original string).
1930
 */
1931

1932
const char *CPLParseNameValueSep(const char *pszNameValue, char **ppszKey,
17✔
1933
                                 char chSep)
1934
{
1935
    for (int i = 0; pszNameValue[i] != '\0'; ++i)
140✔
1936
    {
1937
        if (pszNameValue[i] == chSep)
138✔
1938
        {
1939
            const char *pszValue = pszNameValue + i + 1;
15✔
1940
            while (*pszValue == ' ' || *pszValue == '\t')
15✔
1941
                ++pszValue;
×
1942

1943
            if (ppszKey != nullptr)
15✔
1944
            {
1945
                *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
15✔
1946
                memcpy(*ppszKey, pszNameValue, i);
15✔
1947
                (*ppszKey)[i] = '\0';
15✔
1948
                while (i > 0 &&
15✔
1949
                       ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
15✔
1950
                {
1951
                    (*ppszKey)[i - 1] = '\0';
×
1952
                    i--;
×
1953
                }
1954
            }
1955

1956
            return pszValue;
15✔
1957
        }
1958
    }
1959

1960
    return nullptr;
2✔
1961
}
1962

1963
/**********************************************************************
1964
 *                       CSLFetchNameValueMultiple()
1965
 **********************************************************************/
1966

1967
/** In a StringList of "Name=Value" pairs, look for all the
1968
 * values with the specified name.  The search is not case
1969
 * sensitive.
1970
 * ("Name:Value" pairs are also supported for backward compatibility
1971
 * with older stuff.)
1972
 *
1973
 * Returns StringList with one entry for each occurrence of the
1974
 * specified name.  The StringList should eventually be destroyed
1975
 * by calling CSLDestroy().
1976
 *
1977
 * Returns NULL if the name is not found.
1978
 */
1979

1980
char **CSLFetchNameValueMultiple(CSLConstList papszStrList, const char *pszName)
14,523✔
1981
{
1982
    if (papszStrList == nullptr || pszName == nullptr)
14,523✔
1983
        return nullptr;
6,571✔
1984

1985
    const size_t nLen = strlen(pszName);
7,952✔
1986
    char **papszValues = nullptr;
7,952✔
1987
    while (*papszStrList != nullptr)
21,091✔
1988
    {
1989
        if (EQUALN(*papszStrList, pszName, nLen) &&
13,139✔
1990
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
55✔
1991
        {
1992
            papszValues = CSLAddString(papszValues, (*papszStrList) + nLen + 1);
55✔
1993
        }
1994
        ++papszStrList;
13,139✔
1995
    }
1996

1997
    return papszValues;
7,952✔
1998
}
1999

2000
/**********************************************************************
2001
 *                       CSLAddNameValue()
2002
 **********************************************************************/
2003

2004
/** Add a new entry to a StringList of "Name=Value" pairs,
2005
 * ("Name:Value" pairs are also supported for backward compatibility
2006
 * with older stuff.)
2007
 *
2008
 * This function does not check if a "Name=Value" pair already exists
2009
 * for that name and can generate multiple entries for the same name.
2010
 * Use CSLSetNameValue() if you want each name to have only one value.
2011
 *
2012
 * Returns the modified StringList.
2013
 */
2014

2015
char **CSLAddNameValue(char **papszStrList, const char *pszName,
401,909✔
2016
                       const char *pszValue)
2017
{
2018
    if (pszName == nullptr || pszValue == nullptr)
401,909✔
2019
        return papszStrList;
29✔
2020

2021
    const size_t nLen = strlen(pszName) + strlen(pszValue) + 2;
401,880✔
2022
    char *pszLine = static_cast<char *>(CPLMalloc(nLen));
401,880✔
2023
    snprintf(pszLine, nLen, "%s=%s", pszName, pszValue);
401,898✔
2024
    papszStrList = CSLAddString(papszStrList, pszLine);
401,898✔
2025
    CPLFree(pszLine);
401,840✔
2026

2027
    return papszStrList;
401,907✔
2028
}
2029

2030
/************************************************************************/
2031
/*                          CSLSetNameValue()                           */
2032
/************************************************************************/
2033

2034
/**
2035
 * Assign value to name in StringList.
2036
 *
2037
 * Set the value for a given name in a StringList of "Name=Value" pairs
2038
 * ("Name:Value" pairs are also supported for backward compatibility
2039
 * with older stuff.)
2040
 *
2041
 * If there is already a value for that name in the list then the value
2042
 * is changed, otherwise a new "Name=Value" pair is added.
2043
 *
2044
 * @param papszList the original list, the modified version is returned.
2045
 * @param pszName the name to be assigned a value.  This should be a well
2046
 * formed token (no spaces or very special characters).
2047
 * @param pszValue the value to assign to the name.  This should not contain
2048
 * any newlines (CR or LF) but is otherwise pretty much unconstrained.  If
2049
 * NULL any corresponding value will be removed.
2050
 *
2051
 * @return modified StringList.
2052
 */
2053

2054
char **CSLSetNameValue(char **papszList, const char *pszName,
432,783✔
2055
                       const char *pszValue)
2056
{
2057
    if (pszName == nullptr)
432,783✔
2058
        return papszList;
38✔
2059

2060
    size_t nLen = strlen(pszName);
432,745✔
2061
    while (nLen > 0 && pszName[nLen - 1] == ' ')
433,419✔
2062
        nLen--;
674✔
2063
    char **papszPtr = papszList;
432,745✔
2064
    while (papszPtr && *papszPtr != nullptr)
7,078,240✔
2065
    {
2066
        if (EQUALN(*papszPtr, pszName, nLen))
6,686,060✔
2067
        {
2068
            size_t i;
2069
            for (i = nLen; (*papszPtr)[i] == ' '; ++i)
42,966✔
2070
            {
2071
            }
2072
            if ((*papszPtr)[i] == '=' || (*papszPtr)[i] == ':')
42,292✔
2073
            {
2074
                // Found it.
2075
                // Change the value... make sure to keep the ':' or '='.
2076
                const char cSep = (*papszPtr)[i];
40,564✔
2077

2078
                CPLFree(*papszPtr);
40,564✔
2079

2080
                // If the value is NULL, remove this entry completely.
2081
                if (pszValue == nullptr)
40,569✔
2082
                {
2083
                    while (papszPtr[1] != nullptr)
43,425✔
2084
                    {
2085
                        *papszPtr = papszPtr[1];
10,541✔
2086
                        ++papszPtr;
10,541✔
2087
                    }
2088
                    *papszPtr = nullptr;
32,884✔
2089
                }
2090

2091
                // Otherwise replace with new value.
2092
                else
2093
                {
2094
                    const size_t nLen2 = strlen(pszName) + strlen(pszValue) + 2;
7,685✔
2095
                    *papszPtr = static_cast<char *>(CPLMalloc(nLen2));
7,685✔
2096
                    snprintf(*papszPtr, nLen2, "%s%c%s", pszName, cSep,
7,644✔
2097
                             pszValue);
2098
                }
2099
                return papszList;
40,528✔
2100
            }
2101
        }
2102
        ++papszPtr;
6,645,500✔
2103
    }
2104

2105
    if (pszValue == nullptr)
392,181✔
2106
        return papszList;
4,341✔
2107

2108
    // The name does not exist yet.  Create a new entry.
2109
    return CSLAddNameValue(papszList, pszName, pszValue);
387,840✔
2110
}
2111

2112
/************************************************************************/
2113
/*                      CSLSetNameValueSeparator()                      */
2114
/************************************************************************/
2115

2116
/**
2117
 * Replace the default separator (":" or "=") with the passed separator
2118
 * in the given name/value list.
2119
 *
2120
 * Note that if a separator other than ":" or "=" is used, the resulting
2121
 * list will not be manipulable by the CSL name/value functions any more.
2122
 *
2123
 * The CPLParseNameValue() function is used to break the existing lines,
2124
 * and it also strips white space from around the existing delimiter, thus
2125
 * the old separator, and any white space will be replaced by the new
2126
 * separator.  For formatting purposes it may be desirable to include some
2127
 * white space in the new separator.  e.g. ": " or " = ".
2128
 *
2129
 * @param papszList the list to update.  Component strings may be freed
2130
 * but the list array will remain at the same location.
2131
 *
2132
 * @param pszSeparator the new separator string to insert.
2133
 */
2134

2135
void CSLSetNameValueSeparator(char **papszList, const char *pszSeparator)
68✔
2136

2137
{
2138
    const int nLines = CSLCount(papszList);
68✔
2139

2140
    for (int iLine = 0; iLine < nLines; ++iLine)
583✔
2141
    {
2142
        char *pszKey = nullptr;
515✔
2143
        const char *pszValue = CPLParseNameValue(papszList[iLine], &pszKey);
515✔
2144
        if (pszValue == nullptr || pszKey == nullptr)
515✔
2145
        {
2146
            CPLFree(pszKey);
×
2147
            continue;
×
2148
        }
2149

2150
        char *pszNewLine = static_cast<char *>(CPLMalloc(
1,030✔
2151
            strlen(pszValue) + strlen(pszKey) + strlen(pszSeparator) + 1));
515✔
2152
        strcpy(pszNewLine, pszKey);
515✔
2153
        strcat(pszNewLine, pszSeparator);
515✔
2154
        strcat(pszNewLine, pszValue);
515✔
2155
        CPLFree(papszList[iLine]);
515✔
2156
        papszList[iLine] = pszNewLine;
515✔
2157
        CPLFree(pszKey);
515✔
2158
    }
2159
}
68✔
2160

2161
/************************************************************************/
2162
/*                          CPLEscapeString()                           */
2163
/************************************************************************/
2164

2165
/**
2166
 * Apply escaping to string to preserve special characters.
2167
 *
2168
 * This function will "escape" a variety of special characters
2169
 * to make the string suitable to embed within a string constant
2170
 * or to write within a text stream but in a form that can be
2171
 * reconstituted to its original form.  The escaping will even preserve
2172
 * zero bytes allowing preservation of raw binary data.
2173
 *
2174
 * CPLES_BackslashQuotable(0): This scheme turns a binary string into
2175
 * a form suitable to be placed within double quotes as a string constant.
2176
 * The backslash, quote, '\\0' and newline characters are all escaped in
2177
 * the usual C style.
2178
 *
2179
 * CPLES_XML(1): This scheme converts the '<', '>', '"' and '&' characters into
2180
 * their XML/HTML equivalent (&lt;, &gt;, &quot; and &amp;) making a string safe
2181
 * to embed as CDATA within an XML element.  The '\\0' is not escaped and
2182
 * should not be included in the input.
2183
 *
2184
 * CPLES_URL(2): Everything except alphanumerics and the characters
2185
 * '$', '-', '_', '.', '+', '!', '*', ''', '(', ')' and ',' (see RFC1738) are
2186
 * converted to a percent followed by a two digit hex encoding of the character
2187
 * (leading zero supplied if needed).  This is the mechanism used for encoding
2188
 * values to be passed in URLs.
2189
 *
2190
 * CPLES_SQL(3): All single quotes are replaced with two single quotes.
2191
 * Suitable for use when constructing literal values for SQL commands where
2192
 * the literal will be enclosed in single quotes.
2193
 *
2194
 * CPLES_CSV(4): If the values contains commas, semicolons, tabs, double quotes,
2195
 * or newlines it placed in double quotes, and double quotes in the value are
2196
 * doubled. Suitable for use when constructing field values for .csv files.
2197
 * Note that CPLUnescapeString() currently does not support this format, only
2198
 * CPLEscapeString().  See cpl_csv.cpp for CSV parsing support.
2199
 *
2200
 * CPLES_SQLI(7): All double quotes are replaced with two double quotes.
2201
 * Suitable for use when constructing identifiers for SQL commands where
2202
 * the literal will be enclosed in double quotes.
2203
 *
2204
 * @param pszInput the string to escape.
2205
 * @param nLength The number of bytes of data to preserve.  If this is -1
2206
 * the strlen(pszString) function will be used to compute the length.
2207
 * @param nScheme the encoding scheme to use.
2208
 *
2209
 * @return an escaped, zero terminated string that should be freed with
2210
 * CPLFree() when no longer needed.
2211
 */
2212

2213
char *CPLEscapeString(const char *pszInput, int nLength, int nScheme)
696,477✔
2214
{
2215
    const size_t szLength =
696,477✔
2216
        (nLength < 0) ? strlen(pszInput) : static_cast<size_t>(nLength);
696,477✔
2217
#define nLength no_longer_use_me
2218

2219
    size_t nSizeAlloc = 1;
696,477✔
2220
#if SIZEOF_VOIDP < 8
2221
    bool bWrapAround = false;
2222
    const auto IncSizeAlloc = [&nSizeAlloc, &bWrapAround](size_t inc)
2223
    {
2224
        constexpr size_t SZ_MAX = std::numeric_limits<size_t>::max();
2225
        if (nSizeAlloc > SZ_MAX - inc)
2226
        {
2227
            bWrapAround = true;
2228
            nSizeAlloc = 0;
2229
        }
2230
        nSizeAlloc += inc;
2231
    };
2232
#else
2233
    const auto IncSizeAlloc = [&nSizeAlloc](size_t inc) { nSizeAlloc += inc; };
43,188,400✔
2234
#endif
2235

2236
    if (nScheme == CPLES_BackslashQuotable)
696,477✔
2237
    {
2238
        for (size_t iIn = 0; iIn < szLength; iIn++)
45,751✔
2239
        {
2240
            if (pszInput[iIn] == '\0' || pszInput[iIn] == '\n' ||
45,631✔
2241
                pszInput[iIn] == '"' || pszInput[iIn] == '\\')
44,877✔
2242
                IncSizeAlloc(2);
876✔
2243
            else
2244
                IncSizeAlloc(1);
44,755✔
2245
        }
2246
    }
2247
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
696,357✔
2248
    {
2249
        for (size_t iIn = 0; iIn < szLength; ++iIn)
43,105,600✔
2250
        {
2251
            if (pszInput[iIn] == '<')
42,412,400✔
2252
            {
2253
                IncSizeAlloc(4);
1,420✔
2254
            }
2255
            else if (pszInput[iIn] == '>')
42,410,900✔
2256
            {
2257
                IncSizeAlloc(4);
1,570✔
2258
            }
2259
            else if (pszInput[iIn] == '&')
42,409,400✔
2260
            {
2261
                IncSizeAlloc(5);
844✔
2262
            }
2263
            else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
42,408,500✔
2264
            {
2265
                IncSizeAlloc(6);
2,080✔
2266
            }
2267
            // Python 2 does not display the UTF-8 character corresponding
2268
            // to the byte-order mark (BOM), so escape it.
2269
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
42,406,400✔
2270
                         0xEF &&
2✔
2271
                     (reinterpret_cast<const unsigned char *>(
2272
                         pszInput))[iIn + 1] == 0xBB &&
2✔
2273
                     (reinterpret_cast<const unsigned char *>(
2274
                         pszInput))[iIn + 2] == 0xBF)
2✔
2275
            {
2276
                IncSizeAlloc(8);
2✔
2277
                iIn += 2;
2✔
2278
            }
2279
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
42,406,400✔
2280
                         0x20 &&
22,192✔
2281
                     pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
22,192✔
2282
                     pszInput[iIn] != 0xD)
110✔
2283
            {
2284
                // These control characters are unrepresentable in XML format,
2285
                // so we just drop them.  #4117
2286
            }
2287
            else
2288
            {
2289
                IncSizeAlloc(1);
42,406,400✔
2290
            }
2291
        }
693,299✔
2292
    }
2293
    else if (nScheme == CPLES_URL)  // Untested at implementation.
3,058✔
2294
    {
2295
        for (size_t iIn = 0; iIn < szLength; ++iIn)
10,231✔
2296
        {
2297
            if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
9,732✔
2298
                (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
3,722✔
2299
                (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
1,871✔
2300
                pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
937✔
2301
                pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
896✔
2302
                pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
516✔
2303
                pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
494✔
2304
                pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
492✔
2305
                pszInput[iIn] == ',')
482✔
2306
            {
2307
                IncSizeAlloc(1);
9,256✔
2308
            }
2309
            else
2310
            {
2311
                IncSizeAlloc(3);
476✔
2312
            }
2313
        }
2314
    }
2315
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2,559✔
2316
    {
2317
        const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
794✔
2318
        for (size_t iIn = 0; iIn < szLength; ++iIn)
11,656✔
2319
        {
2320
            if (pszInput[iIn] == chQuote)
10,862✔
2321
            {
2322
                IncSizeAlloc(2);
5✔
2323
            }
2324
            else
2325
            {
2326
                IncSizeAlloc(1);
10,857✔
2327
            }
2328
        }
794✔
2329
    }
2330
    else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
1,765✔
2331
    {
2332
        if (nScheme == CPLES_CSV && strcspn(pszInput, "\",;\t\n\r") == szLength)
1,765✔
2333
        {
2334
            char *pszOutput =
2335
                static_cast<char *>(VSI_MALLOC_VERBOSE(szLength + 1));
1,527✔
2336
            if (pszOutput == nullptr)
1,527✔
2337
                return nullptr;
×
2338
            memcpy(pszOutput, pszInput, szLength + 1);
1,527✔
2339
            return pszOutput;
1,527✔
2340
        }
2341
        else
2342
        {
2343
            IncSizeAlloc(1);
238✔
2344
            for (size_t iIn = 0; iIn < szLength; ++iIn)
13,101✔
2345
            {
2346
                if (pszInput[iIn] == '\"')
12,863✔
2347
                {
2348
                    IncSizeAlloc(2);
169✔
2349
                }
2350
                else
2351
                    IncSizeAlloc(1);
12,694✔
2352
            }
2353
            IncSizeAlloc(1);
238✔
2354
        }
238✔
2355
    }
2356
    else
2357
    {
2358
        CPLError(CE_Failure, CPLE_AppDefined,
×
2359
                 "Undefined escaping scheme (%d) in CPLEscapeString()",
2360
                 nScheme);
2361
        return CPLStrdup("");
×
2362
    }
2363

2364
#if SIZEOF_VOIDP < 8
2365
    if (bWrapAround)
2366
    {
2367
        CPLError(CE_Failure, CPLE_OutOfMemory,
2368
                 "Out of memory in CPLEscapeString()");
2369
        return nullptr;
2370
    }
2371
#endif
2372

2373
    char *pszOutput = static_cast<char *>(VSI_MALLOC_VERBOSE(nSizeAlloc));
694,950✔
2374
    if (pszOutput == nullptr)
694,950✔
2375
        return nullptr;
×
2376

2377
    size_t iOut = 0;
694,950✔
2378

2379
    if (nScheme == CPLES_BackslashQuotable)
694,950✔
2380
    {
2381
        for (size_t iIn = 0; iIn < szLength; iIn++)
45,751✔
2382
        {
2383
            if (pszInput[iIn] == '\0')
45,631✔
2384
            {
2385
                pszOutput[iOut++] = '\\';
689✔
2386
                pszOutput[iOut++] = '0';
689✔
2387
            }
2388
            else if (pszInput[iIn] == '\n')
44,942✔
2389
            {
2390
                pszOutput[iOut++] = '\\';
65✔
2391
                pszOutput[iOut++] = 'n';
65✔
2392
            }
2393
            else if (pszInput[iIn] == '"')
44,877✔
2394
            {
2395
                pszOutput[iOut++] = '\\';
121✔
2396
                pszOutput[iOut++] = '\"';
121✔
2397
            }
2398
            else if (pszInput[iIn] == '\\')
44,756✔
2399
            {
2400
                pszOutput[iOut++] = '\\';
1✔
2401
                pszOutput[iOut++] = '\\';
1✔
2402
            }
2403
            else
2404
                pszOutput[iOut++] = pszInput[iIn];
44,755✔
2405
        }
2406
        pszOutput[iOut++] = '\0';
120✔
2407
    }
2408
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
694,830✔
2409
    {
2410
        for (size_t iIn = 0; iIn < szLength; ++iIn)
43,105,600✔
2411
        {
2412
            if (pszInput[iIn] == '<')
42,412,400✔
2413
            {
2414
                pszOutput[iOut++] = '&';
1,420✔
2415
                pszOutput[iOut++] = 'l';
1,420✔
2416
                pszOutput[iOut++] = 't';
1,420✔
2417
                pszOutput[iOut++] = ';';
1,420✔
2418
            }
2419
            else if (pszInput[iIn] == '>')
42,410,900✔
2420
            {
2421
                pszOutput[iOut++] = '&';
1,570✔
2422
                pszOutput[iOut++] = 'g';
1,570✔
2423
                pszOutput[iOut++] = 't';
1,570✔
2424
                pszOutput[iOut++] = ';';
1,570✔
2425
            }
2426
            else if (pszInput[iIn] == '&')
42,409,400✔
2427
            {
2428
                pszOutput[iOut++] = '&';
844✔
2429
                pszOutput[iOut++] = 'a';
844✔
2430
                pszOutput[iOut++] = 'm';
844✔
2431
                pszOutput[iOut++] = 'p';
844✔
2432
                pszOutput[iOut++] = ';';
844✔
2433
            }
2434
            else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
42,408,500✔
2435
            {
2436
                pszOutput[iOut++] = '&';
2,080✔
2437
                pszOutput[iOut++] = 'q';
2,080✔
2438
                pszOutput[iOut++] = 'u';
2,080✔
2439
                pszOutput[iOut++] = 'o';
2,080✔
2440
                pszOutput[iOut++] = 't';
2,080✔
2441
                pszOutput[iOut++] = ';';
2,080✔
2442
            }
2443
            // Python 2 does not display the UTF-8 character corresponding
2444
            // to the byte-order mark (BOM), so escape it.
2445
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
42,406,400✔
2446
                         0xEF &&
2✔
2447
                     (reinterpret_cast<const unsigned char *>(
2448
                         pszInput))[iIn + 1] == 0xBB &&
2✔
2449
                     (reinterpret_cast<const unsigned char *>(
2450
                         pszInput))[iIn + 2] == 0xBF)
2✔
2451
            {
2452
                pszOutput[iOut++] = '&';
2✔
2453
                pszOutput[iOut++] = '#';
2✔
2454
                pszOutput[iOut++] = 'x';
2✔
2455
                pszOutput[iOut++] = 'F';
2✔
2456
                pszOutput[iOut++] = 'E';
2✔
2457
                pszOutput[iOut++] = 'F';
2✔
2458
                pszOutput[iOut++] = 'F';
2✔
2459
                pszOutput[iOut++] = ';';
2✔
2460
                iIn += 2;
2✔
2461
            }
2462
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
42,406,400✔
2463
                         0x20 &&
22,192✔
2464
                     pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
22,192✔
2465
                     pszInput[iIn] != 0xD)
110✔
2466
            {
2467
                // These control characters are unrepresentable in XML format,
2468
                // so we just drop them.  #4117
2469
            }
2470
            else
2471
            {
2472
                pszOutput[iOut++] = pszInput[iIn];
42,406,400✔
2473
            }
2474
        }
2475
        pszOutput[iOut++] = '\0';
693,299✔
2476
    }
2477
    else if (nScheme == CPLES_URL)  // Untested at implementation.
1,531✔
2478
    {
2479
        for (size_t iIn = 0; iIn < szLength; ++iIn)
10,231✔
2480
        {
2481
            if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
9,732✔
2482
                (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
3,722✔
2483
                (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
1,871✔
2484
                pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
937✔
2485
                pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
896✔
2486
                pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
516✔
2487
                pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
494✔
2488
                pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
492✔
2489
                pszInput[iIn] == ',')
482✔
2490
            {
2491
                pszOutput[iOut++] = pszInput[iIn];
9,256✔
2492
            }
2493
            else
2494
            {
2495
                snprintf(pszOutput + iOut, nSizeAlloc - iOut, "%%%02X",
476✔
2496
                         static_cast<unsigned char>(pszInput[iIn]));
476✔
2497
                iOut += 3;
476✔
2498
            }
2499
        }
2500
        pszOutput[iOut++] = '\0';
499✔
2501
    }
2502
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
1,032✔
2503
    {
2504
        const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
794✔
2505
        for (size_t iIn = 0; iIn < szLength; ++iIn)
11,656✔
2506
        {
2507
            if (pszInput[iIn] == chQuote)
10,862✔
2508
            {
2509
                pszOutput[iOut++] = chQuote;
5✔
2510
                pszOutput[iOut++] = chQuote;
5✔
2511
            }
2512
            else
2513
            {
2514
                pszOutput[iOut++] = pszInput[iIn];
10,857✔
2515
            }
2516
        }
2517
        pszOutput[iOut++] = '\0';
794✔
2518
    }
2519
    else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
238✔
2520
    {
2521
        pszOutput[iOut++] = '\"';
238✔
2522

2523
        for (size_t iIn = 0; iIn < szLength; ++iIn)
13,101✔
2524
        {
2525
            if (pszInput[iIn] == '\"')
12,863✔
2526
            {
2527
                pszOutput[iOut++] = '\"';
169✔
2528
                pszOutput[iOut++] = '\"';
169✔
2529
            }
2530
            else
2531
                pszOutput[iOut++] = pszInput[iIn];
12,694✔
2532
        }
2533
        pszOutput[iOut++] = '\"';
238✔
2534
        pszOutput[iOut++] = '\0';
238✔
2535
    }
2536

2537
    return pszOutput;
694,950✔
2538
#undef nLength
2539
}
2540

2541
/************************************************************************/
2542
/*                         CPLUnescapeString()                          */
2543
/************************************************************************/
2544

2545
/**
2546
 * Unescape a string.
2547
 *
2548
 * This function does the opposite of CPLEscapeString().  Given a string
2549
 * with special values escaped according to some scheme, it will return a
2550
 * new copy of the string returned to its original form.
2551
 *
2552
 * @param pszInput the input string.  This is a zero terminated string.
2553
 * @param pnLength location to return the length of the unescaped string,
2554
 * which may in some cases include embedded '\\0' characters.
2555
 * @param nScheme the escaped scheme to undo (see CPLEscapeString() for a
2556
 * list).  Does not yet support CSV.
2557
 *
2558
 * @return a copy of the unescaped string that should be freed by the
2559
 * application using CPLFree() when no longer needed.
2560
 */
2561

2562
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
2563
char *CPLUnescapeString(const char *pszInput, int *pnLength, int nScheme)
36,971✔
2564

2565
{
2566
    int iOut = 0;
36,971✔
2567

2568
    // TODO: Why times 4?
2569
    char *pszOutput = static_cast<char *>(CPLMalloc(4 * strlen(pszInput) + 1));
36,971✔
2570
    pszOutput[0] = '\0';
36,971✔
2571

2572
    if (nScheme == CPLES_BackslashQuotable)
36,971✔
2573
    {
2574
        for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
53,012✔
2575
        {
2576
            if (pszInput[iIn] == '\\')
52,566✔
2577
            {
2578
                ++iIn;
769✔
2579
                if (pszInput[iIn] == '\0')
769✔
2580
                    break;
×
2581
                if (pszInput[iIn] == 'n')
769✔
2582
                    pszOutput[iOut++] = '\n';
6✔
2583
                else if (pszInput[iIn] == '0')
763✔
2584
                    pszOutput[iOut++] = '\0';
675✔
2585
                else
2586
                    pszOutput[iOut++] = pszInput[iIn];
88✔
2587
            }
2588
            else
2589
            {
2590
                pszOutput[iOut++] = pszInput[iIn];
51,797✔
2591
            }
2592
        }
2593
    }
2594
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
36,525✔
2595
    {
2596
        char ch = '\0';
35,901✔
2597
        for (int iIn = 0; (ch = pszInput[iIn]) != '\0'; ++iIn)
32,967,300✔
2598
        {
2599
            if (ch != '&')
32,931,400✔
2600
            {
2601
                pszOutput[iOut++] = ch;
32,605,900✔
2602
            }
2603
            else if (STARTS_WITH_CI(pszInput + iIn, "&lt;"))
325,531✔
2604
            {
2605
                pszOutput[iOut++] = '<';
5,097✔
2606
                iIn += 3;
5,097✔
2607
            }
2608
            else if (STARTS_WITH_CI(pszInput + iIn, "&gt;"))
320,434✔
2609
            {
2610
                pszOutput[iOut++] = '>';
5,248✔
2611
                iIn += 3;
5,248✔
2612
            }
2613
            else if (STARTS_WITH_CI(pszInput + iIn, "&amp;"))
315,186✔
2614
            {
2615
                pszOutput[iOut++] = '&';
227,032✔
2616
                iIn += 4;
227,032✔
2617
            }
2618
            else if (STARTS_WITH_CI(pszInput + iIn, "&apos;"))
88,154✔
2619
            {
2620
                pszOutput[iOut++] = '\'';
686✔
2621
                iIn += 5;
686✔
2622
            }
2623
            else if (STARTS_WITH_CI(pszInput + iIn, "&quot;"))
87,468✔
2624
            {
2625
                pszOutput[iOut++] = '"';
87,304✔
2626
                iIn += 5;
87,304✔
2627
            }
2628
            else if (STARTS_WITH_CI(pszInput + iIn, "&#x"))
164✔
2629
            {
2630
                wchar_t anVal[2] = {0, 0};
3✔
2631
                iIn += 3;
3✔
2632

2633
                unsigned int nVal = 0;
3✔
2634
                while (true)
2635
                {
2636
                    ch = pszInput[iIn++];
7✔
2637
                    if (ch >= 'a' && ch <= 'f')
7✔
2638
                        nVal = nVal * 16U +
1✔
2639
                               static_cast<unsigned int>(ch - 'a' + 10);
2640
                    else if (ch >= 'A' && ch <= 'F')
6✔
2641
                        nVal = nVal * 16U +
1✔
2642
                               static_cast<unsigned int>(ch - 'A' + 10);
2643
                    else if (ch >= '0' && ch <= '9')
5✔
2644
                        nVal = nVal * 16U + static_cast<unsigned int>(ch - '0');
2✔
2645
                    else
2646
                        break;
2647
                }
2648
                anVal[0] = static_cast<wchar_t>(nVal);
3✔
2649
                if (ch != ';')
3✔
2650
                    break;
1✔
2651
                iIn--;
2✔
2652

2653
                char *pszUTF8 =
2654
                    CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
2✔
2655
                int nLen = static_cast<int>(strlen(pszUTF8));
2✔
2656
                memcpy(pszOutput + iOut, pszUTF8, nLen);
2✔
2657
                CPLFree(pszUTF8);
2✔
2658
                iOut += nLen;
2✔
2659
            }
2660
            else if (STARTS_WITH_CI(pszInput + iIn, "&#"))
161✔
2661
            {
2662
                wchar_t anVal[2] = {0, 0};
159✔
2663
                iIn += 2;
159✔
2664

2665
                unsigned int nVal = 0;
159✔
2666
                while (true)
2667
                {
2668
                    ch = pszInput[iIn++];
646✔
2669
                    if (ch >= '0' && ch <= '9')
646✔
2670
                        nVal = nVal * 10U + static_cast<unsigned int>(ch - '0');
487✔
2671
                    else
2672
                        break;
2673
                }
2674
                anVal[0] = static_cast<wchar_t>(nVal);
159✔
2675
                if (ch != ';')
159✔
2676
                    break;
1✔
2677
                iIn--;
158✔
2678

2679
                char *pszUTF8 =
2680
                    CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
158✔
2681
                const int nLen = static_cast<int>(strlen(pszUTF8));
158✔
2682
                memcpy(pszOutput + iOut, pszUTF8, nLen);
158✔
2683
                CPLFree(pszUTF8);
158✔
2684
                iOut += nLen;
158✔
2685
            }
2686
            else
2687
            {
2688
                // Illegal escape sequence.
2689
                CPLDebug("CPL",
2✔
2690
                         "Error unescaping CPLES_XML text, '&' character "
2691
                         "followed by unhandled escape sequence.");
2692
                break;
2✔
2693
            }
2694
        }
35,901✔
2695
    }
2696
    else if (nScheme == CPLES_URL)
624✔
2697
    {
2698
        for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
31,071✔
2699
        {
2700
            if (pszInput[iIn] == '%' && pszInput[iIn + 1] != '\0' &&
30,492✔
2701
                pszInput[iIn + 2] != '\0')
770✔
2702
            {
2703
                int nHexChar = 0;
770✔
2704

2705
                if (pszInput[iIn + 1] >= 'A' && pszInput[iIn + 1] <= 'F')
770✔
2706
                    nHexChar += 16 * (pszInput[iIn + 1] - 'A' + 10);
×
2707
                else if (pszInput[iIn + 1] >= 'a' && pszInput[iIn + 1] <= 'f')
770✔
2708
                    nHexChar += 16 * (pszInput[iIn + 1] - 'a' + 10);
×
2709
                else if (pszInput[iIn + 1] >= '0' && pszInput[iIn + 1] <= '9')
770✔
2710
                    nHexChar += 16 * (pszInput[iIn + 1] - '0');
770✔
2711
                else
2712
                    CPLDebug("CPL",
×
2713
                             "Error unescaping CPLES_URL text, percent not "
2714
                             "followed by two hex digits.");
2715

2716
                if (pszInput[iIn + 2] >= 'A' && pszInput[iIn + 2] <= 'F')
770✔
2717
                    nHexChar += pszInput[iIn + 2] - 'A' + 10;
746✔
2718
                else if (pszInput[iIn + 2] >= 'a' && pszInput[iIn + 2] <= 'f')
24✔
2719
                    nHexChar += pszInput[iIn + 2] - 'a' + 10;
×
2720
                else if (pszInput[iIn + 2] >= '0' && pszInput[iIn + 2] <= '9')
24✔
2721
                    nHexChar += pszInput[iIn + 2] - '0';
24✔
2722
                else
2723
                    CPLDebug("CPL",
×
2724
                             "Error unescaping CPLES_URL text, percent not "
2725
                             "followed by two hex digits.");
2726

2727
                pszOutput[iOut++] = static_cast<char>(nHexChar);
770✔
2728
                iIn += 2;
770✔
2729
            }
2730
            else if (pszInput[iIn] == '+')
29,722✔
2731
            {
2732
                pszOutput[iOut++] = ' ';
×
2733
            }
2734
            else
2735
            {
2736
                pszOutput[iOut++] = pszInput[iIn];
29,722✔
2737
            }
2738
        }
2739
    }
2740
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
45✔
2741
    {
2742
        char szQuote = nScheme == CPLES_SQL ? '\'' : '\"';
45✔
2743
        for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
565✔
2744
        {
2745
            if (pszInput[iIn] == szQuote && pszInput[iIn + 1] == szQuote)
520✔
2746
            {
2747
                ++iIn;
3✔
2748
                pszOutput[iOut++] = pszInput[iIn];
3✔
2749
            }
2750
            else
2751
            {
2752
                pszOutput[iOut++] = pszInput[iIn];
517✔
2753
            }
2754
        }
45✔
2755
    }
2756
    else if (nScheme == CPLES_CSV)
×
2757
    {
2758
        CPLError(CE_Fatal, CPLE_NotSupported,
×
2759
                 "CSV Unescaping not yet implemented.");
2760
    }
2761
    else
2762
    {
2763
        CPLError(CE_Fatal, CPLE_NotSupported, "Unknown escaping style.");
×
2764
    }
2765

2766
    pszOutput[iOut] = '\0';
36,972✔
2767

2768
    if (pnLength != nullptr)
36,972✔
2769
        *pnLength = iOut;
21,968✔
2770

2771
    return pszOutput;
36,972✔
2772
}
2773

2774
/************************************************************************/
2775
/*                           CPLBinaryToHex()                           */
2776
/************************************************************************/
2777

2778
/**
2779
 * Binary to hexadecimal translation.
2780
 *
2781
 * @param nBytes number of bytes of binary data in pabyData.
2782
 * @param pabyData array of data bytes to translate.
2783
 *
2784
 * @return hexadecimal translation, zero terminated.  Free with CPLFree().
2785
 */
2786

2787
char *CPLBinaryToHex(int nBytes, const GByte *pabyData)
4,213✔
2788

2789
{
2790
    CPLAssert(nBytes >= 0);
4,213✔
2791
    char *pszHex = static_cast<char *>(
2792
        VSI_MALLOC_VERBOSE(static_cast<size_t>(nBytes) * 2 + 1));
4,213✔
2793
    if (!pszHex)
4,213✔
2794
    {
2795
        pszHex = CPLStrdup("");
×
2796
        return pszHex;
×
2797
    }
2798
    pszHex[nBytes * 2] = '\0';
4,213✔
2799

2800
    constexpr char achHex[] = "0123456789ABCDEF";
4,213✔
2801

2802
    for (size_t i = 0; i < static_cast<size_t>(nBytes); ++i)
248,148✔
2803
    {
2804
        const int nLow = pabyData[i] & 0x0f;
243,935✔
2805
        const int nHigh = (pabyData[i] & 0xf0) >> 4;
243,935✔
2806

2807
        pszHex[i * 2] = achHex[nHigh];
243,935✔
2808
        pszHex[i * 2 + 1] = achHex[nLow];
243,935✔
2809
    }
2810

2811
    return pszHex;
4,213✔
2812
}
2813

2814
/************************************************************************/
2815
/*                           CPLHexToBinary()                           */
2816
/************************************************************************/
2817

2818
constexpr unsigned char hex2char[256] = {
2819
    // Not Hex characters.
2820
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2821
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2822
    // 0-9
2823
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
2824
    // A-F
2825
    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2826
    // Not Hex characters.
2827
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2828
    // a-f
2829
    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2830
    0, 0, 0, 0, 0, 0, 0, 0, 0,
2831
    // Not Hex characters (upper 128 characters).
2832
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2833
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2834
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2835
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2836
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2837
    0, 0, 0};
2838

2839
/**
2840
 * Hexadecimal to binary translation
2841
 *
2842
 * @param pszHex the input hex encoded string.
2843
 * @param pnBytes the returned count of decoded bytes placed here.
2844
 *
2845
 * @return returns binary buffer of data - free with CPLFree().
2846
 */
2847

2848
GByte *CPLHexToBinary(const char *pszHex, int *pnBytes)
3,903✔
2849
{
2850
    const GByte *pabyHex = reinterpret_cast<const GByte *>(pszHex);
3,903✔
2851
    const size_t nHexLen = strlen(pszHex);
3,903✔
2852

2853
    GByte *pabyWKB = static_cast<GByte *>(CPLMalloc(nHexLen / 2 + 2));
3,903✔
2854

2855
    for (size_t i = 0; i < nHexLen / 2; ++i)
1,046,450✔
2856
    {
2857
        const unsigned char h1 = hex2char[pabyHex[2 * i]];
1,042,550✔
2858
        const unsigned char h2 = hex2char[pabyHex[2 * i + 1]];
1,042,550✔
2859

2860
        // First character is high bits, second is low bits.
2861
        pabyWKB[i] = static_cast<GByte>((h1 << 4) | h2);
1,042,550✔
2862
    }
2863
    pabyWKB[nHexLen / 2] = 0;
3,903✔
2864
    *pnBytes = static_cast<int>(nHexLen / 2);
3,903✔
2865

2866
    return pabyWKB;
3,903✔
2867
}
2868

2869
/************************************************************************/
2870
/*                         CPLGetValueType()                            */
2871
/************************************************************************/
2872

2873
/**
2874
 * Detect the type of the value contained in a string, whether it is
2875
 * a real, an integer or a string
2876
 * Leading and trailing spaces are skipped in the analysis.
2877
 *
2878
 * Note: in the context of this function, integer must be understood in a
2879
 * broad sense. It does not mean that the value can fit into a 32 bit integer
2880
 * for example. It might be larger.
2881
 *
2882
 * @param pszValue the string to analyze
2883
 *
2884
 * @return returns the type of the value contained in the string.
2885
 */
2886

2887
CPLValueType CPLGetValueType(const char *pszValue)
538,813✔
2888
{
2889
    // Doubles : "+25.e+3", "-25.e-3", "25.e3", "25e3", " 25e3 "
2890
    // Not doubles: "25e 3", "25e.3", "-2-5e3", "2-5e3", "25.25.3", "-3d", "d1"
2891
    //              "XXeYYYYYYYYYYYYYYYYYYY" that evaluates to infinity
2892

2893
    if (pszValue == nullptr)
538,813✔
2894
        return CPL_VALUE_STRING;
×
2895

2896
    const char *pszValueInit = pszValue;
538,813✔
2897

2898
    // Skip leading spaces.
2899
    while (isspace(static_cast<unsigned char>(*pszValue)))
538,864✔
2900
        ++pszValue;
51✔
2901

2902
    if (*pszValue == '\0')
538,813✔
2903
        return CPL_VALUE_STRING;
376✔
2904

2905
    // Skip leading + or -.
2906
    if (*pszValue == '+' || *pszValue == '-')
538,437✔
2907
        ++pszValue;
84,555✔
2908

2909
    constexpr char DIGIT_ZERO = '0';
538,437✔
2910
    if (pszValue[0] == DIGIT_ZERO && pszValue[1] != '\0' && pszValue[1] != '.')
538,437✔
2911
        return CPL_VALUE_STRING;
903✔
2912

2913
    bool bFoundDot = false;
537,534✔
2914
    bool bFoundExponent = false;
537,534✔
2915
    bool bIsLastCharExponent = false;
537,534✔
2916
    bool bIsReal = false;
537,534✔
2917
    const char *pszAfterExponent = nullptr;
537,534✔
2918
    bool bFoundMantissa = false;
537,534✔
2919

2920
    for (; *pszValue != '\0'; ++pszValue)
6,903,580✔
2921
    {
2922
        if (isdigit(static_cast<unsigned char>(*pszValue)))
6,409,680✔
2923
        {
2924
            bIsLastCharExponent = false;
5,977,940✔
2925
            bFoundMantissa = true;
5,977,940✔
2926
        }
2927
        else if (isspace(static_cast<unsigned char>(*pszValue)))
431,737✔
2928
        {
2929
            const char *pszTmp = pszValue;
772✔
2930
            while (isspace(static_cast<unsigned char>(*pszTmp)))
1,548✔
2931
                ++pszTmp;
776✔
2932
            if (*pszTmp == 0)
772✔
2933
                break;
24✔
2934
            else
2935
                return CPL_VALUE_STRING;
748✔
2936
        }
2937
        else if (*pszValue == '-' || *pszValue == '+')
430,965✔
2938
        {
2939
            if (bIsLastCharExponent)
610✔
2940
            {
2941
                // Do nothing.
2942
            }
2943
            else
2944
            {
2945
                return CPL_VALUE_STRING;
340✔
2946
            }
2947
            bIsLastCharExponent = false;
270✔
2948
        }
2949
        else if (*pszValue == '.')
430,355✔
2950
        {
2951
            bIsReal = true;
387,566✔
2952
            if (!bFoundDot && !bIsLastCharExponent)
387,566✔
2953
                bFoundDot = true;
387,563✔
2954
            else
2955
                return CPL_VALUE_STRING;
3✔
2956
            bIsLastCharExponent = false;
387,563✔
2957
        }
2958
        else if (*pszValue == 'D' || *pszValue == 'd' || *pszValue == 'E' ||
42,789✔
2959
                 *pszValue == 'e')
38,218✔
2960
        {
2961
            if (!bFoundMantissa)
4,835✔
2962
                return CPL_VALUE_STRING;
4,556✔
2963
            if (!(pszValue[1] == '+' || pszValue[1] == '-' ||
279✔
2964
                  isdigit(static_cast<unsigned char>(pszValue[1]))))
9✔
2965
                return CPL_VALUE_STRING;
2✔
2966

2967
            bIsReal = true;
277✔
2968
            if (!bFoundExponent)
277✔
2969
                bFoundExponent = true;
276✔
2970
            else
2971
                return CPL_VALUE_STRING;
1✔
2972
            pszAfterExponent = pszValue + 1;
276✔
2973
            bIsLastCharExponent = true;
276✔
2974
        }
2975
        else
2976
        {
2977
            return CPL_VALUE_STRING;
37,954✔
2978
        }
2979
    }
2980

2981
    if (bIsReal && pszAfterExponent && strlen(pszAfterExponent) > 3)
493,930✔
2982
    {
2983
        // cppcheck-suppress unreadVariable
2984
        const double dfVal = CPLAtof(pszValueInit);
15✔
2985
        if (std::isinf(dfVal))
15✔
2986
            return CPL_VALUE_STRING;
1✔
2987
    }
2988

2989
    return bIsReal ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
493,929✔
2990
}
2991

2992
/************************************************************************/
2993
/*                              CPLStrlcpy()                            */
2994
/************************************************************************/
2995

2996
/**
2997
 * Copy source string to a destination buffer.
2998
 *
2999
 * This function ensures that the destination buffer is always NUL terminated
3000
 * (provided that its length is at least 1).
3001
 *
3002
 * This function is designed to be a safer, more consistent, and less error
3003
 * prone replacement for strncpy. Its contract is identical to libbsd's strlcpy.
3004
 *
3005
 * Truncation can be detected by testing if the return value of CPLStrlcpy
3006
 * is greater or equal to nDestSize.
3007

3008
\verbatim
3009
char szDest[5] = {};
3010
if( CPLStrlcpy(szDest, "abcde", sizeof(szDest)) >= sizeof(szDest) )
3011
    fprintf(stderr, "truncation occurred !\n");
3012
\endverbatim
3013

3014
 * @param pszDest   destination buffer
3015
 * @param pszSrc    source string. Must be NUL terminated
3016
 * @param nDestSize size of destination buffer (including space for the NUL
3017
 *     terminator character)
3018
 *
3019
 * @return the length of the source string (=strlen(pszSrc))
3020
 *
3021
 * @since GDAL 1.7.0
3022
 */
3023
size_t CPLStrlcpy(char *pszDest, const char *pszSrc, size_t nDestSize)
86,738✔
3024
{
3025
    if (nDestSize == 0)
86,738✔
3026
        return strlen(pszSrc);
×
3027

3028
    char *pszDestIter = pszDest;
86,738✔
3029
    const char *pszSrcIter = pszSrc;
86,738✔
3030

3031
    --nDestSize;
86,738✔
3032
    while (nDestSize != 0 && *pszSrcIter != '\0')
802,058✔
3033
    {
3034
        *pszDestIter = *pszSrcIter;
715,320✔
3035
        ++pszDestIter;
715,320✔
3036
        ++pszSrcIter;
715,320✔
3037
        --nDestSize;
715,320✔
3038
    }
3039
    *pszDestIter = '\0';
86,738✔
3040
    return pszSrcIter - pszSrc + strlen(pszSrcIter);
86,738✔
3041
}
3042

3043
/************************************************************************/
3044
/*                              CPLStrlcat()                            */
3045
/************************************************************************/
3046

3047
/**
3048
 * Appends a source string to a destination buffer.
3049
 *
3050
 * This function ensures that the destination buffer is always NUL terminated
3051
 * (provided that its length is at least 1 and that there is at least one byte
3052
 * free in pszDest, that is to say strlen(pszDest_before) < nDestSize)
3053
 *
3054
 * This function is designed to be a safer, more consistent, and less error
3055
 * prone replacement for strncat. Its contract is identical to libbsd's strlcat.
3056
 *
3057
 * Truncation can be detected by testing if the return value of CPLStrlcat
3058
 * is greater or equal to nDestSize.
3059

3060
\verbatim
3061
char szDest[5] = {};
3062
CPLStrlcpy(szDest, "ab", sizeof(szDest));
3063
if( CPLStrlcat(szDest, "cde", sizeof(szDest)) >= sizeof(szDest) )
3064
    fprintf(stderr, "truncation occurred !\n");
3065
\endverbatim
3066

3067
 * @param pszDest   destination buffer. Must be NUL terminated before
3068
 *         running CPLStrlcat
3069
 * @param pszSrc    source string. Must be NUL terminated
3070
 * @param nDestSize size of destination buffer (including space for the
3071
 *         NUL terminator character)
3072
 *
3073
 * @return the theoretical length of the destination string after concatenation
3074
 *         (=strlen(pszDest_before) + strlen(pszSrc)).
3075
 *         If strlen(pszDest_before) >= nDestSize, then it returns
3076
 *         nDestSize + strlen(pszSrc)
3077
 *
3078
 * @since GDAL 1.7.0
3079
 */
3080
size_t CPLStrlcat(char *pszDest, const char *pszSrc, size_t nDestSize)
362✔
3081
{
3082
    char *pszDestIter = pszDest;
362✔
3083

3084
    while (nDestSize != 0 && *pszDestIter != '\0')
25,725✔
3085
    {
3086
        ++pszDestIter;
25,363✔
3087
        --nDestSize;
25,363✔
3088
    }
3089

3090
    return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
362✔
3091
}
3092

3093
/************************************************************************/
3094
/*                              CPLStrnlen()                            */
3095
/************************************************************************/
3096

3097
/**
3098
 * Returns the length of a NUL terminated string by reading at most
3099
 * the specified number of bytes.
3100
 *
3101
 * The CPLStrnlen() function returns min(strlen(pszStr), nMaxLen).
3102
 * Only the first nMaxLen bytes of the string will be read. Useful to
3103
 * test if a string contains at least nMaxLen characters without reading
3104
 * the full string up to the NUL terminating character.
3105
 *
3106
 * @param pszStr    a NUL terminated string
3107
 * @param nMaxLen   maximum number of bytes to read in pszStr
3108
 *
3109
 * @return strlen(pszStr) if the length is lesser than nMaxLen, otherwise
3110
 * nMaxLen if the NUL character has not been found in the first nMaxLen bytes.
3111
 *
3112
 * @since GDAL 1.7.0
3113
 */
3114

3115
size_t CPLStrnlen(const char *pszStr, size_t nMaxLen)
441,306✔
3116
{
3117
    size_t nLen = 0;
441,306✔
3118
    while (nLen < nMaxLen && *pszStr != '\0')
23,815,700✔
3119
    {
3120
        ++nLen;
23,374,400✔
3121
        ++pszStr;
23,374,400✔
3122
    }
3123
    return nLen;
441,306✔
3124
}
3125

3126
/************************************************************************/
3127
/*                            CSLParseCommandLine()                     */
3128
/************************************************************************/
3129

3130
/**
3131
 * Tokenize command line arguments in a list of strings.
3132
 *
3133
 * @param pszCommandLine  command line
3134
 *
3135
 * @return NULL terminated list of strings to free with CSLDestroy()
3136
 *
3137
 * @since GDAL 2.1
3138
 */
3139
char **CSLParseCommandLine(const char *pszCommandLine)
883✔
3140
{
3141
    return CSLTokenizeString(pszCommandLine);
883✔
3142
}
3143

3144
/************************************************************************/
3145
/*                              CPLToupper()                            */
3146
/************************************************************************/
3147

3148
/** Converts a (ASCII) lowercase character to uppercase.
3149
 *
3150
 * Same as standard toupper(), except that it is not locale sensitive.
3151
 *
3152
 * @since GDAL 3.9
3153
 */
3154
int CPLToupper(int c)
24,399,900✔
3155
{
3156
    return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c;
24,399,900✔
3157
}
3158

3159
/************************************************************************/
3160
/*                              CPLTolower()                            */
3161
/************************************************************************/
3162

3163
/** Converts a (ASCII) uppercase character to lowercase.
3164
 *
3165
 * Same as standard tolower(), except that it is not locale sensitive.
3166
 *
3167
 * @since GDAL 3.9
3168
 */
3169
int CPLTolower(int c)
19,010,300✔
3170
{
3171
    return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c;
19,010,300✔
3172
}
3173

3174
/************************************************************************/
3175
/*                      CPLRemoveSQLComments()                          */
3176
/************************************************************************/
3177

3178
/** Remove SQL comments from a string
3179
 *
3180
 * @param osInput Input string.
3181
 * @since GDAL 3.11
3182
 */
3183
std::string CPLRemoveSQLComments(const std::string &osInput)
33✔
3184
{
3185
    const CPLStringList aosLines(
3186
        CSLTokenizeStringComplex(osInput.c_str(), "\r\n", FALSE, FALSE));
66✔
3187
    std::string osSQL;
33✔
3188
    for (const char *pszLine : aosLines)
77✔
3189
    {
3190
        char chQuote = 0;
44✔
3191
        int i = 0;
44✔
3192
        for (; pszLine[i] != '\0'; ++i)
740✔
3193
        {
3194
            if (chQuote)
705✔
3195
            {
3196
                if (pszLine[i] == chQuote)
16✔
3197
                {
3198
                    // Deal with escaped quote character which is repeated,
3199
                    // so 'foo''bar' or "foo""bar"
3200
                    if (pszLine[i + 1] == chQuote)
5✔
3201
                    {
3202
                        i++;
2✔
3203
                    }
3204
                    else
3205
                    {
3206
                        chQuote = 0;
3✔
3207
                    }
3208
                }
3209
            }
3210
            else if (pszLine[i] == '\'' || pszLine[i] == '"')
689✔
3211
            {
3212
                chQuote = pszLine[i];
3✔
3213
            }
3214
            else if (pszLine[i] == '-' && pszLine[i + 1] == '-')
686✔
3215
            {
3216
                break;
9✔
3217
            }
3218
        }
3219
        if (i > 0)
44✔
3220
        {
3221
            if (!osSQL.empty())
37✔
3222
                osSQL += ' ';
4✔
3223
            osSQL.append(pszLine, i);
37✔
3224
        }
3225
    }
3226
    return osSQL;
66✔
3227
}
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