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

OSGeo / gdal / 8872387746

29 Apr 2024 02:16AM UTC coverage: 69.076% (+0.003%) from 69.073%
8872387746

Pull #9801

github

web-flow
Bump actions/upload-artifact from 4.3.2 to 4.3.3

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.2 to 4.3.3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/1746f4ab6...65462800f)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #9801: Bump actions/upload-artifact from 4.3.2 to 4.3.3

534153 of 773282 relevant lines covered (69.08%)

205719.18 hits per line

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

89.29
/port/cpl_string.cpp
1
/**********************************************************************
2
 *
3
 * Name:     cpl_string.cpp
4
 * Project:  CPL - Common Portability Library
5
 * Purpose:  String and Stringlist manipulation functions.
6
 * Author:   Daniel Morissette, danmo@videotron.ca
7
 *
8
 **********************************************************************
9
 * Copyright (c) 1998, Daniel Morissette
10
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a
13
 * copy of this software and associated documentation files (the "Software"),
14
 * to deal in the Software without restriction, including without limitation
15
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16
 * and/or sell copies of the Software, and to permit persons to whom the
17
 * Software is furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included
20
 * in all copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28
 * DEALINGS IN THE SOFTWARE.
29
 **********************************************************************
30
 *
31
 * Independent Security Audit 2003/04/04 Andrey Kiselev:
32
 *   Completed audit of this module. All functions may be used without buffer
33
 *   overflows and stack corruptions with any kind of input data strings with
34
 *   except of CPLSPrintf() and CSLAppendPrintf() (see note below).
35
 *
36
 * Security Audit 2003/03/28 warmerda:
37
 *   Completed security audit.  I believe that this module may be safely used
38
 *   to parse tokenize arbitrary input strings, assemble arbitrary sets of
39
 *   names values into string lists, unescape and escape text even if provided
40
 *   by a potentially hostile source.
41
 *
42
 *   CPLSPrintf() and CSLAppendPrintf() may not be safely invoked on
43
 *   arbitrary length inputs since it has a fixed size output buffer on system
44
 *   without vsnprintf().
45
 *
46
 **********************************************************************/
47

48
#undef WARN_STANDARD_PRINTF
49

50
#include "cpl_port.h"
51
#include "cpl_string.h"
52

53
#include <cctype>
54
#include <climits>
55
#include <cstdlib>
56
#include <cstring>
57

58
#include <limits>
59

60
#include "cpl_config.h"
61
#include "cpl_multiproc.h"
62
#include "cpl_vsi.h"
63

64
#if !defined(va_copy) && defined(__va_copy)
65
#define va_copy __va_copy
66
#endif
67

68
/*=====================================================================
69
                    StringList manipulation functions.
70
 =====================================================================*/
71

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

76
/** Append a string to a StringList and return a pointer to the modified
77
 * StringList.
78
 *
79
 * If the input StringList is NULL, then a new StringList is created.
80
 * Note that CSLAddString performance when building a list is in O(n^2)
81
 * which can cause noticeable slow down when n > 10000.
82
 */
83
char **CSLAddString(char **papszStrList, const char *pszNewString)
415,458✔
84
{
85
    char **papszRet = CSLAddStringMayFail(papszStrList, pszNewString);
415,458✔
86
    if (papszRet == nullptr && pszNewString != nullptr)
415,368✔
87
        abort();
×
88
    return papszRet;
415,368✔
89
}
90

91
/** Same as CSLAddString() but may return NULL in case of (memory) failure */
92
char **CSLAddStringMayFail(char **papszStrList, const char *pszNewString)
448,234✔
93
{
94
    if (pszNewString == nullptr)
448,234✔
95
        return papszStrList;  // Nothing to do!
131✔
96

97
    char *pszDup = VSI_STRDUP_VERBOSE(pszNewString);
448,103✔
98
    if (pszDup == nullptr)
448,003✔
99
        return nullptr;
×
100

101
    // Allocate room for the new string.
102
    char **papszStrListNew = nullptr;
448,003✔
103
    int nItems = 0;
448,003✔
104

105
    if (papszStrList == nullptr)
448,003✔
106
        papszStrListNew =
107
            static_cast<char **>(VSI_CALLOC_VERBOSE(2, sizeof(char *)));
61,174✔
108
    else
109
    {
110
        nItems = CSLCount(papszStrList);
386,829✔
111
        papszStrListNew = static_cast<char **>(
112
            VSI_REALLOC_VERBOSE(papszStrList, (nItems + 2) * sizeof(char *)));
386,799✔
113
    }
114
    if (papszStrListNew == nullptr)
447,980✔
115
    {
116
        VSIFree(pszDup);
×
117
        return nullptr;
×
118
    }
119

120
    // Copy the string in the list.
121
    papszStrListNew[nItems] = pszDup;
447,980✔
122
    papszStrListNew[nItems + 1] = nullptr;
447,980✔
123

124
    return papszStrListNew;
447,980✔
125
}
126

127
/************************************************************************/
128
/*                              CSLCount()                              */
129
/************************************************************************/
130

131
/**
132
 * Return number of items in a string list.
133
 *
134
 * Returns the number of items in a string list, not counting the
135
 * terminating NULL.  Passing in NULL is safe, and will result in a count
136
 * of zero.
137
 *
138
 * Lists are counted by iterating through them so long lists will
139
 * take more time than short lists.  Care should be taken to avoid using
140
 * CSLCount() as an end condition for loops as it will result in O(n^2)
141
 * behavior.
142
 *
143
 * @param papszStrList the string list to count.
144
 *
145
 * @return the number of entries.
146
 */
147
int CSLCount(CSLConstList papszStrList)
1,198,060✔
148
{
149
    if (!papszStrList)
1,198,060✔
150
        return 0;
133,927✔
151

152
    int nItems = 0;
1,064,140✔
153

154
    while (*papszStrList != nullptr)
12,039,700✔
155
    {
156
        ++nItems;
10,975,500✔
157
        ++papszStrList;
10,975,500✔
158
    }
159

160
    return nItems;
1,064,140✔
161
}
162

163
/************************************************************************/
164
/*                            CSLGetField()                             */
165
/************************************************************************/
166

167
/**
168
 * Fetches the indicated field, being careful not to crash if the field
169
 * doesn't exist within this string list.
170
 *
171
 * The returned pointer should not be freed, and doesn't necessarily last long.
172
 */
173
const char *CSLGetField(CSLConstList papszStrList, int iField)
1,963✔
174

175
{
176
    if (papszStrList == nullptr || iField < 0)
1,963✔
177
        return ("");
×
178

179
    for (int i = 0; i < iField + 1; i++)
4,323✔
180
    {
181
        if (papszStrList[i] == nullptr)
2,362✔
182
            return "";
2✔
183
    }
184

185
    return (papszStrList[iField]);
1,961✔
186
}
187

188
/************************************************************************/
189
/*                             CSLDestroy()                             */
190
/************************************************************************/
191

192
/**
193
 * Free string list.
194
 *
195
 * Frees the passed string list (null terminated array of strings).
196
 * It is safe to pass NULL.
197
 *
198
 * @param papszStrList the list to free.
199
 */
200
void CPL_STDCALL CSLDestroy(char **papszStrList)
8,201,660✔
201
{
202
    if (!papszStrList)
8,201,660✔
203
        return;
6,066,970✔
204

205
    for (char **papszPtr = papszStrList; *papszPtr != nullptr; ++papszPtr)
10,967,200✔
206
    {
207
        CPLFree(*papszPtr);
8,832,070✔
208
    }
209

210
    CPLFree(papszStrList);
2,135,100✔
211
}
212

213
/************************************************************************/
214
/*                            CSLDuplicate()                            */
215
/************************************************************************/
216

217
/**
218
 * Clone a string list.
219
 *
220
 * Efficiently allocates a copy of a string list.  The returned list is
221
 * owned by the caller and should be freed with CSLDestroy().
222
 *
223
 * @param papszStrList the input string list.
224
 *
225
 * @return newly allocated copy.
226
 */
227

228
char **CSLDuplicate(CSLConstList papszStrList)
152,189✔
229
{
230
    const int nLines = CSLCount(papszStrList);
152,189✔
231

232
    if (nLines == 0)
152,179✔
233
        return nullptr;
103,653✔
234

235
    CSLConstList papszSrc = papszStrList;
48,526✔
236

237
    char **papszNewList =
238
        static_cast<char **>(VSI_MALLOC2_VERBOSE(nLines + 1, sizeof(char *)));
48,526✔
239

240
    char **papszDst = papszNewList;
48,522✔
241

242
    for (; *papszSrc != nullptr; ++papszSrc, ++papszDst)
488,515✔
243
    {
244
        *papszDst = VSI_STRDUP_VERBOSE(*papszSrc);
439,993✔
245
        if (*papszDst == nullptr)
439,993✔
246
        {
247
            CSLDestroy(papszNewList);
×
248
            return nullptr;
×
249
        }
250
    }
251
    *papszDst = nullptr;
48,522✔
252

253
    return papszNewList;
48,522✔
254
}
255

256
/************************************************************************/
257
/*                               CSLMerge                               */
258
/************************************************************************/
259

260
/**
261
 * \brief Merge two lists.
262
 *
263
 * The two lists are merged, ensuring that if any keys appear in both
264
 * that the value from the second (papszOverride) list take precedence.
265
 *
266
 * @param papszOrig the original list, being modified.
267
 * @param papszOverride the list of items being merged in.  This list
268
 * is unaltered and remains owned by the caller.
269
 *
270
 * @return updated list.
271
 */
272

273
char **CSLMerge(char **papszOrig, CSLConstList papszOverride)
4,200✔
274

275
{
276
    if (papszOrig == nullptr && papszOverride != nullptr)
4,200✔
277
        return CSLDuplicate(papszOverride);
634✔
278

279
    if (papszOverride == nullptr)
3,566✔
280
        return papszOrig;
2,622✔
281

282
    for (int i = 0; papszOverride[i] != nullptr; ++i)
4,523✔
283
    {
284
        char *pszKey = nullptr;
3,579✔
285
        const char *pszValue = CPLParseNameValue(papszOverride[i], &pszKey);
3,579✔
286

287
        papszOrig = CSLSetNameValue(papszOrig, pszKey, pszValue);
3,579✔
288
        CPLFree(pszKey);
3,579✔
289
    }
290

291
    return papszOrig;
944✔
292
}
293

294
/************************************************************************/
295
/*                             CSLLoad2()                               */
296
/************************************************************************/
297

298
/**
299
 * Load a text file into a string list.
300
 *
301
 * The VSI*L API is used, so VSIFOpenL() supported objects that aren't
302
 * physical files can also be accessed.  Files are returned as a string list,
303
 * with one item in the string list per line.  End of line markers are
304
 * stripped (by CPLReadLineL()).
305
 *
306
 * If reading the file fails a CPLError() will be issued and NULL returned.
307
 *
308
 * @param pszFname the name of the file to read.
309
 * @param nMaxLines maximum number of lines to read before stopping, or -1 for
310
 * no limit.
311
 * @param nMaxCols maximum number of characters in a line before stopping, or -1
312
 * for no limit.
313
 * @param papszOptions NULL-terminated array of options. Unused for now.
314
 *
315
 * @return a string list with the files lines, now owned by caller. To be freed
316
 * with CSLDestroy()
317
 *
318
 * @since GDAL 1.7.0
319
 */
320

321
char **CSLLoad2(const char *pszFname, int nMaxLines, int nMaxCols,
3,098✔
322
                CSLConstList papszOptions)
323
{
324
    VSILFILE *fp = VSIFOpenL(pszFname, "rb");
3,098✔
325

326
    if (!fp)
3,098✔
327
    {
328
        if (CPLFetchBool(papszOptions, "EMIT_ERROR_IF_CANNOT_OPEN_FILE", true))
1,983✔
329
        {
330
            // Unable to open file.
331
            CPLError(CE_Failure, CPLE_OpenFailed,
1✔
332
                     "CSLLoad2(\"%s\") failed: unable to open file.", pszFname);
333
        }
334
        return nullptr;
1,983✔
335
    }
336

337
    char **papszStrList = nullptr;
1,115✔
338
    int nLines = 0;
1,115✔
339
    int nAllocatedLines = 0;
1,115✔
340

341
    while (!VSIFEofL(fp) && (nMaxLines == -1 || nLines < nMaxLines))
9,526✔
342
    {
343
        const char *pszLine = CPLReadLine2L(fp, nMaxCols, papszOptions);
8,420✔
344
        if (pszLine == nullptr)
8,420✔
345
            break;
9✔
346

347
        if (nLines + 1 >= nAllocatedLines)
8,411✔
348
        {
349
            nAllocatedLines = 16 + nAllocatedLines * 2;
1,241✔
350
            char **papszStrListNew = static_cast<char **>(
351
                VSIRealloc(papszStrList, nAllocatedLines * sizeof(char *)));
1,241✔
352
            if (papszStrListNew == nullptr)
1,241✔
353
            {
354
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
×
355
                CPLReadLineL(nullptr);
×
356
                CPLError(CE_Failure, CPLE_OutOfMemory,
×
357
                         "CSLLoad2(\"%s\") "
358
                         "failed: not enough memory to allocate lines.",
359
                         pszFname);
360
                return papszStrList;
×
361
            }
362
            papszStrList = papszStrListNew;
1,241✔
363
        }
364
        papszStrList[nLines] = CPLStrdup(pszLine);
8,411✔
365
        papszStrList[nLines + 1] = nullptr;
8,411✔
366
        ++nLines;
8,411✔
367
    }
368

369
    CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
1,115✔
370

371
    // Free the internal thread local line buffer.
372
    CPLReadLineL(nullptr);
1,115✔
373

374
    return papszStrList;
1,115✔
375
}
376

377
/************************************************************************/
378
/*                              CSLLoad()                               */
379
/************************************************************************/
380

381
/**
382
 * Load a text file into a string list.
383
 *
384
 * The VSI*L API is used, so VSIFOpenL() supported objects that aren't
385
 * physical files can also be accessed.  Files are returned as a string list,
386
 * with one item in the string list per line.  End of line markers are
387
 * stripped (by CPLReadLineL()).
388
 *
389
 * If reading the file fails a CPLError() will be issued and NULL returned.
390
 *
391
 * @param pszFname the name of the file to read.
392
 *
393
 * @return a string list with the files lines, now owned by caller. To be freed
394
 * with CSLDestroy()
395
 */
396

397
char **CSLLoad(const char *pszFname)
307✔
398
{
399
    return CSLLoad2(pszFname, -1, -1, nullptr);
307✔
400
}
401

402
/**********************************************************************
403
 *                       CSLSave()
404
 **********************************************************************/
405

406
/** Write a StringList to a text file.
407
 *
408
 * Returns the number of lines written, or 0 if the file could not
409
 * be written.
410
 */
411

412
int CSLSave(CSLConstList papszStrList, const char *pszFname)
49✔
413
{
414
    if (papszStrList == nullptr)
49✔
415
        return 0;
×
416

417
    VSILFILE *fp = VSIFOpenL(pszFname, "wt");
49✔
418
    if (fp == nullptr)
49✔
419
    {
420
        // Unable to open file.
421
        CPLError(CE_Failure, CPLE_OpenFailed,
1✔
422
                 "CSLSave(\"%s\") failed: unable to open output file.",
423
                 pszFname);
424
        return 0;
1✔
425
    }
426

427
    int nLines = 0;
48✔
428
    while (*papszStrList != nullptr)
385✔
429
    {
430
        if (VSIFPrintfL(fp, "%s\n", *papszStrList) < 1)
337✔
431
        {
432
            CPLError(CE_Failure, CPLE_FileIO,
×
433
                     "CSLSave(\"%s\") failed: unable to write to output file.",
434
                     pszFname);
435
            break;  // A Problem happened... abort.
×
436
        }
437

438
        ++nLines;
337✔
439
        ++papszStrList;
337✔
440
    }
441

442
    if (VSIFCloseL(fp) != 0)
48✔
443
    {
444
        CPLError(CE_Failure, CPLE_FileIO,
×
445
                 "CSLSave(\"%s\") failed: unable to write to output file.",
446
                 pszFname);
447
    }
448

449
    return nLines;
48✔
450
}
451

452
/**********************************************************************
453
 *                       CSLPrint()
454
 **********************************************************************/
455

456
/** Print a StringList to fpOut.  If fpOut==NULL, then output is sent
457
 * to stdout.
458
 *
459
 * Returns the number of lines printed.
460
 */
461
int CSLPrint(CSLConstList papszStrList, FILE *fpOut)
×
462
{
463
    if (!papszStrList)
×
464
        return 0;
×
465

466
    if (fpOut == nullptr)
×
467
        fpOut = stdout;
×
468

469
    int nLines = 0;
×
470

471
    while (*papszStrList != nullptr)
×
472
    {
473
        if (VSIFPrintf(fpOut, "%s\n", *papszStrList) < 0)
×
474
            return nLines;
×
475
        ++nLines;
×
476
        ++papszStrList;
×
477
    }
478

479
    return nLines;
×
480
}
481

482
/**********************************************************************
483
 *                       CSLInsertStrings()
484
 **********************************************************************/
485

486
/** Copies the contents of a StringList inside another StringList
487
 * before the specified line.
488
 *
489
 * nInsertAtLineNo is a 0-based line index before which the new strings
490
 * should be inserted.  If this value is -1 or is larger than the actual
491
 * number of strings in the list then the strings are added at the end
492
 * of the source StringList.
493
 *
494
 * Returns the modified StringList.
495
 */
496

497
char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo,
17,301✔
498
                        CSLConstList papszNewLines)
499
{
500
    if (papszNewLines == nullptr)
17,301✔
501
        return papszStrList;  // Nothing to do!
35✔
502

503
    const int nToInsert = CSLCount(papszNewLines);
17,266✔
504
    if (nToInsert == 0)
17,266✔
505
        return papszStrList;  // Nothing to do!
1,242✔
506

507
    const int nSrcLines = CSLCount(papszStrList);
16,024✔
508
    const int nDstLines = nSrcLines + nToInsert;
16,024✔
509

510
    // Allocate room for the new strings.
511
    papszStrList = static_cast<char **>(
512
        CPLRealloc(papszStrList, (nDstLines + 1) * sizeof(char *)));
16,024✔
513

514
    // Make sure the array is NULL-terminated.  It may not be if
515
    // papszStrList was NULL before Realloc().
516
    papszStrList[nSrcLines] = nullptr;
16,024✔
517

518
    // Make some room in the original list at the specified location.
519
    // Note that we also have to move the NULL pointer at the end of
520
    // the source StringList.
521
    if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
16,024✔
522
        nInsertAtLineNo = nSrcLines;
15,278✔
523

524
    {
525
        char **ppszSrc = papszStrList + nSrcLines;
16,024✔
526
        char **ppszDst = papszStrList + nDstLines;
16,024✔
527

528
        for (int i = nSrcLines; i >= nInsertAtLineNo; --i)
33,358✔
529
        {
530
            *ppszDst = *ppszSrc;
17,334✔
531
            --ppszDst;
17,334✔
532
            --ppszSrc;
17,334✔
533
        }
534
    }
535

536
    // Copy the strings to the list.
537
    CSLConstList ppszSrc = papszNewLines;
16,024✔
538
    char **ppszDst = papszStrList + nInsertAtLineNo;
16,024✔
539

540
    for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
144,171✔
541
    {
542
        *ppszDst = CPLStrdup(*ppszSrc);
128,147✔
543
    }
544

545
    return papszStrList;
16,024✔
546
}
547

548
/**********************************************************************
549
 *                       CSLInsertString()
550
 **********************************************************************/
551

552
/** Insert a string at a given line number inside a StringList
553
 *
554
 * nInsertAtLineNo is a 0-based line index before which the new string
555
 * should be inserted.  If this value is -1 or is larger than the actual
556
 * number of strings in the list then the string is added at the end
557
 * of the source StringList.
558
 *
559
 * Returns the modified StringList.
560
 */
561

562
char **CSLInsertString(char **papszStrList, int nInsertAtLineNo,
475✔
563
                       const char *pszNewLine)
564
{
565
    char *apszList[2] = {const_cast<char *>(pszNewLine), nullptr};
475✔
566

567
    return CSLInsertStrings(papszStrList, nInsertAtLineNo, apszList);
950✔
568
}
569

570
/**********************************************************************
571
 *                       CSLRemoveStrings()
572
 **********************************************************************/
573

574
/** Remove strings inside a StringList
575
 *
576
 * nFirstLineToDelete is the 0-based line index of the first line to
577
 * remove. If this value is -1 or is larger than the actual
578
 * number of strings in list then the nNumToRemove last strings are
579
 * removed.
580
 *
581
 * If ppapszRetStrings != NULL then the deleted strings won't be
582
 * free'd, they will be stored in a new StringList and the pointer to
583
 * this new list will be returned in *ppapszRetStrings.
584
 *
585
 * Returns the modified StringList.
586
 */
587

588
char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
5,275✔
589
                        int nNumToRemove, char ***ppapszRetStrings)
590
{
591
    const int nSrcLines = CSLCount(papszStrList);
5,275✔
592

593
    if (nNumToRemove < 1 || nSrcLines == 0)
5,275✔
594
        return papszStrList;  // Nothing to do!
×
595

596
    // If operation will result in an empty StringList, don't waste
597
    // time here.
598
    const int nDstLines = nSrcLines - nNumToRemove;
5,275✔
599
    if (nDstLines < 1)
5,275✔
600
    {
601
        CSLDestroy(papszStrList);
680✔
602
        return nullptr;
680✔
603
    }
604

605
    // Remove lines from the source StringList.
606
    // Either free() each line or store them to a new StringList depending on
607
    // the caller's choice.
608
    char **ppszDst = papszStrList + nFirstLineToDelete;
4,595✔
609

610
    if (ppapszRetStrings == nullptr)
4,595✔
611
    {
612
        // free() all the strings that will be removed.
613
        for (int i = 0; i < nNumToRemove; ++i)
9,190✔
614
        {
615
            CPLFree(*ppszDst);
4,595✔
616
            *ppszDst = nullptr;
4,595✔
617
        }
618
    }
619
    else
620
    {
621
        // Store the strings to remove in a new StringList.
622
        *ppapszRetStrings =
×
623
            static_cast<char **>(CPLCalloc(nNumToRemove + 1, sizeof(char *)));
×
624

625
        for (int i = 0; i < nNumToRemove; ++i)
×
626
        {
627
            (*ppapszRetStrings)[i] = *ppszDst;
×
628
            *ppszDst = nullptr;
×
629
            ++ppszDst;
×
630
        }
631
    }
632

633
    // Shift down all the lines that follow the lines to remove.
634
    if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines)
4,595✔
635
        nFirstLineToDelete = nDstLines;
×
636

637
    char **ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
4,595✔
638
    ppszDst = papszStrList + nFirstLineToDelete;
4,595✔
639

640
    for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
9,071✔
641
    {
642
        *ppszDst = *ppszSrc;
4,476✔
643
    }
644
    // Move the NULL pointer at the end of the StringList.
645
    *ppszDst = *ppszSrc;
4,595✔
646

647
    // At this point, we could realloc() papszStrList to a smaller size, but
648
    // since this array will likely grow again in further operations on the
649
    // StringList we'll leave it as it is.
650
    return papszStrList;
4,595✔
651
}
652

653
/************************************************************************/
654
/*                           CSLFindString()                            */
655
/************************************************************************/
656

657
/**
658
 * Find a string within a string list (case insensitive).
659
 *
660
 * Returns the index of the entry in the string list that contains the
661
 * target string.  The string in the string list must be a full match for
662
 * the target, but the search is case insensitive.
663
 *
664
 * @param papszList the string list to be searched.
665
 * @param pszTarget the string to be searched for.
666
 *
667
 * @return the index of the string within the list or -1 on failure.
668
 */
669

670
int CSLFindString(CSLConstList papszList, const char *pszTarget)
3,678,180✔
671

672
{
673
    if (papszList == nullptr)
3,678,180✔
674
        return -1;
132,536✔
675

676
    for (int i = 0; papszList[i] != nullptr; ++i)
28,423,500✔
677
    {
678
        if (EQUAL(papszList[i], pszTarget))
25,033,900✔
679
            return i;
156,070✔
680
    }
681

682
    return -1;
3,389,580✔
683
}
684

685
/************************************************************************/
686
/*                     CSLFindStringCaseSensitive()                     */
687
/************************************************************************/
688

689
/**
690
 * Find a string within a string list(case sensitive)
691
 *
692
 * Returns the index of the entry in the string list that contains the
693
 * target string.  The string in the string list must be a full match for
694
 * the target.
695
 *
696
 * @param papszList the string list to be searched.
697
 * @param pszTarget the string to be searched for.
698
 *
699
 * @return the index of the string within the list or -1 on failure.
700
 *
701
 * @since GDAL 2.0
702
 */
703

704
int CSLFindStringCaseSensitive(CSLConstList papszList, const char *pszTarget)
3,310✔
705

706
{
707
    if (papszList == nullptr)
3,310✔
708
        return -1;
199✔
709

710
    for (int i = 0; papszList[i] != nullptr; ++i)
158,267✔
711
    {
712
        if (strcmp(papszList[i], pszTarget) == 0)
155,170✔
713
            return i;
14✔
714
    }
715

716
    return -1;
3,097✔
717
}
718

719
/************************************************************************/
720
/*                           CSLPartialFindString()                     */
721
/************************************************************************/
722

723
/**
724
 * Find a substring within a string list.
725
 *
726
 * Returns the index of the entry in the string list that contains the
727
 * target string as a substring.  The search is case sensitive (unlike
728
 * CSLFindString()).
729
 *
730
 * @param papszHaystack the string list to be searched.
731
 * @param pszNeedle the substring to be searched for.
732
 *
733
 * @return the index of the string within the list or -1 on failure.
734
 */
735

736
int CSLPartialFindString(CSLConstList papszHaystack, const char *pszNeedle)
19,901✔
737
{
738
    if (papszHaystack == nullptr || pszNeedle == nullptr)
19,901✔
739
        return -1;
7,211✔
740

741
    for (int i = 0; papszHaystack[i] != nullptr; ++i)
28,996✔
742
    {
743
        if (strstr(papszHaystack[i], pszNeedle))
21,584✔
744
            return i;
5,278✔
745
    }
746

747
    return -1;
7,412✔
748
}
749

750
/**********************************************************************
751
 *                       CSLTokenizeString()
752
 **********************************************************************/
753

754
/** Tokenizes a string and returns a StringList with one string for
755
 * each token.
756
 */
757
char **CSLTokenizeString(const char *pszString)
115,426✔
758
{
759
    return CSLTokenizeString2(pszString, " ", CSLT_HONOURSTRINGS);
115,426✔
760
}
761

762
/************************************************************************/
763
/*                      CSLTokenizeStringComplex()                      */
764
/************************************************************************/
765

766
/** Obsolete tokenizing api. Use CSLTokenizeString2() */
767
char **CSLTokenizeStringComplex(const char *pszString,
388,643✔
768
                                const char *pszDelimiters, int bHonourStrings,
769
                                int bAllowEmptyTokens)
770
{
771
    int nFlags = 0;
388,643✔
772

773
    if (bHonourStrings)
388,643✔
774
        nFlags |= CSLT_HONOURSTRINGS;
111,036✔
775
    if (bAllowEmptyTokens)
388,643✔
776
        nFlags |= CSLT_ALLOWEMPTYTOKENS;
17,257✔
777

778
    return CSLTokenizeString2(pszString, pszDelimiters, nFlags);
388,643✔
779
}
780

781
/************************************************************************/
782
/*                         CSLTokenizeString2()                         */
783
/************************************************************************/
784

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

816
\code
817
    char **papszTokens =
818
        CSLTokenizeString2( pszCommand, " \t\n",
819
                            CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS );
820

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

824
    CSLDestroy( papszTokens );
825
\endcode
826

827
 * @param pszString the string to be split into tokens.
828
 * @param pszDelimiters one or more characters to be used as token delimiters.
829
 * @param nCSLTFlags an ORing of one or more of the CSLT_ flag values.
830
 *
831
 * @return a string list of tokens owned by the caller.
832
 */
833

834
char **CSLTokenizeString2(const char *pszString, const char *pszDelimiters,
917,493✔
835
                          int nCSLTFlags)
836
{
837
    if (pszString == nullptr)
917,493✔
838
        return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
3,784✔
839

840
    CPLStringList oRetList;
1,827,420✔
841
    const bool bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS) != 0;
913,709✔
842
    const bool bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS) != 0;
913,709✔
843
    const bool bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES) != 0;
913,709✔
844
    const bool bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES) != 0;
913,709✔
845

846
    char *pszToken = static_cast<char *>(CPLCalloc(10, 1));
913,709✔
847
    size_t nTokenMax = 10;
913,709✔
848

849
    while (*pszString != '\0')
3,245,310✔
850
    {
851
        bool bInString = false;
2,331,600✔
852
        bool bStartString = true;
2,331,600✔
853
        size_t nTokenLen = 0;
2,331,600✔
854

855
        // Try to find the next delimiter, marking end of token.
856
        for (; *pszString != '\0'; ++pszString)
32,969,300✔
857
        {
858
            // Extend token buffer if we are running close to its end.
859
            if (nTokenLen >= nTokenMax - 3)
32,109,400✔
860
            {
861
                if (nTokenMax > std::numeric_limits<size_t>::max() / 2)
875,875✔
862
                {
863
                    CPLFree(pszToken);
×
864
                    return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
×
865
                }
866
                nTokenMax = nTokenMax * 2;
875,875✔
867
                char *pszNewToken = static_cast<char *>(
868
                    VSI_REALLOC_VERBOSE(pszToken, nTokenMax));
875,875✔
869
                if (pszNewToken == nullptr)
875,875✔
870
                {
871
                    CPLFree(pszToken);
×
872
                    return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
×
873
                }
874
                pszToken = pszNewToken;
875,875✔
875
            }
876

877
            // End if this is a delimiter skip it and break.
878
            if (!bInString && strchr(pszDelimiters, *pszString) != nullptr)
32,109,400✔
879
            {
880
                ++pszString;
1,471,700✔
881
                break;
1,471,700✔
882
            }
883

884
            // If this is a quote, and we are honouring constant
885
            // strings, then process the constant strings, with out delim
886
            // but don't copy over the quotes.
887
            if (bHonourStrings && *pszString == '"')
30,637,700✔
888
            {
889
                if (nCSLTFlags & CSLT_PRESERVEQUOTES)
72,960✔
890
                {
891
                    pszToken[nTokenLen] = *pszString;
4,181✔
892
                    ++nTokenLen;
4,181✔
893
                }
894

895
                bInString = !bInString;
72,960✔
896
                continue;
72,960✔
897
            }
898

899
            /*
900
             * Within string constants we allow for escaped quotes, but in
901
             * processing them we will unescape the quotes and \\ sequence
902
             * reduces to \
903
             */
904
            if (bInString && pszString[0] == '\\')
30,564,800✔
905
            {
906
                if (pszString[1] == '"' || pszString[1] == '\\')
110✔
907
                {
908
                    if (nCSLTFlags & CSLT_PRESERVEESCAPES)
44✔
909
                    {
910
                        pszToken[nTokenLen] = *pszString;
6✔
911
                        ++nTokenLen;
6✔
912
                    }
913

914
                    ++pszString;
44✔
915
                }
916
            }
917

918
            // Strip spaces at the token start if requested.
919
            if (!bInString && bStripLeadSpaces && bStartString &&
30,564,800✔
920
                isspace(static_cast<unsigned char>(*pszString)))
30,981✔
921
                continue;
4,593✔
922

923
            bStartString = false;
30,560,200✔
924

925
            pszToken[nTokenLen] = *pszString;
30,560,200✔
926
            ++nTokenLen;
30,560,200✔
927
        }
928

929
        // Strip spaces at the token end if requested.
930
        if (!bInString && bStripEndSpaces)
2,331,600✔
931
        {
932
            while (nTokenLen &&
31,876✔
933
                   isspace(static_cast<unsigned char>(pszToken[nTokenLen - 1])))
26,740✔
934
                nTokenLen--;
38✔
935
        }
936

937
        pszToken[nTokenLen] = '\0';
2,331,600✔
938

939
        // Add the token.
940
        if (pszToken[0] != '\0' || bAllowEmptyTokens)
2,331,600✔
941
            oRetList.AddString(pszToken);
2,215,150✔
942
    }
943

944
    /*
945
     * If the last token was empty, then we need to capture
946
     * it now, as the loop would skip it.
947
     */
948
    if (*pszString == '\0' && bAllowEmptyTokens && oRetList.Count() > 0 &&
939,425✔
949
        strchr(pszDelimiters, *(pszString - 1)) != nullptr)
25,716✔
950
    {
951
        oRetList.AddString("");
1,215✔
952
    }
953

954
    CPLFree(pszToken);
913,709✔
955

956
    if (oRetList.List() == nullptr)
913,709✔
957
    {
958
        // Prefer to return empty lists as a pointer to
959
        // a null pointer since some client code might depend on this.
960
        oRetList.Assign(static_cast<char **>(CPLCalloc(sizeof(char *), 1)));
23,188✔
961
    }
962

963
    return oRetList.StealList();
913,709✔
964
}
965

966
/**********************************************************************
967
 *                       CPLSPrintf()
968
 *
969
 * NOTE: This function should move to cpl_conv.cpp.
970
 **********************************************************************/
971

972
// For now, assume that a 8000 chars buffer will be enough.
973
constexpr int CPLSPrintf_BUF_SIZE = 8000;
974
constexpr int CPLSPrintf_BUF_Count = 10;
975

976
/** CPLSPrintf() that works with 10 static buffer.
977
 *
978
 * It returns a ref. to a static buffer that should not be freed and
979
 * is valid only until the next call to CPLSPrintf().
980
 */
981

982
const char *CPLSPrintf(CPL_FORMAT_STRING(const char *fmt), ...)
778,280✔
983
{
984
    va_list args;
985

986
    /* -------------------------------------------------------------------- */
987
    /*      Get the thread local buffer ring data.                          */
988
    /* -------------------------------------------------------------------- */
989
    char *pachBufRingInfo = static_cast<char *>(CPLGetTLS(CTLS_CPLSPRINTF));
778,280✔
990

991
    if (pachBufRingInfo == nullptr)
778,280✔
992
    {
993
        pachBufRingInfo = static_cast<char *>(CPLCalloc(
1,328✔
994
            1, sizeof(int) + CPLSPrintf_BUF_Count * CPLSPrintf_BUF_SIZE));
995
        CPLSetTLS(CTLS_CPLSPRINTF, pachBufRingInfo, TRUE);
1,328✔
996
    }
997

998
    /* -------------------------------------------------------------------- */
999
    /*      Work out which string in the "ring" we want to use this         */
1000
    /*      time.                                                           */
1001
    /* -------------------------------------------------------------------- */
1002
    int *pnBufIndex = reinterpret_cast<int *>(pachBufRingInfo);
778,280✔
1003
    const size_t nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
778,280✔
1004
    char *pachBuffer = pachBufRingInfo + nOffset;
778,280✔
1005

1006
    *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
778,280✔
1007

1008
    /* -------------------------------------------------------------------- */
1009
    /*      Format the result.                                              */
1010
    /* -------------------------------------------------------------------- */
1011

1012
    va_start(args, fmt);
778,280✔
1013

1014
    const int ret =
1015
        CPLvsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE - 1, fmt, args);
778,280✔
1016
    if (ret < 0 || ret >= CPLSPrintf_BUF_SIZE - 1)
778,280✔
1017
    {
1018
        CPLError(CE_Failure, CPLE_AppDefined,
×
1019
                 "CPLSPrintf() called with too "
1020
                 "big string. Output will be truncated !");
1021
    }
1022

1023
    va_end(args);
778,280✔
1024

1025
    return pachBuffer;
778,280✔
1026
}
1027

1028
/**********************************************************************
1029
 *                       CSLAppendPrintf()
1030
 **********************************************************************/
1031

1032
/** Use CPLSPrintf() to append a new line at the end of a StringList.
1033
 * Returns the modified StringList.
1034
 */
1035
char **CSLAppendPrintf(char **papszStrList, CPL_FORMAT_STRING(const char *fmt),
39✔
1036
                       ...)
1037
{
1038
    va_list args;
1039

1040
    va_start(args, fmt);
39✔
1041
    CPLString osWork;
78✔
1042
    osWork.vPrintf(fmt, args);
39✔
1043
    va_end(args);
39✔
1044

1045
    return CSLAddString(papszStrList, osWork);
78✔
1046
}
1047

1048
/************************************************************************/
1049
/*                            CPLVASPrintf()                            */
1050
/************************************************************************/
1051

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

1056
{
1057
    CPLString osWork;
×
1058

1059
    osWork.vPrintf(fmt, ap);
×
1060

1061
    if (buf)
×
1062
        *buf = CPLStrdup(osWork.c_str());
×
1063

1064
    return static_cast<int>(osWork.size());
×
1065
}
1066

1067
/************************************************************************/
1068
/*                  CPLvsnprintf_get_end_of_formatting()                */
1069
/************************************************************************/
1070

1071
static const char *CPLvsnprintf_get_end_of_formatting(const char *fmt)
2,496,210✔
1072
{
1073
    char ch = '\0';
2,496,210✔
1074
    // Flag.
1075
    for (; (ch = *fmt) != '\0'; ++fmt)
2,574,760✔
1076
    {
1077
        if (ch == '\'')
2,574,760✔
1078
            continue;  // Bad idea as this is locale specific.
×
1079
        if (ch == '-' || ch == '+' || ch == ' ' || ch == '#' || ch == '0')
2,574,760✔
1080
            continue;
78,551✔
1081
        break;
2,496,200✔
1082
    }
1083

1084
    // Field width.
1085
    for (; (ch = *fmt) != '\0'; ++fmt)
2,743,300✔
1086
    {
1087
        if (ch == '$')
2,743,310✔
1088
            return nullptr;  // Do not support this.
×
1089
        if (*fmt >= '0' && *fmt <= '9')
2,743,310✔
1090
            continue;
247,089✔
1091
        break;
2,496,220✔
1092
    }
1093

1094
    // Precision.
1095
    if (ch == '.')
2,496,210✔
1096
    {
1097
        ++fmt;
565,593✔
1098
        for (; (ch = *fmt) != '\0'; ++fmt)
1,623,680✔
1099
        {
1100
            if (ch == '$')
1,623,680✔
1101
                return nullptr;  // Do not support this.
×
1102
            if (*fmt >= '0' && *fmt <= '9')
1,623,680✔
1103
                continue;
1,058,080✔
1104
            break;
565,593✔
1105
        }
1106
    }
1107

1108
    // Length modifier.
1109
    for (; (ch = *fmt) != '\0'; ++fmt)
2,575,360✔
1110
    {
1111
        if (ch == 'h' || ch == 'l' || ch == 'j' || ch == 'z' || ch == 't' ||
2,575,360✔
1112
            ch == 'L')
1113
            continue;
79,152✔
1114
        else if (ch == 'I' && fmt[1] == '6' && fmt[2] == '4')
2,496,210✔
1115
            fmt += 2;
×
1116
        else
1117
            return fmt;
2,496,210✔
1118
    }
1119

1120
    return nullptr;
×
1121
}
1122

1123
/************************************************************************/
1124
/*                           CPLvsnprintf()                             */
1125
/************************************************************************/
1126

1127
#define call_native_snprintf(type)                                             \
1128
    local_ret = snprintf(str + offset_out, size - offset_out, localfmt,        \
1129
                         va_arg(wrk_args, type))
1130

1131
/** vsnprintf() wrapper that is not sensitive to LC_NUMERIC settings.
1132
 *
1133
 * This function has the same contract as standard vsnprintf(), except that
1134
 * formatting of floating-point numbers will use decimal point, whatever the
1135
 * current locale is set.
1136
 *
1137
 * @param str output buffer
1138
 * @param size size of the output buffer (including space for terminating nul)
1139
 * @param fmt formatting string
1140
 * @param args arguments
1141
 * @return the number of characters (excluding terminating nul) that would be
1142
 * written if size is big enough. Or potentially -1 with Microsoft C runtime
1143
 * for Visual Studio < 2015.
1144
 * @since GDAL 2.0
1145
 */
1146
int CPLvsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt),
1,562,480✔
1147
                 va_list args)
1148
{
1149
    if (size == 0)
1,562,480✔
1150
        return vsnprintf(str, size, fmt, args);
×
1151

1152
    va_list wrk_args;
1153

1154
#ifdef va_copy
1155
    va_copy(wrk_args, args);
1,562,480✔
1156
#else
1157
    wrk_args = args;
1158
#endif
1159

1160
    const char *fmt_ori = fmt;
1,562,480✔
1161
    size_t offset_out = 0;
1,562,480✔
1162
    char ch = '\0';
1,562,480✔
1163
    bool bFormatUnknown = false;
1,562,480✔
1164

1165
    for (; (ch = *fmt) != '\0'; ++fmt)
27,545,700✔
1166
    {
1167
        if (ch == '%')
25,985,700✔
1168
        {
1169
            if (strncmp(fmt, "%.*f", 4) == 0)
2,497,020✔
1170
            {
1171
                const int precision = va_arg(wrk_args, int);
778✔
1172
                const double val = va_arg(wrk_args, double);
778✔
1173
                const int local_ret =
1174
                    snprintf(str + offset_out, size - offset_out, "%.*f",
786✔
1175
                             precision, val);
1176
                // MSVC vsnprintf() returns -1.
1177
                if (local_ret < 0 || offset_out + local_ret >= size)
786✔
1178
                    break;
1179
                for (int j = 0; j < local_ret; ++j)
15,660✔
1180
                {
1181
                    if (str[offset_out + j] == ',')
14,882✔
1182
                    {
1183
                        str[offset_out + j] = '.';
×
1184
                        break;
×
1185
                    }
1186
                }
1187
                offset_out += local_ret;
778✔
1188
                fmt += strlen("%.*f") - 1;
778✔
1189
                continue;
778✔
1190
            }
1191

1192
            const char *ptrend = CPLvsnprintf_get_end_of_formatting(fmt + 1);
2,496,250✔
1193
            if (ptrend == nullptr || ptrend - fmt >= 20)
2,496,220✔
1194
            {
1195
                bFormatUnknown = true;
×
1196
                break;
×
1197
            }
1198
            char end = *ptrend;
2,496,230✔
1199
            char end_m1 = ptrend[-1];
2,496,230✔
1200

1201
            char localfmt[22] = {};
2,496,230✔
1202
            memcpy(localfmt, fmt, ptrend - fmt + 1);
2,496,230✔
1203
            localfmt[ptrend - fmt + 1] = '\0';
2,496,230✔
1204

1205
            int local_ret = 0;
2,496,230✔
1206
            if (end == '%')
2,496,230✔
1207
            {
1208
                if (offset_out == size - 1)
11,751✔
1209
                    break;
×
1210
                local_ret = 1;
11,751✔
1211
                str[offset_out] = '%';
11,751✔
1212
            }
1213
            else if (end == 'd' || end == 'i' || end == 'c')
2,484,480✔
1214
            {
1215
                if (end_m1 == 'h')
896,127✔
1216
                    call_native_snprintf(int);
×
1217
                else if (end_m1 == 'l' && ptrend[-2] != 'l')
896,127✔
1218
                    call_native_snprintf(long);
1,474✔
1219
                else if (end_m1 == 'l' && ptrend[-2] == 'l')
894,653✔
1220
                    call_native_snprintf(GIntBig);
22,760✔
1221
                else if (end_m1 == '4' && ptrend[-2] == '6' &&
871,893✔
1222
                         ptrend[-3] == 'I')
×
1223
                    // Microsoft I64 modifier.
1224
                    call_native_snprintf(GIntBig);
×
1225
                else if (end_m1 == 'z')
871,893✔
1226
                    call_native_snprintf(size_t);
×
1227
                else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
871,893✔
1228
                         (end_m1 >= 'A' && end_m1 <= 'Z'))
×
1229
                {
1230
                    bFormatUnknown = true;
×
1231
                    break;
×
1232
                }
1233
                else
1234
                    call_native_snprintf(int);
871,893✔
1235
            }
1236
            else if (end == 'o' || end == 'u' || end == 'x' || end == 'X')
1,588,350✔
1237
            {
1238
                if (end_m1 == 'h')
53,370✔
1239
                    call_native_snprintf(unsigned int);
×
1240
                else if (end_m1 == 'l' && ptrend[-2] != 'l')
53,370✔
1241
                    call_native_snprintf(unsigned long);
424✔
1242
                else if (end_m1 == 'l' && ptrend[-2] == 'l')
52,946✔
1243
                    call_native_snprintf(GUIntBig);
12,898✔
1244
                else if (end_m1 == '4' && ptrend[-2] == '6' &&
40,048✔
1245
                         ptrend[-3] == 'I')
×
1246
                    // Microsoft I64 modifier.
1247
                    call_native_snprintf(GUIntBig);
×
1248
                else if (end_m1 == 'z')
40,048✔
1249
                    call_native_snprintf(size_t);
×
1250
                else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
40,048✔
1251
                         (end_m1 >= 'A' && end_m1 <= 'Z'))
×
1252
                {
1253
                    bFormatUnknown = true;
×
1254
                    break;
×
1255
                }
1256
                else
1257
                    call_native_snprintf(unsigned int);
40,048✔
1258
            }
1259
            else if (end == 'e' || end == 'E' || end == 'f' || end == 'F' ||
1,534,980✔
1260
                     end == 'g' || end == 'G' || end == 'a' || end == 'A')
947,899✔
1261
            {
1262
                if (end_m1 == 'L')
587,096✔
1263
                    call_native_snprintf(long double);
×
1264
                else
1265
                    call_native_snprintf(double);
587,096✔
1266
                // MSVC vsnprintf() returns -1.
1267
                if (local_ret < 0 || offset_out + local_ret >= size)
587,097✔
1268
                    break;
1269
                for (int j = 0; j < local_ret; ++j)
8,595,020✔
1270
                {
1271
                    if (str[offset_out + j] == ',')
8,008,010✔
1272
                    {
1273
                        str[offset_out + j] = '.';
×
1274
                        break;
×
1275
                    }
1276
                }
587,006✔
1277
            }
1278
            else if (end == 's')
947,888✔
1279
            {
1280
                const char *pszPtr = va_arg(wrk_args, const char *);
902,213✔
1281
                CPLAssert(pszPtr);
902,181✔
1282
                local_ret = snprintf(str + offset_out, size - offset_out,
902,191✔
1283
                                     localfmt, pszPtr);
1284
            }
1285
            else if (end == 'p')
45,675✔
1286
            {
1287
                call_native_snprintf(void *);
44,899✔
1288
            }
1289
            else
1290
            {
1291
                bFormatUnknown = true;
776✔
1292
                break;
776✔
1293
            }
1294
            // MSVC vsnprintf() returns -1.
1295
            if (local_ret < 0 || offset_out + local_ret >= size)
2,495,330✔
1296
                break;
1297
            offset_out += local_ret;
2,494,410✔
1298
            fmt = ptrend;
2,494,410✔
1299
        }
1300
        else
1301
        {
1302
            if (offset_out == size - 1)
23,488,600✔
1303
                break;
577✔
1304
            str[offset_out++] = *fmt;
23,488,100✔
1305
        }
1306
    }
1307
    if (ch == '\0' && offset_out < size)
1,562,430✔
1308
        str[offset_out] = '\0';
1,560,080✔
1309
    else
1310
    {
1311
        if (bFormatUnknown)
2,352✔
1312
        {
1313
            CPLDebug("CPL",
784✔
1314
                     "CPLvsnprintf() called with unsupported "
1315
                     "formatting string: %s",
1316
                     fmt_ori);
1317
        }
1318
#ifdef va_copy
1319
        va_end(wrk_args);
2,363✔
1320
        va_copy(wrk_args, args);
2,363✔
1321
#else
1322
        wrk_args = args;
1323
#endif
1324
#if defined(HAVE_VSNPRINTF)
1325
        offset_out = vsnprintf(str, size, fmt_ori, wrk_args);
2,363✔
1326
#else
1327
        offset_out = vsprintf(str, fmt_ori, wrk_args);
1328
#endif
1329
    }
1330

1331
#ifdef va_copy
1332
    va_end(wrk_args);
1,562,440✔
1333
#endif
1334

1335
    return static_cast<int>(offset_out);
1,562,440✔
1336
}
1337

1338
/************************************************************************/
1339
/*                           CPLsnprintf()                              */
1340
/************************************************************************/
1341

1342
#if !defined(ALIAS_CPLSNPRINTF_AS_SNPRINTF)
1343

1344
#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ <= 2
1345
#pragma clang diagnostic push
1346
#pragma clang diagnostic ignored "-Wunknown-pragmas"
1347
#pragma clang diagnostic ignored "-Wdocumentation"
1348
#endif
1349

1350
/** snprintf() wrapper that is not sensitive to LC_NUMERIC settings.
1351
 *
1352
 * This function has the same contract as standard snprintf(), except that
1353
 * formatting of floating-point numbers will use decimal point, whatever the
1354
 * current locale is set.
1355
 *
1356
 * @param str output buffer
1357
 * @param size size of the output buffer (including space for terminating nul)
1358
 * @param fmt formatting string
1359
 * @param ... arguments
1360
 * @return the number of characters (excluding terminating nul) that would be
1361
 * written if size is big enough. Or potentially -1 with Microsoft C runtime
1362
 * for Visual Studio < 2015.
1363
 * @since GDAL 2.0
1364
 */
1365

1366
int CPLsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt), ...)
166,400✔
1367
{
1368
    va_list args;
1369

1370
    va_start(args, fmt);
166,400✔
1371
    const int ret = CPLvsnprintf(str, size, fmt, args);
166,400✔
1372
    va_end(args);
166,400✔
1373
    return ret;
166,400✔
1374
}
1375

1376
#endif  //  !defined(ALIAS_CPLSNPRINTF_AS_SNPRINTF)
1377

1378
/************************************************************************/
1379
/*                           CPLsprintf()                               */
1380
/************************************************************************/
1381

1382
/** sprintf() wrapper that is not sensitive to LC_NUMERIC settings.
1383
  *
1384
  * This function has the same contract as standard sprintf(), except that
1385
  * formatting of floating-point numbers will use decimal point, whatever the
1386
  * current locale is set.
1387
  *
1388
  * @param str output buffer (must be large enough to hold the result)
1389
  * @param fmt formatting string
1390
  * @param ... arguments
1391
  * @return the number of characters (excluding terminating nul) written in
1392
` * output buffer.
1393
  * @since GDAL 2.0
1394
  */
1395
int CPLsprintf(char *str, CPL_FORMAT_STRING(const char *fmt), ...)
×
1396
{
1397
    va_list args;
1398

1399
    va_start(args, fmt);
×
1400
    const int ret = CPLvsnprintf(str, INT_MAX, fmt, args);
×
1401
    va_end(args);
×
1402
    return ret;
×
1403
}
1404

1405
/************************************************************************/
1406
/*                           CPLprintf()                                */
1407
/************************************************************************/
1408

1409
/** printf() wrapper that is not sensitive to LC_NUMERIC settings.
1410
 *
1411
 * This function has the same contract as standard printf(), except that
1412
 * formatting of floating-point numbers will use decimal point, whatever the
1413
 * current locale is set.
1414
 *
1415
 * @param fmt formatting string
1416
 * @param ... arguments
1417
 * @return the number of characters (excluding terminating nul) written in
1418
 * output buffer.
1419
 * @since GDAL 2.0
1420
 */
1421
int CPLprintf(CPL_FORMAT_STRING(const char *fmt), ...)
157✔
1422
{
1423
    va_list wrk_args, args;
1424

1425
    va_start(args, fmt);
157✔
1426

1427
#ifdef va_copy
1428
    va_copy(wrk_args, args);
157✔
1429
#else
1430
    wrk_args = args;
1431
#endif
1432

1433
    char szBuffer[4096] = {};
157✔
1434
    // Quiet coverity by staring off nul terminated.
1435
    int ret = CPLvsnprintf(szBuffer, sizeof(szBuffer), fmt, wrk_args);
157✔
1436

1437
#ifdef va_copy
1438
    va_end(wrk_args);
157✔
1439
#endif
1440

1441
    if (ret < int(sizeof(szBuffer)) - 1)
157✔
1442
        ret = printf("%s", szBuffer); /*ok*/
157✔
1443
    else
1444
    {
1445
#ifdef va_copy
1446
        va_copy(wrk_args, args);
×
1447
#else
1448
        wrk_args = args;
1449
#endif
1450

1451
        ret = vfprintf(stdout, fmt, wrk_args);
×
1452

1453
#ifdef va_copy
1454
        va_end(wrk_args);
×
1455
#endif
1456
    }
1457

1458
    va_end(args);
157✔
1459

1460
    return ret;
157✔
1461
}
1462

1463
/************************************************************************/
1464
/*                           CPLsscanf()                                */
1465
/************************************************************************/
1466

1467
/** \brief sscanf() wrapper that is not sensitive to LC_NUMERIC settings.
1468
 *
1469
 * This function has the same contract as standard sscanf(), except that
1470
 * formatting of floating-point numbers will use decimal point, whatever the
1471
 * current locale is set.
1472
 *
1473
 * CAUTION: only works with a very limited number of formatting strings,
1474
 * consisting only of "%lf" and regular characters.
1475
 *
1476
 * @param str input string
1477
 * @param fmt formatting string
1478
 * @param ... arguments
1479
 * @return the number of matched patterns;
1480
 * @since GDAL 2.0
1481
 */
1482
#ifdef DOXYGEN_XML
1483
int CPLsscanf(const char *str, const char *fmt, ...)
1484
#else
1485
int CPLsscanf(const char *str, CPL_SCANF_FORMAT_STRING(const char *fmt), ...)
1,778✔
1486
#endif
1487
{
1488
    bool error = false;
1,778✔
1489
    int ret = 0;
1,778✔
1490
    const char *fmt_ori = fmt;
1,778✔
1491
    va_list args;
1492

1493
    va_start(args, fmt);
1,778✔
1494
    for (; *fmt != '\0' && *str != '\0'; ++fmt)
13,555✔
1495
    {
1496
        if (*fmt == '%')
11,777✔
1497
        {
1498
            if (fmt[1] == 'l' && fmt[2] == 'f')
6,759✔
1499
            {
1500
                fmt += 2;
6,759✔
1501
                char *end;
1502
                *(va_arg(args, double *)) = CPLStrtod(str, &end);
6,759✔
1503
                if (end > str)
6,759✔
1504
                {
1505
                    ++ret;
6,759✔
1506
                    str = end;
6,759✔
1507
                }
1508
                else
1509
                    break;
6,759✔
1510
            }
1511
            else
1512
            {
1513
                error = true;
×
1514
                break;
×
1515
            }
1516
        }
1517
        else if (isspace(static_cast<unsigned char>(*fmt)))
5,018✔
1518
        {
1519
            while (*str != '\0' && isspace(static_cast<unsigned char>(*str)))
1,754✔
1520
                ++str;
877✔
1521
        }
1522
        else if (*str != *fmt)
4,141✔
1523
            break;
×
1524
        else
1525
            ++str;
4,141✔
1526
    }
1527
    va_end(args);
1,778✔
1528

1529
    if (error)
1,778✔
1530
    {
1531
        CPLError(CE_Failure, CPLE_NotSupported,
×
1532
                 "Format %s not supported by CPLsscanf()", fmt_ori);
1533
    }
1534

1535
    return ret;
1,778✔
1536
}
1537

1538
#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ <= 2
1539
#pragma clang diagnostic pop
1540
#endif
1541

1542
/************************************************************************/
1543
/*                         CPLTestBool()                                */
1544
/************************************************************************/
1545

1546
/**
1547
 * Test what boolean value contained in the string.
1548
 *
1549
 * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned false.
1550
 * Otherwise, true will be returned.
1551
 *
1552
 * @param pszValue the string should be tested.
1553
 *
1554
 * @return true or false.
1555
 */
1556

1557
bool CPLTestBool(const char *pszValue)
2,313,980✔
1558
{
1559
    return !(EQUAL(pszValue, "NO") || EQUAL(pszValue, "FALSE") ||
2,954,100✔
1560
             EQUAL(pszValue, "OFF") || EQUAL(pszValue, "0"));
2,954,100✔
1561
}
1562

1563
/************************************************************************/
1564
/*                         CSLTestBoolean()                             */
1565
/************************************************************************/
1566

1567
/**
1568
 * Test what boolean value contained in the string.
1569
 *
1570
 * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned FALSE.
1571
 * Otherwise, TRUE will be returned.
1572
 *
1573
 * Deprecated.  Removed in GDAL 3.x.
1574
 *
1575
 * Use CPLTestBoolean() for C and CPLTestBool() for C++.
1576
 *
1577
 * @param pszValue the string should be tested.
1578
 *
1579
 * @return TRUE or FALSE.
1580
 */
1581

1582
int CSLTestBoolean(const char *pszValue)
627✔
1583
{
1584
    return CPLTestBool(pszValue) ? TRUE : FALSE;
627✔
1585
}
1586

1587
/************************************************************************/
1588
/*                         CPLTestBoolean()                             */
1589
/************************************************************************/
1590

1591
/**
1592
 * Test what boolean value contained in the string.
1593
 *
1594
 * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned FALSE.
1595
 * Otherwise, TRUE will be returned.
1596
 *
1597
 * Use this only in C code.  In C++, prefer CPLTestBool().
1598
 *
1599
 * @param pszValue the string should be tested.
1600
 *
1601
 * @return TRUE or FALSE.
1602
 */
1603

1604
int CPLTestBoolean(const char *pszValue)
38✔
1605
{
1606
    return CPLTestBool(pszValue) ? TRUE : FALSE;
38✔
1607
}
1608

1609
/**********************************************************************
1610
 *                       CPLFetchBool()
1611
 **********************************************************************/
1612

1613
/** Check for boolean key value.
1614
 *
1615
 * In a StringList of "Name=Value" pairs, look to see if there is a key
1616
 * with the given name, and if it can be interpreted as being TRUE.  If
1617
 * the key appears without any "=Value" portion it will be considered true.
1618
 * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
1619
 * if the key appears in the list it will be considered TRUE.  If the key
1620
 * doesn't appear at all, the indicated default value will be returned.
1621
 *
1622
 * @param papszStrList the string list to search.
1623
 * @param pszKey the key value to look for (case insensitive).
1624
 * @param bDefault the value to return if the key isn't found at all.
1625
 *
1626
 * @return true or false
1627
 */
1628

1629
bool CPLFetchBool(CSLConstList papszStrList, const char *pszKey, bool bDefault)
199,272✔
1630

1631
{
1632
    if (CSLFindString(papszStrList, pszKey) != -1)
199,272✔
1633
        return true;
2✔
1634

1635
    const char *const pszValue = CSLFetchNameValue(papszStrList, pszKey);
199,239✔
1636
    if (pszValue == nullptr)
199,244✔
1637
        return bDefault;
186,902✔
1638

1639
    return CPLTestBool(pszValue);
12,342✔
1640
}
1641

1642
/**********************************************************************
1643
 *                       CSLFetchBoolean()
1644
 **********************************************************************/
1645

1646
/** DEPRECATED.  Check for boolean key value.
1647
 *
1648
 * In a StringList of "Name=Value" pairs, look to see if there is a key
1649
 * with the given name, and if it can be interpreted as being TRUE.  If
1650
 * the key appears without any "=Value" portion it will be considered true.
1651
 * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
1652
 * if the key appears in the list it will be considered TRUE.  If the key
1653
 * doesn't appear at all, the indicated default value will be returned.
1654
 *
1655
 * @param papszStrList the string list to search.
1656
 * @param pszKey the key value to look for (case insensitive).
1657
 * @param bDefault the value to return if the key isn't found at all.
1658
 *
1659
 * @return TRUE or FALSE
1660
 */
1661

1662
int CSLFetchBoolean(CSLConstList papszStrList, const char *pszKey, int bDefault)
1,273✔
1663

1664
{
1665
    return CPLFetchBool(papszStrList, pszKey, CPL_TO_BOOL(bDefault));
1,273✔
1666
}
1667

1668
/************************************************************************/
1669
/*                     CSLFetchNameValueDefaulted()                     */
1670
/************************************************************************/
1671

1672
/** Same as CSLFetchNameValue() but return pszDefault in case of no match */
1673
const char *CSLFetchNameValueDef(CSLConstList papszStrList, const char *pszName,
439,517✔
1674
                                 const char *pszDefault)
1675

1676
{
1677
    const char *pszResult = CSLFetchNameValue(papszStrList, pszName);
439,517✔
1678
    if (pszResult != nullptr)
439,448✔
1679
        return pszResult;
36,006✔
1680

1681
    return pszDefault;
403,442✔
1682
}
1683

1684
/**********************************************************************
1685
 *                       CSLFetchNameValue()
1686
 **********************************************************************/
1687

1688
/** In a StringList of "Name=Value" pairs, look for the
1689
 * first value associated with the specified name.  The search is not
1690
 * case sensitive.
1691
 * ("Name:Value" pairs are also supported for backward compatibility
1692
 * with older stuff.)
1693
 *
1694
 * Returns a reference to the value in the StringList that the caller
1695
 * should not attempt to free.
1696
 *
1697
 * Returns NULL if the name is not found.
1698
 */
1699

1700
const char *CSLFetchNameValue(CSLConstList papszStrList, const char *pszName)
12,321,000✔
1701
{
1702
    if (papszStrList == nullptr || pszName == nullptr)
12,321,000✔
1703
        return nullptr;
3,744,690✔
1704

1705
    const size_t nLen = strlen(pszName);
8,576,290✔
1706
    while (*papszStrList != nullptr)
12,644,700✔
1707
    {
1708
        if (EQUALN(*papszStrList, pszName, nLen) &&
4,223,720✔
1709
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
158,232✔
1710
        {
1711
            return (*papszStrList) + nLen + 1;
155,349✔
1712
        }
1713
        ++papszStrList;
4,068,370✔
1714
    }
1715
    return nullptr;
8,420,940✔
1716
}
1717

1718
/************************************************************************/
1719
/*                            CSLFindName()                             */
1720
/************************************************************************/
1721

1722
/**
1723
 * Find StringList entry with given key name.
1724
 *
1725
 * @param papszStrList the string list to search.
1726
 * @param pszName the key value to look for (case insensitive).
1727
 *
1728
 * @return -1 on failure or the list index of the first occurrence
1729
 * matching the given key.
1730
 */
1731

1732
int CSLFindName(CSLConstList papszStrList, const char *pszName)
13,803,800✔
1733
{
1734
    if (papszStrList == nullptr || pszName == nullptr)
13,803,800✔
1735
        return -1;
456,956✔
1736

1737
    const size_t nLen = strlen(pszName);
13,346,800✔
1738
    int iIndex = 0;
13,346,800✔
1739
    while (*papszStrList != nullptr)
106,213,000✔
1740
    {
1741
        if (EQUALN(*papszStrList, pszName, nLen) &&
99,967,500✔
1742
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
7,580,910✔
1743
        {
1744
            return iIndex;
7,101,320✔
1745
        }
1746
        ++iIndex;
92,866,200✔
1747
        ++papszStrList;
92,866,200✔
1748
    }
1749
    return -1;
6,245,510✔
1750
}
1751

1752
/**********************************************************************
1753
 *                       CPLParseNameValue()
1754
 **********************************************************************/
1755

1756
/**
1757
 * Parse NAME=VALUE string into name and value components.
1758
 *
1759
 * Note that if ppszKey is non-NULL, the key (or name) portion will be
1760
 * allocated using CPLMalloc(), and returned in that pointer.  It is the
1761
 * applications responsibility to free this string, but the application should
1762
 * not modify or free the returned value portion.
1763
 *
1764
 * This function also support "NAME:VALUE" strings and will strip white
1765
 * space from around the delimiter when forming name and value strings.
1766
 *
1767
 * Eventually CSLFetchNameValue() and friends may be modified to use
1768
 * CPLParseNameValue().
1769
 *
1770
 * @param pszNameValue string in "NAME=VALUE" format.
1771
 * @param ppszKey optional pointer though which to return the name
1772
 * portion.
1773
 *
1774
 * @return the value portion (pointing into original string).
1775
 */
1776

1777
const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey)
68,231✔
1778
{
1779
    for (int i = 0; pszNameValue[i] != '\0'; ++i)
965,986✔
1780
    {
1781
        if (pszNameValue[i] == '=' || pszNameValue[i] == ':')
963,153✔
1782
        {
1783
            const char *pszValue = pszNameValue + i + 1;
65,398✔
1784
            while (*pszValue == ' ' || *pszValue == '\t')
72,042✔
1785
                ++pszValue;
6,644✔
1786

1787
            if (ppszKey != nullptr)
65,398✔
1788
            {
1789
                *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
65,376✔
1790
                memcpy(*ppszKey, pszNameValue, i);
65,376✔
1791
                (*ppszKey)[i] = '\0';
65,376✔
1792
                while (i > 0 &&
65,694✔
1793
                       ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
65,694✔
1794
                {
1795
                    (*ppszKey)[i - 1] = '\0';
318✔
1796
                    i--;
318✔
1797
                }
1798
            }
1799

1800
            return pszValue;
65,398✔
1801
        }
1802
    }
1803

1804
    return nullptr;
2,833✔
1805
}
1806

1807
/**********************************************************************
1808
 *                       CPLParseNameValueSep()
1809
 **********************************************************************/
1810
/**
1811
 * Parse NAME<Sep>VALUE string into name and value components.
1812
 *
1813
 * This is derived directly from CPLParseNameValue() which will separate
1814
 * on '=' OR ':', here chSep is required for specifying the separator
1815
 * explicitly.
1816
 *
1817
 * @param pszNameValue string in "NAME=VALUE" format.
1818
 * @param ppszKey optional pointer though which to return the name
1819
 * portion.
1820
 * @param chSep required single char separator
1821
 * @return the value portion (pointing into original string).
1822
 */
1823

1824
const char *CPLParseNameValueSep(const char *pszNameValue, char **ppszKey,
17✔
1825
                                 char chSep)
1826
{
1827
    for (int i = 0; pszNameValue[i] != '\0'; ++i)
140✔
1828
    {
1829
        if (pszNameValue[i] == chSep)
138✔
1830
        {
1831
            const char *pszValue = pszNameValue + i + 1;
15✔
1832
            while (*pszValue == ' ' || *pszValue == '\t')
15✔
1833
                ++pszValue;
×
1834

1835
            if (ppszKey != nullptr)
15✔
1836
            {
1837
                *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
15✔
1838
                memcpy(*ppszKey, pszNameValue, i);
15✔
1839
                (*ppszKey)[i] = '\0';
15✔
1840
                while (i > 0 &&
15✔
1841
                       ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
15✔
1842
                {
1843
                    (*ppszKey)[i - 1] = '\0';
×
1844
                    i--;
×
1845
                }
1846
            }
1847

1848
            return pszValue;
15✔
1849
        }
1850
    }
1851

1852
    return nullptr;
2✔
1853
}
1854

1855
/**********************************************************************
1856
 *                       CSLFetchNameValueMultiple()
1857
 **********************************************************************/
1858

1859
/** In a StringList of "Name=Value" pairs, look for all the
1860
 * values with the specified name.  The search is not case
1861
 * sensitive.
1862
 * ("Name:Value" pairs are also supported for backward compatibility
1863
 * with older stuff.)
1864
 *
1865
 * Returns StringList with one entry for each occurrence of the
1866
 * specified name.  The StringList should eventually be destroyed
1867
 * by calling CSLDestroy().
1868
 *
1869
 * Returns NULL if the name is not found.
1870
 */
1871

1872
char **CSLFetchNameValueMultiple(CSLConstList papszStrList, const char *pszName)
7,354✔
1873
{
1874
    if (papszStrList == nullptr || pszName == nullptr)
7,354✔
1875
        return nullptr;
1,820✔
1876

1877
    const size_t nLen = strlen(pszName);
5,534✔
1878
    char **papszValues = nullptr;
5,534✔
1879
    while (*papszStrList != nullptr)
13,164✔
1880
    {
1881
        if (EQUALN(*papszStrList, pszName, nLen) &&
7,630✔
1882
            ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
51✔
1883
        {
1884
            papszValues = CSLAddString(papszValues, (*papszStrList) + nLen + 1);
51✔
1885
        }
1886
        ++papszStrList;
7,630✔
1887
    }
1888

1889
    return papszValues;
5,534✔
1890
}
1891

1892
/**********************************************************************
1893
 *                       CSLAddNameValue()
1894
 **********************************************************************/
1895

1896
/** Add a new entry to a StringList of "Name=Value" pairs,
1897
 * ("Name:Value" pairs are also supported for backward compatibility
1898
 * with older stuff.)
1899
 *
1900
 * This function does not check if a "Name=Value" pair already exists
1901
 * for that name and can generate multiple entries for the same name.
1902
 * Use CSLSetNameValue() if you want each name to have only one value.
1903
 *
1904
 * Returns the modified StringList.
1905
 */
1906

1907
char **CSLAddNameValue(char **papszStrList, const char *pszName,
386,578✔
1908
                       const char *pszValue)
1909
{
1910
    if (pszName == nullptr || pszValue == nullptr)
386,578✔
1911
        return papszStrList;
×
1912

1913
    const size_t nLen = strlen(pszName) + strlen(pszValue) + 2;
386,579✔
1914
    char *pszLine = static_cast<char *>(CPLMalloc(nLen));
386,579✔
1915
    snprintf(pszLine, nLen, "%s=%s", pszName, pszValue);
386,655✔
1916
    papszStrList = CSLAddString(papszStrList, pszLine);
386,655✔
1917
    CPLFree(pszLine);
386,562✔
1918

1919
    return papszStrList;
386,659✔
1920
}
1921

1922
/************************************************************************/
1923
/*                          CSLSetNameValue()                           */
1924
/************************************************************************/
1925

1926
/**
1927
 * Assign value to name in StringList.
1928
 *
1929
 * Set the value for a given name in a StringList of "Name=Value" pairs
1930
 * ("Name:Value" pairs are also supported for backward compatibility
1931
 * with older stuff.)
1932
 *
1933
 * If there is already a value for that name in the list then the value
1934
 * is changed, otherwise a new "Name=Value" pair is added.
1935
 *
1936
 * @param papszList the original list, the modified version is returned.
1937
 * @param pszName the name to be assigned a value.  This should be a well
1938
 * formed token (no spaces or very special characters).
1939
 * @param pszValue the value to assign to the name.  This should not contain
1940
 * any newlines (CR or LF) but is otherwise pretty much unconstrained.  If
1941
 * NULL any corresponding value will be removed.
1942
 *
1943
 * @return modified StringList.
1944
 */
1945

1946
char **CSLSetNameValue(char **papszList, const char *pszName,
410,174✔
1947
                       const char *pszValue)
1948
{
1949
    if (pszName == nullptr)
410,174✔
1950
        return papszList;
38✔
1951

1952
    size_t nLen = strlen(pszName);
410,136✔
1953
    while (nLen > 0 && pszName[nLen - 1] == ' ')
410,810✔
1954
        nLen--;
674✔
1955
    char **papszPtr = papszList;
410,136✔
1956
    while (papszPtr && *papszPtr != nullptr)
6,975,940✔
1957
    {
1958
        if (EQUALN(*papszPtr, pszName, nLen))
6,599,570✔
1959
        {
1960
            size_t i;
1961
            for (i = nLen; (*papszPtr)[i] == ' '; ++i)
36,081✔
1962
            {
1963
            }
1964
            if ((*papszPtr)[i] == '=' || (*papszPtr)[i] == ':')
35,407✔
1965
            {
1966
                // Found it.
1967
                // Change the value... make sure to keep the ':' or '='.
1968
                const char cSep = (*papszPtr)[i];
33,763✔
1969

1970
                CPLFree(*papszPtr);
33,763✔
1971

1972
                // If the value is NULL, remove this entry completely.
1973
                if (pszValue == nullptr)
33,733✔
1974
                {
1975
                    while (papszPtr[1] != nullptr)
34,991✔
1976
                    {
1977
                        *papszPtr = papszPtr[1];
7,877✔
1978
                        ++papszPtr;
7,877✔
1979
                    }
1980
                    *papszPtr = nullptr;
27,114✔
1981
                }
1982

1983
                // Otherwise replace with new value.
1984
                else
1985
                {
1986
                    const size_t nLen2 = strlen(pszName) + strlen(pszValue) + 2;
6,619✔
1987
                    *papszPtr = static_cast<char *>(CPLMalloc(nLen2));
6,619✔
1988
                    snprintf(*papszPtr, nLen2, "%s%c%s", pszName, cSep,
6,566✔
1989
                             pszValue);
1990
                }
1991
                return papszList;
33,680✔
1992
            }
1993
        }
1994
        ++papszPtr;
6,565,800✔
1995
    }
1996

1997
    if (pszValue == nullptr)
376,373✔
1998
        return papszList;
4,220✔
1999

2000
    // The name does not exist yet.  Create a new entry.
2001
    return CSLAddNameValue(papszList, pszName, pszValue);
372,153✔
2002
}
2003

2004
/************************************************************************/
2005
/*                      CSLSetNameValueSeparator()                      */
2006
/************************************************************************/
2007

2008
/**
2009
 * Replace the default separator (":" or "=") with the passed separator
2010
 * in the given name/value list.
2011
 *
2012
 * Note that if a separator other than ":" or "=" is used, the resulting
2013
 * list will not be manipulable by the CSL name/value functions any more.
2014
 *
2015
 * The CPLParseNameValue() function is used to break the existing lines,
2016
 * and it also strips white space from around the existing delimiter, thus
2017
 * the old separator, and any white space will be replaced by the new
2018
 * separator.  For formatting purposes it may be desirable to include some
2019
 * white space in the new separator.  e.g. ": " or " = ".
2020
 *
2021
 * @param papszList the list to update.  Component strings may be freed
2022
 * but the list array will remain at the same location.
2023
 *
2024
 * @param pszSeparator the new separator string to insert.
2025
 */
2026

2027
void CSLSetNameValueSeparator(char **papszList, const char *pszSeparator)
89✔
2028

2029
{
2030
    const int nLines = CSLCount(papszList);
89✔
2031

2032
    for (int iLine = 0; iLine < nLines; ++iLine)
777✔
2033
    {
2034
        char *pszKey = nullptr;
688✔
2035
        const char *pszValue = CPLParseNameValue(papszList[iLine], &pszKey);
688✔
2036
        if (pszValue == nullptr || pszKey == nullptr)
688✔
2037
        {
2038
            CPLFree(pszKey);
×
2039
            continue;
×
2040
        }
2041

2042
        char *pszNewLine = static_cast<char *>(CPLMalloc(
1,376✔
2043
            strlen(pszValue) + strlen(pszKey) + strlen(pszSeparator) + 1));
688✔
2044
        strcpy(pszNewLine, pszKey);
688✔
2045
        strcat(pszNewLine, pszSeparator);
688✔
2046
        strcat(pszNewLine, pszValue);
688✔
2047
        CPLFree(papszList[iLine]);
688✔
2048
        papszList[iLine] = pszNewLine;
688✔
2049
        CPLFree(pszKey);
688✔
2050
    }
2051
}
89✔
2052

2053
/************************************************************************/
2054
/*                          CPLEscapeString()                           */
2055
/************************************************************************/
2056

2057
/**
2058
 * Apply escaping to string to preserve special characters.
2059
 *
2060
 * This function will "escape" a variety of special characters
2061
 * to make the string suitable to embed within a string constant
2062
 * or to write within a text stream but in a form that can be
2063
 * reconstituted to its original form.  The escaping will even preserve
2064
 * zero bytes allowing preservation of raw binary data.
2065
 *
2066
 * CPLES_BackslashQuotable(0): This scheme turns a binary string into
2067
 * a form suitable to be placed within double quotes as a string constant.
2068
 * The backslash, quote, '\\0' and newline characters are all escaped in
2069
 * the usual C style.
2070
 *
2071
 * CPLES_XML(1): This scheme converts the '<', '>', '"' and '&' characters into
2072
 * their XML/HTML equivalent (&lt;, &gt;, &quot; and &amp;) making a string safe
2073
 * to embed as CDATA within an XML element.  The '\\0' is not escaped and
2074
 * should not be included in the input.
2075
 *
2076
 * CPLES_URL(2): Everything except alphanumerics and the characters
2077
 * '$', '-', '_', '.', '+', '!', '*', ''', '(', ')' and ',' (see RFC1738) are
2078
 * converted to a percent followed by a two digit hex encoding of the character
2079
 * (leading zero supplied if needed).  This is the mechanism used for encoding
2080
 * values to be passed in URLs.
2081
 *
2082
 * CPLES_SQL(3): All single quotes are replaced with two single quotes.
2083
 * Suitable for use when constructing literal values for SQL commands where
2084
 * the literal will be enclosed in single quotes.
2085
 *
2086
 * CPLES_CSV(4): If the values contains commas, semicolons, tabs, double quotes,
2087
 * or newlines it placed in double quotes, and double quotes in the value are
2088
 * doubled. Suitable for use when constructing field values for .csv files.
2089
 * Note that CPLUnescapeString() currently does not support this format, only
2090
 * CPLEscapeString().  See cpl_csv.cpp for CSV parsing support.
2091
 *
2092
 * CPLES_SQLI(7): All double quotes are replaced with two double quotes.
2093
 * Suitable for use when constructing identifiers for SQL commands where
2094
 * the literal will be enclosed in double quotes.
2095
 *
2096
 * @param pszInput the string to escape.
2097
 * @param nLength The number of bytes of data to preserve.  If this is -1
2098
 * the strlen(pszString) function will be used to compute the length.
2099
 * @param nScheme the encoding scheme to use.
2100
 *
2101
 * @return an escaped, zero terminated string that should be freed with
2102
 * CPLFree() when no longer needed.
2103
 */
2104

2105
char *CPLEscapeString(const char *pszInput, int nLength, int nScheme)
448,536✔
2106
{
2107
    const size_t szLength =
448,536✔
2108
        (nLength < 0) ? strlen(pszInput) : static_cast<size_t>(nLength);
448,536✔
2109
#define nLength no_longer_use_me
2110

2111
    size_t nSizeAlloc = 1;
448,536✔
2112
#if SIZEOF_VOIDP < 8
2113
    bool bWrapAround = false;
2114
    const auto IncSizeAlloc = [&nSizeAlloc, &bWrapAround](size_t inc)
2115
    {
2116
        constexpr size_t SZ_MAX = std::numeric_limits<size_t>::max();
2117
        if (nSizeAlloc > SZ_MAX - inc)
2118
        {
2119
            bWrapAround = true;
2120
            nSizeAlloc = 0;
2121
        }
2122
        nSizeAlloc += inc;
2123
    };
2124
#else
2125
    const auto IncSizeAlloc = [&nSizeAlloc](size_t inc) { nSizeAlloc += inc; };
40,228,700✔
2126
#endif
2127

2128
    if (nScheme == CPLES_BackslashQuotable)
448,536✔
2129
    {
2130
        for (size_t iIn = 0; iIn < szLength; iIn++)
44,026✔
2131
        {
2132
            if (pszInput[iIn] == '\0' || pszInput[iIn] == '\n' ||
43,908✔
2133
                pszInput[iIn] == '"' || pszInput[iIn] == '\\')
43,154✔
2134
                IncSizeAlloc(2);
876✔
2135
            else
2136
                IncSizeAlloc(1);
43,032✔
2137
        }
2138
    }
2139
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
448,418✔
2140
    {
2141
        for (size_t iIn = 0; iIn < szLength; ++iIn)
40,151,100✔
2142
        {
2143
            if (pszInput[iIn] == '<')
39,705,600✔
2144
            {
2145
                IncSizeAlloc(4);
1,420✔
2146
            }
2147
            else if (pszInput[iIn] == '>')
39,704,200✔
2148
            {
2149
                IncSizeAlloc(4);
1,570✔
2150
            }
2151
            else if (pszInput[iIn] == '&')
39,702,600✔
2152
            {
2153
                IncSizeAlloc(5);
845✔
2154
            }
2155
            else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
39,701,800✔
2156
            {
2157
                IncSizeAlloc(6);
1,910✔
2158
            }
2159
            // Python 2 does not display the UTF-8 character corresponding
2160
            // to the byte-order mark (BOM), so escape it.
2161
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
39,699,900✔
2162
                         0xEF &&
2✔
2163
                     (reinterpret_cast<const unsigned char *>(
2164
                         pszInput))[iIn + 1] == 0xBB &&
2✔
2165
                     (reinterpret_cast<const unsigned char *>(
2166
                         pszInput))[iIn + 2] == 0xBF)
2✔
2167
            {
2168
                IncSizeAlloc(8);
2✔
2169
                iIn += 2;
2✔
2170
            }
2171
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
39,699,900✔
2172
                         0x20 &&
22,171✔
2173
                     pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
22,171✔
2174
                     pszInput[iIn] != 0xD)
110✔
2175
            {
2176
                // These control characters are unrepresentable in XML format,
2177
                // so we just drop them.  #4117
2178
            }
2179
            else
2180
            {
2181
                IncSizeAlloc(1);
39,699,900✔
2182
            }
2183
        }
445,500✔
2184
    }
2185
    else if (nScheme == CPLES_URL)  // Untested at implementation.
2,918✔
2186
    {
2187
        for (size_t iIn = 0; iIn < szLength; ++iIn)
7,033✔
2188
        {
2189
            if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
6,623✔
2190
                (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
2,589✔
2191
                (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
1,134✔
2192
                pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
515✔
2193
                pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
475✔
2194
                pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
272✔
2195
                pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
254✔
2196
                pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
252✔
2197
                pszInput[iIn] == ',')
242✔
2198
            {
2199
                IncSizeAlloc(1);
6,387✔
2200
            }
2201
            else
2202
            {
2203
                IncSizeAlloc(3);
236✔
2204
            }
2205
        }
2206
    }
2207
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2,508✔
2208
    {
2209
        const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
780✔
2210
        for (size_t iIn = 0; iIn < szLength; ++iIn)
11,574✔
2211
        {
2212
            if (pszInput[iIn] == chQuote)
10,794✔
2213
            {
2214
                IncSizeAlloc(2);
7✔
2215
            }
2216
            else
2217
            {
2218
                IncSizeAlloc(1);
10,787✔
2219
            }
2220
        }
780✔
2221
    }
2222
    else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
1,728✔
2223
    {
2224
        if (nScheme == CPLES_CSV && strcspn(pszInput, "\",;\t\n\r") == szLength)
1,728✔
2225
        {
2226
            char *pszOutput =
2227
                static_cast<char *>(VSI_MALLOC_VERBOSE(szLength + 1));
1,505✔
2228
            if (pszOutput == nullptr)
1,505✔
2229
                return nullptr;
×
2230
            memcpy(pszOutput, pszInput, szLength + 1);
1,505✔
2231
            return pszOutput;
1,505✔
2232
        }
2233
        else
2234
        {
2235
            IncSizeAlloc(1);
223✔
2236
            for (size_t iIn = 0; iIn < szLength; ++iIn)
12,991✔
2237
            {
2238
                if (pszInput[iIn] == '\"')
12,768✔
2239
                {
2240
                    IncSizeAlloc(2);
169✔
2241
                }
2242
                else
2243
                    IncSizeAlloc(1);
12,599✔
2244
            }
2245
            IncSizeAlloc(1);
223✔
2246
        }
223✔
2247
    }
2248
    else
2249
    {
2250
        CPLError(CE_Failure, CPLE_AppDefined,
×
2251
                 "Undefined escaping scheme (%d) in CPLEscapeString()",
2252
                 nScheme);
2253
        return CPLStrdup("");
×
2254
    }
2255

2256
#if SIZEOF_VOIDP < 8
2257
    if (bWrapAround)
2258
    {
2259
        CPLError(CE_Failure, CPLE_OutOfMemory,
2260
                 "Out of memory in CPLEscapeString()");
2261
        return nullptr;
2262
    }
2263
#endif
2264

2265
    char *pszOutput = static_cast<char *>(VSI_MALLOC_VERBOSE(nSizeAlloc));
447,031✔
2266
    if (pszOutput == nullptr)
447,031✔
2267
        return nullptr;
×
2268

2269
    size_t iOut = 0;
447,031✔
2270

2271
    if (nScheme == CPLES_BackslashQuotable)
447,031✔
2272
    {
2273
        for (size_t iIn = 0; iIn < szLength; iIn++)
44,026✔
2274
        {
2275
            if (pszInput[iIn] == '\0')
43,908✔
2276
            {
2277
                pszOutput[iOut++] = '\\';
689✔
2278
                pszOutput[iOut++] = '0';
689✔
2279
            }
2280
            else if (pszInput[iIn] == '\n')
43,219✔
2281
            {
2282
                pszOutput[iOut++] = '\\';
65✔
2283
                pszOutput[iOut++] = 'n';
65✔
2284
            }
2285
            else if (pszInput[iIn] == '"')
43,154✔
2286
            {
2287
                pszOutput[iOut++] = '\\';
121✔
2288
                pszOutput[iOut++] = '\"';
121✔
2289
            }
2290
            else if (pszInput[iIn] == '\\')
43,033✔
2291
            {
2292
                pszOutput[iOut++] = '\\';
1✔
2293
                pszOutput[iOut++] = '\\';
1✔
2294
            }
2295
            else
2296
                pszOutput[iOut++] = pszInput[iIn];
43,032✔
2297
        }
2298
        pszOutput[iOut++] = '\0';
118✔
2299
    }
2300
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
446,913✔
2301
    {
2302
        for (size_t iIn = 0; iIn < szLength; ++iIn)
40,151,100✔
2303
        {
2304
            if (pszInput[iIn] == '<')
39,705,600✔
2305
            {
2306
                pszOutput[iOut++] = '&';
1,420✔
2307
                pszOutput[iOut++] = 'l';
1,420✔
2308
                pszOutput[iOut++] = 't';
1,420✔
2309
                pszOutput[iOut++] = ';';
1,420✔
2310
            }
2311
            else if (pszInput[iIn] == '>')
39,704,200✔
2312
            {
2313
                pszOutput[iOut++] = '&';
1,570✔
2314
                pszOutput[iOut++] = 'g';
1,570✔
2315
                pszOutput[iOut++] = 't';
1,570✔
2316
                pszOutput[iOut++] = ';';
1,570✔
2317
            }
2318
            else if (pszInput[iIn] == '&')
39,702,600✔
2319
            {
2320
                pszOutput[iOut++] = '&';
845✔
2321
                pszOutput[iOut++] = 'a';
845✔
2322
                pszOutput[iOut++] = 'm';
845✔
2323
                pszOutput[iOut++] = 'p';
845✔
2324
                pszOutput[iOut++] = ';';
845✔
2325
            }
2326
            else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
39,701,800✔
2327
            {
2328
                pszOutput[iOut++] = '&';
1,910✔
2329
                pszOutput[iOut++] = 'q';
1,910✔
2330
                pszOutput[iOut++] = 'u';
1,910✔
2331
                pszOutput[iOut++] = 'o';
1,910✔
2332
                pszOutput[iOut++] = 't';
1,910✔
2333
                pszOutput[iOut++] = ';';
1,910✔
2334
            }
2335
            // Python 2 does not display the UTF-8 character corresponding
2336
            // to the byte-order mark (BOM), so escape it.
2337
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
39,699,900✔
2338
                         0xEF &&
2✔
2339
                     (reinterpret_cast<const unsigned char *>(
2340
                         pszInput))[iIn + 1] == 0xBB &&
2✔
2341
                     (reinterpret_cast<const unsigned char *>(
2342
                         pszInput))[iIn + 2] == 0xBF)
2✔
2343
            {
2344
                pszOutput[iOut++] = '&';
2✔
2345
                pszOutput[iOut++] = '#';
2✔
2346
                pszOutput[iOut++] = 'x';
2✔
2347
                pszOutput[iOut++] = 'F';
2✔
2348
                pszOutput[iOut++] = 'E';
2✔
2349
                pszOutput[iOut++] = 'F';
2✔
2350
                pszOutput[iOut++] = 'F';
2✔
2351
                pszOutput[iOut++] = ';';
2✔
2352
                iIn += 2;
2✔
2353
            }
2354
            else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
39,699,900✔
2355
                         0x20 &&
22,171✔
2356
                     pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
22,171✔
2357
                     pszInput[iIn] != 0xD)
110✔
2358
            {
2359
                // These control characters are unrepresentable in XML format,
2360
                // so we just drop them.  #4117
2361
            }
2362
            else
2363
            {
2364
                pszOutput[iOut++] = pszInput[iIn];
39,699,900✔
2365
            }
2366
        }
2367
        pszOutput[iOut++] = '\0';
445,500✔
2368
    }
2369
    else if (nScheme == CPLES_URL)  // Untested at implementation.
1,413✔
2370
    {
2371
        for (size_t iIn = 0; iIn < szLength; ++iIn)
7,033✔
2372
        {
2373
            if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
6,623✔
2374
                (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
2,589✔
2375
                (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
1,134✔
2376
                pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
515✔
2377
                pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
475✔
2378
                pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
272✔
2379
                pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
254✔
2380
                pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
252✔
2381
                pszInput[iIn] == ',')
242✔
2382
            {
2383
                pszOutput[iOut++] = pszInput[iIn];
6,387✔
2384
            }
2385
            else
2386
            {
2387
                snprintf(pszOutput + iOut, nSizeAlloc - iOut, "%%%02X",
236✔
2388
                         static_cast<unsigned char>(pszInput[iIn]));
236✔
2389
                iOut += 3;
236✔
2390
            }
2391
        }
2392
        pszOutput[iOut++] = '\0';
410✔
2393
    }
2394
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
1,003✔
2395
    {
2396
        const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
780✔
2397
        for (size_t iIn = 0; iIn < szLength; ++iIn)
11,574✔
2398
        {
2399
            if (pszInput[iIn] == chQuote)
10,794✔
2400
            {
2401
                pszOutput[iOut++] = chQuote;
7✔
2402
                pszOutput[iOut++] = chQuote;
7✔
2403
            }
2404
            else
2405
            {
2406
                pszOutput[iOut++] = pszInput[iIn];
10,787✔
2407
            }
2408
        }
2409
        pszOutput[iOut++] = '\0';
780✔
2410
    }
2411
    else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
223✔
2412
    {
2413
        pszOutput[iOut++] = '\"';
223✔
2414

2415
        for (size_t iIn = 0; iIn < szLength; ++iIn)
12,991✔
2416
        {
2417
            if (pszInput[iIn] == '\"')
12,768✔
2418
            {
2419
                pszOutput[iOut++] = '\"';
169✔
2420
                pszOutput[iOut++] = '\"';
169✔
2421
            }
2422
            else
2423
                pszOutput[iOut++] = pszInput[iIn];
12,599✔
2424
        }
2425
        pszOutput[iOut++] = '\"';
223✔
2426
        pszOutput[iOut++] = '\0';
223✔
2427
    }
2428

2429
    return pszOutput;
447,031✔
2430
#undef nLength
2431
}
2432

2433
/************************************************************************/
2434
/*                         CPLUnescapeString()                          */
2435
/************************************************************************/
2436

2437
/**
2438
 * Unescape a string.
2439
 *
2440
 * This function does the opposite of CPLEscapeString().  Given a string
2441
 * with special values escaped according to some scheme, it will return a
2442
 * new copy of the string returned to its original form.
2443
 *
2444
 * @param pszInput the input string.  This is a zero terminated string.
2445
 * @param pnLength location to return the length of the unescaped string,
2446
 * which may in some cases include embedded '\\0' characters.
2447
 * @param nScheme the escaped scheme to undo (see CPLEscapeString() for a
2448
 * list).  Does not yet support CSV.
2449
 *
2450
 * @return a copy of the unescaped string that should be freed by the
2451
 * application using CPLFree() when no longer needed.
2452
 */
2453

2454
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
2455
char *CPLUnescapeString(const char *pszInput, int *pnLength, int nScheme)
31,994✔
2456

2457
{
2458
    int iOut = 0;
31,994✔
2459

2460
    // TODO: Why times 4?
2461
    char *pszOutput = static_cast<char *>(CPLMalloc(4 * strlen(pszInput) + 1));
31,994✔
2462
    pszOutput[0] = '\0';
31,994✔
2463

2464
    if (nScheme == CPLES_BackslashQuotable)
31,994✔
2465
    {
2466
        for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
49,436✔
2467
        {
2468
            if (pszInput[iIn] == '\\')
48,994✔
2469
            {
2470
                ++iIn;
769✔
2471
                if (pszInput[iIn] == '\0')
769✔
2472
                    break;
×
2473
                if (pszInput[iIn] == 'n')
769✔
2474
                    pszOutput[iOut++] = '\n';
6✔
2475
                else if (pszInput[iIn] == '0')
763✔
2476
                    pszOutput[iOut++] = '\0';
675✔
2477
                else
2478
                    pszOutput[iOut++] = pszInput[iIn];
88✔
2479
            }
2480
            else
2481
            {
2482
                pszOutput[iOut++] = pszInput[iIn];
48,225✔
2483
            }
2484
        }
2485
    }
2486
    else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
31,552✔
2487
    {
2488
        char ch = '\0';
31,045✔
2489
        for (int iIn = 0; (ch = pszInput[iIn]) != '\0'; ++iIn)
32,650,500✔
2490
        {
2491
            if (ch != '&')
32,619,400✔
2492
            {
2493
                pszOutput[iOut++] = ch;
32,299,100✔
2494
            }
2495
            else if (STARTS_WITH_CI(pszInput + iIn, "&lt;"))
320,350✔
2496
            {
2497
                pszOutput[iOut++] = '<';
19,801✔
2498
                iIn += 3;
19,801✔
2499
            }
2500
            else if (STARTS_WITH_CI(pszInput + iIn, "&gt;"))
300,549✔
2501
            {
2502
                pszOutput[iOut++] = '>';
19,952✔
2503
                iIn += 3;
19,952✔
2504
            }
2505
            else if (STARTS_WITH_CI(pszInput + iIn, "&amp;"))
280,597✔
2506
            {
2507
                pszOutput[iOut++] = '&';
198,759✔
2508
                iIn += 4;
198,759✔
2509
            }
2510
            else if (STARTS_WITH_CI(pszInput + iIn, "&apos;"))
81,838✔
2511
            {
2512
                pszOutput[iOut++] = '\'';
686✔
2513
                iIn += 5;
686✔
2514
            }
2515
            else if (STARTS_WITH_CI(pszInput + iIn, "&quot;"))
81,152✔
2516
            {
2517
                pszOutput[iOut++] = '"';
80,988✔
2518
                iIn += 5;
80,988✔
2519
            }
2520
            else if (STARTS_WITH_CI(pszInput + iIn, "&#x"))
164✔
2521
            {
2522
                wchar_t anVal[2] = {0, 0};
3✔
2523
                iIn += 3;
3✔
2524

2525
                unsigned int nVal = 0;
3✔
2526
                while (true)
2527
                {
2528
                    ch = pszInput[iIn++];
7✔
2529
                    if (ch >= 'a' && ch <= 'f')
7✔
2530
                        nVal = nVal * 16U +
1✔
2531
                               static_cast<unsigned int>(ch - 'a' + 10);
2532
                    else if (ch >= 'A' && ch <= 'F')
6✔
2533
                        nVal = nVal * 16U +
1✔
2534
                               static_cast<unsigned int>(ch - 'A' + 10);
2535
                    else if (ch >= '0' && ch <= '9')
5✔
2536
                        nVal = nVal * 16U + static_cast<unsigned int>(ch - '0');
2✔
2537
                    else
2538
                        break;
2539
                }
2540
                anVal[0] = static_cast<wchar_t>(nVal);
3✔
2541
                if (ch != ';')
3✔
2542
                    break;
1✔
2543
                iIn--;
2✔
2544

2545
                char *pszUTF8 =
2546
                    CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
2✔
2547
                int nLen = static_cast<int>(strlen(pszUTF8));
2✔
2548
                memcpy(pszOutput + iOut, pszUTF8, nLen);
2✔
2549
                CPLFree(pszUTF8);
2✔
2550
                iOut += nLen;
2✔
2551
            }
2552
            else if (STARTS_WITH_CI(pszInput + iIn, "&#"))
161✔
2553
            {
2554
                wchar_t anVal[2] = {0, 0};
159✔
2555
                iIn += 2;
159✔
2556

2557
                unsigned int nVal = 0;
159✔
2558
                while (true)
2559
                {
2560
                    ch = pszInput[iIn++];
646✔
2561
                    if (ch >= '0' && ch <= '9')
646✔
2562
                        nVal = nVal * 10U + static_cast<unsigned int>(ch - '0');
487✔
2563
                    else
2564
                        break;
2565
                }
2566
                anVal[0] = static_cast<wchar_t>(nVal);
159✔
2567
                if (ch != ';')
159✔
2568
                    break;
1✔
2569
                iIn--;
158✔
2570

2571
                char *pszUTF8 =
2572
                    CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
158✔
2573
                const int nLen = static_cast<int>(strlen(pszUTF8));
158✔
2574
                memcpy(pszOutput + iOut, pszUTF8, nLen);
158✔
2575
                CPLFree(pszUTF8);
158✔
2576
                iOut += nLen;
158✔
2577
            }
2578
            else
2579
            {
2580
                // Illegal escape sequence.
2581
                CPLDebug("CPL",
2✔
2582
                         "Error unescaping CPLES_XML text, '&' character "
2583
                         "followed by unhandled escape sequence.");
2584
                break;
2✔
2585
            }
2586
        }
31,045✔
2587
    }
2588
    else if (nScheme == CPLES_URL)
507✔
2589
    {
2590
        for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
25,186✔
2591
        {
2592
            if (pszInput[iIn] == '%' && pszInput[iIn + 1] != '\0' &&
24,726✔
2593
                pszInput[iIn + 2] != '\0')
293✔
2594
            {
2595
                int nHexChar = 0;
293✔
2596

2597
                if (pszInput[iIn + 1] >= 'A' && pszInput[iIn + 1] <= 'F')
293✔
2598
                    nHexChar += 16 * (pszInput[iIn + 1] - 'A' + 10);
×
2599
                else if (pszInput[iIn + 1] >= 'a' && pszInput[iIn + 1] <= 'f')
293✔
2600
                    nHexChar += 16 * (pszInput[iIn + 1] - 'a' + 10);
×
2601
                else if (pszInput[iIn + 1] >= '0' && pszInput[iIn + 1] <= '9')
293✔
2602
                    nHexChar += 16 * (pszInput[iIn + 1] - '0');
293✔
2603
                else
2604
                    CPLDebug("CPL",
×
2605
                             "Error unescaping CPLES_URL text, percent not "
2606
                             "followed by two hex digits.");
2607

2608
                if (pszInput[iIn + 2] >= 'A' && pszInput[iIn + 2] <= 'F')
293✔
2609
                    nHexChar += pszInput[iIn + 2] - 'A' + 10;
273✔
2610
                else if (pszInput[iIn + 2] >= 'a' && pszInput[iIn + 2] <= 'f')
20✔
2611
                    nHexChar += pszInput[iIn + 2] - 'a' + 10;
×
2612
                else if (pszInput[iIn + 2] >= '0' && pszInput[iIn + 2] <= '9')
20✔
2613
                    nHexChar += pszInput[iIn + 2] - '0';
20✔
2614
                else
2615
                    CPLDebug("CPL",
×
2616
                             "Error unescaping CPLES_URL text, percent not "
2617
                             "followed by two hex digits.");
2618

2619
                pszOutput[iOut++] = static_cast<char>(nHexChar);
293✔
2620
                iIn += 2;
293✔
2621
            }
2622
            else if (pszInput[iIn] == '+')
24,433✔
2623
            {
2624
                pszOutput[iOut++] = ' ';
×
2625
            }
2626
            else
2627
            {
2628
                pszOutput[iOut++] = pszInput[iIn];
24,433✔
2629
            }
2630
        }
2631
    }
2632
    else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
47✔
2633
    {
2634
        char szQuote = nScheme == CPLES_SQL ? '\'' : '\"';
47✔
2635
        for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
573✔
2636
        {
2637
            if (pszInput[iIn] == szQuote && pszInput[iIn + 1] == szQuote)
526✔
2638
            {
2639
                ++iIn;
5✔
2640
                pszOutput[iOut++] = pszInput[iIn];
5✔
2641
            }
2642
            else
2643
            {
2644
                pszOutput[iOut++] = pszInput[iIn];
521✔
2645
            }
2646
        }
47✔
2647
    }
2648
    else if (nScheme == CPLES_CSV)
×
2649
    {
2650
        CPLError(CE_Fatal, CPLE_NotSupported,
×
2651
                 "CSV Unescaping not yet implemented.");
2652
    }
2653
    else
2654
    {
2655
        CPLError(CE_Fatal, CPLE_NotSupported, "Unknown escaping style.");
×
2656
    }
2657

2658
    pszOutput[iOut] = '\0';
31,994✔
2659

2660
    if (pnLength != nullptr)
31,994✔
2661
        *pnLength = iOut;
20,896✔
2662

2663
    return pszOutput;
31,994✔
2664
}
2665

2666
/************************************************************************/
2667
/*                           CPLBinaryToHex()                           */
2668
/************************************************************************/
2669

2670
/**
2671
 * Binary to hexadecimal translation.
2672
 *
2673
 * @param nBytes number of bytes of binary data in pabyData.
2674
 * @param pabyData array of data bytes to translate.
2675
 *
2676
 * @return hexadecimal translation, zero terminated.  Free with CPLFree().
2677
 */
2678

2679
char *CPLBinaryToHex(int nBytes, const GByte *pabyData)
4,222✔
2680

2681
{
2682
    char *pszHex = static_cast<char *>(CPLMalloc(nBytes * 2 + 1));
4,222✔
2683
    pszHex[nBytes * 2] = '\0';
4,222✔
2684

2685
    constexpr char achHex[] = "0123456789ABCDEF";
4,222✔
2686

2687
    for (int i = 0; i < nBytes; ++i)
251,703✔
2688
    {
2689
        const int nLow = pabyData[i] & 0x0f;
247,481✔
2690
        const int nHigh = (pabyData[i] & 0xf0) >> 4;
247,481✔
2691

2692
        pszHex[i * 2] = achHex[nHigh];
247,481✔
2693
        pszHex[i * 2 + 1] = achHex[nLow];
247,481✔
2694
    }
2695

2696
    return pszHex;
4,222✔
2697
}
2698

2699
/************************************************************************/
2700
/*                           CPLHexToBinary()                           */
2701
/************************************************************************/
2702

2703
constexpr unsigned char hex2char[256] = {
2704
    // Not Hex characters.
2705
    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,
2706
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2707
    // 0-9
2708
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
2709
    // A-F
2710
    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2711
    // Not Hex characters.
2712
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2713
    // a-f
2714
    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2715
    0, 0, 0, 0, 0, 0, 0, 0, 0,
2716
    // Not Hex characters (upper 128 characters).
2717
    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,
2718
    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,
2719
    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,
2720
    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,
2721
    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,
2722
    0, 0, 0};
2723

2724
/**
2725
 * Hexadecimal to binary translation
2726
 *
2727
 * @param pszHex the input hex encoded string.
2728
 * @param pnBytes the returned count of decoded bytes placed here.
2729
 *
2730
 * @return returns binary buffer of data - free with CPLFree().
2731
 */
2732

2733
GByte *CPLHexToBinary(const char *pszHex, int *pnBytes)
3,882✔
2734
{
2735
    const GByte *pabyHex = reinterpret_cast<const GByte *>(pszHex);
3,882✔
2736
    const size_t nHexLen = strlen(pszHex);
3,882✔
2737

2738
    GByte *pabyWKB = static_cast<GByte *>(CPLMalloc(nHexLen / 2 + 2));
3,882✔
2739

2740
    for (size_t i = 0; i < nHexLen / 2; ++i)
1,012,510✔
2741
    {
2742
        const unsigned char h1 = hex2char[pabyHex[2 * i]];
1,008,630✔
2743
        const unsigned char h2 = hex2char[pabyHex[2 * i + 1]];
1,008,630✔
2744

2745
        // First character is high bits, second is low bits.
2746
        pabyWKB[i] = static_cast<GByte>((h1 << 4) | h2);
1,008,630✔
2747
    }
2748
    pabyWKB[nHexLen / 2] = 0;
3,882✔
2749
    *pnBytes = static_cast<int>(nHexLen / 2);
3,882✔
2750

2751
    return pabyWKB;
3,882✔
2752
}
2753

2754
/************************************************************************/
2755
/*                         CPLGetValueType()                            */
2756
/************************************************************************/
2757

2758
/**
2759
 * Detect the type of the value contained in a string, whether it is
2760
 * a real, an integer or a string
2761
 * Leading and trailing spaces are skipped in the analysis.
2762
 *
2763
 * Note: in the context of this function, integer must be understood in a
2764
 * broad sense. It does not mean that the value can fit into a 32 bit integer
2765
 * for example. It might be larger.
2766
 *
2767
 * @param pszValue the string to analyze
2768
 *
2769
 * @return returns the type of the value contained in the string.
2770
 */
2771

2772
CPLValueType CPLGetValueType(const char *pszValue)
446,610✔
2773
{
2774
    // Doubles : "+25.e+3", "-25.e-3", "25.e3", "25e3", " 25e3 "
2775
    // Not doubles: "25e 3", "25e.3", "-2-5e3", "2-5e3", "25.25.3", "-3d", "d1"
2776
    //              "XXeYYYYYYYYYYYYYYYYYYY" that evaluates to infinity
2777

2778
    if (pszValue == nullptr)
446,610✔
2779
        return CPL_VALUE_STRING;
×
2780

2781
    const char *pszValueInit = pszValue;
446,610✔
2782

2783
    // Skip leading spaces.
2784
    while (isspace(static_cast<unsigned char>(*pszValue)))
446,661✔
2785
        ++pszValue;
51✔
2786

2787
    if (*pszValue == '\0')
446,610✔
2788
        return CPL_VALUE_STRING;
366✔
2789

2790
    // Skip leading + or -.
2791
    if (*pszValue == '+' || *pszValue == '-')
446,244✔
2792
        ++pszValue;
84,262✔
2793

2794
    bool bFoundDot = false;
446,244✔
2795
    bool bFoundExponent = false;
446,244✔
2796
    bool bIsLastCharExponent = false;
446,244✔
2797
    bool bIsReal = false;
446,244✔
2798
    const char *pszAfterExponent = nullptr;
446,244✔
2799
    bool bFoundMantissa = false;
446,244✔
2800

2801
    for (; *pszValue != '\0'; ++pszValue)
5,529,730✔
2802
    {
2803
        if (isdigit(static_cast<unsigned char>(*pszValue)))
5,130,730✔
2804
        {
2805
            bIsLastCharExponent = false;
4,783,670✔
2806
            bFoundMantissa = true;
4,783,670✔
2807
        }
2808
        else if (isspace(static_cast<unsigned char>(*pszValue)))
347,061✔
2809
        {
2810
            const char *pszTmp = pszValue;
1,027✔
2811
            while (isspace(static_cast<unsigned char>(*pszTmp)))
2,058✔
2812
                ++pszTmp;
1,031✔
2813
            if (*pszTmp == 0)
1,027✔
2814
                break;
28✔
2815
            else
2816
                return CPL_VALUE_STRING;
999✔
2817
        }
2818
        else if (*pszValue == '-' || *pszValue == '+')
346,034✔
2819
        {
2820
            if (bIsLastCharExponent)
800✔
2821
            {
2822
                // Do nothing.
2823
            }
2824
            else
2825
            {
2826
                return CPL_VALUE_STRING;
319✔
2827
            }
2828
            bIsLastCharExponent = false;
481✔
2829
        }
2830
        else if (*pszValue == '.')
345,234✔
2831
        {
2832
            bIsReal = true;
298,851✔
2833
            if (!bFoundDot && !bIsLastCharExponent)
298,851✔
2834
                bFoundDot = true;
298,848✔
2835
            else
2836
                return CPL_VALUE_STRING;
3✔
2837
            bIsLastCharExponent = false;
298,848✔
2838
        }
2839
        else if (*pszValue == 'D' || *pszValue == 'd' || *pszValue == 'E' ||
46,383✔
2840
                 *pszValue == 'e')
41,943✔
2841
        {
2842
            if (!bFoundMantissa)
4,669✔
2843
                return CPL_VALUE_STRING;
4,179✔
2844
            if (!(pszValue[1] == '+' || pszValue[1] == '-' ||
490✔
2845
                  isdigit(static_cast<unsigned char>(pszValue[1]))))
9✔
2846
                return CPL_VALUE_STRING;
2✔
2847

2848
            bIsReal = true;
488✔
2849
            if (!bFoundExponent)
488✔
2850
                bFoundExponent = true;
487✔
2851
            else
2852
                return CPL_VALUE_STRING;
1✔
2853
            pszAfterExponent = pszValue + 1;
487✔
2854
            bIsLastCharExponent = true;
487✔
2855
        }
2856
        else
2857
        {
2858
            return CPL_VALUE_STRING;
41,714✔
2859
        }
2860
    }
2861

2862
    if (bIsReal && pszAfterExponent && strlen(pszAfterExponent) > 3)
399,027✔
2863
    {
2864
        // cppcheck-suppress unreadVariable
2865
        const double dfVal = CPLAtof(pszValueInit);
15✔
2866
        if (CPLIsInf(dfVal))
15✔
2867
            return CPL_VALUE_STRING;
1✔
2868
    }
2869

2870
    return bIsReal ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
399,026✔
2871
}
2872

2873
/************************************************************************/
2874
/*                              CPLStrlcpy()                            */
2875
/************************************************************************/
2876

2877
/**
2878
 * Copy source string to a destination buffer.
2879
 *
2880
 * This function ensures that the destination buffer is always NUL terminated
2881
 * (provided that its length is at least 1).
2882
 *
2883
 * This function is designed to be a safer, more consistent, and less error
2884
 * prone replacement for strncpy. Its contract is identical to libbsd's strlcpy.
2885
 *
2886
 * Truncation can be detected by testing if the return value of CPLStrlcpy
2887
 * is greater or equal to nDestSize.
2888

2889
\verbatim
2890
char szDest[5] = {};
2891
if( CPLStrlcpy(szDest, "abcde", sizeof(szDest)) >= sizeof(szDest) )
2892
    fprintf(stderr, "truncation occurred !\n");
2893
\endverbatim
2894

2895
 * @param pszDest   destination buffer
2896
 * @param pszSrc    source string. Must be NUL terminated
2897
 * @param nDestSize size of destination buffer (including space for the NUL
2898
 *     terminator character)
2899
 *
2900
 * @return the length of the source string (=strlen(pszSrc))
2901
 *
2902
 * @since GDAL 1.7.0
2903
 */
2904
size_t CPLStrlcpy(char *pszDest, const char *pszSrc, size_t nDestSize)
4,531,050✔
2905
{
2906
    if (nDestSize == 0)
4,531,050✔
2907
        return strlen(pszSrc);
×
2908

2909
    char *pszDestIter = pszDest;
4,531,050✔
2910
    const char *pszSrcIter = pszSrc;
4,531,050✔
2911

2912
    --nDestSize;
4,531,050✔
2913
    while (nDestSize != 0 && *pszSrcIter != '\0')
44,497,400✔
2914
    {
2915
        *pszDestIter = *pszSrcIter;
39,966,400✔
2916
        ++pszDestIter;
39,966,400✔
2917
        ++pszSrcIter;
39,966,400✔
2918
        --nDestSize;
39,966,400✔
2919
    }
2920
    *pszDestIter = '\0';
4,531,050✔
2921
    return pszSrcIter - pszSrc + strlen(pszSrcIter);
4,531,050✔
2922
}
2923

2924
/************************************************************************/
2925
/*                              CPLStrlcat()                            */
2926
/************************************************************************/
2927

2928
/**
2929
 * Appends a source string to a destination buffer.
2930
 *
2931
 * This function ensures that the destination buffer is always NUL terminated
2932
 * (provided that its length is at least 1 and that there is at least one byte
2933
 * free in pszDest, that is to say strlen(pszDest_before) < nDestSize)
2934
 *
2935
 * This function is designed to be a safer, more consistent, and less error
2936
 * prone replacement for strncat. Its contract is identical to libbsd's strlcat.
2937
 *
2938
 * Truncation can be detected by testing if the return value of CPLStrlcat
2939
 * is greater or equal to nDestSize.
2940

2941
\verbatim
2942
char szDest[5] = {};
2943
CPLStrlcpy(szDest, "ab", sizeof(szDest));
2944
if( CPLStrlcat(szDest, "cde", sizeof(szDest)) >= sizeof(szDest) )
2945
    fprintf(stderr, "truncation occurred !\n");
2946
\endverbatim
2947

2948
 * @param pszDest   destination buffer. Must be NUL terminated before
2949
 *         running CPLStrlcat
2950
 * @param pszSrc    source string. Must be NUL terminated
2951
 * @param nDestSize size of destination buffer (including space for the
2952
 *         NUL terminator character)
2953
 *
2954
 * @return the theoretical length of the destination string after concatenation
2955
 *         (=strlen(pszDest_before) + strlen(pszSrc)).
2956
 *         If strlen(pszDest_before) >= nDestSize, then it returns
2957
 *         nDestSize + strlen(pszSrc)
2958
 *
2959
 * @since GDAL 1.7.0
2960
 */
2961
size_t CPLStrlcat(char *pszDest, const char *pszSrc, size_t nDestSize)
1,721,100✔
2962
{
2963
    char *pszDestIter = pszDest;
1,721,100✔
2964

2965
    while (nDestSize != 0 && *pszDestIter != '\0')
72,990,400✔
2966
    {
2967
        ++pszDestIter;
71,269,300✔
2968
        --nDestSize;
71,269,300✔
2969
    }
2970

2971
    return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
1,721,100✔
2972
}
2973

2974
/************************************************************************/
2975
/*                              CPLStrnlen()                            */
2976
/************************************************************************/
2977

2978
/**
2979
 * Returns the length of a NUL terminated string by reading at most
2980
 * the specified number of bytes.
2981
 *
2982
 * The CPLStrnlen() function returns min(strlen(pszStr), nMaxLen).
2983
 * Only the first nMaxLen bytes of the string will be read. Useful to
2984
 * test if a string contains at least nMaxLen characters without reading
2985
 * the full string up to the NUL terminating character.
2986
 *
2987
 * @param pszStr    a NUL terminated string
2988
 * @param nMaxLen   maximum number of bytes to read in pszStr
2989
 *
2990
 * @return strlen(pszStr) if the length is lesser than nMaxLen, otherwise
2991
 * nMaxLen if the NUL character has not been found in the first nMaxLen bytes.
2992
 *
2993
 * @since GDAL 1.7.0
2994
 */
2995

2996
size_t CPLStrnlen(const char *pszStr, size_t nMaxLen)
399,205✔
2997
{
2998
    size_t nLen = 0;
399,205✔
2999
    while (nLen < nMaxLen && *pszStr != '\0')
16,638,400✔
3000
    {
3001
        ++nLen;
16,239,200✔
3002
        ++pszStr;
16,239,200✔
3003
    }
3004
    return nLen;
399,205✔
3005
}
3006

3007
/************************************************************************/
3008
/*                            CSLParseCommandLine()                     */
3009
/************************************************************************/
3010

3011
/**
3012
 * Tokenize command line arguments in a list of strings.
3013
 *
3014
 * @param pszCommandLine  command line
3015
 *
3016
 * @return NULL terminated list of strings to free with CSLDestroy()
3017
 *
3018
 * @since GDAL 2.1
3019
 */
3020
char **CSLParseCommandLine(const char *pszCommandLine)
791✔
3021
{
3022
    return CSLTokenizeString(pszCommandLine);
791✔
3023
}
3024

3025
/************************************************************************/
3026
/*                              CPLToupper()                            */
3027
/************************************************************************/
3028

3029
/** Converts a (ASCII) lowercase character to uppercase.
3030
 *
3031
 * Same as standard toupper(), except that it is not locale sensitive.
3032
 *
3033
 * @since GDAL 3.9
3034
 */
3035
int CPLToupper(int c)
20,825,400✔
3036
{
3037
    return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c;
20,825,400✔
3038
}
3039

3040
/************************************************************************/
3041
/*                              CPLTolower()                            */
3042
/************************************************************************/
3043

3044
/** Converts a (ASCII) uppercase character to lowercase.
3045
 *
3046
 * Same as standard tolower(), except that it is not locale sensitive.
3047
 *
3048
 * @since GDAL 3.9
3049
 */
3050
int CPLTolower(int c)
17,069,100✔
3051
{
3052
    return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c;
17,069,100✔
3053
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc