Coverage Report

Created: 2025-06-09 08:44

/src/gdal/port/cpl_string.cpp
Line
Count
Source (jump to first uncovered line)
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)
69
14.7M
{
70
14.7M
    char **papszRet = CSLAddStringMayFail(papszStrList, pszNewString);
71
14.7M
    if (papszRet == nullptr && pszNewString != nullptr)
72
0
        abort();
73
14.7M
    return papszRet;
74
14.7M
}
75
76
/** Same as CSLAddString() but may return NULL in case of (memory) failure */
77
char **CSLAddStringMayFail(char **papszStrList, const char *pszNewString)
78
16.2M
{
79
16.2M
    if (pszNewString == nullptr)
80
0
        return papszStrList;  // Nothing to do!
81
82
16.2M
    char *pszDup = VSI_STRDUP_VERBOSE(pszNewString);
83
16.2M
    if (pszDup == nullptr)
84
0
        return nullptr;
85
86
    // Allocate room for the new string.
87
16.2M
    char **papszStrListNew = nullptr;
88
16.2M
    int nItems = 0;
89
90
16.2M
    if (papszStrList == nullptr)
91
1.64M
        papszStrListNew =
92
1.64M
            static_cast<char **>(VSI_CALLOC_VERBOSE(2, sizeof(char *)));
93
14.5M
    else
94
14.5M
    {
95
14.5M
        nItems = CSLCount(papszStrList);
96
14.5M
        papszStrListNew = static_cast<char **>(
97
14.5M
            VSI_REALLOC_VERBOSE(papszStrList, (nItems + 2) * sizeof(char *)));
98
14.5M
    }
99
16.2M
    if (papszStrListNew == nullptr)
100
0
    {
101
0
        VSIFree(pszDup);
102
0
        return nullptr;
103
0
    }
104
105
    // Copy the string in the list.
106
16.2M
    papszStrListNew[nItems] = pszDup;
107
16.2M
    papszStrListNew[nItems + 1] = nullptr;
108
109
16.2M
    return papszStrListNew;
110
16.2M
}
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)
133
124M
{
134
124M
    if (!papszStrList)
135
5.75M
        return 0;
136
137
118M
    int nItems = 0;
138
139
7.23G
    while (*papszStrList != nullptr)
140
7.11G
    {
141
7.11G
        ++nItems;
142
7.11G
        ++papszStrList;
143
7.11G
    }
144
145
118M
    return nItems;
146
124M
}
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)
159
160
5.00M
{
161
5.00M
    if (papszStrList == nullptr || iField < 0)
162
0
        return ("");
163
164
9.94M
    for (int i = 0; i < iField + 1; i++)
165
5.07M
    {
166
5.07M
        if (papszStrList[i] == nullptr)
167
128k
            return "";
168
5.07M
    }
169
170
4.87M
    return (papszStrList[iField]);
171
5.00M
}
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)
186
553M
{
187
553M
    if (!papszStrList)
188
288M
        return;
189
190
753M
    for (char **papszPtr = papszStrList; *papszPtr != nullptr; ++papszPtr)
191
488M
    {
192
488M
        CPLFree(*papszPtr);
193
488M
    }
194
195
264M
    CPLFree(papszStrList);
196
264M
}
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)
214
5.82M
{
215
5.82M
    const int nLines = CSLCount(papszStrList);
216
217
5.82M
    if (nLines == 0)
218
5.31M
        return nullptr;
219
220
510k
    CSLConstList papszSrc = papszStrList;
221
222
510k
    char **papszNewList =
223
510k
        static_cast<char **>(VSI_MALLOC2_VERBOSE(nLines + 1, sizeof(char *)));
224
225
510k
    char **papszDst = papszNewList;
226
227
8.99M
    for (; *papszSrc != nullptr; ++papszSrc, ++papszDst)
228
8.48M
    {
229
8.48M
        *papszDst = VSI_STRDUP_VERBOSE(*papszSrc);
230
8.48M
        if (*papszDst == nullptr)
231
0
        {
232
0
            CSLDestroy(papszNewList);
233
0
            return nullptr;
234
0
        }
235
8.48M
    }
236
510k
    *papszDst = nullptr;
237
238
510k
    return papszNewList;
239
510k
}
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)
259
260
132k
{
261
132k
    if (papszOrig == nullptr && papszOverride != nullptr)
262
4.50k
        return CSLDuplicate(papszOverride);
263
264
127k
    if (papszOverride == nullptr)
265
107k
        return papszOrig;
266
267
156k
    for (int i = 0; papszOverride[i] != nullptr; ++i)
268
136k
    {
269
136k
        char *pszKey = nullptr;
270
136k
        const char *pszValue = CPLParseNameValue(papszOverride[i], &pszKey);
271
272
136k
        papszOrig = CSLSetNameValue(papszOrig, pszKey, pszValue);
273
136k
        CPLFree(pszKey);
274
136k
    }
275
276
20.7k
    return papszOrig;
277
127k
}
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,
307
                CSLConstList papszOptions)
308
54.0k
{
309
54.0k
    VSILFILE *fp = VSIFOpenL(pszFname, "rb");
310
311
54.0k
    if (!fp)
312
374
    {
313
374
        if (CPLFetchBool(papszOptions, "EMIT_ERROR_IF_CANNOT_OPEN_FILE", true))
314
52
        {
315
            // Unable to open file.
316
52
            CPLError(CE_Failure, CPLE_OpenFailed,
317
52
                     "CSLLoad2(\"%s\") failed: unable to open file.", pszFname);
318
52
        }
319
374
        return nullptr;
320
374
    }
321
322
53.6k
    char **papszStrList = nullptr;
323
53.6k
    int nLines = 0;
324
53.6k
    int nAllocatedLines = 0;
325
326
23.2M
    while (!VSIFEofL(fp) && (nMaxLines == -1 || nLines < nMaxLines))
327
23.2M
    {
328
23.2M
        const char *pszLine = CPLReadLine2L(fp, nMaxCols, papszOptions);
329
23.2M
        if (pszLine == nullptr)
330
31.0k
            break;
331
332
23.1M
        if (nLines + 1 >= nAllocatedLines)
333
159k
        {
334
159k
            nAllocatedLines = 16 + nAllocatedLines * 2;
335
159k
            char **papszStrListNew = static_cast<char **>(
336
159k
                VSIRealloc(papszStrList, nAllocatedLines * sizeof(char *)));
337
159k
            if (papszStrListNew == nullptr)
338
0
            {
339
0
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
340
0
                CPLReadLineL(nullptr);
341
0
                CPLError(CE_Failure, CPLE_OutOfMemory,
342
0
                         "CSLLoad2(\"%s\") "
343
0
                         "failed: not enough memory to allocate lines.",
344
0
                         pszFname);
345
0
                return papszStrList;
346
0
            }
347
159k
            papszStrList = papszStrListNew;
348
159k
        }
349
23.1M
        papszStrList[nLines] = CPLStrdup(pszLine);
350
23.1M
        papszStrList[nLines + 1] = nullptr;
351
23.1M
        ++nLines;
352
23.1M
    }
353
354
53.6k
    CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
355
356
    // Free the internal thread local line buffer.
357
53.6k
    CPLReadLineL(nullptr);
358
359
53.6k
    return papszStrList;
360
53.6k
}
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)
383
37.6k
{
384
37.6k
    return CSLLoad2(pszFname, -1, -1, nullptr);
385
37.6k
}
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)
398
205
{
399
205
    if (papszStrList == nullptr)
400
0
        return 0;
401
402
205
    VSILFILE *fp = VSIFOpenL(pszFname, "wt");
403
205
    if (fp == nullptr)
404
0
    {
405
        // Unable to open file.
406
0
        CPLError(CE_Failure, CPLE_OpenFailed,
407
0
                 "CSLSave(\"%s\") failed: unable to open output file.",
408
0
                 pszFname);
409
0
        return 0;
410
0
    }
411
412
205
    int nLines = 0;
413
34.8k
    while (*papszStrList != nullptr)
414
34.6k
    {
415
34.6k
        if (VSIFPrintfL(fp, "%s\n", *papszStrList) < 1)
416
0
        {
417
0
            CPLError(CE_Failure, CPLE_FileIO,
418
0
                     "CSLSave(\"%s\") failed: unable to write to output file.",
419
0
                     pszFname);
420
0
            break;  // A Problem happened... abort.
421
0
        }
422
423
34.6k
        ++nLines;
424
34.6k
        ++papszStrList;
425
34.6k
    }
426
427
205
    if (VSIFCloseL(fp) != 0)
428
0
    {
429
0
        CPLError(CE_Failure, CPLE_FileIO,
430
0
                 "CSLSave(\"%s\") failed: unable to write to output file.",
431
0
                 pszFname);
432
0
    }
433
434
205
    return nLines;
435
205
}
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
0
{
448
0
    if (!papszStrList)
449
0
        return 0;
450
451
0
    if (fpOut == nullptr)
452
0
        fpOut = stdout;
453
454
0
    int nLines = 0;
455
456
0
    while (*papszStrList != nullptr)
457
0
    {
458
0
        if (VSIFPrintf(fpOut, "%s\n", *papszStrList) < 0)
459
0
            return nLines;
460
0
        ++nLines;
461
0
        ++papszStrList;
462
0
    }
463
464
0
    return nLines;
465
0
}
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,
483
                        CSLConstList papszNewLines)
484
70.9k
{
485
70.9k
    if (papszNewLines == nullptr)
486
12
        return papszStrList;  // Nothing to do!
487
488
70.8k
    const int nToInsert = CSLCount(papszNewLines);
489
70.8k
    if (nToInsert == 0)
490
0
        return papszStrList;  // Nothing to do!
491
492
70.8k
    const int nSrcLines = CSLCount(papszStrList);
493
70.8k
    const int nDstLines = nSrcLines + nToInsert;
494
495
    // Allocate room for the new strings.
496
70.8k
    papszStrList = static_cast<char **>(
497
70.8k
        CPLRealloc(papszStrList, (nDstLines + 1) * sizeof(char *)));
498
499
    // Make sure the array is NULL-terminated.  It may not be if
500
    // papszStrList was NULL before Realloc().
501
70.8k
    papszStrList[nSrcLines] = nullptr;
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
70.8k
    if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
507
63.0k
        nInsertAtLineNo = nSrcLines;
508
509
70.8k
    {
510
70.8k
        char **ppszSrc = papszStrList + nSrcLines;
511
70.8k
        char **ppszDst = papszStrList + nDstLines;
512
513
672k
        for (int i = nSrcLines; i >= nInsertAtLineNo; --i)
514
601k
        {
515
601k
            *ppszDst = *ppszSrc;
516
601k
            --ppszDst;
517
601k
            --ppszSrc;
518
601k
        }
519
70.8k
    }
520
521
    // Copy the strings to the list.
522
70.8k
    CSLConstList ppszSrc = papszNewLines;
523
70.8k
    char **ppszDst = papszStrList + nInsertAtLineNo;
524
525
352k
    for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
526
281k
    {
527
281k
        *ppszDst = CPLStrdup(*ppszSrc);
528
281k
    }
529
530
70.8k
    return papszStrList;
531
70.8k
}
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,
548
                       const char *pszNewLine)
549
7.46k
{
550
7.46k
    char *apszList[2] = {const_cast<char *>(pszNewLine), nullptr};
551
552
7.46k
    return CSLInsertStrings(papszStrList, nInsertAtLineNo, apszList);
553
7.46k
}
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,
574
                        int nNumToRemove, char ***ppapszRetStrings)
575
11.2k
{
576
11.2k
    const int nSrcLines = CSLCount(papszStrList);
577
578
11.2k
    if (nNumToRemove < 1 || nSrcLines == 0)
579
0
        return papszStrList;  // Nothing to do!
580
581
    // If operation will result in an empty StringList, don't waste
582
    // time here.
583
11.2k
    const int nDstLines = nSrcLines - nNumToRemove;
584
11.2k
    if (nDstLines < 1)
585
4.57k
    {
586
4.57k
        CSLDestroy(papszStrList);
587
4.57k
        return nullptr;
588
4.57k
    }
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
6.62k
    char **ppszDst = papszStrList + nFirstLineToDelete;
594
595
6.62k
    if (ppapszRetStrings == nullptr)
596
6.62k
    {
597
        // free() all the strings that will be removed.
598
13.2k
        for (int i = 0; i < nNumToRemove; ++i)
599
6.62k
        {
600
6.62k
            CPLFree(*ppszDst);
601
6.62k
            *ppszDst = nullptr;
602
6.62k
        }
603
6.62k
    }
604
0
    else
605
0
    {
606
        // Store the strings to remove in a new StringList.
607
0
        *ppapszRetStrings =
608
0
            static_cast<char **>(CPLCalloc(nNumToRemove + 1, sizeof(char *)));
609
610
0
        for (int i = 0; i < nNumToRemove; ++i)
611
0
        {
612
0
            (*ppapszRetStrings)[i] = *ppszDst;
613
0
            *ppszDst = nullptr;
614
0
            ++ppszDst;
615
0
        }
616
0
    }
617
618
    // Shift down all the lines that follow the lines to remove.
619
6.62k
    if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines)
620
0
        nFirstLineToDelete = nDstLines;
621
622
6.62k
    char **ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
623
6.62k
    ppszDst = papszStrList + nFirstLineToDelete;
624
625
12.1k
    for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
626
5.49k
    {
627
5.49k
        *ppszDst = *ppszSrc;
628
5.49k
    }
629
    // Move the NULL pointer at the end of the StringList.
630
6.62k
    *ppszDst = *ppszSrc;
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
6.62k
    return papszStrList;
636
11.2k
}
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)
656
657
44.4M
{
658
44.4M
    if (papszList == nullptr)
659
3.66M
        return -1;
660
661
103M
    for (int i = 0; papszList[i] != nullptr; ++i)
662
64.6M
    {
663
64.6M
        if (EQUAL(papszList[i], pszTarget))
664
1.96M
            return i;
665
64.6M
    }
666
667
38.8M
    return -1;
668
40.8M
}
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)
690
691
20.5k
{
692
20.5k
    if (papszList == nullptr)
693
15.7k
        return -1;
694
695
19.9k
    for (int i = 0; papszList[i] != nullptr; ++i)
696
15.1k
    {
697
15.1k
        if (strcmp(papszList[i], pszTarget) == 0)
698
16
            return i;
699
15.1k
    }
700
701
4.73k
    return -1;
702
4.75k
}
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)
722
138k
{
723
138k
    if (papszHaystack == nullptr || pszNeedle == nullptr)
724
120k
        return -1;
725
726
265k
    for (int i = 0; papszHaystack[i] != nullptr; ++i)
727
258k
    {
728
258k
        if (strstr(papszHaystack[i], pszNeedle))
729
11.2k
            return i;
730
258k
    }
731
732
6.90k
    return -1;
733
18.1k
}
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)
743
24.9M
{
744
24.9M
    return CSLTokenizeString2(pszString, " ", CSLT_HONOURSTRINGS);
745
24.9M
}
746
747
/************************************************************************/
748
/*                      CSLTokenizeStringComplex()                      */
749
/************************************************************************/
750
751
/** Obsolete tokenizing api. Use CSLTokenizeString2() */
752
char **CSLTokenizeStringComplex(const char *pszString,
753
                                const char *pszDelimiters, int bHonourStrings,
754
                                int bAllowEmptyTokens)
755
38.8M
{
756
38.8M
    int nFlags = 0;
757
758
38.8M
    if (bHonourStrings)
759
28.7M
        nFlags |= CSLT_HONOURSTRINGS;
760
38.8M
    if (bAllowEmptyTokens)
761
593k
        nFlags |= CSLT_ALLOWEMPTYTOKENS;
762
763
38.8M
    return CSLTokenizeString2(pszString, pszDelimiters, nFlags);
764
38.8M
}
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,
820
                          int nCSLTFlags)
821
93.1M
{
822
93.1M
    if (pszString == nullptr)
823
346k
        return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
824
825
92.8M
    CPLStringList oRetList;
826
92.8M
    const bool bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS) != 0;
827
92.8M
    const bool bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS) != 0;
828
92.8M
    const bool bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES) != 0;
829
92.8M
    const bool bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES) != 0;
830
831
92.8M
    char *pszToken = static_cast<char *>(CPLCalloc(10, 1));
832
92.8M
    size_t nTokenMax = 10;
833
834
350M
    while (*pszString != '\0')
835
257M
    {
836
257M
        bool bInString = false;
837
257M
        bool bStartString = true;
838
257M
        size_t nTokenLen = 0;
839
840
        // Try to find the next delimiter, marking end of token.
841
3.66G
        for (; *pszString != '\0'; ++pszString)
842
3.59G
        {
843
            // Extend token buffer if we are running close to its end.
844
3.59G
            if (nTokenLen >= nTokenMax - 3)
845
66.8M
            {
846
66.8M
                if (nTokenMax > std::numeric_limits<size_t>::max() / 2)
847
0
                {
848
0
                    CPLFree(pszToken);
849
0
                    return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
850
0
                }
851
66.8M
                nTokenMax = nTokenMax * 2;
852
66.8M
                char *pszNewToken = static_cast<char *>(
853
66.8M
                    VSI_REALLOC_VERBOSE(pszToken, nTokenMax));
854
66.8M
                if (pszNewToken == nullptr)
855
0
                {
856
0
                    CPLFree(pszToken);
857
0
                    return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
858
0
                }
859
66.8M
                pszToken = pszNewToken;
860
66.8M
            }
861
862
            // End if this is a delimiter skip it and break.
863
3.59G
            if (!bInString && strchr(pszDelimiters, *pszString) != nullptr)
864
185M
            {
865
185M
                ++pszString;
866
185M
                break;
867
185M
            }
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
3.41G
            if (bHonourStrings && *pszString == '"')
873
17.7M
            {
874
17.7M
                if (nCSLTFlags & CSLT_PRESERVEQUOTES)
875
9.77M
                {
876
9.77M
                    pszToken[nTokenLen] = *pszString;
877
9.77M
                    ++nTokenLen;
878
9.77M
                }
879
880
17.7M
                bInString = !bInString;
881
17.7M
                continue;
882
17.7M
            }
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
3.39G
            if (bInString && pszString[0] == '\\')
890
646k
            {
891
646k
                if (pszString[1] == '"' || pszString[1] == '\\')
892
336k
                {
893
336k
                    if (nCSLTFlags & CSLT_PRESERVEESCAPES)
894
60.1k
                    {
895
60.1k
                        pszToken[nTokenLen] = *pszString;
896
60.1k
                        ++nTokenLen;
897
60.1k
                    }
898
899
336k
                    ++pszString;
900
336k
                }
901
646k
            }
902
903
            // Strip spaces at the token start if requested.
904
3.39G
            if (!bInString && bStripLeadSpaces && bStartString &&
905
3.39G
                isspace(static_cast<unsigned char>(*pszString)))
906
277k
                continue;
907
908
3.39G
            bStartString = false;
909
910
3.39G
            pszToken[nTokenLen] = *pszString;
911
3.39G
            ++nTokenLen;
912
3.39G
        }
913
914
        // Strip spaces at the token end if requested.
915
257M
        if (!bInString && bStripEndSpaces)
916
4.38M
        {
917
4.54M
            while (nTokenLen &&
918
4.54M
                   isspace(static_cast<unsigned char>(pszToken[nTokenLen - 1])))
919
158k
                nTokenLen--;
920
4.38M
        }
921
922
257M
        pszToken[nTokenLen] = '\0';
923
924
        // Add the token.
925
257M
        if (pszToken[0] != '\0' || bAllowEmptyTokens)
926
185M
            oRetList.AddString(pszToken);
927
257M
    }
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
92.8M
    if (*pszString == '\0' && bAllowEmptyTokens && oRetList.Count() > 0 &&
934
92.8M
        strchr(pszDelimiters, *(pszString - 1)) != nullptr)
935
505k
    {
936
505k
        oRetList.AddString("");
937
505k
    }
938
939
92.8M
    CPLFree(pszToken);
940
941
92.8M
    if (oRetList.List() == nullptr)
942
17.9M
    {
943
        // Prefer to return empty lists as a pointer to
944
        // a null pointer since some client code might depend on this.
945
17.9M
        oRetList.Assign(static_cast<char **>(CPLCalloc(sizeof(char *), 1)));
946
17.9M
    }
947
948
92.8M
    return oRetList.StealList();
949
92.8M
}
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), ...)
968
276M
{
969
276M
    va_list args;
970
971
    /* -------------------------------------------------------------------- */
972
    /*      Get the thread local buffer ring data.                          */
973
    /* -------------------------------------------------------------------- */
974
276M
    char *pachBufRingInfo = static_cast<char *>(CPLGetTLS(CTLS_CPLSPRINTF));
975
976
276M
    if (pachBufRingInfo == nullptr)
977
171
    {
978
171
        pachBufRingInfo = static_cast<char *>(CPLCalloc(
979
171
            1, sizeof(int) + CPLSPrintf_BUF_Count * CPLSPrintf_BUF_SIZE));
980
171
        CPLSetTLS(CTLS_CPLSPRINTF, pachBufRingInfo, TRUE);
981
171
    }
982
983
    /* -------------------------------------------------------------------- */
984
    /*      Work out which string in the "ring" we want to use this         */
985
    /*      time.                                                           */
986
    /* -------------------------------------------------------------------- */
987
276M
    int *pnBufIndex = reinterpret_cast<int *>(pachBufRingInfo);
988
276M
    const size_t nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
989
276M
    char *pachBuffer = pachBufRingInfo + nOffset;
990
991
276M
    *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
992
993
    /* -------------------------------------------------------------------- */
994
    /*      Format the result.                                              */
995
    /* -------------------------------------------------------------------- */
996
997
276M
    va_start(args, fmt);
998
999
276M
    const int ret =
1000
276M
        CPLvsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE - 1, fmt, args);
1001
276M
    if (ret < 0 || ret >= CPLSPrintf_BUF_SIZE - 1)
1002
1.08k
    {
1003
1.08k
        CPLError(CE_Failure, CPLE_AppDefined,
1004
1.08k
                 "CPLSPrintf() called with too "
1005
1.08k
                 "big string. Output will be truncated !");
1006
1.08k
    }
1007
1008
276M
    va_end(args);
1009
1010
276M
    return pachBuffer;
1011
276M
}
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),
1021
                       ...)
1022
14.6k
{
1023
14.6k
    va_list args;
1024
1025
14.6k
    va_start(args, fmt);
1026
14.6k
    CPLString osWork;
1027
14.6k
    osWork.vPrintf(fmt, args);
1028
14.6k
    va_end(args);
1029
1030
14.6k
    return CSLAddString(papszStrList, osWork);
1031
14.6k
}
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
0
{
1042
0
    CPLString osWork;
1043
1044
0
    osWork.vPrintf(fmt, ap);
1045
1046
0
    if (buf)
1047
0
        *buf = CPLStrdup(osWork.c_str());
1048
1049
0
    return static_cast<int>(osWork.size());
1050
0
}
1051
1052
/************************************************************************/
1053
/*                  CPLvsnprintf_get_end_of_formatting()                */
1054
/************************************************************************/
1055
1056
static const char *CPLvsnprintf_get_end_of_formatting(const char *fmt)
1057
867M
{
1058
867M
    char ch = '\0';
1059
    // Flag.
1060
1.10G
    for (; (ch = *fmt) != '\0'; ++fmt)
1061
1.10G
    {
1062
1.10G
        if (ch == '\'')
1063
0
            continue;  // Bad idea as this is locale specific.
1064
1.10G
        if (ch == '-' || ch == '+' || ch == ' ' || ch == '#' || ch == '0')
1065
239M
            continue;
1066
867M
        break;
1067
1.10G
    }
1068
1069
    // Field width.
1070
1.10G
    for (; (ch = *fmt) != '\0'; ++fmt)
1071
1.10G
    {
1072
1.10G
        if (ch == '$')
1073
0
            return nullptr;  // Do not support this.
1074
1.10G
        if (*fmt >= '0' && *fmt <= '9')
1075
239M
            continue;
1076
867M
        break;
1077
1.10G
    }
1078
1079
    // Precision.
1080
867M
    if (ch == '.')
1081
11.7M
    {
1082
11.7M
        ++fmt;
1083
30.2M
        for (; (ch = *fmt) != '\0'; ++fmt)
1084
30.2M
        {
1085
30.2M
            if (ch == '$')
1086
0
                return nullptr;  // Do not support this.
1087
30.2M
            if (*fmt >= '0' && *fmt <= '9')
1088
18.5M
                continue;
1089
11.7M
            break;
1090
30.2M
        }
1091
11.7M
    }
1092
1093
    // Length modifier.
1094
937M
    for (; (ch = *fmt) != '\0'; ++fmt)
1095
937M
    {
1096
937M
        if (ch == 'h' || ch == 'l' || ch == 'j' || ch == 'z' || ch == 't' ||
1097
937M
            ch == 'L')
1098
69.3M
            continue;
1099
867M
        else if (ch == 'I' && fmt[1] == '6' && fmt[2] == '4')
1100
0
            fmt += 2;
1101
867M
        else
1102
867M
            return fmt;
1103
937M
    }
1104
1105
0
    return nullptr;
1106
867M
}
1107
1108
/************************************************************************/
1109
/*                           CPLvsnprintf()                             */
1110
/************************************************************************/
1111
1112
#define call_native_snprintf(type)                                             \
1113
507M
    local_ret = snprintf(str + offset_out, size - offset_out, localfmt,        \
1114
507M
                         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),
1132
                 va_list args)
1133
566M
{
1134
566M
    if (size == 0)
1135
0
        return vsnprintf(str, size, fmt, args);
1136
1137
566M
    va_list wrk_args;
1138
1139
566M
#ifdef va_copy
1140
566M
    va_copy(wrk_args, args);
1141
#else
1142
    wrk_args = args;
1143
#endif
1144
1145
566M
    const char *fmt_ori = fmt;
1146
566M
    size_t offset_out = 0;
1147
566M
    char ch = '\0';
1148
566M
    bool bFormatUnknown = false;
1149
1150
8.48G
    for (; (ch = *fmt) != '\0'; ++fmt)
1151
7.92G
    {
1152
7.92G
        if (ch == '%')
1153
867M
        {
1154
867M
            if (strncmp(fmt, "%.*f", 4) == 0)
1155
2.54k
            {
1156
2.54k
                const int precision = va_arg(wrk_args, int);
1157
2.54k
                const double val = va_arg(wrk_args, double);
1158
2.54k
                const int local_ret =
1159
2.54k
                    snprintf(str + offset_out, size - offset_out, "%.*f",
1160
2.54k
                             precision, val);
1161
                // MSVC vsnprintf() returns -1.
1162
2.54k
                if (local_ret < 0 || offset_out + local_ret >= size)
1163
0
                    break;
1164
51.3k
                for (int j = 0; j < local_ret; ++j)
1165
48.8k
                {
1166
48.8k
                    if (str[offset_out + j] == ',')
1167
0
                    {
1168
0
                        str[offset_out + j] = '.';
1169
0
                        break;
1170
0
                    }
1171
48.8k
                }
1172
2.54k
                offset_out += local_ret;
1173
2.54k
                fmt += strlen("%.*f") - 1;
1174
2.54k
                continue;
1175
2.54k
            }
1176
1177
867M
            const char *ptrend = CPLvsnprintf_get_end_of_formatting(fmt + 1);
1178
867M
            if (ptrend == nullptr || ptrend - fmt >= 20)
1179
0
            {
1180
0
                bFormatUnknown = true;
1181
0
                break;
1182
0
            }
1183
867M
            char end = *ptrend;
1184
867M
            char end_m1 = ptrend[-1];
1185
1186
867M
            char localfmt[22] = {};
1187
867M
            memcpy(localfmt, fmt, ptrend - fmt + 1);
1188
867M
            localfmt[ptrend - fmt + 1] = '\0';
1189
1190
867M
            int local_ret = 0;
1191
867M
            if (end == '%')
1192
200M
            {
1193
200M
                if (offset_out == size - 1)
1194
0
                    break;
1195
200M
                local_ret = 1;
1196
200M
                str[offset_out] = '%';
1197
200M
            }
1198
667M
            else if (end == 'd' || end == 'i' || end == 'c')
1199
172M
            {
1200
172M
                if (end_m1 == 'h')
1201
0
                    call_native_snprintf(int);
1202
172M
                else if (end_m1 == 'l' && ptrend[-2] != 'l')
1203
948k
                    call_native_snprintf(long);
1204
171M
                else if (end_m1 == 'l' && ptrend[-2] == 'l')
1205
5.70M
                    call_native_snprintf(GIntBig);
1206
165M
                else if (end_m1 == '4' && ptrend[-2] == '6' &&
1207
165M
                         ptrend[-3] == 'I')
1208
                    // Microsoft I64 modifier.
1209
0
                    call_native_snprintf(GIntBig);
1210
165M
                else if (end_m1 == 'z')
1211
0
                    call_native_snprintf(size_t);
1212
165M
                else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
1213
165M
                         (end_m1 >= 'A' && end_m1 <= 'Z'))
1214
0
                {
1215
0
                    bFormatUnknown = true;
1216
0
                    break;
1217
0
                }
1218
165M
                else
1219
165M
                    call_native_snprintf(int);
1220
172M
            }
1221
495M
            else if (end == 'o' || end == 'u' || end == 'x' || end == 'X')
1222
324M
            {
1223
324M
                if (end_m1 == 'h')
1224
18
                    call_native_snprintf(unsigned int);
1225
324M
                else if (end_m1 == 'l' && ptrend[-2] != 'l')
1226
666k
                    call_native_snprintf(unsigned long);
1227
324M
                else if (end_m1 == 'l' && ptrend[-2] == 'l')
1228
28.1M
                    call_native_snprintf(GUIntBig);
1229
295M
                else if (end_m1 == '4' && ptrend[-2] == '6' &&
1230
295M
                         ptrend[-3] == 'I')
1231
                    // Microsoft I64 modifier.
1232
0
                    call_native_snprintf(GUIntBig);
1233
295M
                else if (end_m1 == 'z')
1234
0
                    call_native_snprintf(size_t);
1235
295M
                else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
1236
295M
                         (end_m1 >= 'A' && end_m1 <= 'Z'))
1237
0
                {
1238
0
                    bFormatUnknown = true;
1239
0
                    break;
1240
0
                }
1241
295M
                else
1242
295M
                    call_native_snprintf(unsigned int);
1243
324M
            }
1244
170M
            else if (end == 'e' || end == 'E' || end == 'f' || end == 'F' ||
1245
170M
                     end == 'g' || end == 'G' || end == 'a' || end == 'A')
1246
9.71M
            {
1247
9.71M
                if (end_m1 == 'L')
1248
0
                    call_native_snprintf(long double);
1249
9.71M
                else
1250
9.71M
                    call_native_snprintf(double);
1251
                // MSVC vsnprintf() returns -1.
1252
9.71M
                if (local_ret < 0 || offset_out + local_ret >= size)
1253
6.02k
                    break;
1254
114M
                for (int j = 0; j < local_ret; ++j)
1255
104M
                {
1256
104M
                    if (str[offset_out + j] == ',')
1257
0
                    {
1258
0
                        str[offset_out + j] = '.';
1259
0
                        break;
1260
0
                    }
1261
104M
                }
1262
9.70M
            }
1263
161M
            else if (end == 's')
1264
160M
            {
1265
160M
                const char *pszPtr = va_arg(wrk_args, const char *);
1266
160M
                CPLAssert(pszPtr);
1267
160M
                local_ret = snprintf(str + offset_out, size - offset_out,
1268
160M
                                     localfmt, pszPtr);
1269
160M
            }
1270
648k
            else if (end == 'p')
1271
328k
            {
1272
328k
                call_native_snprintf(void *);
1273
328k
            }
1274
319k
            else
1275
319k
            {
1276
319k
                bFormatUnknown = true;
1277
319k
                break;
1278
319k
            }
1279
            // MSVC vsnprintf() returns -1.
1280
867M
            if (local_ret < 0 || offset_out + local_ret >= size)
1281
1.56M
                break;
1282
865M
            offset_out += local_ret;
1283
865M
            fmt = ptrend;
1284
865M
        }
1285
7.05G
        else
1286
7.05G
        {
1287
7.05G
            if (offset_out == size - 1)
1288
58.3k
                break;
1289
7.05G
            str[offset_out++] = *fmt;
1290
7.05G
        }
1291
7.92G
    }
1292
566M
    if (ch == '\0' && offset_out < size)
1293
564M
        str[offset_out] = '\0';
1294
1.95M
    else
1295
1.95M
    {
1296
1.95M
        if (bFormatUnknown)
1297
319k
        {
1298
319k
            CPLDebug("CPL",
1299
319k
                     "CPLvsnprintf() called with unsupported "
1300
319k
                     "formatting string: %s",
1301
319k
                     fmt_ori);
1302
319k
        }
1303
1.95M
#ifdef va_copy
1304
1.95M
        va_end(wrk_args);
1305
1.95M
        va_copy(wrk_args, args);
1306
#else
1307
        wrk_args = args;
1308
#endif
1309
1.95M
#if defined(HAVE_VSNPRINTF)
1310
1.95M
        offset_out = vsnprintf(str, size, fmt_ori, wrk_args);
1311
#else
1312
        offset_out = vsprintf(str, fmt_ori, wrk_args);
1313
#endif
1314
1.95M
    }
1315
1316
566M
#ifdef va_copy
1317
566M
    va_end(wrk_args);
1318
566M
#endif
1319
1320
566M
    return static_cast<int>(offset_out);
1321
566M
}
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), ...)
1352
5.68M
{
1353
5.68M
    va_list args;
1354
1355
5.68M
    va_start(args, fmt);
1356
5.68M
    const int ret = CPLvsnprintf(str, size, fmt, args);
1357
5.68M
    va_end(args);
1358
5.68M
    return ret;
1359
5.68M
}
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
24.0k
{
1382
24.0k
    va_list args;
1383
1384
24.0k
    va_start(args, fmt);
1385
24.0k
    const int ret = CPLvsnprintf(str, INT_MAX, fmt, args);
1386
24.0k
    va_end(args);
1387
24.0k
    return ret;
1388
24.0k
}
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), ...)
1407
0
{
1408
0
    va_list wrk_args, args;
1409
1410
0
    va_start(args, fmt);
1411
1412
0
#ifdef va_copy
1413
0
    va_copy(wrk_args, args);
1414
#else
1415
    wrk_args = args;
1416
#endif
1417
1418
0
    char szBuffer[4096] = {};
1419
    // Quiet coverity by staring off nul terminated.
1420
0
    int ret = CPLvsnprintf(szBuffer, sizeof(szBuffer), fmt, wrk_args);
1421
1422
0
#ifdef va_copy
1423
0
    va_end(wrk_args);
1424
0
#endif
1425
1426
0
    if (ret < int(sizeof(szBuffer)) - 1)
1427
0
        ret = printf("%s", szBuffer); /*ok*/
1428
0
    else
1429
0
    {
1430
0
#ifdef va_copy
1431
0
        va_copy(wrk_args, args);
1432
#else
1433
        wrk_args = args;
1434
#endif
1435
1436
0
        ret = vfprintf(stdout, fmt, wrk_args);
1437
1438
0
#ifdef va_copy
1439
0
        va_end(wrk_args);
1440
0
#endif
1441
0
    }
1442
1443
0
    va_end(args);
1444
1445
0
    return ret;
1446
0
}
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), ...)
1471
#endif
1472
704k
{
1473
704k
    bool error = false;
1474
704k
    int ret = 0;
1475
704k
    const char *fmt_ori = fmt;
1476
704k
    va_list args;
1477
1478
704k
    va_start(args, fmt);
1479
1.80M
    for (; *fmt != '\0' && *str != '\0'; ++fmt)
1480
1.64M
    {
1481
1.64M
        if (*fmt == '%')
1482
1.17M
        {
1483
1.17M
            if (fmt[1] == 'l' && fmt[2] == 'f')
1484
1.17M
            {
1485
1.17M
                fmt += 2;
1486
1.17M
                char *end;
1487
1.17M
                *(va_arg(args, double *)) = CPLStrtod(str, &end);
1488
1.17M
                if (end > str)
1489
621k
                {
1490
621k
                    ++ret;
1491
621k
                    str = end;
1492
621k
                }
1493
550k
                else
1494
550k
                    break;
1495
1.17M
            }
1496
0
            else
1497
0
            {
1498
0
                error = true;
1499
0
                break;
1500
0
            }
1501
1.17M
        }
1502
477k
        else if (isspace(static_cast<unsigned char>(*fmt)))
1503
474k
        {
1504
696k
            while (*str != '\0' && isspace(static_cast<unsigned char>(*str)))
1505
222k
                ++str;
1506
474k
        }
1507
2.86k
        else if (*str != *fmt)
1508
111
            break;
1509
2.75k
        else
1510
2.75k
            ++str;
1511
1.64M
    }
1512
704k
    va_end(args);
1513
1514
704k
    if (error)
1515
0
    {
1516
0
        CPLError(CE_Failure, CPLE_NotSupported,
1517
0
                 "Format %s not supported by CPLsscanf()", fmt_ori);
1518
0
    }
1519
1520
704k
    return ret;
1521
704k
}
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)
1543
124M
{
1544
124M
    return !(EQUAL(pszValue, "NO") || EQUAL(pszValue, "FALSE") ||
1545
124M
             EQUAL(pszValue, "OFF") || EQUAL(pszValue, "0"));
1546
124M
}
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)
1568
280
{
1569
280
    return CPLTestBool(pszValue) ? TRUE : FALSE;
1570
280
}
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)
1590
1.55k
{
1591
1.55k
    return CPLTestBool(pszValue) ? TRUE : FALSE;
1592
1.55k
}
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)
1615
1616
7.26M
{
1617
7.26M
    if (CSLFindString(papszStrList, pszKey) != -1)
1618
419
        return true;
1619
1620
7.26M
    const char *const pszValue = CSLFetchNameValue(papszStrList, pszKey);
1621
7.26M
    if (pszValue == nullptr)
1622
7.19M
        return bDefault;
1623
1624
66.6k
    return CPLTestBool(pszValue);
1625
7.26M
}
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)
1648
1649
57
{
1650
57
    return CPLFetchBool(papszStrList, pszKey, CPL_TO_BOOL(bDefault));
1651
57
}
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,
1659
                                 const char *pszDefault)
1660
1661
11.0M
{
1662
11.0M
    const char *pszResult = CSLFetchNameValue(papszStrList, pszName);
1663
11.0M
    if (pszResult != nullptr)
1664
802k
        return pszResult;
1665
1666
10.2M
    return pszDefault;
1667
11.0M
}
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)
1686
826M
{
1687
826M
    if (papszStrList == nullptr || pszName == nullptr)
1688
152M
        return nullptr;
1689
1690
673M
    const size_t nLen = strlen(pszName);
1691
4.96G
    while (*papszStrList != nullptr)
1692
4.30G
    {
1693
4.30G
        if (EQUALN(*papszStrList, pszName, nLen) &&
1694
4.30G
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
1695
8.86M
        {
1696
8.86M
            return (*papszStrList) + nLen + 1;
1697
8.86M
        }
1698
4.29G
        ++papszStrList;
1699
4.29G
    }
1700
664M
    return nullptr;
1701
673M
}
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)
1718
456M
{
1719
456M
    if (papszStrList == nullptr || pszName == nullptr)
1720
65.0M
        return -1;
1721
1722
391M
    const size_t nLen = strlen(pszName);
1723
391M
    int iIndex = 0;
1724
3.10G
    while (*papszStrList != nullptr)
1725
3.01G
    {
1726
3.01G
        if (EQUALN(*papszStrList, pszName, nLen) &&
1727
3.01G
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
1728
294M
        {
1729
294M
            return iIndex;
1730
294M
        }
1731
2.71G
        ++iIndex;
1732
2.71G
        ++papszStrList;
1733
2.71G
    }
1734
96.7M
    return -1;
1735
391M
}
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,
1759
                          bool *pbUnitSpecified)
1760
1.97M
{
1761
1.97M
    const char *start = pszValue;
1762
1.97M
    char *end = nullptr;
1763
1764
    // trim leading whitespace
1765
1.97M
    while (*start == ' ')
1766
0
    {
1767
0
        start++;
1768
0
    }
1769
1770
1.97M
    auto len = CPLStrnlen(start, 100);
1771
1.97M
    double value = CPLStrtodM(start, &end);
1772
1.97M
    const char *unit = nullptr;
1773
1.97M
    bool unitIsNotPercent = false;
1774
1775
1.97M
    if (end == start)
1776
0
    {
1777
0
        CPLError(CE_Failure, CPLE_IllegalArg, "Received non-numeric value: %s",
1778
0
                 pszValue);
1779
0
        return CE_Failure;
1780
0
    }
1781
1782
1.97M
    if (value < 0 || !std::isfinite(value))
1783
0
    {
1784
0
        CPLError(CE_Failure, CPLE_IllegalArg,
1785
0
                 "Memory size must be a positive number or zero.");
1786
0
        return CE_Failure;
1787
0
    }
1788
1789
5.91M
    for (const char *c = end; c < start + len; c++)
1790
3.94M
    {
1791
3.94M
        if (unit == nullptr)
1792
1.97M
        {
1793
            // check various suffixes and convert number into bytes
1794
1.97M
            if (*c == '%')
1795
0
            {
1796
0
                if (value < 0 || value > 100)
1797
0
                {
1798
0
                    CPLError(CE_Failure, CPLE_IllegalArg,
1799
0
                             "Memory percentage must be between 0 and 100.");
1800
0
                    return CE_Failure;
1801
0
                }
1802
0
                auto bytes = CPLGetUsablePhysicalRAM();
1803
0
                if (bytes == 0)
1804
0
                {
1805
0
                    CPLError(CE_Failure, CPLE_NotSupported,
1806
0
                             "Cannot determine usable physical RAM");
1807
0
                    return CE_Failure;
1808
0
                }
1809
0
                value *= static_cast<double>(bytes / 100);
1810
0
                unit = c;
1811
0
            }
1812
1.97M
            else
1813
1.97M
            {
1814
1.97M
                switch (*c)
1815
1.97M
                {
1816
0
                    case 'G':
1817
0
                    case 'g':
1818
0
                        value *= 1024;
1819
0
                        [[fallthrough]];
1820
1.97M
                    case 'M':
1821
1.97M
                    case 'm':
1822
1.97M
                        value *= 1024;
1823
1.97M
                        [[fallthrough]];
1824
1.97M
                    case 'K':
1825
1.97M
                    case 'k':
1826
1.97M
                        value *= 1024;
1827
1.97M
                        unit = c;
1828
1.97M
                        unitIsNotPercent = true;
1829
1.97M
                        break;
1830
0
                    case ' ':
1831
0
                        break;
1832
0
                    default:
1833
0
                        CPLError(CE_Failure, CPLE_IllegalArg,
1834
0
                                 "Unexpected value: %s", pszValue);
1835
0
                        return CE_Failure;
1836
1.97M
                }
1837
1.97M
            }
1838
1.97M
        }
1839
1.97M
        else if (unitIsNotPercent && c == unit + 1 && (*c == 'b' || *c == 'B'))
1840
1.97M
        {
1841
            // ignore 'B' or 'b' as part of unit
1842
1.97M
            continue;
1843
1.97M
        }
1844
0
        else if (*c != ' ')
1845
0
        {
1846
0
            CPLError(CE_Failure, CPLE_IllegalArg, "Unexpected value: %s",
1847
0
                     pszValue);
1848
0
            return CE_Failure;
1849
0
        }
1850
3.94M
    }
1851
1852
1.97M
    *pnValue = static_cast<GIntBig>(value);
1853
1.97M
    if (pbUnitSpecified)
1854
36
    {
1855
36
        *pbUnitSpecified = (unit != nullptr);
1856
36
    }
1857
1.97M
    return CE_None;
1858
1.97M
}
1859
1860
/**********************************************************************
1861
 *                       CPLParseNameValue()
1862
 **********************************************************************/
1863
1864
/**
1865
 * Parse NAME=VALUE string into name and value components.
1866
 *
1867
 * Note that if ppszKey is non-NULL, the key (or name) portion will be
1868
 * allocated using CPLMalloc(), and returned in that pointer.  It is the
1869
 * applications responsibility to free this string, but the application should
1870
 * not modify or free the returned value portion.
1871
 *
1872
 * This function also support "NAME:VALUE" strings and will strip white
1873
 * space from around the delimiter when forming name and value strings.
1874
 *
1875
 * Eventually CSLFetchNameValue() and friends may be modified to use
1876
 * CPLParseNameValue().
1877
 *
1878
 * @param pszNameValue string in "NAME=VALUE" format.
1879
 * @param ppszKey optional pointer though which to return the name
1880
 * portion.
1881
 *
1882
 * @return the value portion (pointing into original string).
1883
 */
1884
1885
const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey)
1886
26.6M
{
1887
523M
    for (int i = 0; pszNameValue[i] != '\0'; ++i)
1888
515M
    {
1889
515M
        if (pszNameValue[i] == '=' || pszNameValue[i] == ':')
1890
19.1M
        {
1891
19.1M
            const char *pszValue = pszNameValue + i + 1;
1892
21.9M
            while (*pszValue == ' ' || *pszValue == '\t')
1893
2.81M
                ++pszValue;
1894
1895
19.1M
            if (ppszKey != nullptr)
1896
19.1M
            {
1897
19.1M
                *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
1898
19.1M
                memcpy(*ppszKey, pszNameValue, i);
1899
19.1M
                (*ppszKey)[i] = '\0';
1900
19.9M
                while (i > 0 &&
1901
19.9M
                       ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
1902
824k
                {
1903
824k
                    (*ppszKey)[i - 1] = '\0';
1904
824k
                    i--;
1905
824k
                }
1906
19.1M
            }
1907
1908
19.1M
            return pszValue;
1909
19.1M
        }
1910
515M
    }
1911
1912
7.53M
    return nullptr;
1913
26.6M
}
1914
1915
/**********************************************************************
1916
 *                       CPLParseNameValueSep()
1917
 **********************************************************************/
1918
/**
1919
 * Parse NAME<Sep>VALUE string into name and value components.
1920
 *
1921
 * This is derived directly from CPLParseNameValue() which will separate
1922
 * on '=' OR ':', here chSep is required for specifying the separator
1923
 * explicitly.
1924
 *
1925
 * @param pszNameValue string in "NAME=VALUE" format.
1926
 * @param ppszKey optional pointer though which to return the name
1927
 * portion.
1928
 * @param chSep required single char separator
1929
 * @return the value portion (pointing into original string).
1930
 */
1931
1932
const char *CPLParseNameValueSep(const char *pszNameValue, char **ppszKey,
1933
                                 char chSep)
1934
0
{
1935
0
    for (int i = 0; pszNameValue[i] != '\0'; ++i)
1936
0
    {
1937
0
        if (pszNameValue[i] == chSep)
1938
0
        {
1939
0
            const char *pszValue = pszNameValue + i + 1;
1940
0
            while (*pszValue == ' ' || *pszValue == '\t')
1941
0
                ++pszValue;
1942
1943
0
            if (ppszKey != nullptr)
1944
0
            {
1945
0
                *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
1946
0
                memcpy(*ppszKey, pszNameValue, i);
1947
0
                (*ppszKey)[i] = '\0';
1948
0
                while (i > 0 &&
1949
0
                       ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
1950
0
                {
1951
0
                    (*ppszKey)[i - 1] = '\0';
1952
0
                    i--;
1953
0
                }
1954
0
            }
1955
1956
0
            return pszValue;
1957
0
        }
1958
0
    }
1959
1960
0
    return nullptr;
1961
0
}
1962
1963
/**********************************************************************
1964
 *                       CSLFetchNameValueMultiple()
1965
 **********************************************************************/
1966
1967
/** In a StringList of "Name=Value" pairs, look for all the
1968
 * values with the specified name.  The search is not case
1969
 * sensitive.
1970
 * ("Name:Value" pairs are also supported for backward compatibility
1971
 * with older stuff.)
1972
 *
1973
 * Returns StringList with one entry for each occurrence of the
1974
 * specified name.  The StringList should eventually be destroyed
1975
 * by calling CSLDestroy().
1976
 *
1977
 * Returns NULL if the name is not found.
1978
 */
1979
1980
char **CSLFetchNameValueMultiple(CSLConstList papszStrList, const char *pszName)
1981
65.7k
{
1982
65.7k
    if (papszStrList == nullptr || pszName == nullptr)
1983
61.2k
        return nullptr;
1984
1985
4.42k
    const size_t nLen = strlen(pszName);
1986
4.42k
    char **papszValues = nullptr;
1987
68.4k
    while (*papszStrList != nullptr)
1988
64.0k
    {
1989
64.0k
        if (EQUALN(*papszStrList, pszName, nLen) &&
1990
64.0k
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
1991
0
        {
1992
0
            papszValues = CSLAddString(papszValues, (*papszStrList) + nLen + 1);
1993
0
        }
1994
64.0k
        ++papszStrList;
1995
64.0k
    }
1996
1997
4.42k
    return papszValues;
1998
65.7k
}
1999
2000
/**********************************************************************
2001
 *                       CSLAddNameValue()
2002
 **********************************************************************/
2003
2004
/** Add a new entry to a StringList of "Name=Value" pairs,
2005
 * ("Name:Value" pairs are also supported for backward compatibility
2006
 * with older stuff.)
2007
 *
2008
 * This function does not check if a "Name=Value" pair already exists
2009
 * for that name and can generate multiple entries for the same name.
2010
 * Use CSLSetNameValue() if you want each name to have only one value.
2011
 *
2012
 * Returns the modified StringList.
2013
 */
2014
2015
char **CSLAddNameValue(char **papszStrList, const char *pszName,
2016
                       const char *pszValue)
2017
7.17M
{
2018
7.17M
    if (pszName == nullptr || pszValue == nullptr)
2019
0
        return papszStrList;
2020
2021
7.17M
    const size_t nLen = strlen(pszName) + strlen(pszValue) + 2;
2022
7.17M
    char *pszLine = static_cast<char *>(CPLMalloc(nLen));
2023
7.17M
    snprintf(pszLine, nLen, "%s=%s", pszName, pszValue);
2024
7.17M
    papszStrList = CSLAddString(papszStrList, pszLine);
2025
7.17M
    CPLFree(pszLine);
2026
2027
7.17M
    return papszStrList;
2028
7.17M
}
2029
2030
/************************************************************************/
2031
/*                          CSLSetNameValue()                           */
2032
/************************************************************************/
2033
2034
/**
2035
 * Assign value to name in StringList.
2036
 *
2037
 * Set the value for a given name in a StringList of "Name=Value" pairs
2038
 * ("Name:Value" pairs are also supported for backward compatibility
2039
 * with older stuff.)
2040
 *
2041
 * If there is already a value for that name in the list then the value
2042
 * is changed, otherwise a new "Name=Value" pair is added.
2043
 *
2044
 * @param papszList the original list, the modified version is returned.
2045
 * @param pszName the name to be assigned a value.  This should be a well
2046
 * formed token (no spaces or very special characters).
2047
 * @param pszValue the value to assign to the name.  This should not contain
2048
 * any newlines (CR or LF) but is otherwise pretty much unconstrained.  If
2049
 * NULL any corresponding value will be removed.
2050
 *
2051
 * @return modified StringList.
2052
 */
2053
2054
char **CSLSetNameValue(char **papszList, const char *pszName,
2055
                       const char *pszValue)
2056
12.5M
{
2057
12.5M
    if (pszName == nullptr)
2058
0
        return papszList;
2059
2060
12.5M
    size_t nLen = strlen(pszName);
2061
12.5M
    while (nLen > 0 && pszName[nLen - 1] == ' ')
2062
50
        nLen--;
2063
12.5M
    char **papszPtr = papszList;
2064
551M
    while (papszPtr && *papszPtr != nullptr)
2065
544M
    {
2066
544M
        if (EQUALN(*papszPtr, pszName, nLen))
2067
11.9M
        {
2068
11.9M
            size_t i;
2069
13.1M
            for (i = nLen; (*papszPtr)[i] == ' '; ++i)
2070
1.15M
            {
2071
1.15M
            }
2072
11.9M
            if ((*papszPtr)[i] == '=' || (*papszPtr)[i] == ':')
2073
5.52M
            {
2074
                // Found it.
2075
                // Change the value... make sure to keep the ':' or '='.
2076
5.52M
                const char cSep = (*papszPtr)[i];
2077
2078
5.52M
                CPLFree(*papszPtr);
2079
2080
                // If the value is NULL, remove this entry completely.
2081
5.52M
                if (pszValue == nullptr)
2082
575k
                {
2083
576k
                    while (papszPtr[1] != nullptr)
2084
136
                    {
2085
136
                        *papszPtr = papszPtr[1];
2086
136
                        ++papszPtr;
2087
136
                    }
2088
575k
                    *papszPtr = nullptr;
2089
575k
                }
2090
2091
                // Otherwise replace with new value.
2092
4.94M
                else
2093
4.94M
                {
2094
4.94M
                    const size_t nLen2 = strlen(pszName) + strlen(pszValue) + 2;
2095
4.94M
                    *papszPtr = static_cast<char *>(CPLMalloc(nLen2));
2096
4.94M
                    snprintf(*papszPtr, nLen2, "%s%c%s", pszName, cSep,
2097
4.94M
                             pszValue);
2098
4.94M
                }
2099
5.52M
                return papszList;
2100
5.52M
            }
2101
11.9M
        }
2102
539M
        ++papszPtr;
2103
539M
    }
2104
2105
7.05M
    if (pszValue == nullptr)
2106
630k
        return papszList;
2107
2108
    // The name does not exist yet.  Create a new entry.
2109
6.42M
    return CSLAddNameValue(papszList, pszName, pszValue);
2110
7.05M
}
2111
2112
/************************************************************************/
2113
/*                      CSLSetNameValueSeparator()                      */
2114
/************************************************************************/
2115
2116
/**
2117
 * Replace the default separator (":" or "=") with the passed separator
2118
 * in the given name/value list.
2119
 *
2120
 * Note that if a separator other than ":" or "=" is used, the resulting
2121
 * list will not be manipulable by the CSL name/value functions any more.
2122
 *
2123
 * The CPLParseNameValue() function is used to break the existing lines,
2124
 * and it also strips white space from around the existing delimiter, thus
2125
 * the old separator, and any white space will be replaced by the new
2126
 * separator.  For formatting purposes it may be desirable to include some
2127
 * white space in the new separator.  e.g. ": " or " = ".
2128
 *
2129
 * @param papszList the list to update.  Component strings may be freed
2130
 * but the list array will remain at the same location.
2131
 *
2132
 * @param pszSeparator the new separator string to insert.
2133
 */
2134
2135
void CSLSetNameValueSeparator(char **papszList, const char *pszSeparator)
2136
2137
1.87M
{
2138
1.87M
    const int nLines = CSLCount(papszList);
2139
2140
9.76M
    for (int iLine = 0; iLine < nLines; ++iLine)
2141
7.89M
    {
2142
7.89M
        char *pszKey = nullptr;
2143
7.89M
        const char *pszValue = CPLParseNameValue(papszList[iLine], &pszKey);
2144
7.89M
        if (pszValue == nullptr || pszKey == nullptr)
2145
103k
        {
2146
103k
            CPLFree(pszKey);
2147
103k
            continue;
2148
103k
        }
2149
2150
7.78M
        char *pszNewLine = static_cast<char *>(CPLMalloc(
2151
7.78M
            strlen(pszValue) + strlen(pszKey) + strlen(pszSeparator) + 1));
2152
7.78M
        strcpy(pszNewLine, pszKey);
2153
7.78M
        strcat(pszNewLine, pszSeparator);
2154
7.78M
        strcat(pszNewLine, pszValue);
2155
7.78M
        CPLFree(papszList[iLine]);
2156
7.78M
        papszList[iLine] = pszNewLine;
2157
7.78M
        CPLFree(pszKey);
2158
7.78M
    }
2159
1.87M
}
2160
2161
/************************************************************************/
2162
/*                          CPLEscapeString()                           */
2163
/************************************************************************/
2164
2165
/**
2166
 * Apply escaping to string to preserve special characters.
2167
 *
2168
 * This function will "escape" a variety of special characters
2169
 * to make the string suitable to embed within a string constant
2170
 * or to write within a text stream but in a form that can be
2171
 * reconstituted to its original form.  The escaping will even preserve
2172
 * zero bytes allowing preservation of raw binary data.
2173
 *
2174
 * CPLES_BackslashQuotable(0): This scheme turns a binary string into
2175
 * a form suitable to be placed within double quotes as a string constant.
2176
 * The backslash, quote, '\\0' and newline characters are all escaped in
2177
 * the usual C style.
2178
 *
2179
 * CPLES_XML(1): This scheme converts the '<', '>', '"' and '&' characters into
2180
 * their XML/HTML equivalent (&lt;, &gt;, &quot; and &amp;) making a string safe
2181
 * to embed as CDATA within an XML element.  The '\\0' is not escaped and
2182
 * should not be included in the input.
2183
 *
2184
 * CPLES_URL(2): Everything except alphanumerics and the characters
2185
 * '$', '-', '_', '.', '+', '!', '*', ''', '(', ')' and ',' (see RFC1738) are
2186
 * converted to a percent followed by a two digit hex encoding of the character
2187
 * (leading zero supplied if needed).  This is the mechanism used for encoding
2188
 * values to be passed in URLs.
2189
 *
2190
 * CPLES_SQL(3): All single quotes are replaced with two single quotes.
2191
 * Suitable for use when constructing literal values for SQL commands where
2192
 * the literal will be enclosed in single quotes.
2193
 *
2194
 * CPLES_CSV(4): If the values contains commas, semicolons, tabs, double quotes,
2195
 * or newlines it placed in double quotes, and double quotes in the value are
2196
 * doubled. Suitable for use when constructing field values for .csv files.
2197
 * Note that CPLUnescapeString() currently does not support this format, only
2198
 * CPLEscapeString().  See cpl_csv.cpp for CSV parsing support.
2199
 *
2200
 * CPLES_SQLI(7): All double quotes are replaced with two double quotes.
2201
 * Suitable for use when constructing identifiers for SQL commands where
2202
 * the literal will be enclosed in double quotes.
2203
 *
2204
 * @param pszInput the string to escape.
2205
 * @param nLength The number of bytes of data to preserve.  If this is -1
2206
 * the strlen(pszString) function will be used to compute the length.
2207
 * @param nScheme the encoding scheme to use.
2208
 *
2209
 * @return an escaped, zero terminated string that should be freed with
2210
 * CPLFree() when no longer needed.
2211
 */
2212
2213
char *CPLEscapeString(const char *pszInput, int nLength, int nScheme)
2214
30.2M
{
2215
30.2M
    const size_t szLength =
2216
30.2M
        (nLength < 0) ? strlen(pszInput) : static_cast<size_t>(nLength);
2217
30.2M
#define nLength no_longer_use_me
2218
2219
30.2M
    size_t nSizeAlloc = 1;
2220
#if SIZEOF_VOIDP < 8
2221
    bool bWrapAround = false;
2222
    const auto IncSizeAlloc = [&nSizeAlloc, &bWrapAround](size_t inc)
2223
    {
2224
        constexpr size_t SZ_MAX = std::numeric_limits<size_t>::max();
2225
        if (nSizeAlloc > SZ_MAX - inc)
2226
        {
2227
            bWrapAround = true;
2228
            nSizeAlloc = 0;
2229
        }
2230
        nSizeAlloc += inc;
2231
    };
2232
#else
2233
590M
    const auto IncSizeAlloc = [&nSizeAlloc](size_t inc) { nSizeAlloc += inc; };
2234
30.2M
#endif
2235
2236
30.2M
    if (nScheme == CPLES_BackslashQuotable)
2237
26
    {
2238
1.62k
        for (size_t iIn = 0; iIn < szLength; iIn++)
2239
1.60k
        {
2240
1.60k
            if (pszInput[iIn] == '\0' || pszInput[iIn] == '\n' ||
2241
1.60k
                pszInput[iIn] == '"' || pszInput[iIn] == '\\')
2242
114
                IncSizeAlloc(2);
2243
1.48k
            else
2244
1.48k
                IncSizeAlloc(1);
2245
1.60k
        }
2246
26
    }
2247
30.2M
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
2248
26.5M
    {
2249
542M
        for (size_t iIn = 0; iIn < szLength; ++iIn)
2250
515M
        {
2251
515M
            if (pszInput[iIn] == '<')
2252
7.62M
            {
2253
7.62M
                IncSizeAlloc(4);
2254
7.62M
            }
2255
507M
            else if (pszInput[iIn] == '>')
2256
65.3M
            {
2257
65.3M
                IncSizeAlloc(4);
2258
65.3M
            }
2259
442M
            else if (pszInput[iIn] == '&')
2260
2.30M
            {
2261
2.30M
                IncSizeAlloc(5);
2262
2.30M
            }
2263
440M
            else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
2264
1.56M
            {
2265
1.56M
                IncSizeAlloc(6);
2266
1.56M
            }
2267
            // Python 2 does not display the UTF-8 character corresponding
2268
            // to the byte-order mark (BOM), so escape it.
2269
438M
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
2270
438M
                         0xEF &&
2271
438M
                     (reinterpret_cast<const unsigned char *>(
2272
215k
                         pszInput))[iIn + 1] == 0xBB &&
2273
438M
                     (reinterpret_cast<const unsigned char *>(
2274
98.7k
                         pszInput))[iIn + 2] == 0xBF)
2275
78.6k
            {
2276
78.6k
                IncSizeAlloc(8);
2277
78.6k
                iIn += 2;
2278
78.6k
            }
2279
438M
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
2280
438M
                         0x20 &&
2281
438M
                     pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
2282
438M
                     pszInput[iIn] != 0xD)
2283
9.38M
            {
2284
                // These control characters are unrepresentable in XML format,
2285
                // so we just drop them.  #4117
2286
9.38M
            }
2287
429M
            else
2288
429M
            {
2289
429M
                IncSizeAlloc(1);
2290
429M
            }
2291
515M
        }
2292
26.5M
    }
2293
3.64M
    else if (nScheme == CPLES_URL)  // Untested at implementation.
2294
337k
    {
2295
73.6M
        for (size_t iIn = 0; iIn < szLength; ++iIn)
2296
73.3M
        {
2297
73.3M
            if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
2298
73.3M
                (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
2299
73.3M
                (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
2300
73.3M
                pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
2301
73.3M
                pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
2302
73.3M
                pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
2303
73.3M
                pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
2304
73.3M
                pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
2305
73.3M
                pszInput[iIn] == ',')
2306
40.5M
            {
2307
40.5M
                IncSizeAlloc(1);
2308
40.5M
            }
2309
32.7M
            else
2310
32.7M
            {
2311
32.7M
                IncSizeAlloc(3);
2312
32.7M
            }
2313
73.3M
        }
2314
337k
    }
2315
3.31M
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2316
28
    {
2317
28
        const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
2318
130k
        for (size_t iIn = 0; iIn < szLength; ++iIn)
2319
130k
        {
2320
130k
            if (pszInput[iIn] == chQuote)
2321
217
            {
2322
217
                IncSizeAlloc(2);
2323
217
            }
2324
130k
            else
2325
130k
            {
2326
130k
                IncSizeAlloc(1);
2327
130k
            }
2328
130k
        }
2329
28
    }
2330
3.31M
    else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
2331
3.31M
    {
2332
3.31M
        if (nScheme == CPLES_CSV && strcspn(pszInput, "\",;\t\n\r") == szLength)
2333
3.14M
        {
2334
3.14M
            char *pszOutput =
2335
3.14M
                static_cast<char *>(VSI_MALLOC_VERBOSE(szLength + 1));
2336
3.14M
            if (pszOutput == nullptr)
2337
0
                return nullptr;
2338
3.14M
            memcpy(pszOutput, pszInput, szLength + 1);
2339
3.14M
            return pszOutput;
2340
3.14M
        }
2341
162k
        else
2342
162k
        {
2343
162k
            IncSizeAlloc(1);
2344
10.9M
            for (size_t iIn = 0; iIn < szLength; ++iIn)
2345
10.7M
            {
2346
10.7M
                if (pszInput[iIn] == '\"')
2347
168k
                {
2348
168k
                    IncSizeAlloc(2);
2349
168k
                }
2350
10.6M
                else
2351
10.6M
                    IncSizeAlloc(1);
2352
10.7M
            }
2353
162k
            IncSizeAlloc(1);
2354
162k
        }
2355
3.31M
    }
2356
0
    else
2357
0
    {
2358
0
        CPLError(CE_Failure, CPLE_AppDefined,
2359
0
                 "Undefined escaping scheme (%d) in CPLEscapeString()",
2360
0
                 nScheme);
2361
0
        return CPLStrdup("");
2362
0
    }
2363
2364
#if SIZEOF_VOIDP < 8
2365
    if (bWrapAround)
2366
    {
2367
        CPLError(CE_Failure, CPLE_OutOfMemory,
2368
                 "Out of memory in CPLEscapeString()");
2369
        return nullptr;
2370
    }
2371
#endif
2372
2373
27.0M
    char *pszOutput = static_cast<char *>(VSI_MALLOC_VERBOSE(nSizeAlloc));
2374
27.0M
    if (pszOutput == nullptr)
2375
0
        return nullptr;
2376
2377
27.0M
    size_t iOut = 0;
2378
2379
27.0M
    if (nScheme == CPLES_BackslashQuotable)
2380
26
    {
2381
1.62k
        for (size_t iIn = 0; iIn < szLength; iIn++)
2382
1.60k
        {
2383
1.60k
            if (pszInput[iIn] == '\0')
2384
0
            {
2385
0
                pszOutput[iOut++] = '\\';
2386
0
                pszOutput[iOut++] = '0';
2387
0
            }
2388
1.60k
            else if (pszInput[iIn] == '\n')
2389
87
            {
2390
87
                pszOutput[iOut++] = '\\';
2391
87
                pszOutput[iOut++] = 'n';
2392
87
            }
2393
1.51k
            else if (pszInput[iIn] == '"')
2394
27
            {
2395
27
                pszOutput[iOut++] = '\\';
2396
27
                pszOutput[iOut++] = '\"';
2397
27
            }
2398
1.48k
            else if (pszInput[iIn] == '\\')
2399
0
            {
2400
0
                pszOutput[iOut++] = '\\';
2401
0
                pszOutput[iOut++] = '\\';
2402
0
            }
2403
1.48k
            else
2404
1.48k
                pszOutput[iOut++] = pszInput[iIn];
2405
1.60k
        }
2406
26
        pszOutput[iOut++] = '\0';
2407
26
    }
2408
27.0M
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
2409
26.5M
    {
2410
542M
        for (size_t iIn = 0; iIn < szLength; ++iIn)
2411
515M
        {
2412
515M
            if (pszInput[iIn] == '<')
2413
7.62M
            {
2414
7.62M
                pszOutput[iOut++] = '&';
2415
7.62M
                pszOutput[iOut++] = 'l';
2416
7.62M
                pszOutput[iOut++] = 't';
2417
7.62M
                pszOutput[iOut++] = ';';
2418
7.62M
            }
2419
507M
            else if (pszInput[iIn] == '>')
2420
65.3M
            {
2421
65.3M
                pszOutput[iOut++] = '&';
2422
65.3M
                pszOutput[iOut++] = 'g';
2423
65.3M
                pszOutput[iOut++] = 't';
2424
65.3M
                pszOutput[iOut++] = ';';
2425
65.3M
            }
2426
442M
            else if (pszInput[iIn] == '&')
2427
2.30M
            {
2428
2.30M
                pszOutput[iOut++] = '&';
2429
2.30M
                pszOutput[iOut++] = 'a';
2430
2.30M
                pszOutput[iOut++] = 'm';
2431
2.30M
                pszOutput[iOut++] = 'p';
2432
2.30M
                pszOutput[iOut++] = ';';
2433
2.30M
            }
2434
440M
            else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
2435
1.56M
            {
2436
1.56M
                pszOutput[iOut++] = '&';
2437
1.56M
                pszOutput[iOut++] = 'q';
2438
1.56M
                pszOutput[iOut++] = 'u';
2439
1.56M
                pszOutput[iOut++] = 'o';
2440
1.56M
                pszOutput[iOut++] = 't';
2441
1.56M
                pszOutput[iOut++] = ';';
2442
1.56M
            }
2443
            // Python 2 does not display the UTF-8 character corresponding
2444
            // to the byte-order mark (BOM), so escape it.
2445
438M
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
2446
438M
                         0xEF &&
2447
438M
                     (reinterpret_cast<const unsigned char *>(
2448
215k
                         pszInput))[iIn + 1] == 0xBB &&
2449
438M
                     (reinterpret_cast<const unsigned char *>(
2450
98.7k
                         pszInput))[iIn + 2] == 0xBF)
2451
78.6k
            {
2452
78.6k
                pszOutput[iOut++] = '&';
2453
78.6k
                pszOutput[iOut++] = '#';
2454
78.6k
                pszOutput[iOut++] = 'x';
2455
78.6k
                pszOutput[iOut++] = 'F';
2456
78.6k
                pszOutput[iOut++] = 'E';
2457
78.6k
                pszOutput[iOut++] = 'F';
2458
78.6k
                pszOutput[iOut++] = 'F';
2459
78.6k
                pszOutput[iOut++] = ';';
2460
78.6k
                iIn += 2;
2461
78.6k
            }
2462
438M
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
2463
438M
                         0x20 &&
2464
438M
                     pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
2465
438M
                     pszInput[iIn] != 0xD)
2466
9.38M
            {
2467
                // These control characters are unrepresentable in XML format,
2468
                // so we just drop them.  #4117
2469
9.38M
            }
2470
429M
            else
2471
429M
            {
2472
429M
                pszOutput[iOut++] = pszInput[iIn];
2473
429M
            }
2474
515M
        }
2475
26.5M
        pszOutput[iOut++] = '\0';
2476
26.5M
    }
2477
499k
    else if (nScheme == CPLES_URL)  // Untested at implementation.
2478
337k
    {
2479
73.6M
        for (size_t iIn = 0; iIn < szLength; ++iIn)
2480
73.3M
        {
2481
73.3M
            if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
2482
73.3M
                (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
2483
73.3M
                (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
2484
73.3M
                pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
2485
73.3M
                pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
2486
73.3M
                pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
2487
73.3M
                pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
2488
73.3M
                pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
2489
73.3M
                pszInput[iIn] == ',')
2490
40.5M
            {
2491
40.5M
                pszOutput[iOut++] = pszInput[iIn];
2492
40.5M
            }
2493
32.7M
            else
2494
32.7M
            {
2495
32.7M
                snprintf(pszOutput + iOut, nSizeAlloc - iOut, "%%%02X",
2496
32.7M
                         static_cast<unsigned char>(pszInput[iIn]));
2497
32.7M
                iOut += 3;
2498
32.7M
            }
2499
73.3M
        }
2500
337k
        pszOutput[iOut++] = '\0';
2501
337k
    }
2502
162k
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2503
28
    {
2504
28
        const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
2505
130k
        for (size_t iIn = 0; iIn < szLength; ++iIn)
2506
130k
        {
2507
130k
            if (pszInput[iIn] == chQuote)
2508
217
            {
2509
217
                pszOutput[iOut++] = chQuote;
2510
217
                pszOutput[iOut++] = chQuote;
2511
217
            }
2512
130k
            else
2513
130k
            {
2514
130k
                pszOutput[iOut++] = pszInput[iIn];
2515
130k
            }
2516
130k
        }
2517
28
        pszOutput[iOut++] = '\0';
2518
28
    }
2519
162k
    else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
2520
162k
    {
2521
162k
        pszOutput[iOut++] = '\"';
2522
2523
10.9M
        for (size_t iIn = 0; iIn < szLength; ++iIn)
2524
10.7M
        {
2525
10.7M
            if (pszInput[iIn] == '\"')
2526
168k
            {
2527
168k
                pszOutput[iOut++] = '\"';
2528
168k
                pszOutput[iOut++] = '\"';
2529
168k
            }
2530
10.6M
            else
2531
10.6M
                pszOutput[iOut++] = pszInput[iIn];
2532
10.7M
        }
2533
162k
        pszOutput[iOut++] = '\"';
2534
162k
        pszOutput[iOut++] = '\0';
2535
162k
    }
2536
2537
27.0M
    return pszOutput;
2538
27.0M
#undef nLength
2539
27.0M
}
2540
2541
/************************************************************************/
2542
/*                         CPLUnescapeString()                          */
2543
/************************************************************************/
2544
2545
/**
2546
 * Unescape a string.
2547
 *
2548
 * This function does the opposite of CPLEscapeString().  Given a string
2549
 * with special values escaped according to some scheme, it will return a
2550
 * new copy of the string returned to its original form.
2551
 *
2552
 * @param pszInput the input string.  This is a zero terminated string.
2553
 * @param pnLength location to return the length of the unescaped string,
2554
 * which may in some cases include embedded '\\0' characters.
2555
 * @param nScheme the escaped scheme to undo (see CPLEscapeString() for a
2556
 * list).  Does not yet support CSV.
2557
 *
2558
 * @return a copy of the unescaped string that should be freed by the
2559
 * application using CPLFree() when no longer needed.
2560
 */
2561
2562
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
2563
char *CPLUnescapeString(const char *pszInput, int *pnLength, int nScheme)
2564
2565
4.14M
{
2566
4.14M
    int iOut = 0;
2567
2568
    // TODO: Why times 4?
2569
4.14M
    char *pszOutput = static_cast<char *>(CPLMalloc(4 * strlen(pszInput) + 1));
2570
4.14M
    pszOutput[0] = '\0';
2571
2572
4.14M
    if (nScheme == CPLES_BackslashQuotable)
2573
972k
    {
2574
29.8M
        for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
2575
28.8M
        {
2576
28.8M
            if (pszInput[iIn] == '\\')
2577
61.5k
            {
2578
61.5k
                ++iIn;
2579
61.5k
                if (pszInput[iIn] == '\0')
2580
6.65k
                    break;
2581
54.8k
                if (pszInput[iIn] == 'n')
2582
11.1k
                    pszOutput[iOut++] = '\n';
2583
43.7k
                else if (pszInput[iIn] == '0')
2584
949
                    pszOutput[iOut++] = '\0';
2585
42.7k
                else
2586
42.7k
                    pszOutput[iOut++] = pszInput[iIn];
2587
54.8k
            }
2588
28.8M
            else
2589
28.8M
            {
2590
28.8M
                pszOutput[iOut++] = pszInput[iIn];
2591
28.8M
            }
2592
28.8M
        }
2593
972k
    }
2594
3.17M
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
2595
1.17M
    {
2596
1.17M
        char ch = '\0';
2597
1.76G
        for (int iIn = 0; (ch = pszInput[iIn]) != '\0'; ++iIn)
2598
1.76G
        {
2599
1.76G
            if (ch != '&')
2600
1.73G
            {
2601
1.73G
                pszOutput[iOut++] = ch;
2602
1.73G
            }
2603
27.7M
            else if (STARTS_WITH_CI(pszInput + iIn, "&lt;"))
2604
11.9M
            {
2605
11.9M
                pszOutput[iOut++] = '<';
2606
11.9M
                iIn += 3;
2607
11.9M
            }
2608
15.8M
            else if (STARTS_WITH_CI(pszInput + iIn, "&gt;"))
2609
11.5M
            {
2610
11.5M
                pszOutput[iOut++] = '>';
2611
11.5M
                iIn += 3;
2612
11.5M
            }
2613
4.24M
            else if (STARTS_WITH_CI(pszInput + iIn, "&amp;"))
2614
1.06M
            {
2615
1.06M
                pszOutput[iOut++] = '&';
2616
1.06M
                iIn += 4;
2617
1.06M
            }
2618
3.18M
            else if (STARTS_WITH_CI(pszInput + iIn, "&apos;"))
2619
34.4k
            {
2620
34.4k
                pszOutput[iOut++] = '\'';
2621
34.4k
                iIn += 5;
2622
34.4k
            }
2623
3.14M
            else if (STARTS_WITH_CI(pszInput + iIn, "&quot;"))
2624
2.13M
            {
2625
2.13M
                pszOutput[iOut++] = '"';
2626
2.13M
                iIn += 5;
2627
2.13M
            }
2628
1.01M
            else if (STARTS_WITH_CI(pszInput + iIn, "&#x"))
2629
88.3k
            {
2630
88.3k
                wchar_t anVal[2] = {0, 0};
2631
88.3k
                iIn += 3;
2632
2633
88.3k
                unsigned int nVal = 0;
2634
528k
                while (true)
2635
528k
                {
2636
528k
                    ch = pszInput[iIn++];
2637
528k
                    if (ch >= 'a' && ch <= 'f')
2638
36.4k
                        nVal = nVal * 16U +
2639
36.4k
                               static_cast<unsigned int>(ch - 'a' + 10);
2640
492k
                    else if (ch >= 'A' && ch <= 'F')
2641
156k
                        nVal = nVal * 16U +
2642
156k
                               static_cast<unsigned int>(ch - 'A' + 10);
2643
336k
                    else if (ch >= '0' && ch <= '9')
2644
248k
                        nVal = nVal * 16U + static_cast<unsigned int>(ch - '0');
2645
88.3k
                    else
2646
88.3k
                        break;
2647
528k
                }
2648
88.3k
                anVal[0] = static_cast<wchar_t>(nVal);
2649
88.3k
                if (ch != ';')
2650
42.8k
                    break;
2651
45.4k
                iIn--;
2652
2653
45.4k
                char *pszUTF8 =
2654
45.4k
                    CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
2655
45.4k
                int nLen = static_cast<int>(strlen(pszUTF8));
2656
45.4k
                memcpy(pszOutput + iOut, pszUTF8, nLen);
2657
45.4k
                CPLFree(pszUTF8);
2658
45.4k
                iOut += nLen;
2659
45.4k
            }
2660
928k
            else if (STARTS_WITH_CI(pszInput + iIn, "&#"))
2661
253k
            {
2662
253k
                wchar_t anVal[2] = {0, 0};
2663
253k
                iIn += 2;
2664
2665
253k
                unsigned int nVal = 0;
2666
1.38M
                while (true)
2667
1.38M
                {
2668
1.38M
                    ch = pszInput[iIn++];
2669
1.38M
                    if (ch >= '0' && ch <= '9')
2670
1.12M
                        nVal = nVal * 10U + static_cast<unsigned int>(ch - '0');
2671
253k
                    else
2672
253k
                        break;
2673
1.38M
                }
2674
253k
                anVal[0] = static_cast<wchar_t>(nVal);
2675
253k
                if (ch != ';')
2676
39.7k
                    break;
2677
213k
                iIn--;
2678
2679
213k
                char *pszUTF8 =
2680
213k
                    CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
2681
213k
                const int nLen = static_cast<int>(strlen(pszUTF8));
2682
213k
                memcpy(pszOutput + iOut, pszUTF8, nLen);
2683
213k
                CPLFree(pszUTF8);
2684
213k
                iOut += nLen;
2685
213k
            }
2686
674k
            else
2687
674k
            {
2688
                // Illegal escape sequence.
2689
674k
                CPLDebug("CPL",
2690
674k
                         "Error unescaping CPLES_XML text, '&' character "
2691
674k
                         "followed by unhandled escape sequence.");
2692
674k
                break;
2693
674k
            }
2694
1.76G
        }
2695
1.17M
    }
2696
1.99M
    else if (nScheme == CPLES_URL)
2697
1.99M
    {
2698
722M
        for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
2699
720M
        {
2700
720M
            if (pszInput[iIn] == '%' && pszInput[iIn + 1] != '\0' &&
2701
720M
                pszInput[iIn + 2] != '\0')
2702
5.39M
            {
2703
5.39M
                int nHexChar = 0;
2704
2705
5.39M
                if (pszInput[iIn + 1] >= 'A' && pszInput[iIn + 1] <= 'F')
2706
300k
                    nHexChar += 16 * (pszInput[iIn + 1] - 'A' + 10);
2707
5.09M
                else if (pszInput[iIn + 1] >= 'a' && pszInput[iIn + 1] <= 'f')
2708
192k
                    nHexChar += 16 * (pszInput[iIn + 1] - 'a' + 10);
2709
4.90M
                else if (pszInput[iIn + 1] >= '0' && pszInput[iIn + 1] <= '9')
2710
744k
                    nHexChar += 16 * (pszInput[iIn + 1] - '0');
2711
4.15M
                else
2712
4.15M
                    CPLDebug("CPL",
2713
4.15M
                             "Error unescaping CPLES_URL text, percent not "
2714
4.15M
                             "followed by two hex digits.");
2715
2716
5.39M
                if (pszInput[iIn + 2] >= 'A' && pszInput[iIn + 2] <= 'F')
2717
802k
                    nHexChar += pszInput[iIn + 2] - 'A' + 10;
2718
4.59M
                else if (pszInput[iIn + 2] >= 'a' && pszInput[iIn + 2] <= 'f')
2719
115k
                    nHexChar += pszInput[iIn + 2] - 'a' + 10;
2720
4.47M
                else if (pszInput[iIn + 2] >= '0' && pszInput[iIn + 2] <= '9')
2721
377k
                    nHexChar += pszInput[iIn + 2] - '0';
2722
4.09M
                else
2723
4.09M
                    CPLDebug("CPL",
2724
4.09M
                             "Error unescaping CPLES_URL text, percent not "
2725
4.09M
                             "followed by two hex digits.");
2726
2727
5.39M
                pszOutput[iOut++] = static_cast<char>(nHexChar);
2728
5.39M
                iIn += 2;
2729
5.39M
            }
2730
715M
            else if (pszInput[iIn] == '+')
2731
2.28M
            {
2732
2.28M
                pszOutput[iOut++] = ' ';
2733
2.28M
            }
2734
712M
            else
2735
712M
            {
2736
712M
                pszOutput[iOut++] = pszInput[iIn];
2737
712M
            }
2738
720M
        }
2739
1.99M
    }
2740
0
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2741
0
    {
2742
0
        char szQuote = nScheme == CPLES_SQL ? '\'' : '\"';
2743
0
        for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
2744
0
        {
2745
0
            if (pszInput[iIn] == szQuote && pszInput[iIn + 1] == szQuote)
2746
0
            {
2747
0
                ++iIn;
2748
0
                pszOutput[iOut++] = pszInput[iIn];
2749
0
            }
2750
0
            else
2751
0
            {
2752
0
                pszOutput[iOut++] = pszInput[iIn];
2753
0
            }
2754
0
        }
2755
0
    }
2756
0
    else if (nScheme == CPLES_CSV)
2757
0
    {
2758
0
        CPLError(CE_Fatal, CPLE_NotSupported,
2759
0
                 "CSV Unescaping not yet implemented.");
2760
0
    }
2761
0
    else
2762
0
    {
2763
0
        CPLError(CE_Fatal, CPLE_NotSupported, "Unknown escaping style.");
2764
0
    }
2765
2766
4.14M
    pszOutput[iOut] = '\0';
2767
2768
4.14M
    if (pnLength != nullptr)
2769
979k
        *pnLength = iOut;
2770
2771
4.14M
    return pszOutput;
2772
4.14M
}
2773
2774
/************************************************************************/
2775
/*                           CPLBinaryToHex()                           */
2776
/************************************************************************/
2777
2778
/**
2779
 * Binary to hexadecimal translation.
2780
 *
2781
 * @param nBytes number of bytes of binary data in pabyData.
2782
 * @param pabyData array of data bytes to translate.
2783
 *
2784
 * @return hexadecimal translation, zero terminated.  Free with CPLFree().
2785
 */
2786
2787
char *CPLBinaryToHex(int nBytes, const GByte *pabyData)
2788
2789
11.8k
{
2790
11.8k
    CPLAssert(nBytes >= 0);
2791
11.8k
    char *pszHex = static_cast<char *>(
2792
11.8k
        VSI_MALLOC_VERBOSE(static_cast<size_t>(nBytes) * 2 + 1));
2793
11.8k
    if (!pszHex)
2794
0
    {
2795
0
        pszHex = CPLStrdup("");
2796
0
        return pszHex;
2797
0
    }
2798
11.8k
    pszHex[nBytes * 2] = '\0';
2799
2800
11.8k
    constexpr char achHex[] = "0123456789ABCDEF";
2801
2802
185k
    for (size_t i = 0; i < static_cast<size_t>(nBytes); ++i)
2803
173k
    {
2804
173k
        const int nLow = pabyData[i] & 0x0f;
2805
173k
        const int nHigh = (pabyData[i] & 0xf0) >> 4;
2806
2807
173k
        pszHex[i * 2] = achHex[nHigh];
2808
173k
        pszHex[i * 2 + 1] = achHex[nLow];
2809
173k
    }
2810
2811
11.8k
    return pszHex;
2812
11.8k
}
2813
2814
/************************************************************************/
2815
/*                           CPLHexToBinary()                           */
2816
/************************************************************************/
2817
2818
constexpr unsigned char hex2char[256] = {
2819
    // Not Hex characters.
2820
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2821
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2822
    // 0-9
2823
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
2824
    // A-F
2825
    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2826
    // Not Hex characters.
2827
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2828
    // a-f
2829
    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2830
    0, 0, 0, 0, 0, 0, 0, 0, 0,
2831
    // Not Hex characters (upper 128 characters).
2832
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2833
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2834
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2835
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2836
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2837
    0, 0, 0};
2838
2839
/**
2840
 * Hexadecimal to binary translation
2841
 *
2842
 * @param pszHex the input hex encoded string.
2843
 * @param pnBytes the returned count of decoded bytes placed here.
2844
 *
2845
 * @return returns binary buffer of data - free with CPLFree().
2846
 */
2847
2848
GByte *CPLHexToBinary(const char *pszHex, int *pnBytes)
2849
2.01M
{
2850
2.01M
    const GByte *pabyHex = reinterpret_cast<const GByte *>(pszHex);
2851
2.01M
    const size_t nHexLen = strlen(pszHex);
2852
2853
2.01M
    GByte *pabyWKB = static_cast<GByte *>(CPLMalloc(nHexLen / 2 + 2));
2854
2855
50.2M
    for (size_t i = 0; i < nHexLen / 2; ++i)
2856
48.1M
    {
2857
48.1M
        const unsigned char h1 = hex2char[pabyHex[2 * i]];
2858
48.1M
        const unsigned char h2 = hex2char[pabyHex[2 * i + 1]];
2859
2860
        // First character is high bits, second is low bits.
2861
48.1M
        pabyWKB[i] = static_cast<GByte>((h1 << 4) | h2);
2862
48.1M
    }
2863
2.01M
    pabyWKB[nHexLen / 2] = 0;
2864
2.01M
    *pnBytes = static_cast<int>(nHexLen / 2);
2865
2866
2.01M
    return pabyWKB;
2867
2.01M
}
2868
2869
/************************************************************************/
2870
/*                         CPLGetValueType()                            */
2871
/************************************************************************/
2872
2873
/**
2874
 * Detect the type of the value contained in a string, whether it is
2875
 * a real, an integer or a string
2876
 * Leading and trailing spaces are skipped in the analysis.
2877
 *
2878
 * Note: in the context of this function, integer must be understood in a
2879
 * broad sense. It does not mean that the value can fit into a 32 bit integer
2880
 * for example. It might be larger.
2881
 *
2882
 * @param pszValue the string to analyze
2883
 *
2884
 * @return returns the type of the value contained in the string.
2885
 */
2886
2887
CPLValueType CPLGetValueType(const char *pszValue)
2888
32.4M
{
2889
    // Doubles : "+25.e+3", "-25.e-3", "25.e3", "25e3", " 25e3 "
2890
    // Not doubles: "25e 3", "25e.3", "-2-5e3", "2-5e3", "25.25.3", "-3d", "d1"
2891
    //              "XXeYYYYYYYYYYYYYYYYYYY" that evaluates to infinity
2892
2893
32.4M
    if (pszValue == nullptr)
2894
0
        return CPL_VALUE_STRING;
2895
2896
32.4M
    const char *pszValueInit = pszValue;
2897
2898
    // Skip leading spaces.
2899
32.8M
    while (isspace(static_cast<unsigned char>(*pszValue)))
2900
360k
        ++pszValue;
2901
2902
32.4M
    if (*pszValue == '\0')
2903
16.3M
        return CPL_VALUE_STRING;
2904
2905
    // Skip leading + or -.
2906
16.0M
    if (*pszValue == '+' || *pszValue == '-')
2907
2.19M
        ++pszValue;
2908
2909
16.0M
    constexpr char DIGIT_ZERO = '0';
2910
16.0M
    if (pszValue[0] == DIGIT_ZERO && pszValue[1] != '\0' && pszValue[1] != '.')
2911
326k
        return CPL_VALUE_STRING;
2912
2913
15.7M
    bool bFoundDot = false;
2914
15.7M
    bool bFoundExponent = false;
2915
15.7M
    bool bIsLastCharExponent = false;
2916
15.7M
    bool bIsReal = false;
2917
15.7M
    const char *pszAfterExponent = nullptr;
2918
15.7M
    bool bFoundMantissa = false;
2919
2920
155M
    for (; *pszValue != '\0'; ++pszValue)
2921
143M
    {
2922
143M
        if (isdigit(static_cast<unsigned char>(*pszValue)))
2923
132M
        {
2924
132M
            bIsLastCharExponent = false;
2925
132M
            bFoundMantissa = true;
2926
132M
        }
2927
11.0M
        else if (isspace(static_cast<unsigned char>(*pszValue)))
2928
243k
        {
2929
243k
            const char *pszTmp = pszValue;
2930
11.7M
            while (isspace(static_cast<unsigned char>(*pszTmp)))
2931
11.4M
                ++pszTmp;
2932
243k
            if (*pszTmp == 0)
2933
148k
                break;
2934
94.1k
            else
2935
94.1k
                return CPL_VALUE_STRING;
2936
243k
        }
2937
10.8M
        else if (*pszValue == '-' || *pszValue == '+')
2938
207k
        {
2939
207k
            if (bIsLastCharExponent)
2940
144k
            {
2941
                // Do nothing.
2942
144k
            }
2943
63.0k
            else
2944
63.0k
            {
2945
63.0k
                return CPL_VALUE_STRING;
2946
63.0k
            }
2947
144k
            bIsLastCharExponent = false;
2948
144k
        }
2949
10.6M
        else if (*pszValue == '.')
2950
6.86M
        {
2951
6.86M
            bIsReal = true;
2952
6.86M
            if (!bFoundDot && !bIsLastCharExponent)
2953
6.77M
                bFoundDot = true;
2954
82.0k
            else
2955
82.0k
                return CPL_VALUE_STRING;
2956
6.77M
            bIsLastCharExponent = false;
2957
6.77M
        }
2958
3.74M
        else if (*pszValue == 'D' || *pszValue == 'd' || *pszValue == 'E' ||
2959
3.74M
                 *pszValue == 'e')
2960
689k
        {
2961
689k
            if (!bFoundMantissa)
2962
179k
                return CPL_VALUE_STRING;
2963
509k
            if (!(pszValue[1] == '+' || pszValue[1] == '-' ||
2964
509k
                  isdigit(static_cast<unsigned char>(pszValue[1]))))
2965
60.2k
                return CPL_VALUE_STRING;
2966
2967
449k
            bIsReal = true;
2968
449k
            if (!bFoundExponent)
2969
428k
                bFoundExponent = true;
2970
21.0k
            else
2971
21.0k
                return CPL_VALUE_STRING;
2972
428k
            pszAfterExponent = pszValue + 1;
2973
428k
            bIsLastCharExponent = true;
2974
428k
        }
2975
3.05M
        else
2976
3.05M
        {
2977
3.05M
            return CPL_VALUE_STRING;
2978
3.05M
        }
2979
143M
    }
2980
2981
12.1M
    if (bIsReal && pszAfterExponent && strlen(pszAfterExponent) > 3)
2982
182k
    {
2983
        // cppcheck-suppress unreadVariable
2984
182k
        const double dfVal = CPLAtof(pszValueInit);
2985
182k
        if (std::isinf(dfVal))
2986
55.2k
            return CPL_VALUE_STRING;
2987
182k
    }
2988
2989
12.1M
    return bIsReal ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
2990
12.1M
}
2991
2992
/************************************************************************/
2993
/*                              CPLStrlcpy()                            */
2994
/************************************************************************/
2995
2996
/**
2997
 * Copy source string to a destination buffer.
2998
 *
2999
 * This function ensures that the destination buffer is always NUL terminated
3000
 * (provided that its length is at least 1).
3001
 *
3002
 * This function is designed to be a safer, more consistent, and less error
3003
 * prone replacement for strncpy. Its contract is identical to libbsd's strlcpy.
3004
 *
3005
 * Truncation can be detected by testing if the return value of CPLStrlcpy
3006
 * is greater or equal to nDestSize.
3007
3008
\verbatim
3009
char szDest[5] = {};
3010
if( CPLStrlcpy(szDest, "abcde", sizeof(szDest)) >= sizeof(szDest) )
3011
    fprintf(stderr, "truncation occurred !\n");
3012
\endverbatim
3013
3014
 * @param pszDest   destination buffer
3015
 * @param pszSrc    source string. Must be NUL terminated
3016
 * @param nDestSize size of destination buffer (including space for the NUL
3017
 *     terminator character)
3018
 *
3019
 * @return the length of the source string (=strlen(pszSrc))
3020
 *
3021
 * @since GDAL 1.7.0
3022
 */
3023
size_t CPLStrlcpy(char *pszDest, const char *pszSrc, size_t nDestSize)
3024
6.17M
{
3025
6.17M
    if (nDestSize == 0)
3026
0
        return strlen(pszSrc);
3027
3028
6.17M
    char *pszDestIter = pszDest;
3029
6.17M
    const char *pszSrcIter = pszSrc;
3030
3031
6.17M
    --nDestSize;
3032
76.0M
    while (nDestSize != 0 && *pszSrcIter != '\0')
3033
69.9M
    {
3034
69.9M
        *pszDestIter = *pszSrcIter;
3035
69.9M
        ++pszDestIter;
3036
69.9M
        ++pszSrcIter;
3037
69.9M
        --nDestSize;
3038
69.9M
    }
3039
6.17M
    *pszDestIter = '\0';
3040
6.17M
    return pszSrcIter - pszSrc + strlen(pszSrcIter);
3041
6.17M
}
3042
3043
/************************************************************************/
3044
/*                              CPLStrlcat()                            */
3045
/************************************************************************/
3046
3047
/**
3048
 * Appends a source string to a destination buffer.
3049
 *
3050
 * This function ensures that the destination buffer is always NUL terminated
3051
 * (provided that its length is at least 1 and that there is at least one byte
3052
 * free in pszDest, that is to say strlen(pszDest_before) < nDestSize)
3053
 *
3054
 * This function is designed to be a safer, more consistent, and less error
3055
 * prone replacement for strncat. Its contract is identical to libbsd's strlcat.
3056
 *
3057
 * Truncation can be detected by testing if the return value of CPLStrlcat
3058
 * is greater or equal to nDestSize.
3059
3060
\verbatim
3061
char szDest[5] = {};
3062
CPLStrlcpy(szDest, "ab", sizeof(szDest));
3063
if( CPLStrlcat(szDest, "cde", sizeof(szDest)) >= sizeof(szDest) )
3064
    fprintf(stderr, "truncation occurred !\n");
3065
\endverbatim
3066
3067
 * @param pszDest   destination buffer. Must be NUL terminated before
3068
 *         running CPLStrlcat
3069
 * @param pszSrc    source string. Must be NUL terminated
3070
 * @param nDestSize size of destination buffer (including space for the
3071
 *         NUL terminator character)
3072
 *
3073
 * @return the theoretical length of the destination string after concatenation
3074
 *         (=strlen(pszDest_before) + strlen(pszSrc)).
3075
 *         If strlen(pszDest_before) >= nDestSize, then it returns
3076
 *         nDestSize + strlen(pszSrc)
3077
 *
3078
 * @since GDAL 1.7.0
3079
 */
3080
size_t CPLStrlcat(char *pszDest, const char *pszSrc, size_t nDestSize)
3081
0
{
3082
0
    char *pszDestIter = pszDest;
3083
3084
0
    while (nDestSize != 0 && *pszDestIter != '\0')
3085
0
    {
3086
0
        ++pszDestIter;
3087
0
        --nDestSize;
3088
0
    }
3089
3090
0
    return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
3091
0
}
3092
3093
/************************************************************************/
3094
/*                              CPLStrnlen()                            */
3095
/************************************************************************/
3096
3097
/**
3098
 * Returns the length of a NUL terminated string by reading at most
3099
 * the specified number of bytes.
3100
 *
3101
 * The CPLStrnlen() function returns min(strlen(pszStr), nMaxLen).
3102
 * Only the first nMaxLen bytes of the string will be read. Useful to
3103
 * test if a string contains at least nMaxLen characters without reading
3104
 * the full string up to the NUL terminating character.
3105
 *
3106
 * @param pszStr    a NUL terminated string
3107
 * @param nMaxLen   maximum number of bytes to read in pszStr
3108
 *
3109
 * @return strlen(pszStr) if the length is lesser than nMaxLen, otherwise
3110
 * nMaxLen if the NUL character has not been found in the first nMaxLen bytes.
3111
 *
3112
 * @since GDAL 1.7.0
3113
 */
3114
3115
size_t CPLStrnlen(const char *pszStr, size_t nMaxLen)
3116
43.8M
{
3117
43.8M
    size_t nLen = 0;
3118
2.82G
    while (nLen < nMaxLen && *pszStr != '\0')
3119
2.78G
    {
3120
2.78G
        ++nLen;
3121
2.78G
        ++pszStr;
3122
2.78G
    }
3123
43.8M
    return nLen;
3124
43.8M
}
3125
3126
/************************************************************************/
3127
/*                            CSLParseCommandLine()                     */
3128
/************************************************************************/
3129
3130
/**
3131
 * Tokenize command line arguments in a list of strings.
3132
 *
3133
 * @param pszCommandLine  command line
3134
 *
3135
 * @return NULL terminated list of strings to free with CSLDestroy()
3136
 *
3137
 * @since GDAL 2.1
3138
 */
3139
char **CSLParseCommandLine(const char *pszCommandLine)
3140
0
{
3141
0
    return CSLTokenizeString(pszCommandLine);
3142
0
}
3143
3144
/************************************************************************/
3145
/*                              CPLToupper()                            */
3146
/************************************************************************/
3147
3148
/** Converts a (ASCII) lowercase character to uppercase.
3149
 *
3150
 * Same as standard toupper(), except that it is not locale sensitive.
3151
 *
3152
 * @since GDAL 3.9
3153
 */
3154
int CPLToupper(int c)
3155
225M
{
3156
225M
    return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c;
3157
225M
}
3158
3159
/************************************************************************/
3160
/*                              CPLTolower()                            */
3161
/************************************************************************/
3162
3163
/** Converts a (ASCII) uppercase character to lowercase.
3164
 *
3165
 * Same as standard tolower(), except that it is not locale sensitive.
3166
 *
3167
 * @since GDAL 3.9
3168
 */
3169
int CPLTolower(int c)
3170
993M
{
3171
993M
    return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c;
3172
993M
}
3173
3174
/************************************************************************/
3175
/*                      CPLRemoveSQLComments()                          */
3176
/************************************************************************/
3177
3178
/** Remove SQL comments from a string
3179
 *
3180
 * @param osInput Input string.
3181
 * @since GDAL 3.11
3182
 */
3183
std::string CPLRemoveSQLComments(const std::string &osInput)
3184
2
{
3185
2
    const CPLStringList aosLines(
3186
2
        CSLTokenizeStringComplex(osInput.c_str(), "\r\n", FALSE, FALSE));
3187
2
    std::string osSQL;
3188
2
    for (const char *pszLine : aosLines)
3189
0
    {
3190
0
        char chQuote = 0;
3191
0
        int i = 0;
3192
0
        for (; pszLine[i] != '\0'; ++i)
3193
0
        {
3194
0
            if (chQuote)
3195
0
            {
3196
0
                if (pszLine[i] == chQuote)
3197
0
                {
3198
                    // Deal with escaped quote character which is repeated,
3199
                    // so 'foo''bar' or "foo""bar"
3200
0
                    if (pszLine[i + 1] == chQuote)
3201
0
                    {
3202
0
                        i++;
3203
0
                    }
3204
0
                    else
3205
0
                    {
3206
0
                        chQuote = 0;
3207
0
                    }
3208
0
                }
3209
0
            }
3210
0
            else if (pszLine[i] == '\'' || pszLine[i] == '"')
3211
0
            {
3212
0
                chQuote = pszLine[i];
3213
0
            }
3214
0
            else if (pszLine[i] == '-' && pszLine[i + 1] == '-')
3215
0
            {
3216
0
                break;
3217
0
            }
3218
0
        }
3219
0
        if (i > 0)
3220
0
        {
3221
0
            if (!osSQL.empty())
3222
0
                osSQL += ' ';
3223
0
            osSQL.append(pszLine, i);
3224
0
        }
3225
0
    }
3226
2
    return osSQL;
3227
2
}