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

OSGeo / gdal / 12706066811

10 Jan 2025 08:38AM UTC coverage: 70.084% (-2.5%) from 72.549%
12706066811

Pull #11629

github

web-flow
Merge 9418dc48f into 0df468c56
Pull Request #11629: add uv documentation for python package

563296 of 803749 relevant lines covered (70.08%)

223434.74 hits per line

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

89.79
/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)
422,303✔
69
{
70
    char **papszRet = CSLAddStringMayFail(papszStrList, pszNewString);
422,303✔
71
    if (papszRet == nullptr && pszNewString != nullptr)
422,187✔
72
        abort();
×
73
    return papszRet;
422,187✔
74
}
75

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

82
    char *pszDup = VSI_STRDUP_VERBOSE(pszNewString);
456,890✔
83
    if (pszDup == nullptr)
456,799✔
84
        return nullptr;
×
85

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

90
    if (papszStrList == nullptr)
456,799✔
91
        papszStrListNew =
92
            static_cast<char **>(VSI_CALLOC_VERBOSE(2, sizeof(char *)));
64,260✔
93
    else
94
    {
95
        nItems = CSLCount(papszStrList);
392,539✔
96
        papszStrListNew = static_cast<char **>(
97
            VSI_REALLOC_VERBOSE(papszStrList, (nItems + 2) * sizeof(char *)));
392,568✔
98
    }
99
    if (papszStrListNew == nullptr)
456,792✔
100
    {
101
        VSIFree(pszDup);
×
102
        return nullptr;
×
103
    }
104

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

109
    return papszStrListNew;
456,792✔
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,328,100✔
133
{
134
    if (!papszStrList)
4,328,100✔
135
        return 0;
3,136,940✔
136

137
    int nItems = 0;
1,191,150✔
138

139
    while (*papszStrList != nullptr)
12,381,900✔
140
    {
141
        ++nItems;
11,190,700✔
142
        ++papszStrList;
11,190,700✔
143
    }
144

145
    return nItems;
1,191,150✔
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)
2,030✔
159

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

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

170
    return (papszStrList[iField]);
2,028✔
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,101,300✔
186
{
187
    if (!papszStrList)
12,101,300✔
188
        return;
9,567,090✔
189

190
    for (char **papszPtr = papszStrList; *papszPtr != nullptr; ++papszPtr)
12,214,900✔
191
    {
192
        CPLFree(*papszPtr);
9,678,510✔
193
    }
194

195
    CPLFree(papszStrList);
2,536,410✔
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,156,990✔
214
{
215
    const int nLines = CSLCount(papszStrList);
3,156,990✔
216

217
    if (nLines == 0)
3,147,450✔
218
        return nullptr;
3,103,700✔
219

220
    CSLConstList papszSrc = papszStrList;
43,748✔
221

222
    char **papszNewList =
223
        static_cast<char **>(VSI_MALLOC2_VERBOSE(nLines + 1, sizeof(char *)));
43,748✔
224

225
    char **papszDst = papszNewList;
53,281✔
226

227
    for (; *papszSrc != nullptr; ++papszSrc, ++papszDst)
344,475✔
228
    {
229
        *papszDst = VSI_STRDUP_VERBOSE(*papszSrc);
291,194✔
230
        if (*papszDst == nullptr)
291,194✔
231
        {
232
            CSLDestroy(papszNewList);
×
233
            return nullptr;
×
234
        }
235
    }
236
    *papszDst = nullptr;
53,281✔
237

238
    return papszNewList;
53,281✔
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)
749,326✔
259

260
{
261
    if (papszOrig == nullptr && papszOverride != nullptr)
749,326✔
262
        return CSLDuplicate(papszOverride);
624✔
263

264
    if (papszOverride == nullptr)
748,702✔
265
        return papszOrig;
746,502✔
266

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

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

276
    return papszOrig;
1,769✔
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,215✔
307
                CSLConstList papszOptions)
308
{
309
    VSILFILE *fp = VSIFOpenL(pszFname, "rb");
3,215✔
310

311
    if (!fp)
3,215✔
312
    {
313
        if (CPLFetchBool(papszOptions, "EMIT_ERROR_IF_CANNOT_OPEN_FILE", true))
2,033✔
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,033✔
320
    }
321

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

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

332
        if (nLines + 1 >= nAllocatedLines)
8,485✔
333
        {
334
            nAllocatedLines = 16 + nAllocatedLines * 2;
1,308✔
335
            char **papszStrListNew = static_cast<char **>(
336
                VSIRealloc(papszStrList, nAllocatedLines * sizeof(char *)));
1,308✔
337
            if (papszStrListNew == nullptr)
1,308✔
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,308✔
348
        }
349
        papszStrList[nLines] = CPLStrdup(pszLine);
8,485✔
350
        papszStrList[nLines + 1] = nullptr;
8,485✔
351
        ++nLines;
8,485✔
352
    }
353

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

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

359
    return papszStrList;
1,182✔
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)
311✔
383
{
384
    return CSLLoad2(pszFname, -1, -1, nullptr);
311✔
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)
49✔
398
{
399
    if (papszStrList == nullptr)
49✔
400
        return 0;
×
401

402
    VSILFILE *fp = VSIFOpenL(pszFname, "wt");
49✔
403
    if (fp == nullptr)
49✔
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;
48✔
413
    while (*papszStrList != nullptr)
385✔
414
    {
415
        if (VSIFPrintfL(fp, "%s\n", *papszStrList) < 1)
337✔
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;
337✔
424
        ++papszStrList;
337✔
425
    }
426

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

434
    return nLines;
48✔
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,375✔
483
                        CSLConstList papszNewLines)
484
{
485
    if (papszNewLines == nullptr)
17,375✔
486
        return papszStrList;  // Nothing to do!
36✔
487

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

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

495
    // Allocate room for the new strings.
496
    papszStrList = static_cast<char **>(
497
        CPLRealloc(papszStrList, (nDstLines + 1) * sizeof(char *)));
16,097✔
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,097✔
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,097✔
507
        nInsertAtLineNo = nSrcLines;
15,310✔
508

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

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

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

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

530
    return papszStrList;
16,097✔
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,
508✔
548
                       const char *pszNewLine)
549
{
550
    char *apszList[2] = {const_cast<char *>(pszNewLine), nullptr};
508✔
551

552
    return CSLInsertStrings(papszStrList, nInsertAtLineNo, apszList);
1,016✔
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,159✔
574
                        int nNumToRemove, char ***ppapszRetStrings)
575
{
576
    const int nSrcLines = CSLCount(papszStrList);
6,159✔
577

578
    if (nNumToRemove < 1 || nSrcLines == 0)
6,159✔
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,159✔
584
    if (nDstLines < 1)
6,159✔
585
    {
586
        CSLDestroy(papszStrList);
1,529✔
587
        return nullptr;
1,529✔
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;
4,630✔
594

595
    if (ppapszRetStrings == nullptr)
4,630✔
596
    {
597
        // free() all the strings that will be removed.
598
        for (int i = 0; i < nNumToRemove; ++i)
9,260✔
599
        {
600
            CPLFree(*ppszDst);
4,630✔
601
            *ppszDst = nullptr;
4,630✔
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)
4,630✔
620
        nFirstLineToDelete = nDstLines;
×
621

622
    char **ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
4,630✔
623
    ppszDst = papszStrList + nFirstLineToDelete;
4,630✔
624

625
    for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
9,152✔
626
    {
627
        *ppszDst = *ppszSrc;
4,522✔
628
    }
629
    // Move the NULL pointer at the end of the StringList.
630
    *ppszDst = *ppszSrc;
4,630✔
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;
4,630✔
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,241,650✔
656

657
{
658
    if (papszList == nullptr)
4,241,650✔
659
        return -1;
149,447✔
660

661
    for (int i = 0; papszList[i] != nullptr; ++i)
31,883,600✔
662
    {
663
        if (EQUAL(papszList[i], pszTarget))
27,968,900✔
664
            return i;
177,548✔
665
    }
666

667
    return -1;
3,914,660✔
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)
3,453✔
690

691
{
692
    if (papszList == nullptr)
3,453✔
693
        return -1;
214✔
694

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

701
    return -1;
3,225✔
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)
21,830✔
722
{
723
    if (papszHaystack == nullptr || pszNeedle == nullptr)
21,830✔
724
        return -1;
8,138✔
725

726
    for (int i = 0; papszHaystack[i] != nullptr; ++i)
30,324✔
727
    {
728
        if (strstr(papszHaystack[i], pszNeedle))
22,794✔
729
            return i;
6,162✔
730
    }
731

732
    return -1;
7,530✔
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)
179,289✔
743
{
744
    return CSLTokenizeString2(pszString, " ", CSLT_HONOURSTRINGS);
179,289✔
745
}
746

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

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

758
    if (bHonourStrings)
559,272✔
759
        nFlags |= CSLT_HONOURSTRINGS;
121,694✔
760
    if (bAllowEmptyTokens)
559,272✔
761
        nFlags |= CSLT_ALLOWEMPTYTOKENS;
17,257✔
762

763
    return CSLTokenizeString2(pszString, pszDelimiters, nFlags);
559,272✔
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,182,820✔
820
                          int nCSLTFlags)
821
{
822
    if (pszString == nullptr)
1,182,820✔
823
        return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
3,924✔
824

825
    CPLStringList oRetList;
2,357,800✔
826
    const bool bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS) != 0;
1,178,900✔
827
    const bool bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS) != 0;
1,178,900✔
828
    const bool bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES) != 0;
1,178,900✔
829
    const bool bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES) != 0;
1,178,900✔
830

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

834
    while (*pszString != '\0')
3,860,640✔
835
    {
836
        bool bInString = false;
2,681,740✔
837
        bool bStartString = true;
2,681,740✔
838
        size_t nTokenLen = 0;
2,681,740✔
839

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

862
            // End if this is a delimiter skip it and break.
863
            if (!bInString && strchr(pszDelimiters, *pszString) != nullptr)
34,060,200✔
864
            {
865
                ++pszString;
1,559,340✔
866
                break;
1,559,340✔
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 == '"')
32,500,800✔
873
            {
874
                if (nCSLTFlags & CSLT_PRESERVEQUOTES)
73,723✔
875
                {
876
                    pszToken[nTokenLen] = *pszString;
4,601✔
877
                    ++nTokenLen;
4,601✔
878
                }
879

880
                bInString = !bInString;
73,723✔
881
                continue;
73,723✔
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] == '\\')
32,427,100✔
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 &&
32,427,100✔
905
                isspace(static_cast<unsigned char>(*pszString)))
31,736✔
906
                continue;
4,658✔
907

908
            bStartString = false;
32,422,500✔
909

910
            pszToken[nTokenLen] = *pszString;
32,422,500✔
911
            ++nTokenLen;
32,422,500✔
912
        }
913

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

922
        pszToken[nTokenLen] = '\0';
2,681,740✔
923

924
        // Add the token.
925
        if (pszToken[0] != '\0' || bAllowEmptyTokens)
2,681,740✔
926
            oRetList.AddString(pszToken);
2,562,110✔
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,204,910✔
934
        strchr(pszDelimiters, *(pszString - 1)) != nullptr)
26,010✔
935
    {
936
        oRetList.AddString("");
1,235✔
937
    }
938

939
    CPLFree(pszToken);
1,178,900✔
940

941
    if (oRetList.List() == nullptr)
1,178,900✔
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,439✔
946
    }
947

948
    return oRetList.StealList();
1,178,900✔
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,223,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,223,970✔
975

976
    if (pachBufRingInfo == nullptr)
1,223,960✔
977
    {
978
        pachBufRingInfo = static_cast<char *>(CPLCalloc(
1,566✔
979
            1, sizeof(int) + CPLSPrintf_BUF_Count * CPLSPrintf_BUF_SIZE));
980
        CPLSetTLS(CTLS_CPLSPRINTF, pachBufRingInfo, TRUE);
1,566✔
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,223,960✔
988
    const size_t nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
1,223,960✔
989
    char *pachBuffer = pachBufRingInfo + nOffset;
1,223,960✔
990

991
    *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
1,223,960✔
992

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

997
    va_start(args, fmt);
1,223,960✔
998

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

1008
    va_end(args);
1,223,950✔
1009

1010
    return pachBuffer;
1,223,950✔
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),
89✔
1021
                       ...)
1022
{
1023
    va_list args;
1024

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

1030
    return CSLAddString(papszStrList, osWork);
178✔
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)
3,924,350✔
1057
{
1058
    char ch = '\0';
3,924,350✔
1059
    // Flag.
1060
    for (; (ch = *fmt) != '\0'; ++fmt)
5,109,690✔
1061
    {
1062
        if (ch == '\'')
5,109,420✔
1063
            continue;  // Bad idea as this is locale specific.
×
1064
        if (ch == '-' || ch == '+' || ch == ' ' || ch == '#' || ch == '0')
5,109,420✔
1065
            continue;
1,185,340✔
1066
        break;
3,924,080✔
1067
    }
1068

1069
    // Field width.
1070
    for (; (ch = *fmt) != '\0'; ++fmt)
5,278,770✔
1071
    {
1072
        if (ch == '$')
5,278,590✔
1073
            return nullptr;  // Do not support this.
×
1074
        if (*fmt >= '0' && *fmt <= '9')
5,278,590✔
1075
            continue;
1,354,420✔
1076
        break;
3,924,160✔
1077
    }
1078

1079
    // Precision.
1080
    if (ch == '.')
3,924,350✔
1081
    {
1082
        ++fmt;
693,345✔
1083
        for (; (ch = *fmt) != '\0'; ++fmt)
1,962,520✔
1084
        {
1085
            if (ch == '$')
1,962,520✔
1086
                return nullptr;  // Do not support this.
×
1087
            if (*fmt >= '0' && *fmt <= '9')
1,962,520✔
1088
                continue;
1,269,180✔
1089
            break;
693,345✔
1090
        }
1091
    }
1092

1093
    // Length modifier.
1094
    for (; (ch = *fmt) != '\0'; ++fmt)
4,005,990✔
1095
    {
1096
        if (ch == 'h' || ch == 'l' || ch == 'j' || ch == 'z' || ch == 't' ||
4,005,990✔
1097
            ch == 'L')
1098
            continue;
81,911✔
1099
        else if (ch == 'I' && fmt[1] == '6' && fmt[2] == '4')
3,924,080✔
1100
            fmt += 2;
×
1101
        else
1102
            return fmt;
3,924,350✔
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,115,790✔
1132
                 va_list args)
1133
{
1134
    if (size == 0)
2,115,790✔
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,115,790✔
1141
#else
1142
    wrk_args = args;
1143
#endif
1144

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

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

1177
            const char *ptrend = CPLvsnprintf_get_end_of_formatting(fmt + 1);
3,924,310✔
1178
            if (ptrend == nullptr || ptrend - fmt >= 20)
3,924,280✔
1179
            {
1180
                bFormatUnknown = true;
56✔
1181
                break;
56✔
1182
            }
1183
            char end = *ptrend;
3,924,220✔
1184
            char end_m1 = ptrend[-1];
3,924,220✔
1185

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

1190
            int local_ret = 0;
3,924,220✔
1191
            if (end == '%')
3,924,220✔
1192
            {
1193
                if (offset_out == size - 1)
14,614✔
1194
                    break;
×
1195
                local_ret = 1;
14,614✔
1196
                str[offset_out] = '%';
14,614✔
1197
            }
1198
            else if (end == 'd' || end == 'i' || end == 'c')
3,909,610✔
1199
            {
1200
                if (end_m1 == 'h')
939,298✔
1201
                    call_native_snprintf(int);
×
1202
                else if (end_m1 == 'l' && ptrend[-2] != 'l')
939,298✔
1203
                    call_native_snprintf(long);
2,195✔
1204
                else if (end_m1 == 'l' && ptrend[-2] == 'l')
937,103✔
1205
                    call_native_snprintf(GIntBig);
23,587✔
1206
                else if (end_m1 == '4' && ptrend[-2] == '6' &&
913,516✔
1207
                         ptrend[-3] == 'I')
×
1208
                    // Microsoft I64 modifier.
1209
                    call_native_snprintf(GIntBig);
×
1210
                else if (end_m1 == 'z')
913,516✔
1211
                    call_native_snprintf(size_t);
×
1212
                else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
913,516✔
1213
                         (end_m1 >= 'A' && end_m1 <= 'Z'))
×
1214
                {
1215
                    bFormatUnknown = true;
×
1216
                    break;
×
1217
                }
1218
                else
1219
                    call_native_snprintf(int);
913,516✔
1220
            }
1221
            else if (end == 'o' || end == 'u' || end == 'x' || end == 'X')
2,970,310✔
1222
            {
1223
                if (end_m1 == 'h')
1,202,050✔
1224
                    call_native_snprintf(unsigned int);
×
1225
                else if (end_m1 == 'l' && ptrend[-2] != 'l')
1,202,050✔
1226
                    call_native_snprintf(unsigned long);
439✔
1227
                else if (end_m1 == 'l' && ptrend[-2] == 'l')
1,201,610✔
1228
                    call_native_snprintf(GUIntBig);
13,083✔
1229
                else if (end_m1 == '4' && ptrend[-2] == '6' &&
1,188,530✔
1230
                         ptrend[-3] == 'I')
×
1231
                    // Microsoft I64 modifier.
1232
                    call_native_snprintf(GUIntBig);
×
1233
                else if (end_m1 == 'z')
1,188,530✔
1234
                    call_native_snprintf(size_t);
×
1235
                else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
1,188,530✔
1236
                         (end_m1 >= 'A' && end_m1 <= 'Z'))
×
1237
                {
1238
                    bFormatUnknown = true;
×
1239
                    break;
×
1240
                }
1241
                else
1242
                    call_native_snprintf(unsigned int);
1,188,530✔
1243
            }
1244
            else if (end == 'e' || end == 'E' || end == 'f' || end == 'F' ||
1,768,260✔
1245
                     end == 'g' || end == 'G' || end == 'a' || end == 'A')
1,051,190✔
1246
            {
1247
                if (end_m1 == 'L')
716,868✔
1248
                    call_native_snprintf(long double);
×
1249
                else
1250
                    call_native_snprintf(double);
716,868✔
1251
                // MSVC vsnprintf() returns -1.
1252
                if (local_ret < 0 || offset_out + local_ret >= size)
716,719✔
1253
                    break;
1254
                for (int j = 0; j < local_ret; ++j)
10,199,600✔
1255
                {
1256
                    if (str[offset_out + j] == ',')
9,482,990✔
1257
                    {
1258
                        str[offset_out + j] = '.';
×
1259
                        break;
×
1260
                    }
1261
                }
716,631✔
1262
            }
1263
            else if (end == 's')
1,051,390✔
1264
            {
1265
                const char *pszPtr = va_arg(wrk_args, const char *);
1,047,330✔
1266
                CPLAssert(pszPtr);
1,047,230✔
1267
                local_ret = snprintf(str + offset_out, size - offset_out,
1,047,440✔
1268
                                     localfmt, pszPtr);
1269
            }
1270
            else if (end == 'p')
4,066✔
1271
            {
1272
                call_native_snprintf(void *);
3,191✔
1273
            }
1274
            else
1275
            {
1276
                bFormatUnknown = true;
875✔
1277
                break;
875✔
1278
            }
1279
            // MSVC vsnprintf() returns -1.
1280
            if (local_ret < 0 || offset_out + local_ret >= size)
3,923,330✔
1281
                break;
1282
            offset_out += local_ret;
3,922,290✔
1283
            fmt = ptrend;
3,922,290✔
1284
        }
1285
        else
1286
        {
1287
            if (offset_out == size - 1)
26,913,900✔
1288
                break;
588✔
1289
            str[offset_out++] = *fmt;
26,913,400✔
1290
        }
1291
    }
1292
    if (ch == '\0' && offset_out < size)
2,115,420✔
1293
        str[offset_out] = '\0';
2,113,210✔
1294
    else
1295
    {
1296
        if (bFormatUnknown)
2,213✔
1297
        {
1298
            CPLDebug("CPL",
784✔
1299
                     "CPLvsnprintf() called with unsupported "
1300
                     "formatting string: %s",
1301
                     fmt_ori);
1302
        }
1303
#ifdef va_copy
1304
        va_end(wrk_args);
2,240✔
1305
        va_copy(wrk_args, args);
2,240✔
1306
#else
1307
        wrk_args = args;
1308
#endif
1309
#if defined(HAVE_VSNPRINTF)
1310
        offset_out = vsnprintf(str, size, fmt_ori, wrk_args);
2,240✔
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,115,450✔
1318
#endif
1319

1320
    return static_cast<int>(offset_out);
2,115,450✔
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), ...)
173,237✔
1352
{
1353
    va_list args;
1354

1355
    va_start(args, fmt);
173,237✔
1356
    const int ret = CPLvsnprintf(str, size, fmt, args);
173,237✔
1357
    va_end(args);
173,237✔
1358
    return ret;
173,237✔
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,806✔
1471
#endif
1472
{
1473
    bool error = false;
1,806✔
1474
    int ret = 0;
1,806✔
1475
    const char *fmt_ori = fmt;
1,806✔
1476
    va_list args;
1477

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

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

1520
    return ret;
1,806✔
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)
2,514,460✔
1543
{
1544
    return !(EQUAL(pszValue, "NO") || EQUAL(pszValue, "FALSE") ||
3,201,920✔
1545
             EQUAL(pszValue, "OFF") || EQUAL(pszValue, "0"));
3,201,920✔
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)
655✔
1568
{
1569
    return CPLTestBool(pszValue) ? TRUE : FALSE;
655✔
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)
40✔
1590
{
1591
    return CPLTestBool(pszValue) ? TRUE : FALSE;
40✔
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)
225,253✔
1615

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

1620
    const char *const pszValue = CSLFetchNameValue(papszStrList, pszKey);
225,204✔
1621
    if (pszValue == nullptr)
225,234✔
1622
        return bDefault;
210,582✔
1623

1624
    return CPLTestBool(pszValue);
14,652✔
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,366✔
1648

1649
{
1650
    return CPLFetchBool(papszStrList, pszKey, CPL_TO_BOOL(bDefault));
1,366✔
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,
459,131✔
1659
                                 const char *pszDefault)
1660

1661
{
1662
    const char *pszResult = CSLFetchNameValue(papszStrList, pszName);
459,131✔
1663
    if (pszResult != nullptr)
459,088✔
1664
        return pszResult;
41,676✔
1665

1666
    return pszDefault;
417,412✔
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)
13,371,500✔
1686
{
1687
    if (papszStrList == nullptr || pszName == nullptr)
13,371,500✔
1688
        return nullptr;
4,058,830✔
1689

1690
    const size_t nLen = strlen(pszName);
9,312,670✔
1691
    while (*papszStrList != nullptr)
14,057,300✔
1692
    {
1693
        if (EQUALN(*papszStrList, pszName, nLen) &&
4,928,310✔
1694
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
186,965✔
1695
        {
1696
            return (*papszStrList) + nLen + 1;
183,711✔
1697
        }
1698
        ++papszStrList;
4,744,600✔
1699
    }
1700
    return nullptr;
9,128,960✔
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)
15,929,700✔
1718
{
1719
    if (papszStrList == nullptr || pszName == nullptr)
15,929,700✔
1720
        return -1;
532,881✔
1721

1722
    const size_t nLen = strlen(pszName);
15,396,800✔
1723
    int iIndex = 0;
15,396,800✔
1724
    while (*papszStrList != nullptr)
124,032,000✔
1725
    {
1726
        if (EQUALN(*papszStrList, pszName, nLen) &&
116,617,000✔
1727
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
8,614,930✔
1728
        {
1729
            return iIndex;
7,981,200✔
1730
        }
1731
        ++iIndex;
108,636,000✔
1732
        ++papszStrList;
108,636,000✔
1733
    }
1734
    return -1;
7,415,580✔
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,
629✔
1759
                          bool *pbUnitSpecified)
1760
{
1761
    const char *start = pszValue;
629✔
1762
    char *end = nullptr;
629✔
1763

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

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

1775
    if (end == start)
629✔
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))
626✔
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++)
1,186✔
1790
    {
1791
        if (unit == nullptr)
567✔
1792
        {
1793
            // check various suffixes and convert number into bytes
1794
            if (*c == '%')
559✔
1795
            {
1796
                if (value < 0 || value > 100)
546✔
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();
544✔
1803
                if (bytes == 0)
544✔
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);
544✔
1810
                unit = c;
544✔
1811
            }
1812
            else
1813
            {
1814
                switch (*c)
13✔
1815
                {
1816
                    case 'G':
×
1817
                    case 'g':
1818
                        value *= 1024;  // fall-through
×
1819
                    case 'M':
4✔
1820
                    case 'm':
1821
                        value *= 1024;  // fall-through
4✔
1822
                    case 'K':
8✔
1823
                    case 'k':
1824
                        value *= 1024;
8✔
1825
                        unit = c;
8✔
1826
                        unitIsNotPercent = true;
8✔
1827
                        break;
8✔
1828
                    case ' ':
3✔
1829
                        break;
3✔
1830
                    default:
2✔
1831
                        CPLError(CE_Failure, CPLE_IllegalArg,
2✔
1832
                                 "Unexpected value: %s", pszValue);
1833
                        return CE_Failure;
2✔
1834
                }
1835
            }
1836
        }
1837
        else if (unitIsNotPercent && c == unit + 1 && (*c == 'b' || *c == 'B'))
8✔
1838
        {
1839
            // ignore 'B' or 'b' as part of unit
1840
            continue;
7✔
1841
        }
1842
        else if (*c != ' ')
1✔
1843
        {
1844
            CPLError(CE_Failure, CPLE_IllegalArg, "Unexpected value: %s",
1✔
1845
                     pszValue);
1846
            return CE_Failure;
1✔
1847
        }
1848
    }
1849

1850
    *pnValue = static_cast<GIntBig>(value);
619✔
1851
    if (pbUnitSpecified)
619✔
1852
    {
1853
        *pbUnitSpecified = (unit != nullptr);
616✔
1854
    }
1855
    return CE_None;
619✔
1856
}
1857

1858
/**********************************************************************
1859
 *                       CPLParseNameValue()
1860
 **********************************************************************/
1861

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

1883
const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey)
73,594✔
1884
{
1885
    for (int i = 0; pszNameValue[i] != '\0'; ++i)
1,036,760✔
1886
    {
1887
        if (pszNameValue[i] == '=' || pszNameValue[i] == ':')
1,033,630✔
1888
        {
1889
            const char *pszValue = pszNameValue + i + 1;
70,461✔
1890
            while (*pszValue == ' ' || *pszValue == '\t')
78,863✔
1891
                ++pszValue;
8,402✔
1892

1893
            if (ppszKey != nullptr)
70,461✔
1894
            {
1895
                *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
70,439✔
1896
                memcpy(*ppszKey, pszNameValue, i);
70,439✔
1897
                (*ppszKey)[i] = '\0';
70,439✔
1898
                while (i > 0 &&
70,710✔
1899
                       ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
70,710✔
1900
                {
1901
                    (*ppszKey)[i - 1] = '\0';
271✔
1902
                    i--;
271✔
1903
                }
1904
            }
1905

1906
            return pszValue;
70,461✔
1907
        }
1908
    }
1909

1910
    return nullptr;
3,133✔
1911
}
1912

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

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

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

1954
            return pszValue;
15✔
1955
        }
1956
    }
1957

1958
    return nullptr;
2✔
1959
}
1960

1961
/**********************************************************************
1962
 *                       CSLFetchNameValueMultiple()
1963
 **********************************************************************/
1964

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

1978
char **CSLFetchNameValueMultiple(CSLConstList papszStrList, const char *pszName)
11,555✔
1979
{
1980
    if (papszStrList == nullptr || pszName == nullptr)
11,555✔
1981
        return nullptr;
4,678✔
1982

1983
    const size_t nLen = strlen(pszName);
6,877✔
1984
    char **papszValues = nullptr;
6,877✔
1985
    while (*papszStrList != nullptr)
17,593✔
1986
    {
1987
        if (EQUALN(*papszStrList, pszName, nLen) &&
10,716✔
1988
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
55✔
1989
        {
1990
            papszValues = CSLAddString(papszValues, (*papszStrList) + nLen + 1);
55✔
1991
        }
1992
        ++papszStrList;
10,716✔
1993
    }
1994

1995
    return papszValues;
6,877✔
1996
}
1997

1998
/**********************************************************************
1999
 *                       CSLAddNameValue()
2000
 **********************************************************************/
2001

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

2013
char **CSLAddNameValue(char **papszStrList, const char *pszName,
395,202✔
2014
                       const char *pszValue)
2015
{
2016
    if (pszName == nullptr || pszValue == nullptr)
395,202✔
2017
        return papszStrList;
38✔
2018

2019
    const size_t nLen = strlen(pszName) + strlen(pszValue) + 2;
395,164✔
2020
    char *pszLine = static_cast<char *>(CPLMalloc(nLen));
395,164✔
2021
    snprintf(pszLine, nLen, "%s=%s", pszName, pszValue);
395,162✔
2022
    papszStrList = CSLAddString(papszStrList, pszLine);
395,162✔
2023
    CPLFree(pszLine);
395,095✔
2024

2025
    return papszStrList;
395,178✔
2026
}
2027

2028
/************************************************************************/
2029
/*                          CSLSetNameValue()                           */
2030
/************************************************************************/
2031

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

2052
char **CSLSetNameValue(char **papszList, const char *pszName,
423,148✔
2053
                       const char *pszValue)
2054
{
2055
    if (pszName == nullptr)
423,148✔
2056
        return papszList;
38✔
2057

2058
    size_t nLen = strlen(pszName);
423,110✔
2059
    while (nLen > 0 && pszName[nLen - 1] == ' ')
423,784✔
2060
        nLen--;
674✔
2061
    char **papszPtr = papszList;
423,110✔
2062
    while (papszPtr && *papszPtr != nullptr)
7,057,960✔
2063
    {
2064
        if (EQUALN(*papszPtr, pszName, nLen))
6,672,450✔
2065
        {
2066
            size_t i;
2067
            for (i = nLen; (*papszPtr)[i] == ' '; ++i)
39,973✔
2068
            {
2069
            }
2070
            if ((*papszPtr)[i] == '=' || (*papszPtr)[i] == ':')
39,299✔
2071
            {
2072
                // Found it.
2073
                // Change the value... make sure to keep the ':' or '='.
2074
                const char cSep = (*papszPtr)[i];
37,606✔
2075

2076
                CPLFree(*papszPtr);
37,606✔
2077

2078
                // If the value is NULL, remove this entry completely.
2079
                if (pszValue == nullptr)
37,553✔
2080
                {
2081
                    while (papszPtr[1] != nullptr)
40,475✔
2082
                    {
2083
                        *papszPtr = papszPtr[1];
10,532✔
2084
                        ++papszPtr;
10,532✔
2085
                    }
2086
                    *papszPtr = nullptr;
29,943✔
2087
                }
2088

2089
                // Otherwise replace with new value.
2090
                else
2091
                {
2092
                    const size_t nLen2 = strlen(pszName) + strlen(pszValue) + 2;
7,610✔
2093
                    *papszPtr = static_cast<char *>(CPLMalloc(nLen2));
7,610✔
2094
                    snprintf(*papszPtr, nLen2, "%s%c%s", pszName, cSep,
7,605✔
2095
                             pszValue);
2096
                }
2097
                return papszList;
37,548✔
2098
            }
2099
        }
2100
        ++papszPtr;
6,634,850✔
2101
    }
2102

2103
    if (pszValue == nullptr)
385,504✔
2104
        return papszList;
4,287✔
2105

2106
    // The name does not exist yet.  Create a new entry.
2107
    return CSLAddNameValue(papszList, pszName, pszValue);
381,217✔
2108
}
2109

2110
/************************************************************************/
2111
/*                      CSLSetNameValueSeparator()                      */
2112
/************************************************************************/
2113

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

2133
void CSLSetNameValueSeparator(char **papszList, const char *pszSeparator)
89✔
2134

2135
{
2136
    const int nLines = CSLCount(papszList);
89✔
2137

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

2148
        char *pszNewLine = static_cast<char *>(CPLMalloc(
1,376✔
2149
            strlen(pszValue) + strlen(pszKey) + strlen(pszSeparator) + 1));
688✔
2150
        strcpy(pszNewLine, pszKey);
688✔
2151
        strcat(pszNewLine, pszSeparator);
688✔
2152
        strcat(pszNewLine, pszValue);
688✔
2153
        CPLFree(papszList[iLine]);
688✔
2154
        papszList[iLine] = pszNewLine;
688✔
2155
        CPLFree(pszKey);
688✔
2156
    }
2157
}
89✔
2158

2159
/************************************************************************/
2160
/*                          CPLEscapeString()                           */
2161
/************************************************************************/
2162

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

2211
char *CPLEscapeString(const char *pszInput, int nLength, int nScheme)
614,491✔
2212
{
2213
    const size_t szLength =
614,491✔
2214
        (nLength < 0) ? strlen(pszInput) : static_cast<size_t>(nLength);
614,491✔
2215
#define nLength no_longer_use_me
2216

2217
    size_t nSizeAlloc = 1;
614,491✔
2218
#if SIZEOF_VOIDP < 8
2219
    bool bWrapAround = false;
2220
    const auto IncSizeAlloc = [&nSizeAlloc, &bWrapAround](size_t inc)
2221
    {
2222
        constexpr size_t SZ_MAX = std::numeric_limits<size_t>::max();
2223
        if (nSizeAlloc > SZ_MAX - inc)
2224
        {
2225
            bWrapAround = true;
2226
            nSizeAlloc = 0;
2227
        }
2228
        nSizeAlloc += inc;
2229
    };
2230
#else
2231
    const auto IncSizeAlloc = [&nSizeAlloc](size_t inc) { nSizeAlloc += inc; };
42,021,000✔
2232
#endif
2233

2234
    if (nScheme == CPLES_BackslashQuotable)
614,491✔
2235
    {
2236
        for (size_t iIn = 0; iIn < szLength; iIn++)
45,751✔
2237
        {
2238
            if (pszInput[iIn] == '\0' || pszInput[iIn] == '\n' ||
45,631✔
2239
                pszInput[iIn] == '"' || pszInput[iIn] == '\\')
44,877✔
2240
                IncSizeAlloc(2);
876✔
2241
            else
2242
                IncSizeAlloc(1);
44,755✔
2243
        }
2244
    }
2245
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
614,371✔
2246
    {
2247
        for (size_t iIn = 0; iIn < szLength; ++iIn)
41,938,500✔
2248
        {
2249
            if (pszInput[iIn] == '<')
41,327,100✔
2250
            {
2251
                IncSizeAlloc(4);
1,420✔
2252
            }
2253
            else if (pszInput[iIn] == '>')
41,325,700✔
2254
            {
2255
                IncSizeAlloc(4);
1,570✔
2256
            }
2257
            else if (pszInput[iIn] == '&')
41,324,100✔
2258
            {
2259
                IncSizeAlloc(5);
845✔
2260
            }
2261
            else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
41,323,300✔
2262
            {
2263
                IncSizeAlloc(6);
1,910✔
2264
            }
2265
            // Python 2 does not display the UTF-8 character corresponding
2266
            // to the byte-order mark (BOM), so escape it.
2267
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
41,321,400✔
2268
                         0xEF &&
2✔
2269
                     (reinterpret_cast<const unsigned char *>(
2270
                         pszInput))[iIn + 1] == 0xBB &&
2✔
2271
                     (reinterpret_cast<const unsigned char *>(
2272
                         pszInput))[iIn + 2] == 0xBF)
2✔
2273
            {
2274
                IncSizeAlloc(8);
2✔
2275
                iIn += 2;
2✔
2276
            }
2277
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
41,321,400✔
2278
                         0x20 &&
22,186✔
2279
                     pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
22,186✔
2280
                     pszInput[iIn] != 0xD)
110✔
2281
            {
2282
                // These control characters are unrepresentable in XML format,
2283
                // so we just drop them.  #4117
2284
            }
2285
            else
2286
            {
2287
                IncSizeAlloc(1);
41,321,400✔
2288
            }
2289
        }
611,350✔
2290
    }
2291
    else if (nScheme == CPLES_URL)  // Untested at implementation.
3,021✔
2292
    {
2293
        for (size_t iIn = 0; iIn < szLength; ++iIn)
10,203✔
2294
        {
2295
            if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
9,707✔
2296
                (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
3,748✔
2297
                (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
1,873✔
2298
                pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
938✔
2299
                pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
897✔
2300
                pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
520✔
2301
                pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
502✔
2302
                pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
500✔
2303
                pszInput[iIn] == ',')
490✔
2304
            {
2305
                IncSizeAlloc(1);
9,223✔
2306
            }
2307
            else
2308
            {
2309
                IncSizeAlloc(3);
484✔
2310
            }
2311
        }
2312
    }
2313
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2,525✔
2314
    {
2315
        const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
785✔
2316
        for (size_t iIn = 0; iIn < szLength; ++iIn)
11,632✔
2317
        {
2318
            if (pszInput[iIn] == chQuote)
10,847✔
2319
            {
2320
                IncSizeAlloc(2);
7✔
2321
            }
2322
            else
2323
            {
2324
                IncSizeAlloc(1);
10,840✔
2325
            }
2326
        }
785✔
2327
    }
2328
    else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
1,740✔
2329
    {
2330
        if (nScheme == CPLES_CSV && strcspn(pszInput, "\",;\t\n\r") == szLength)
1,740✔
2331
        {
2332
            char *pszOutput =
2333
                static_cast<char *>(VSI_MALLOC_VERBOSE(szLength + 1));
1,517✔
2334
            if (pszOutput == nullptr)
1,517✔
2335
                return nullptr;
×
2336
            memcpy(pszOutput, pszInput, szLength + 1);
1,517✔
2337
            return pszOutput;
1,517✔
2338
        }
2339
        else
2340
        {
2341
            IncSizeAlloc(1);
223✔
2342
            for (size_t iIn = 0; iIn < szLength; ++iIn)
12,991✔
2343
            {
2344
                if (pszInput[iIn] == '\"')
12,768✔
2345
                {
2346
                    IncSizeAlloc(2);
169✔
2347
                }
2348
                else
2349
                    IncSizeAlloc(1);
12,599✔
2350
            }
2351
            IncSizeAlloc(1);
223✔
2352
        }
223✔
2353
    }
2354
    else
2355
    {
2356
        CPLError(CE_Failure, CPLE_AppDefined,
×
2357
                 "Undefined escaping scheme (%d) in CPLEscapeString()",
2358
                 nScheme);
2359
        return CPLStrdup("");
×
2360
    }
2361

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

2371
    char *pszOutput = static_cast<char *>(VSI_MALLOC_VERBOSE(nSizeAlloc));
612,974✔
2372
    if (pszOutput == nullptr)
612,974✔
2373
        return nullptr;
×
2374

2375
    size_t iOut = 0;
612,974✔
2376

2377
    if (nScheme == CPLES_BackslashQuotable)
612,974✔
2378
    {
2379
        for (size_t iIn = 0; iIn < szLength; iIn++)
45,751✔
2380
        {
2381
            if (pszInput[iIn] == '\0')
45,631✔
2382
            {
2383
                pszOutput[iOut++] = '\\';
689✔
2384
                pszOutput[iOut++] = '0';
689✔
2385
            }
2386
            else if (pszInput[iIn] == '\n')
44,942✔
2387
            {
2388
                pszOutput[iOut++] = '\\';
65✔
2389
                pszOutput[iOut++] = 'n';
65✔
2390
            }
2391
            else if (pszInput[iIn] == '"')
44,877✔
2392
            {
2393
                pszOutput[iOut++] = '\\';
121✔
2394
                pszOutput[iOut++] = '\"';
121✔
2395
            }
2396
            else if (pszInput[iIn] == '\\')
44,756✔
2397
            {
2398
                pszOutput[iOut++] = '\\';
1✔
2399
                pszOutput[iOut++] = '\\';
1✔
2400
            }
2401
            else
2402
                pszOutput[iOut++] = pszInput[iIn];
44,755✔
2403
        }
2404
        pszOutput[iOut++] = '\0';
120✔
2405
    }
2406
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
612,854✔
2407
    {
2408
        for (size_t iIn = 0; iIn < szLength; ++iIn)
41,938,500✔
2409
        {
2410
            if (pszInput[iIn] == '<')
41,327,100✔
2411
            {
2412
                pszOutput[iOut++] = '&';
1,420✔
2413
                pszOutput[iOut++] = 'l';
1,420✔
2414
                pszOutput[iOut++] = 't';
1,420✔
2415
                pszOutput[iOut++] = ';';
1,420✔
2416
            }
2417
            else if (pszInput[iIn] == '>')
41,325,700✔
2418
            {
2419
                pszOutput[iOut++] = '&';
1,570✔
2420
                pszOutput[iOut++] = 'g';
1,570✔
2421
                pszOutput[iOut++] = 't';
1,570✔
2422
                pszOutput[iOut++] = ';';
1,570✔
2423
            }
2424
            else if (pszInput[iIn] == '&')
41,324,100✔
2425
            {
2426
                pszOutput[iOut++] = '&';
845✔
2427
                pszOutput[iOut++] = 'a';
845✔
2428
                pszOutput[iOut++] = 'm';
845✔
2429
                pszOutput[iOut++] = 'p';
845✔
2430
                pszOutput[iOut++] = ';';
845✔
2431
            }
2432
            else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
41,323,300✔
2433
            {
2434
                pszOutput[iOut++] = '&';
1,910✔
2435
                pszOutput[iOut++] = 'q';
1,910✔
2436
                pszOutput[iOut++] = 'u';
1,910✔
2437
                pszOutput[iOut++] = 'o';
1,910✔
2438
                pszOutput[iOut++] = 't';
1,910✔
2439
                pszOutput[iOut++] = ';';
1,910✔
2440
            }
2441
            // Python 2 does not display the UTF-8 character corresponding
2442
            // to the byte-order mark (BOM), so escape it.
2443
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
41,321,400✔
2444
                         0xEF &&
2✔
2445
                     (reinterpret_cast<const unsigned char *>(
2446
                         pszInput))[iIn + 1] == 0xBB &&
2✔
2447
                     (reinterpret_cast<const unsigned char *>(
2448
                         pszInput))[iIn + 2] == 0xBF)
2✔
2449
            {
2450
                pszOutput[iOut++] = '&';
2✔
2451
                pszOutput[iOut++] = '#';
2✔
2452
                pszOutput[iOut++] = 'x';
2✔
2453
                pszOutput[iOut++] = 'F';
2✔
2454
                pszOutput[iOut++] = 'E';
2✔
2455
                pszOutput[iOut++] = 'F';
2✔
2456
                pszOutput[iOut++] = 'F';
2✔
2457
                pszOutput[iOut++] = ';';
2✔
2458
                iIn += 2;
2✔
2459
            }
2460
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
41,321,400✔
2461
                         0x20 &&
22,186✔
2462
                     pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
22,186✔
2463
                     pszInput[iIn] != 0xD)
110✔
2464
            {
2465
                // These control characters are unrepresentable in XML format,
2466
                // so we just drop them.  #4117
2467
            }
2468
            else
2469
            {
2470
                pszOutput[iOut++] = pszInput[iIn];
41,321,400✔
2471
            }
2472
        }
2473
        pszOutput[iOut++] = '\0';
611,350✔
2474
    }
2475
    else if (nScheme == CPLES_URL)  // Untested at implementation.
1,504✔
2476
    {
2477
        for (size_t iIn = 0; iIn < szLength; ++iIn)
10,203✔
2478
        {
2479
            if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
9,707✔
2480
                (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
3,748✔
2481
                (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
1,873✔
2482
                pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
938✔
2483
                pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
897✔
2484
                pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
520✔
2485
                pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
502✔
2486
                pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
500✔
2487
                pszInput[iIn] == ',')
490✔
2488
            {
2489
                pszOutput[iOut++] = pszInput[iIn];
9,223✔
2490
            }
2491
            else
2492
            {
2493
                snprintf(pszOutput + iOut, nSizeAlloc - iOut, "%%%02X",
484✔
2494
                         static_cast<unsigned char>(pszInput[iIn]));
484✔
2495
                iOut += 3;
484✔
2496
            }
2497
        }
2498
        pszOutput[iOut++] = '\0';
496✔
2499
    }
2500
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
1,008✔
2501
    {
2502
        const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
785✔
2503
        for (size_t iIn = 0; iIn < szLength; ++iIn)
11,632✔
2504
        {
2505
            if (pszInput[iIn] == chQuote)
10,847✔
2506
            {
2507
                pszOutput[iOut++] = chQuote;
7✔
2508
                pszOutput[iOut++] = chQuote;
7✔
2509
            }
2510
            else
2511
            {
2512
                pszOutput[iOut++] = pszInput[iIn];
10,840✔
2513
            }
2514
        }
2515
        pszOutput[iOut++] = '\0';
785✔
2516
    }
2517
    else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
223✔
2518
    {
2519
        pszOutput[iOut++] = '\"';
223✔
2520

2521
        for (size_t iIn = 0; iIn < szLength; ++iIn)
12,991✔
2522
        {
2523
            if (pszInput[iIn] == '\"')
12,768✔
2524
            {
2525
                pszOutput[iOut++] = '\"';
169✔
2526
                pszOutput[iOut++] = '\"';
169✔
2527
            }
2528
            else
2529
                pszOutput[iOut++] = pszInput[iIn];
12,599✔
2530
        }
2531
        pszOutput[iOut++] = '\"';
223✔
2532
        pszOutput[iOut++] = '\0';
223✔
2533
    }
2534

2535
    return pszOutput;
612,974✔
2536
#undef nLength
2537
}
2538

2539
/************************************************************************/
2540
/*                         CPLUnescapeString()                          */
2541
/************************************************************************/
2542

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

2560
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
2561
char *CPLUnescapeString(const char *pszInput, int *pnLength, int nScheme)
33,691✔
2562

2563
{
2564
    int iOut = 0;
33,691✔
2565

2566
    // TODO: Why times 4?
2567
    char *pszOutput = static_cast<char *>(CPLMalloc(4 * strlen(pszInput) + 1));
33,691✔
2568
    pszOutput[0] = '\0';
33,691✔
2569

2570
    if (nScheme == CPLES_BackslashQuotable)
33,691✔
2571
    {
2572
        for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
53,012✔
2573
        {
2574
            if (pszInput[iIn] == '\\')
52,566✔
2575
            {
2576
                ++iIn;
769✔
2577
                if (pszInput[iIn] == '\0')
769✔
2578
                    break;
×
2579
                if (pszInput[iIn] == 'n')
769✔
2580
                    pszOutput[iOut++] = '\n';
6✔
2581
                else if (pszInput[iIn] == '0')
763✔
2582
                    pszOutput[iOut++] = '\0';
675✔
2583
                else
2584
                    pszOutput[iOut++] = pszInput[iIn];
88✔
2585
            }
2586
            else
2587
            {
2588
                pszOutput[iOut++] = pszInput[iIn];
51,797✔
2589
            }
2590
        }
2591
    }
2592
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
33,245✔
2593
    {
2594
        char ch = '\0';
32,622✔
2595
        for (int iIn = 0; (ch = pszInput[iIn]) != '\0'; ++iIn)
32,910,900✔
2596
        {
2597
            if (ch != '&')
32,878,300✔
2598
            {
2599
                pszOutput[iOut++] = ch;
32,544,400✔
2600
            }
2601
            else if (STARTS_WITH_CI(pszInput + iIn, "&lt;"))
333,830✔
2602
            {
2603
                pszOutput[iOut++] = '<';
20,565✔
2604
                iIn += 3;
20,565✔
2605
            }
2606
            else if (STARTS_WITH_CI(pszInput + iIn, "&gt;"))
313,265✔
2607
            {
2608
                pszOutput[iOut++] = '>';
20,716✔
2609
                iIn += 3;
20,716✔
2610
            }
2611
            else if (STARTS_WITH_CI(pszInput + iIn, "&amp;"))
292,549✔
2612
            {
2613
                pszOutput[iOut++] = '&';
206,603✔
2614
                iIn += 4;
206,603✔
2615
            }
2616
            else if (STARTS_WITH_CI(pszInput + iIn, "&apos;"))
85,946✔
2617
            {
2618
                pszOutput[iOut++] = '\'';
686✔
2619
                iIn += 5;
686✔
2620
            }
2621
            else if (STARTS_WITH_CI(pszInput + iIn, "&quot;"))
85,260✔
2622
            {
2623
                pszOutput[iOut++] = '"';
85,096✔
2624
                iIn += 5;
85,096✔
2625
            }
2626
            else if (STARTS_WITH_CI(pszInput + iIn, "&#x"))
164✔
2627
            {
2628
                wchar_t anVal[2] = {0, 0};
3✔
2629
                iIn += 3;
3✔
2630

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

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

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

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

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

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

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

2764
    pszOutput[iOut] = '\0';
33,691✔
2765

2766
    if (pnLength != nullptr)
33,691✔
2767
        *pnLength = iOut;
21,784✔
2768

2769
    return pszOutput;
33,691✔
2770
}
2771

2772
/************************************************************************/
2773
/*                           CPLBinaryToHex()                           */
2774
/************************************************************************/
2775

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

2785
char *CPLBinaryToHex(int nBytes, const GByte *pabyData)
4,210✔
2786

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

2798
    constexpr char achHex[] = "0123456789ABCDEF";
4,210✔
2799

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

2805
        pszHex[i * 2] = achHex[nHigh];
243,880✔
2806
        pszHex[i * 2 + 1] = achHex[nLow];
243,880✔
2807
    }
2808

2809
    return pszHex;
4,210✔
2810
}
2811

2812
/************************************************************************/
2813
/*                           CPLHexToBinary()                           */
2814
/************************************************************************/
2815

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

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

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

2851
    GByte *pabyWKB = static_cast<GByte *>(CPLMalloc(nHexLen / 2 + 2));
3,913✔
2852

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

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

2864
    return pabyWKB;
3,913✔
2865
}
2866

2867
/************************************************************************/
2868
/*                         CPLGetValueType()                            */
2869
/************************************************************************/
2870

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

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

2891
    if (pszValue == nullptr)
551,190✔
2892
        return CPL_VALUE_STRING;
×
2893

2894
    const char *pszValueInit = pszValue;
551,190✔
2895

2896
    // Skip leading spaces.
2897
    while (isspace(static_cast<unsigned char>(*pszValue)))
551,241✔
2898
        ++pszValue;
51✔
2899

2900
    if (*pszValue == '\0')
551,190✔
2901
        return CPL_VALUE_STRING;
370✔
2902

2903
    // Skip leading + or -.
2904
    if (*pszValue == '+' || *pszValue == '-')
550,820✔
2905
        ++pszValue;
85,435✔
2906

2907
    constexpr char DIGIT_ZERO = '0';
550,820✔
2908
    if (pszValue[0] == DIGIT_ZERO && pszValue[1] != '\0' && pszValue[1] != '.')
550,820✔
2909
        return CPL_VALUE_STRING;
901✔
2910

2911
    bool bFoundDot = false;
549,919✔
2912
    bool bFoundExponent = false;
549,919✔
2913
    bool bIsLastCharExponent = false;
549,919✔
2914
    bool bIsReal = false;
549,919✔
2915
    const char *pszAfterExponent = nullptr;
549,919✔
2916
    bool bFoundMantissa = false;
549,919✔
2917

2918
    for (; *pszValue != '\0'; ++pszValue)
6,965,090✔
2919
    {
2920
        if (isdigit(static_cast<unsigned char>(*pszValue)))
6,463,320✔
2921
        {
2922
            bIsLastCharExponent = false;
6,026,160✔
2923
            bFoundMantissa = true;
6,026,160✔
2924
        }
2925
        else if (isspace(static_cast<unsigned char>(*pszValue)))
437,153✔
2926
        {
2927
            const char *pszTmp = pszValue;
764✔
2928
            while (isspace(static_cast<unsigned char>(*pszTmp)))
1,532✔
2929
                ++pszTmp;
768✔
2930
            if (*pszTmp == 0)
764✔
2931
                break;
24✔
2932
            else
2933
                return CPL_VALUE_STRING;
740✔
2934
        }
2935
        else if (*pszValue == '-' || *pszValue == '+')
436,389✔
2936
        {
2937
            if (bIsLastCharExponent)
853✔
2938
            {
2939
                // Do nothing.
2940
            }
2941
            else
2942
            {
2943
                return CPL_VALUE_STRING;
340✔
2944
            }
2945
            bIsLastCharExponent = false;
513✔
2946
        }
2947
        else if (*pszValue == '.')
435,536✔
2948
        {
2949
            bIsReal = true;
387,983✔
2950
            if (!bFoundDot && !bIsLastCharExponent)
387,983✔
2951
                bFoundDot = true;
387,980✔
2952
            else
2953
                return CPL_VALUE_STRING;
3✔
2954
            bIsLastCharExponent = false;
387,980✔
2955
        }
2956
        else if (*pszValue == 'D' || *pszValue == 'd' || *pszValue == 'E' ||
47,553✔
2957
                 *pszValue == 'e')
42,810✔
2958
        {
2959
            if (!bFoundMantissa)
5,007✔
2960
                return CPL_VALUE_STRING;
4,485✔
2961
            if (!(pszValue[1] == '+' || pszValue[1] == '-' ||
522✔
2962
                  isdigit(static_cast<unsigned char>(pszValue[1]))))
9✔
2963
                return CPL_VALUE_STRING;
2✔
2964

2965
            bIsReal = true;
520✔
2966
            if (!bFoundExponent)
520✔
2967
                bFoundExponent = true;
519✔
2968
            else
2969
                return CPL_VALUE_STRING;
1✔
2970
            pszAfterExponent = pszValue + 1;
519✔
2971
            bIsLastCharExponent = true;
519✔
2972
        }
2973
        else
2974
        {
2975
            return CPL_VALUE_STRING;
42,546✔
2976
        }
2977
    }
2978

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

2987
    return bIsReal ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
501,801✔
2988
}
2989

2990
/************************************************************************/
2991
/*                              CPLStrlcpy()                            */
2992
/************************************************************************/
2993

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

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

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

3026
    char *pszDestIter = pszDest;
4,560,700✔
3027
    const char *pszSrcIter = pszSrc;
4,560,700✔
3028

3029
    --nDestSize;
4,560,700✔
3030
    while (nDestSize != 0 && *pszSrcIter != '\0')
36,814,800✔
3031
    {
3032
        *pszDestIter = *pszSrcIter;
32,254,100✔
3033
        ++pszDestIter;
32,254,100✔
3034
        ++pszSrcIter;
32,254,100✔
3035
        --nDestSize;
32,254,100✔
3036
    }
3037
    *pszDestIter = '\0';
4,560,700✔
3038
    return pszSrcIter - pszSrc + strlen(pszSrcIter);
4,560,700✔
3039
}
3040

3041
/************************************************************************/
3042
/*                              CPLStrlcat()                            */
3043
/************************************************************************/
3044

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

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

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

3082
    while (nDestSize != 0 && *pszDestIter != '\0')
80,143,100✔
3083
    {
3084
        ++pszDestIter;
78,294,900✔
3085
        --nDestSize;
78,294,900✔
3086
    }
3087

3088
    return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
1,848,250✔
3089
}
3090

3091
/************************************************************************/
3092
/*                              CPLStrnlen()                            */
3093
/************************************************************************/
3094

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

3113
size_t CPLStrnlen(const char *pszStr, size_t nMaxLen)
419,009✔
3114
{
3115
    size_t nLen = 0;
419,009✔
3116
    while (nLen < nMaxLen && *pszStr != '\0')
18,323,400✔
3117
    {
3118
        ++nLen;
17,904,400✔
3119
        ++pszStr;
17,904,400✔
3120
    }
3121
    return nLen;
419,009✔
3122
}
3123

3124
/************************************************************************/
3125
/*                            CSLParseCommandLine()                     */
3126
/************************************************************************/
3127

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

3142
/************************************************************************/
3143
/*                              CPLToupper()                            */
3144
/************************************************************************/
3145

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

3157
/************************************************************************/
3158
/*                              CPLTolower()                            */
3159
/************************************************************************/
3160

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

3172
/************************************************************************/
3173
/*                      CPLRemoveSQLComments()                          */
3174
/************************************************************************/
3175

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