LCOV - code coverage report
Current view: top level - port - cpl_string.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 902 1008 89.5 %
Date: 2024-04-28 23:18:46 Functions: 52 55 94.5 %

          Line data    Source code
       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      415321 : char **CSLAddString(char **papszStrList, const char *pszNewString)
      84             : {
      85      415321 :     char **papszRet = CSLAddStringMayFail(papszStrList, pszNewString);
      86      415223 :     if (papszRet == nullptr && pszNewString != nullptr)
      87           0 :         abort();
      88      415223 :     return papszRet;
      89             : }
      90             : 
      91             : /** Same as CSLAddString() but may return NULL in case of (memory) failure */
      92      447671 : char **CSLAddStringMayFail(char **papszStrList, const char *pszNewString)
      93             : {
      94      447671 :     if (pszNewString == nullptr)
      95         131 :         return papszStrList;  // Nothing to do!
      96             : 
      97      447540 :     char *pszDup = VSI_STRDUP_VERBOSE(pszNewString);
      98      447419 :     if (pszDup == nullptr)
      99           0 :         return nullptr;
     100             : 
     101             :     // Allocate room for the new string.
     102      447419 :     char **papszStrListNew = nullptr;
     103      447419 :     int nItems = 0;
     104             : 
     105      447419 :     if (papszStrList == nullptr)
     106             :         papszStrListNew =
     107       60937 :             static_cast<char **>(VSI_CALLOC_VERBOSE(2, sizeof(char *)));
     108             :     else
     109             :     {
     110      386482 :         nItems = CSLCount(papszStrList);
     111             :         papszStrListNew = static_cast<char **>(
     112      386530 :             VSI_REALLOC_VERBOSE(papszStrList, (nItems + 2) * sizeof(char *)));
     113             :     }
     114      447413 :     if (papszStrListNew == nullptr)
     115             :     {
     116           0 :         VSIFree(pszDup);
     117           0 :         return nullptr;
     118             :     }
     119             : 
     120             :     // Copy the string in the list.
     121      447413 :     papszStrListNew[nItems] = pszDup;
     122      447413 :     papszStrListNew[nItems + 1] = nullptr;
     123             : 
     124      447413 :     return papszStrListNew;
     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     1194060 : int CSLCount(CSLConstList papszStrList)
     148             : {
     149     1194060 :     if (!papszStrList)
     150      133612 :         return 0;
     151             : 
     152     1060440 :     int nItems = 0;
     153             : 
     154    12025400 :     while (*papszStrList != nullptr)
     155             :     {
     156    10964900 :         ++nItems;
     157    10964900 :         ++papszStrList;
     158             :     }
     159             : 
     160     1060440 :     return nItems;
     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        1963 : const char *CSLGetField(CSLConstList papszStrList, int iField)
     174             : 
     175             : {
     176        1963 :     if (papszStrList == nullptr || iField < 0)
     177           0 :         return ("");
     178             : 
     179        4323 :     for (int i = 0; i < iField + 1; i++)
     180             :     {
     181        2362 :         if (papszStrList[i] == nullptr)
     182           2 :             return "";
     183             :     }
     184             : 
     185        1961 :     return (papszStrList[iField]);
     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     8197600 : void CPL_STDCALL CSLDestroy(char **papszStrList)
     201             : {
     202     8197600 :     if (!papszStrList)
     203     6066780 :         return;
     204             : 
     205    10954300 :     for (char **papszPtr = papszStrList; *papszPtr != nullptr; ++papszPtr)
     206             :     {
     207     8823220 :         CPLFree(*papszPtr);
     208             :     }
     209             : 
     210     2131070 :     CPLFree(papszStrList);
     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      151799 : char **CSLDuplicate(CSLConstList papszStrList)
     229             : {
     230      151799 :     const int nLines = CSLCount(papszStrList);
     231             : 
     232      151796 :     if (nLines == 0)
     233      103573 :         return nullptr;
     234             : 
     235       48223 :     CSLConstList papszSrc = papszStrList;
     236             : 
     237             :     char **papszNewList =
     238       48223 :         static_cast<char **>(VSI_MALLOC2_VERBOSE(nLines + 1, sizeof(char *)));
     239             : 
     240       48222 :     char **papszDst = papszNewList;
     241             : 
     242      486716 :     for (; *papszSrc != nullptr; ++papszSrc, ++papszDst)
     243             :     {
     244      438494 :         *papszDst = VSI_STRDUP_VERBOSE(*papszSrc);
     245      438494 :         if (*papszDst == nullptr)
     246             :         {
     247           0 :             CSLDestroy(papszNewList);
     248           0 :             return nullptr;
     249             :         }
     250             :     }
     251       48222 :     *papszDst = nullptr;
     252             : 
     253       48222 :     return papszNewList;
     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        4096 : char **CSLMerge(char **papszOrig, CSLConstList papszOverride)
     274             : 
     275             : {
     276        4096 :     if (papszOrig == nullptr && papszOverride != nullptr)
     277         530 :         return CSLDuplicate(papszOverride);
     278             : 
     279        3566 :     if (papszOverride == nullptr)
     280        2643 :         return papszOrig;
     281             : 
     282        4397 :     for (int i = 0; papszOverride[i] != nullptr; ++i)
     283             :     {
     284        3474 :         char *pszKey = nullptr;
     285        3474 :         const char *pszValue = CPLParseNameValue(papszOverride[i], &pszKey);
     286             : 
     287        3474 :         papszOrig = CSLSetNameValue(papszOrig, pszKey, pszValue);
     288        3474 :         CPLFree(pszKey);
     289             :     }
     290             : 
     291         923 :     return papszOrig;
     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        3098 : char **CSLLoad2(const char *pszFname, int nMaxLines, int nMaxCols,
     322             :                 CSLConstList papszOptions)
     323             : {
     324        3098 :     VSILFILE *fp = VSIFOpenL(pszFname, "rb");
     325             : 
     326        3098 :     if (!fp)
     327             :     {
     328        1983 :         if (CPLFetchBool(papszOptions, "EMIT_ERROR_IF_CANNOT_OPEN_FILE", true))
     329             :         {
     330             :             // Unable to open file.
     331           1 :             CPLError(CE_Failure, CPLE_OpenFailed,
     332             :                      "CSLLoad2(\"%s\") failed: unable to open file.", pszFname);
     333             :         }
     334        1983 :         return nullptr;
     335             :     }
     336             : 
     337        1115 :     char **papszStrList = nullptr;
     338        1115 :     int nLines = 0;
     339        1115 :     int nAllocatedLines = 0;
     340             : 
     341        9526 :     while (!VSIFEofL(fp) && (nMaxLines == -1 || nLines < nMaxLines))
     342             :     {
     343        8420 :         const char *pszLine = CPLReadLine2L(fp, nMaxCols, papszOptions);
     344        8420 :         if (pszLine == nullptr)
     345           9 :             break;
     346             : 
     347        8411 :         if (nLines + 1 >= nAllocatedLines)
     348             :         {
     349        1241 :             nAllocatedLines = 16 + nAllocatedLines * 2;
     350             :             char **papszStrListNew = static_cast<char **>(
     351        1241 :                 VSIRealloc(papszStrList, nAllocatedLines * sizeof(char *)));
     352        1241 :             if (papszStrListNew == nullptr)
     353             :             {
     354           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     355           0 :                 CPLReadLineL(nullptr);
     356           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
     357             :                          "CSLLoad2(\"%s\") "
     358             :                          "failed: not enough memory to allocate lines.",
     359             :                          pszFname);
     360           0 :                 return papszStrList;
     361             :             }
     362        1241 :             papszStrList = papszStrListNew;
     363             :         }
     364        8411 :         papszStrList[nLines] = CPLStrdup(pszLine);
     365        8411 :         papszStrList[nLines + 1] = nullptr;
     366        8411 :         ++nLines;
     367             :     }
     368             : 
     369        1115 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     370             : 
     371             :     // Free the internal thread local line buffer.
     372        1115 :     CPLReadLineL(nullptr);
     373             : 
     374        1115 :     return papszStrList;
     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         307 : char **CSLLoad(const char *pszFname)
     398             : {
     399         307 :     return CSLLoad2(pszFname, -1, -1, nullptr);
     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          49 : int CSLSave(CSLConstList papszStrList, const char *pszFname)
     413             : {
     414          49 :     if (papszStrList == nullptr)
     415           0 :         return 0;
     416             : 
     417          49 :     VSILFILE *fp = VSIFOpenL(pszFname, "wt");
     418          49 :     if (fp == nullptr)
     419             :     {
     420             :         // Unable to open file.
     421           1 :         CPLError(CE_Failure, CPLE_OpenFailed,
     422             :                  "CSLSave(\"%s\") failed: unable to open output file.",
     423             :                  pszFname);
     424           1 :         return 0;
     425             :     }
     426             : 
     427          48 :     int nLines = 0;
     428         385 :     while (*papszStrList != nullptr)
     429             :     {
     430         337 :         if (VSIFPrintfL(fp, "%s\n", *papszStrList) < 1)
     431             :         {
     432           0 :             CPLError(CE_Failure, CPLE_FileIO,
     433             :                      "CSLSave(\"%s\") failed: unable to write to output file.",
     434             :                      pszFname);
     435           0 :             break;  // A Problem happened... abort.
     436             :         }
     437             : 
     438         337 :         ++nLines;
     439         337 :         ++papszStrList;
     440             :     }
     441             : 
     442          48 :     if (VSIFCloseL(fp) != 0)
     443             :     {
     444           0 :         CPLError(CE_Failure, CPLE_FileIO,
     445             :                  "CSLSave(\"%s\") failed: unable to write to output file.",
     446             :                  pszFname);
     447             :     }
     448             : 
     449          48 :     return nLines;
     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           0 : int CSLPrint(CSLConstList papszStrList, FILE *fpOut)
     462             : {
     463           0 :     if (!papszStrList)
     464           0 :         return 0;
     465             : 
     466           0 :     if (fpOut == nullptr)
     467           0 :         fpOut = stdout;
     468             : 
     469           0 :     int nLines = 0;
     470             : 
     471           0 :     while (*papszStrList != nullptr)
     472             :     {
     473           0 :         if (VSIFPrintf(fpOut, "%s\n", *papszStrList) < 0)
     474           0 :             return nLines;
     475           0 :         ++nLines;
     476           0 :         ++papszStrList;
     477             :     }
     478             : 
     479           0 :     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       17301 : char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo,
     498             :                         CSLConstList papszNewLines)
     499             : {
     500       17301 :     if (papszNewLines == nullptr)
     501          35 :         return papszStrList;  // Nothing to do!
     502             : 
     503       17266 :     const int nToInsert = CSLCount(papszNewLines);
     504       17266 :     if (nToInsert == 0)
     505        1242 :         return papszStrList;  // Nothing to do!
     506             : 
     507       16024 :     const int nSrcLines = CSLCount(papszStrList);
     508       16024 :     const int nDstLines = nSrcLines + nToInsert;
     509             : 
     510             :     // Allocate room for the new strings.
     511             :     papszStrList = static_cast<char **>(
     512       16024 :         CPLRealloc(papszStrList, (nDstLines + 1) * sizeof(char *)));
     513             : 
     514             :     // Make sure the array is NULL-terminated.  It may not be if
     515             :     // papszStrList was NULL before Realloc().
     516       16024 :     papszStrList[nSrcLines] = nullptr;
     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       16024 :     if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
     522       15278 :         nInsertAtLineNo = nSrcLines;
     523             : 
     524             :     {
     525       16024 :         char **ppszSrc = papszStrList + nSrcLines;
     526       16024 :         char **ppszDst = papszStrList + nDstLines;
     527             : 
     528       33358 :         for (int i = nSrcLines; i >= nInsertAtLineNo; --i)
     529             :         {
     530       17334 :             *ppszDst = *ppszSrc;
     531       17334 :             --ppszDst;
     532       17334 :             --ppszSrc;
     533             :         }
     534             :     }
     535             : 
     536             :     // Copy the strings to the list.
     537       16024 :     CSLConstList ppszSrc = papszNewLines;
     538       16024 :     char **ppszDst = papszStrList + nInsertAtLineNo;
     539             : 
     540      144171 :     for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
     541             :     {
     542      128147 :         *ppszDst = CPLStrdup(*ppszSrc);
     543             :     }
     544             : 
     545       16024 :     return papszStrList;
     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         475 : char **CSLInsertString(char **papszStrList, int nInsertAtLineNo,
     563             :                        const char *pszNewLine)
     564             : {
     565         475 :     char *apszList[2] = {const_cast<char *>(pszNewLine), nullptr};
     566             : 
     567         950 :     return CSLInsertStrings(papszStrList, nInsertAtLineNo, apszList);
     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        5275 : char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
     589             :                         int nNumToRemove, char ***ppapszRetStrings)
     590             : {
     591        5275 :     const int nSrcLines = CSLCount(papszStrList);
     592             : 
     593        5275 :     if (nNumToRemove < 1 || nSrcLines == 0)
     594           0 :         return papszStrList;  // Nothing to do!
     595             : 
     596             :     // If operation will result in an empty StringList, don't waste
     597             :     // time here.
     598        5275 :     const int nDstLines = nSrcLines - nNumToRemove;
     599        5275 :     if (nDstLines < 1)
     600             :     {
     601         680 :         CSLDestroy(papszStrList);
     602         680 :         return nullptr;
     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        4595 :     char **ppszDst = papszStrList + nFirstLineToDelete;
     609             : 
     610        4595 :     if (ppapszRetStrings == nullptr)
     611             :     {
     612             :         // free() all the strings that will be removed.
     613        9190 :         for (int i = 0; i < nNumToRemove; ++i)
     614             :         {
     615        4595 :             CPLFree(*ppszDst);
     616        4595 :             *ppszDst = nullptr;
     617             :         }
     618             :     }
     619             :     else
     620             :     {
     621             :         // Store the strings to remove in a new StringList.
     622           0 :         *ppapszRetStrings =
     623           0 :             static_cast<char **>(CPLCalloc(nNumToRemove + 1, sizeof(char *)));
     624             : 
     625           0 :         for (int i = 0; i < nNumToRemove; ++i)
     626             :         {
     627           0 :             (*ppapszRetStrings)[i] = *ppszDst;
     628           0 :             *ppszDst = nullptr;
     629           0 :             ++ppszDst;
     630             :         }
     631             :     }
     632             : 
     633             :     // Shift down all the lines that follow the lines to remove.
     634        4595 :     if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines)
     635           0 :         nFirstLineToDelete = nDstLines;
     636             : 
     637        4595 :     char **ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
     638        4595 :     ppszDst = papszStrList + nFirstLineToDelete;
     639             : 
     640        9071 :     for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
     641             :     {
     642        4476 :         *ppszDst = *ppszSrc;
     643             :     }
     644             :     // Move the NULL pointer at the end of the StringList.
     645        4595 :     *ppszDst = *ppszSrc;
     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        4595 :     return papszStrList;
     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     3678090 : int CSLFindString(CSLConstList papszList, const char *pszTarget)
     671             : 
     672             : {
     673     3678090 :     if (papszList == nullptr)
     674      132348 :         return -1;
     675             : 
     676    28524600 :     for (int i = 0; papszList[i] != nullptr; ++i)
     677             :     {
     678    25134800 :         if (EQUAL(papszList[i], pszTarget))
     679      155960 :             return i;
     680             :     }
     681             : 
     682     3389780 :     return -1;
     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        3310 : int CSLFindStringCaseSensitive(CSLConstList papszList, const char *pszTarget)
     705             : 
     706             : {
     707        3310 :     if (papszList == nullptr)
     708         199 :         return -1;
     709             : 
     710      158267 :     for (int i = 0; papszList[i] != nullptr; ++i)
     711             :     {
     712      155170 :         if (strcmp(papszList[i], pszTarget) == 0)
     713          14 :             return i;
     714             :     }
     715             : 
     716        3097 :     return -1;
     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       19901 : int CSLPartialFindString(CSLConstList papszHaystack, const char *pszNeedle)
     737             : {
     738       19901 :     if (papszHaystack == nullptr || pszNeedle == nullptr)
     739        7211 :         return -1;
     740             : 
     741       28996 :     for (int i = 0; papszHaystack[i] != nullptr; ++i)
     742             :     {
     743       21584 :         if (strstr(papszHaystack[i], pszNeedle))
     744        5278 :             return i;
     745             :     }
     746             : 
     747        7412 :     return -1;
     748             : }
     749             : 
     750             : /**********************************************************************
     751             :  *                       CSLTokenizeString()
     752             :  **********************************************************************/
     753             : 
     754             : /** Tokenizes a string and returns a StringList with one string for
     755             :  * each token.
     756             :  */
     757      115426 : char **CSLTokenizeString(const char *pszString)
     758             : {
     759      115426 :     return CSLTokenizeString2(pszString, " ", CSLT_HONOURSTRINGS);
     760             : }
     761             : 
     762             : /************************************************************************/
     763             : /*                      CSLTokenizeStringComplex()                      */
     764             : /************************************************************************/
     765             : 
     766             : /** Obsolete tokenizing api. Use CSLTokenizeString2() */
     767      388585 : char **CSLTokenizeStringComplex(const char *pszString,
     768             :                                 const char *pszDelimiters, int bHonourStrings,
     769             :                                 int bAllowEmptyTokens)
     770             : {
     771      388585 :     int nFlags = 0;
     772             : 
     773      388585 :     if (bHonourStrings)
     774      111033 :         nFlags |= CSLT_HONOURSTRINGS;
     775      388585 :     if (bAllowEmptyTokens)
     776       17257 :         nFlags |= CSLT_ALLOWEMPTYTOKENS;
     777             : 
     778      388585 :     return CSLTokenizeString2(pszString, pszDelimiters, nFlags);
     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      915121 : char **CSLTokenizeString2(const char *pszString, const char *pszDelimiters,
     835             :                           int nCSLTFlags)
     836             : {
     837      915121 :     if (pszString == nullptr)
     838        3784 :         return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
     839             : 
     840     1822670 :     CPLStringList oRetList;
     841      911337 :     const bool bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS) != 0;
     842      911337 :     const bool bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS) != 0;
     843      911337 :     const bool bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES) != 0;
     844      911337 :     const bool bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES) != 0;
     845             : 
     846      911337 :     char *pszToken = static_cast<char *>(CPLCalloc(10, 1));
     847      911337 :     size_t nTokenMax = 10;
     848             : 
     849     3240560 :     while (*pszString != '\0')
     850             :     {
     851     2329220 :         bool bInString = false;
     852     2329220 :         bool bStartString = true;
     853     2329220 :         size_t nTokenLen = 0;
     854             : 
     855             :         // Try to find the next delimiter, marking end of token.
     856    32964200 :         for (; *pszString != '\0'; ++pszString)
     857             :         {
     858             :             // Extend token buffer if we are running close to its end.
     859    32106600 :             if (nTokenLen >= nTokenMax - 3)
     860             :             {
     861      875858 :                 if (nTokenMax > std::numeric_limits<size_t>::max() / 2)
     862             :                 {
     863           0 :                     CPLFree(pszToken);
     864           0 :                     return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
     865             :                 }
     866      875858 :                 nTokenMax = nTokenMax * 2;
     867             :                 char *pszNewToken = static_cast<char *>(
     868      875858 :                     VSI_REALLOC_VERBOSE(pszToken, nTokenMax));
     869      875858 :                 if (pszNewToken == nullptr)
     870             :                 {
     871           0 :                     CPLFree(pszToken);
     872           0 :                     return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
     873             :                 }
     874      875858 :                 pszToken = pszNewToken;
     875             :             }
     876             : 
     877             :             // End if this is a delimiter skip it and break.
     878    32106600 :             if (!bInString && strchr(pszDelimiters, *pszString) != nullptr)
     879             :             {
     880     1471700 :                 ++pszString;
     881     1471700 :                 break;
     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    30634900 :             if (bHonourStrings && *pszString == '"')
     888             :             {
     889       72960 :                 if (nCSLTFlags & CSLT_PRESERVEQUOTES)
     890             :                 {
     891        4181 :                     pszToken[nTokenLen] = *pszString;
     892        4181 :                     ++nTokenLen;
     893             :                 }
     894             : 
     895       72960 :                 bInString = !bInString;
     896       72960 :                 continue;
     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    30562000 :             if (bInString && pszString[0] == '\\')
     905             :             {
     906         110 :                 if (pszString[1] == '"' || pszString[1] == '\\')
     907             :                 {
     908          44 :                     if (nCSLTFlags & CSLT_PRESERVEESCAPES)
     909             :                     {
     910           6 :                         pszToken[nTokenLen] = *pszString;
     911           6 :                         ++nTokenLen;
     912             :                     }
     913             : 
     914          44 :                     ++pszString;
     915             :                 }
     916             :             }
     917             : 
     918             :             // Strip spaces at the token start if requested.
     919    30562000 :             if (!bInString && bStripLeadSpaces && bStartString &&
     920       30981 :                 isspace(static_cast<unsigned char>(*pszString)))
     921        4593 :                 continue;
     922             : 
     923    30557400 :             bStartString = false;
     924             : 
     925    30557400 :             pszToken[nTokenLen] = *pszString;
     926    30557400 :             ++nTokenLen;
     927             :         }
     928             : 
     929             :         // Strip spaces at the token end if requested.
     930     2329220 :         if (!bInString && bStripEndSpaces)
     931             :         {
     932       31876 :             while (nTokenLen &&
     933       26740 :                    isspace(static_cast<unsigned char>(pszToken[nTokenLen - 1])))
     934          38 :                 nTokenLen--;
     935             :         }
     936             : 
     937     2329220 :         pszToken[nTokenLen] = '\0';
     938             : 
     939             :         // Add the token.
     940     2329220 :         if (pszToken[0] != '\0' || bAllowEmptyTokens)
     941     2212780 :             oRetList.AddString(pszToken);
     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      937053 :     if (*pszString == '\0' && bAllowEmptyTokens && oRetList.Count() > 0 &&
     949       25716 :         strchr(pszDelimiters, *(pszString - 1)) != nullptr)
     950             :     {
     951        1215 :         oRetList.AddString("");
     952             :     }
     953             : 
     954      911337 :     CPLFree(pszToken);
     955             : 
     956      911337 :     if (oRetList.List() == nullptr)
     957             :     {
     958             :         // Prefer to return empty lists as a pointer to
     959             :         // a null pointer since some client code might depend on this.
     960       23188 :         oRetList.Assign(static_cast<char **>(CPLCalloc(sizeof(char *), 1)));
     961             :     }
     962             : 
     963      911337 :     return oRetList.StealList();
     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      778213 : const char *CPLSPrintf(CPL_FORMAT_STRING(const char *fmt), ...)
     983             : {
     984             :     va_list args;
     985             : 
     986             :     /* -------------------------------------------------------------------- */
     987             :     /*      Get the thread local buffer ring data.                          */
     988             :     /* -------------------------------------------------------------------- */
     989      778213 :     char *pachBufRingInfo = static_cast<char *>(CPLGetTLS(CTLS_CPLSPRINTF));
     990             : 
     991      778213 :     if (pachBufRingInfo == nullptr)
     992             :     {
     993        1327 :         pachBufRingInfo = static_cast<char *>(CPLCalloc(
     994             :             1, sizeof(int) + CPLSPrintf_BUF_Count * CPLSPrintf_BUF_SIZE));
     995        1327 :         CPLSetTLS(CTLS_CPLSPRINTF, pachBufRingInfo, TRUE);
     996             :     }
     997             : 
     998             :     /* -------------------------------------------------------------------- */
     999             :     /*      Work out which string in the "ring" we want to use this         */
    1000             :     /*      time.                                                           */
    1001             :     /* -------------------------------------------------------------------- */
    1002      778213 :     int *pnBufIndex = reinterpret_cast<int *>(pachBufRingInfo);
    1003      778213 :     const size_t nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
    1004      778213 :     char *pachBuffer = pachBufRingInfo + nOffset;
    1005             : 
    1006      778213 :     *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
    1007             : 
    1008             :     /* -------------------------------------------------------------------- */
    1009             :     /*      Format the result.                                              */
    1010             :     /* -------------------------------------------------------------------- */
    1011             : 
    1012      778213 :     va_start(args, fmt);
    1013             : 
    1014             :     const int ret =
    1015      778213 :         CPLvsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE - 1, fmt, args);
    1016      778213 :     if (ret < 0 || ret >= CPLSPrintf_BUF_SIZE - 1)
    1017             :     {
    1018           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1019             :                  "CPLSPrintf() called with too "
    1020             :                  "big string. Output will be truncated !");
    1021             :     }
    1022             : 
    1023      778213 :     va_end(args);
    1024             : 
    1025      778213 :     return pachBuffer;
    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          39 : char **CSLAppendPrintf(char **papszStrList, CPL_FORMAT_STRING(const char *fmt),
    1036             :                        ...)
    1037             : {
    1038             :     va_list args;
    1039             : 
    1040          39 :     va_start(args, fmt);
    1041          78 :     CPLString osWork;
    1042          39 :     osWork.vPrintf(fmt, args);
    1043          39 :     va_end(args);
    1044             : 
    1045          78 :     return CSLAddString(papszStrList, osWork);
    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           0 : int CPLVASPrintf(char **buf, CPL_FORMAT_STRING(const char *fmt), va_list ap)
    1055             : 
    1056             : {
    1057           0 :     CPLString osWork;
    1058             : 
    1059           0 :     osWork.vPrintf(fmt, ap);
    1060             : 
    1061           0 :     if (buf)
    1062           0 :         *buf = CPLStrdup(osWork.c_str());
    1063             : 
    1064           0 :     return static_cast<int>(osWork.size());
    1065             : }
    1066             : 
    1067             : /************************************************************************/
    1068             : /*                  CPLvsnprintf_get_end_of_formatting()                */
    1069             : /************************************************************************/
    1070             : 
    1071     2494510 : static const char *CPLvsnprintf_get_end_of_formatting(const char *fmt)
    1072             : {
    1073     2494510 :     char ch = '\0';
    1074             :     // Flag.
    1075     2573070 :     for (; (ch = *fmt) != '\0'; ++fmt)
    1076             :     {
    1077     2573030 :         if (ch == '\'')
    1078           0 :             continue;  // Bad idea as this is locale specific.
    1079     2573030 :         if (ch == '-' || ch == '+' || ch == ' ' || ch == '#' || ch == '0')
    1080       78560 :             continue;
    1081     2494470 :         break;
    1082             :     }
    1083             : 
    1084             :     // Field width.
    1085     2741600 :     for (; (ch = *fmt) != '\0'; ++fmt)
    1086             :     {
    1087     2741570 :         if (ch == '$')
    1088           0 :             return nullptr;  // Do not support this.
    1089     2741570 :         if (*fmt >= '0' && *fmt <= '9')
    1090      247089 :             continue;
    1091     2494480 :         break;
    1092             :     }
    1093             : 
    1094             :     // Precision.
    1095     2494510 :     if (ch == '.')
    1096             :     {
    1097      565055 :         ++fmt;
    1098     1622120 :         for (; (ch = *fmt) != '\0'; ++fmt)
    1099             :         {
    1100     1622120 :             if (ch == '$')
    1101           0 :                 return nullptr;  // Do not support this.
    1102     1622120 :             if (*fmt >= '0' && *fmt <= '9')
    1103     1057060 :                 continue;
    1104      565055 :             break;
    1105             :         }
    1106             :     }
    1107             : 
    1108             :     // Length modifier.
    1109     2573610 :     for (; (ch = *fmt) != '\0'; ++fmt)
    1110             :     {
    1111     2573610 :         if (ch == 'h' || ch == 'l' || ch == 'j' || ch == 'z' || ch == 't' ||
    1112             :             ch == 'L')
    1113       79140 :             continue;
    1114     2494470 :         else if (ch == 'I' && fmt[1] == '6' && fmt[2] == '4')
    1115           0 :             fmt += 2;
    1116             :         else
    1117     2494510 :             return fmt;
    1118             :     }
    1119             : 
    1120           0 :     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     1561280 : int CPLvsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt),
    1147             :                  va_list args)
    1148             : {
    1149     1561280 :     if (size == 0)
    1150           0 :         return vsnprintf(str, size, fmt, args);
    1151             : 
    1152             :     va_list wrk_args;
    1153             : 
    1154             : #ifdef va_copy
    1155     1561280 :     va_copy(wrk_args, args);
    1156             : #else
    1157             :     wrk_args = args;
    1158             : #endif
    1159             : 
    1160     1561280 :     const char *fmt_ori = fmt;
    1161     1561280 :     size_t offset_out = 0;
    1162     1561280 :     char ch = '\0';
    1163     1561280 :     bool bFormatUnknown = false;
    1164             : 
    1165    27537500 :     for (; (ch = *fmt) != '\0'; ++fmt)
    1166             :     {
    1167    25978700 :         if (ch == '%')
    1168             :         {
    1169     2495310 :             if (strncmp(fmt, "%.*f", 4) == 0)
    1170             :             {
    1171         778 :                 const int precision = va_arg(wrk_args, int);
    1172         778 :                 const double val = va_arg(wrk_args, double);
    1173             :                 const int local_ret =
    1174         670 :                     snprintf(str + offset_out, size - offset_out, "%.*f",
    1175             :                              precision, val);
    1176             :                 // MSVC vsnprintf() returns -1.
    1177         670 :                 if (local_ret < 0 || offset_out + local_ret >= size)
    1178             :                     break;
    1179       15660 :                 for (int j = 0; j < local_ret; ++j)
    1180             :                 {
    1181       14882 :                     if (str[offset_out + j] == ',')
    1182             :                     {
    1183           0 :                         str[offset_out + j] = '.';
    1184           0 :                         break;
    1185             :                     }
    1186             :                 }
    1187         778 :                 offset_out += local_ret;
    1188         778 :                 fmt += strlen("%.*f") - 1;
    1189         778 :                 continue;
    1190             :             }
    1191             : 
    1192     2494530 :             const char *ptrend = CPLvsnprintf_get_end_of_formatting(fmt + 1);
    1193     2494490 :             if (ptrend == nullptr || ptrend - fmt >= 20)
    1194             :             {
    1195          72 :                 bFormatUnknown = true;
    1196          72 :                 break;
    1197             :             }
    1198     2494420 :             char end = *ptrend;
    1199     2494420 :             char end_m1 = ptrend[-1];
    1200             : 
    1201     2494420 :             char localfmt[22] = {};
    1202     2494420 :             memcpy(localfmt, fmt, ptrend - fmt + 1);
    1203     2494420 :             localfmt[ptrend - fmt + 1] = '\0';
    1204             : 
    1205     2494420 :             int local_ret = 0;
    1206     2494420 :             if (end == '%')
    1207             :             {
    1208       11267 :                 if (offset_out == size - 1)
    1209           0 :                     break;
    1210       11267 :                 local_ret = 1;
    1211       11267 :                 str[offset_out] = '%';
    1212             :             }
    1213     2483160 :             else if (end == 'd' || end == 'i' || end == 'c')
    1214             :             {
    1215      895473 :                 if (end_m1 == 'h')
    1216           0 :                     call_native_snprintf(int);
    1217      895473 :                 else if (end_m1 == 'l' && ptrend[-2] != 'l')
    1218        1474 :                     call_native_snprintf(long);
    1219      893999 :                 else if (end_m1 == 'l' && ptrend[-2] == 'l')
    1220       22752 :                     call_native_snprintf(GIntBig);
    1221      871247 :                 else if (end_m1 == '4' && ptrend[-2] == '6' &&
    1222           0 :                          ptrend[-3] == 'I')
    1223             :                     // Microsoft I64 modifier.
    1224           0 :                     call_native_snprintf(GIntBig);
    1225      871247 :                 else if (end_m1 == 'z')
    1226           0 :                     call_native_snprintf(size_t);
    1227      871247 :                 else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
    1228           0 :                          (end_m1 >= 'A' && end_m1 <= 'Z'))
    1229             :                 {
    1230           0 :                     bFormatUnknown = true;
    1231           0 :                     break;
    1232             :                 }
    1233             :                 else
    1234      871247 :                     call_native_snprintf(int);
    1235             :             }
    1236     1587680 :             else if (end == 'o' || end == 'u' || end == 'x' || end == 'X')
    1237             :             {
    1238       53403 :                 if (end_m1 == 'h')
    1239           0 :                     call_native_snprintf(unsigned int);
    1240       53403 :                 else if (end_m1 == 'l' && ptrend[-2] != 'l')
    1241         424 :                     call_native_snprintf(unsigned long);
    1242       52979 :                 else if (end_m1 == 'l' && ptrend[-2] == 'l')
    1243       12898 :                     call_native_snprintf(GUIntBig);
    1244       40081 :                 else if (end_m1 == '4' && ptrend[-2] == '6' &&
    1245           0 :                          ptrend[-3] == 'I')
    1246             :                     // Microsoft I64 modifier.
    1247           0 :                     call_native_snprintf(GUIntBig);
    1248       40081 :                 else if (end_m1 == 'z')
    1249           0 :                     call_native_snprintf(size_t);
    1250       40081 :                 else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
    1251           0 :                          (end_m1 >= 'A' && end_m1 <= 'Z'))
    1252             :                 {
    1253           0 :                     bFormatUnknown = true;
    1254           0 :                     break;
    1255             :                 }
    1256             :                 else
    1257       40081 :                     call_native_snprintf(unsigned int);
    1258             :             }
    1259     1534280 :             else if (end == 'e' || end == 'E' || end == 'f' || end == 'F' ||
    1260      947736 :                      end == 'g' || end == 'G' || end == 'a' || end == 'A')
    1261             :             {
    1262      586541 :                 if (end_m1 == 'L')
    1263           0 :                     call_native_snprintf(long double);
    1264             :                 else
    1265      586541 :                     call_native_snprintf(double);
    1266             :                 // MSVC vsnprintf() returns -1.
    1267      586559 :                 if (local_ret < 0 || offset_out + local_ret >= size)
    1268             :                     break;
    1269     8592180 :                 for (int j = 0; j < local_ret; ++j)
    1270             :                 {
    1271     8005710 :                     if (str[offset_out + j] == ',')
    1272             :                     {
    1273           0 :                         str[offset_out + j] = '.';
    1274           0 :                         break;
    1275             :                     }
    1276      586467 :                 }
    1277             :             }
    1278      947738 :             else if (end == 's')
    1279             :             {
    1280      902079 :                 const char *pszPtr = va_arg(wrk_args, const char *);
    1281      902076 :                 CPLAssert(pszPtr);
    1282      902085 :                 local_ret = snprintf(str + offset_out, size - offset_out,
    1283             :                                      localfmt, pszPtr);
    1284             :             }
    1285       45659 :             else if (end == 'p')
    1286             :             {
    1287       44855 :                 call_native_snprintf(void *);
    1288             :             }
    1289             :             else
    1290             :             {
    1291         804 :                 bFormatUnknown = true;
    1292         804 :                 break;
    1293             :             }
    1294             :             // MSVC vsnprintf() returns -1.
    1295     2493590 :             if (local_ret < 0 || offset_out + local_ret >= size)
    1296             :                 break;
    1297     2492660 :             offset_out += local_ret;
    1298     2492660 :             fmt = ptrend;
    1299             :         }
    1300             :         else
    1301             :         {
    1302    23483400 :             if (offset_out == size - 1)
    1303         577 :                 break;
    1304    23482800 :             str[offset_out++] = *fmt;
    1305             :         }
    1306             :     }
    1307     1561200 :     if (ch == '\0' && offset_out < size)
    1308     1558860 :         str[offset_out] = '\0';
    1309             :     else
    1310             :     {
    1311        2343 :         if (bFormatUnknown)
    1312             :         {
    1313         784 :             CPLDebug("CPL",
    1314             :                      "CPLvsnprintf() called with unsupported "
    1315             :                      "formatting string: %s",
    1316             :                      fmt_ori);
    1317             :         }
    1318             : #ifdef va_copy
    1319        2360 :         va_end(wrk_args);
    1320        2360 :         va_copy(wrk_args, args);
    1321             : #else
    1322             :         wrk_args = args;
    1323             : #endif
    1324             : #if defined(HAVE_VSNPRINTF)
    1325        2360 :         offset_out = vsnprintf(str, size, fmt_ori, wrk_args);
    1326             : #else
    1327             :         offset_out = vsprintf(str, fmt_ori, wrk_args);
    1328             : #endif
    1329             :     }
    1330             : 
    1331             : #ifdef va_copy
    1332     1561220 :     va_end(wrk_args);
    1333             : #endif
    1334             : 
    1335     1561220 :     return static_cast<int>(offset_out);
    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      165378 : int CPLsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt), ...)
    1367             : {
    1368             :     va_list args;
    1369             : 
    1370      165378 :     va_start(args, fmt);
    1371      165378 :     const int ret = CPLvsnprintf(str, size, fmt, args);
    1372      165377 :     va_end(args);
    1373      165377 :     return ret;
    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           0 : int CPLsprintf(char *str, CPL_FORMAT_STRING(const char *fmt), ...)
    1396             : {
    1397             :     va_list args;
    1398             : 
    1399           0 :     va_start(args, fmt);
    1400           0 :     const int ret = CPLvsnprintf(str, INT_MAX, fmt, args);
    1401           0 :     va_end(args);
    1402           0 :     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         157 : int CPLprintf(CPL_FORMAT_STRING(const char *fmt), ...)
    1422             : {
    1423             :     va_list wrk_args, args;
    1424             : 
    1425         157 :     va_start(args, fmt);
    1426             : 
    1427             : #ifdef va_copy
    1428         157 :     va_copy(wrk_args, args);
    1429             : #else
    1430             :     wrk_args = args;
    1431             : #endif
    1432             : 
    1433         157 :     char szBuffer[4096] = {};
    1434             :     // Quiet coverity by staring off nul terminated.
    1435         157 :     int ret = CPLvsnprintf(szBuffer, sizeof(szBuffer), fmt, wrk_args);
    1436             : 
    1437             : #ifdef va_copy
    1438         157 :     va_end(wrk_args);
    1439             : #endif
    1440             : 
    1441         157 :     if (ret < int(sizeof(szBuffer)) - 1)
    1442         157 :         ret = printf("%s", szBuffer); /*ok*/
    1443             :     else
    1444             :     {
    1445             : #ifdef va_copy
    1446           0 :         va_copy(wrk_args, args);
    1447             : #else
    1448             :         wrk_args = args;
    1449             : #endif
    1450             : 
    1451           0 :         ret = vfprintf(stdout, fmt, wrk_args);
    1452             : 
    1453             : #ifdef va_copy
    1454           0 :         va_end(wrk_args);
    1455             : #endif
    1456             :     }
    1457             : 
    1458         157 :     va_end(args);
    1459             : 
    1460         157 :     return ret;
    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        1778 : int CPLsscanf(const char *str, CPL_SCANF_FORMAT_STRING(const char *fmt), ...)
    1486             : #endif
    1487             : {
    1488        1778 :     bool error = false;
    1489        1778 :     int ret = 0;
    1490        1778 :     const char *fmt_ori = fmt;
    1491             :     va_list args;
    1492             : 
    1493        1778 :     va_start(args, fmt);
    1494       13555 :     for (; *fmt != '\0' && *str != '\0'; ++fmt)
    1495             :     {
    1496       11777 :         if (*fmt == '%')
    1497             :         {
    1498        6759 :             if (fmt[1] == 'l' && fmt[2] == 'f')
    1499             :             {
    1500        6759 :                 fmt += 2;
    1501             :                 char *end;
    1502        6759 :                 *(va_arg(args, double *)) = CPLStrtod(str, &end);
    1503        6759 :                 if (end > str)
    1504             :                 {
    1505        6759 :                     ++ret;
    1506        6759 :                     str = end;
    1507             :                 }
    1508             :                 else
    1509        6759 :                     break;
    1510             :             }
    1511             :             else
    1512             :             {
    1513           0 :                 error = true;
    1514           0 :                 break;
    1515             :             }
    1516             :         }
    1517        5018 :         else if (isspace(static_cast<unsigned char>(*fmt)))
    1518             :         {
    1519        1754 :             while (*str != '\0' && isspace(static_cast<unsigned char>(*str)))
    1520         877 :                 ++str;
    1521             :         }
    1522        4141 :         else if (*str != *fmt)
    1523           0 :             break;
    1524             :         else
    1525        4141 :             ++str;
    1526             :     }
    1527        1778 :     va_end(args);
    1528             : 
    1529        1778 :     if (error)
    1530             :     {
    1531           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1532             :                  "Format %s not supported by CPLsscanf()", fmt_ori);
    1533             :     }
    1534             : 
    1535        1778 :     return ret;
    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     2313300 : bool CPLTestBool(const char *pszValue)
    1558             : {
    1559     2952870 :     return !(EQUAL(pszValue, "NO") || EQUAL(pszValue, "FALSE") ||
    1560     2952870 :              EQUAL(pszValue, "OFF") || EQUAL(pszValue, "0"));
    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         627 : int CSLTestBoolean(const char *pszValue)
    1583             : {
    1584         627 :     return CPLTestBool(pszValue) ? TRUE : FALSE;
    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          38 : int CPLTestBoolean(const char *pszValue)
    1605             : {
    1606          38 :     return CPLTestBool(pszValue) ? TRUE : FALSE;
    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      199295 : bool CPLFetchBool(CSLConstList papszStrList, const char *pszKey, bool bDefault)
    1630             : 
    1631             : {
    1632      199295 :     if (CSLFindString(papszStrList, pszKey) != -1)
    1633           2 :         return true;
    1634             : 
    1635      199270 :     const char *const pszValue = CSLFetchNameValue(papszStrList, pszKey);
    1636      199282 :     if (pszValue == nullptr)
    1637      186964 :         return bDefault;
    1638             : 
    1639       12318 :     return CPLTestBool(pszValue);
    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        1273 : int CSLFetchBoolean(CSLConstList papszStrList, const char *pszKey, int bDefault)
    1663             : 
    1664             : {
    1665        1273 :     return CPLFetchBool(papszStrList, pszKey, CPL_TO_BOOL(bDefault));
    1666             : }
    1667             : 
    1668             : /************************************************************************/
    1669             : /*                     CSLFetchNameValueDefaulted()                     */
    1670             : /************************************************************************/
    1671             : 
    1672             : /** Same as CSLFetchNameValue() but return pszDefault in case of no match */
    1673      439577 : const char *CSLFetchNameValueDef(CSLConstList papszStrList, const char *pszName,
    1674             :                                  const char *pszDefault)
    1675             : 
    1676             : {
    1677      439577 :     const char *pszResult = CSLFetchNameValue(papszStrList, pszName);
    1678      439549 :     if (pszResult != nullptr)
    1679       36006 :         return pszResult;
    1680             : 
    1681      403543 :     return pszDefault;
    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    12326400 : const char *CSLFetchNameValue(CSLConstList papszStrList, const char *pszName)
    1701             : {
    1702    12326400 :     if (papszStrList == nullptr || pszName == nullptr)
    1703     3750070 :         return nullptr;
    1704             : 
    1705     8576280 :     const size_t nLen = strlen(pszName);
    1706    12644800 :     while (*papszStrList != nullptr)
    1707             :     {
    1708     4223780 :         if (EQUALN(*papszStrList, pszName, nLen) &&
    1709      158256 :             ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
    1710             :         {
    1711      155307 :             return (*papszStrList) + nLen + 1;
    1712             :         }
    1713     4068470 :         ++papszStrList;
    1714             :     }
    1715     8420980 :     return nullptr;
    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    13785700 : int CSLFindName(CSLConstList papszStrList, const char *pszName)
    1733             : {
    1734    13785700 :     if (papszStrList == nullptr || pszName == nullptr)
    1735      450578 :         return -1;
    1736             : 
    1737    13335100 :     const size_t nLen = strlen(pszName);
    1738    13335100 :     int iIndex = 0;
    1739   106280000 :     while (*papszStrList != nullptr)
    1740             :     {
    1741   100037000 :         if (EQUALN(*papszStrList, pszName, nLen) &&
    1742     7567940 :             ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
    1743             :         {
    1744     7092700 :             return iIndex;
    1745             :         }
    1746    92944600 :         ++iIndex;
    1747    92944600 :         ++papszStrList;
    1748             :     }
    1749     6242420 :     return -1;
    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       67922 : const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey)
    1778             : {
    1779      960240 :     for (int i = 0; pszNameValue[i] != '\0'; ++i)
    1780             :     {
    1781      957411 :         if (pszNameValue[i] == '=' || pszNameValue[i] == ':')
    1782             :         {
    1783       65093 :             const char *pszValue = pszNameValue + i + 1;
    1784       71712 :             while (*pszValue == ' ' || *pszValue == '\t')
    1785        6619 :                 ++pszValue;
    1786             : 
    1787       65093 :             if (ppszKey != nullptr)
    1788             :             {
    1789       65071 :                 *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
    1790       65071 :                 memcpy(*ppszKey, pszNameValue, i);
    1791       65071 :                 (*ppszKey)[i] = '\0';
    1792       65389 :                 while (i > 0 &&
    1793       65389 :                        ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
    1794             :                 {
    1795         318 :                     (*ppszKey)[i - 1] = '\0';
    1796         318 :                     i--;
    1797             :                 }
    1798             :             }
    1799             : 
    1800       65093 :             return pszValue;
    1801             :         }
    1802             :     }
    1803             : 
    1804        2829 :     return nullptr;
    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          17 : const char *CPLParseNameValueSep(const char *pszNameValue, char **ppszKey,
    1825             :                                  char chSep)
    1826             : {
    1827         140 :     for (int i = 0; pszNameValue[i] != '\0'; ++i)
    1828             :     {
    1829         138 :         if (pszNameValue[i] == chSep)
    1830             :         {
    1831          15 :             const char *pszValue = pszNameValue + i + 1;
    1832          15 :             while (*pszValue == ' ' || *pszValue == '\t')
    1833           0 :                 ++pszValue;
    1834             : 
    1835          15 :             if (ppszKey != nullptr)
    1836             :             {
    1837          15 :                 *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
    1838          15 :                 memcpy(*ppszKey, pszNameValue, i);
    1839          15 :                 (*ppszKey)[i] = '\0';
    1840          15 :                 while (i > 0 &&
    1841          15 :                        ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
    1842             :                 {
    1843           0 :                     (*ppszKey)[i - 1] = '\0';
    1844           0 :                     i--;
    1845             :                 }
    1846             :             }
    1847             : 
    1848          15 :             return pszValue;
    1849             :         }
    1850             :     }
    1851             : 
    1852           2 :     return nullptr;
    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        7354 : char **CSLFetchNameValueMultiple(CSLConstList papszStrList, const char *pszName)
    1873             : {
    1874        7354 :     if (papszStrList == nullptr || pszName == nullptr)
    1875        1820 :         return nullptr;
    1876             : 
    1877        5534 :     const size_t nLen = strlen(pszName);
    1878        5534 :     char **papszValues = nullptr;
    1879       13164 :     while (*papszStrList != nullptr)
    1880             :     {
    1881        7630 :         if (EQUALN(*papszStrList, pszName, nLen) &&
    1882          51 :             ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
    1883             :         {
    1884          51 :             papszValues = CSLAddString(papszValues, (*papszStrList) + nLen + 1);
    1885             :         }
    1886        7630 :         ++papszStrList;
    1887             :     }
    1888             : 
    1889        5534 :     return papszValues;
    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      386561 : char **CSLAddNameValue(char **papszStrList, const char *pszName,
    1908             :                        const char *pszValue)
    1909             : {
    1910      386561 :     if (pszName == nullptr || pszValue == nullptr)
    1911           0 :         return papszStrList;
    1912             : 
    1913      386575 :     const size_t nLen = strlen(pszName) + strlen(pszValue) + 2;
    1914      386575 :     char *pszLine = static_cast<char *>(CPLMalloc(nLen));
    1915      386637 :     snprintf(pszLine, nLen, "%s=%s", pszName, pszValue);
    1916      386637 :     papszStrList = CSLAddString(papszStrList, pszLine);
    1917      386523 :     CPLFree(pszLine);
    1918             : 
    1919      386650 :     return papszStrList;
    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      410065 : char **CSLSetNameValue(char **papszList, const char *pszName,
    1947             :                        const char *pszValue)
    1948             : {
    1949      410065 :     if (pszName == nullptr)
    1950          38 :         return papszList;
    1951             : 
    1952      410027 :     size_t nLen = strlen(pszName);
    1953      410701 :     while (nLen > 0 && pszName[nLen - 1] == ' ')
    1954         674 :         nLen--;
    1955      410027 :     char **papszPtr = papszList;
    1956     6975610 :     while (papszPtr && *papszPtr != nullptr)
    1957             :     {
    1958     6599250 :         if (EQUALN(*papszPtr, pszName, nLen))
    1959             :         {
    1960             :             size_t i;
    1961       35998 :             for (i = nLen; (*papszPtr)[i] == ' '; ++i)
    1962             :             {
    1963             :             }
    1964       35324 :             if ((*papszPtr)[i] == '=' || (*papszPtr)[i] == ':')
    1965             :             {
    1966             :                 // Found it.
    1967             :                 // Change the value... make sure to keep the ':' or '='.
    1968       33671 :                 const char cSep = (*papszPtr)[i];
    1969             : 
    1970       33671 :                 CPLFree(*papszPtr);
    1971             : 
    1972             :                 // If the value is NULL, remove this entry completely.
    1973       33659 :                 if (pszValue == nullptr)
    1974             :                 {
    1975       34956 :                     while (papszPtr[1] != nullptr)
    1976             :                     {
    1977        7877 :                         *papszPtr = papszPtr[1];
    1978        7877 :                         ++papszPtr;
    1979             :                     }
    1980       27079 :                     *papszPtr = nullptr;
    1981             :                 }
    1982             : 
    1983             :                 // Otherwise replace with new value.
    1984             :                 else
    1985             :                 {
    1986        6580 :                     const size_t nLen2 = strlen(pszName) + strlen(pszValue) + 2;
    1987        6580 :                     *papszPtr = static_cast<char *>(CPLMalloc(nLen2));
    1988        6461 :                     snprintf(*papszPtr, nLen2, "%s%c%s", pszName, cSep,
    1989             :                              pszValue);
    1990             :                 }
    1991       33540 :                 return papszList;
    1992             :             }
    1993             :         }
    1994     6565580 :         ++papszPtr;
    1995             :     }
    1996             : 
    1997      376356 :     if (pszValue == nullptr)
    1998        4220 :         return papszList;
    1999             : 
    2000             :     // The name does not exist yet.  Create a new entry.
    2001      372136 :     return CSLAddNameValue(papszList, pszName, pszValue);
    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          89 : void CSLSetNameValueSeparator(char **papszList, const char *pszSeparator)
    2028             : 
    2029             : {
    2030          89 :     const int nLines = CSLCount(papszList);
    2031             : 
    2032         777 :     for (int iLine = 0; iLine < nLines; ++iLine)
    2033             :     {
    2034         688 :         char *pszKey = nullptr;
    2035         688 :         const char *pszValue = CPLParseNameValue(papszList[iLine], &pszKey);
    2036         688 :         if (pszValue == nullptr || pszKey == nullptr)
    2037             :         {
    2038           0 :             CPLFree(pszKey);
    2039           0 :             continue;
    2040             :         }
    2041             : 
    2042        1376 :         char *pszNewLine = static_cast<char *>(CPLMalloc(
    2043         688 :             strlen(pszValue) + strlen(pszKey) + strlen(pszSeparator) + 1));
    2044         688 :         strcpy(pszNewLine, pszKey);
    2045         688 :         strcat(pszNewLine, pszSeparator);
    2046         688 :         strcat(pszNewLine, pszValue);
    2047         688 :         CPLFree(papszList[iLine]);
    2048         688 :         papszList[iLine] = pszNewLine;
    2049         688 :         CPLFree(pszKey);
    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      448006 : char *CPLEscapeString(const char *pszInput, int nLength, int nScheme)
    2106             : {
    2107      448006 :     const size_t szLength =
    2108      448006 :         (nLength < 0) ? strlen(pszInput) : static_cast<size_t>(nLength);
    2109             : #define nLength no_longer_use_me
    2110             : 
    2111      448006 :     size_t nSizeAlloc = 1;
    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    40223500 :     const auto IncSizeAlloc = [&nSizeAlloc](size_t inc) { nSizeAlloc += inc; };
    2126             : #endif
    2127             : 
    2128      448006 :     if (nScheme == CPLES_BackslashQuotable)
    2129             :     {
    2130       44026 :         for (size_t iIn = 0; iIn < szLength; iIn++)
    2131             :         {
    2132       43908 :             if (pszInput[iIn] == '\0' || pszInput[iIn] == '\n' ||
    2133       43154 :                 pszInput[iIn] == '"' || pszInput[iIn] == '\\')
    2134         876 :                 IncSizeAlloc(2);
    2135             :             else
    2136       43032 :                 IncSizeAlloc(1);
    2137             :         }
    2138             :     }
    2139      447888 :     else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
    2140             :     {
    2141    40145900 :         for (size_t iIn = 0; iIn < szLength; ++iIn)
    2142             :         {
    2143    39701000 :             if (pszInput[iIn] == '<')
    2144             :             {
    2145        1420 :                 IncSizeAlloc(4);
    2146             :             }
    2147    39699500 :             else if (pszInput[iIn] == '>')
    2148             :             {
    2149        1570 :                 IncSizeAlloc(4);
    2150             :             }
    2151    39698000 :             else if (pszInput[iIn] == '&')
    2152             :             {
    2153         845 :                 IncSizeAlloc(5);
    2154             :             }
    2155    39697100 :             else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
    2156             :             {
    2157        1910 :                 IncSizeAlloc(6);
    2158             :             }
    2159             :             // Python 2 does not display the UTF-8 character corresponding
    2160             :             // to the byte-order mark (BOM), so escape it.
    2161    39695200 :             else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
    2162           2 :                          0xEF &&
    2163             :                      (reinterpret_cast<const unsigned char *>(
    2164           2 :                          pszInput))[iIn + 1] == 0xBB &&
    2165             :                      (reinterpret_cast<const unsigned char *>(
    2166           2 :                          pszInput))[iIn + 2] == 0xBF)
    2167             :             {
    2168           2 :                 IncSizeAlloc(8);
    2169           2 :                 iIn += 2;
    2170             :             }
    2171    39695200 :             else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
    2172       22171 :                          0x20 &&
    2173       22171 :                      pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
    2174         110 :                      pszInput[iIn] != 0xD)
    2175             :             {
    2176             :                 // These control characters are unrepresentable in XML format,
    2177             :                 // so we just drop them.  #4117
    2178             :             }
    2179             :             else
    2180             :             {
    2181    39695200 :                 IncSizeAlloc(1);
    2182             :             }
    2183      444970 :         }
    2184             :     }
    2185        2918 :     else if (nScheme == CPLES_URL)  // Untested at implementation.
    2186             :     {
    2187        7033 :         for (size_t iIn = 0; iIn < szLength; ++iIn)
    2188             :         {
    2189        6623 :             if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
    2190        2580 :                 (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
    2191        1125 :                 (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
    2192         515 :                 pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
    2193         475 :                 pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
    2194         272 :                 pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
    2195         254 :                 pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
    2196         252 :                 pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
    2197         242 :                 pszInput[iIn] == ',')
    2198             :             {
    2199        6387 :                 IncSizeAlloc(1);
    2200             :             }
    2201             :             else
    2202             :             {
    2203         236 :                 IncSizeAlloc(3);
    2204             :             }
    2205             :         }
    2206             :     }
    2207        2508 :     else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
    2208             :     {
    2209         780 :         const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
    2210       11574 :         for (size_t iIn = 0; iIn < szLength; ++iIn)
    2211             :         {
    2212       10794 :             if (pszInput[iIn] == chQuote)
    2213             :             {
    2214           7 :                 IncSizeAlloc(2);
    2215             :             }
    2216             :             else
    2217             :             {
    2218       10787 :                 IncSizeAlloc(1);
    2219             :             }
    2220         780 :         }
    2221             :     }
    2222        1728 :     else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
    2223             :     {
    2224        1728 :         if (nScheme == CPLES_CSV && strcspn(pszInput, "\",;\t\n\r") == szLength)
    2225             :         {
    2226             :             char *pszOutput =
    2227        1505 :                 static_cast<char *>(VSI_MALLOC_VERBOSE(szLength + 1));
    2228        1505 :             if (pszOutput == nullptr)
    2229           0 :                 return nullptr;
    2230        1505 :             memcpy(pszOutput, pszInput, szLength + 1);
    2231        1505 :             return pszOutput;
    2232             :         }
    2233             :         else
    2234             :         {
    2235         223 :             IncSizeAlloc(1);
    2236       12991 :             for (size_t iIn = 0; iIn < szLength; ++iIn)
    2237             :             {
    2238       12768 :                 if (pszInput[iIn] == '\"')
    2239             :                 {
    2240         169 :                     IncSizeAlloc(2);
    2241             :                 }
    2242             :                 else
    2243       12599 :                     IncSizeAlloc(1);
    2244             :             }
    2245         223 :             IncSizeAlloc(1);
    2246         223 :         }
    2247             :     }
    2248             :     else
    2249             :     {
    2250           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2251             :                  "Undefined escaping scheme (%d) in CPLEscapeString()",
    2252             :                  nScheme);
    2253           0 :         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      446501 :     char *pszOutput = static_cast<char *>(VSI_MALLOC_VERBOSE(nSizeAlloc));
    2266      446501 :     if (pszOutput == nullptr)
    2267           0 :         return nullptr;
    2268             : 
    2269      446501 :     size_t iOut = 0;
    2270             : 
    2271      446501 :     if (nScheme == CPLES_BackslashQuotable)
    2272             :     {
    2273       44026 :         for (size_t iIn = 0; iIn < szLength; iIn++)
    2274             :         {
    2275       43908 :             if (pszInput[iIn] == '\0')
    2276             :             {
    2277         689 :                 pszOutput[iOut++] = '\\';
    2278         689 :                 pszOutput[iOut++] = '0';
    2279             :             }
    2280       43219 :             else if (pszInput[iIn] == '\n')
    2281             :             {
    2282          65 :                 pszOutput[iOut++] = '\\';
    2283          65 :                 pszOutput[iOut++] = 'n';
    2284             :             }
    2285       43154 :             else if (pszInput[iIn] == '"')
    2286             :             {
    2287         121 :                 pszOutput[iOut++] = '\\';
    2288         121 :                 pszOutput[iOut++] = '\"';
    2289             :             }
    2290       43033 :             else if (pszInput[iIn] == '\\')
    2291             :             {
    2292           1 :                 pszOutput[iOut++] = '\\';
    2293           1 :                 pszOutput[iOut++] = '\\';
    2294             :             }
    2295             :             else
    2296       43032 :                 pszOutput[iOut++] = pszInput[iIn];
    2297             :         }
    2298         118 :         pszOutput[iOut++] = '\0';
    2299             :     }
    2300      446383 :     else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
    2301             :     {
    2302    40145900 :         for (size_t iIn = 0; iIn < szLength; ++iIn)
    2303             :         {
    2304    39701000 :             if (pszInput[iIn] == '<')
    2305             :             {
    2306        1420 :                 pszOutput[iOut++] = '&';
    2307        1420 :                 pszOutput[iOut++] = 'l';
    2308        1420 :                 pszOutput[iOut++] = 't';
    2309        1420 :                 pszOutput[iOut++] = ';';
    2310             :             }
    2311    39699500 :             else if (pszInput[iIn] == '>')
    2312             :             {
    2313        1570 :                 pszOutput[iOut++] = '&';
    2314        1570 :                 pszOutput[iOut++] = 'g';
    2315        1570 :                 pszOutput[iOut++] = 't';
    2316        1570 :                 pszOutput[iOut++] = ';';
    2317             :             }
    2318    39698000 :             else if (pszInput[iIn] == '&')
    2319             :             {
    2320         845 :                 pszOutput[iOut++] = '&';
    2321         845 :                 pszOutput[iOut++] = 'a';
    2322         845 :                 pszOutput[iOut++] = 'm';
    2323         845 :                 pszOutput[iOut++] = 'p';
    2324         845 :                 pszOutput[iOut++] = ';';
    2325             :             }
    2326    39697100 :             else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
    2327             :             {
    2328        1910 :                 pszOutput[iOut++] = '&';
    2329        1910 :                 pszOutput[iOut++] = 'q';
    2330        1910 :                 pszOutput[iOut++] = 'u';
    2331        1910 :                 pszOutput[iOut++] = 'o';
    2332        1910 :                 pszOutput[iOut++] = 't';
    2333        1910 :                 pszOutput[iOut++] = ';';
    2334             :             }
    2335             :             // Python 2 does not display the UTF-8 character corresponding
    2336             :             // to the byte-order mark (BOM), so escape it.
    2337    39695200 :             else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
    2338           2 :                          0xEF &&
    2339             :                      (reinterpret_cast<const unsigned char *>(
    2340           2 :                          pszInput))[iIn + 1] == 0xBB &&
    2341             :                      (reinterpret_cast<const unsigned char *>(
    2342           2 :                          pszInput))[iIn + 2] == 0xBF)
    2343             :             {
    2344           2 :                 pszOutput[iOut++] = '&';
    2345           2 :                 pszOutput[iOut++] = '#';
    2346           2 :                 pszOutput[iOut++] = 'x';
    2347           2 :                 pszOutput[iOut++] = 'F';
    2348           2 :                 pszOutput[iOut++] = 'E';
    2349           2 :                 pszOutput[iOut++] = 'F';
    2350           2 :                 pszOutput[iOut++] = 'F';
    2351           2 :                 pszOutput[iOut++] = ';';
    2352           2 :                 iIn += 2;
    2353             :             }
    2354    39695200 :             else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
    2355       22171 :                          0x20 &&
    2356       22171 :                      pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
    2357         110 :                      pszInput[iIn] != 0xD)
    2358             :             {
    2359             :                 // These control characters are unrepresentable in XML format,
    2360             :                 // so we just drop them.  #4117
    2361             :             }
    2362             :             else
    2363             :             {
    2364    39695200 :                 pszOutput[iOut++] = pszInput[iIn];
    2365             :             }
    2366             :         }
    2367      444970 :         pszOutput[iOut++] = '\0';
    2368             :     }
    2369        1413 :     else if (nScheme == CPLES_URL)  // Untested at implementation.
    2370             :     {
    2371        7033 :         for (size_t iIn = 0; iIn < szLength; ++iIn)
    2372             :         {
    2373        6623 :             if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
    2374        2580 :                 (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
    2375        1125 :                 (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
    2376         515 :                 pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
    2377         475 :                 pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
    2378         272 :                 pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
    2379         254 :                 pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
    2380         252 :                 pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
    2381         242 :                 pszInput[iIn] == ',')
    2382             :             {
    2383        6387 :                 pszOutput[iOut++] = pszInput[iIn];
    2384             :             }
    2385             :             else
    2386             :             {
    2387         236 :                 snprintf(pszOutput + iOut, nSizeAlloc - iOut, "%%%02X",
    2388         236 :                          static_cast<unsigned char>(pszInput[iIn]));
    2389         236 :                 iOut += 3;
    2390             :             }
    2391             :         }
    2392         410 :         pszOutput[iOut++] = '\0';
    2393             :     }
    2394        1003 :     else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
    2395             :     {
    2396         780 :         const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
    2397       11574 :         for (size_t iIn = 0; iIn < szLength; ++iIn)
    2398             :         {
    2399       10794 :             if (pszInput[iIn] == chQuote)
    2400             :             {
    2401           7 :                 pszOutput[iOut++] = chQuote;
    2402           7 :                 pszOutput[iOut++] = chQuote;
    2403             :             }
    2404             :             else
    2405             :             {
    2406       10787 :                 pszOutput[iOut++] = pszInput[iIn];
    2407             :             }
    2408             :         }
    2409         780 :         pszOutput[iOut++] = '\0';
    2410             :     }
    2411         223 :     else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
    2412             :     {
    2413         223 :         pszOutput[iOut++] = '\"';
    2414             : 
    2415       12991 :         for (size_t iIn = 0; iIn < szLength; ++iIn)
    2416             :         {
    2417       12768 :             if (pszInput[iIn] == '\"')
    2418             :             {
    2419         169 :                 pszOutput[iOut++] = '\"';
    2420         169 :                 pszOutput[iOut++] = '\"';
    2421             :             }
    2422             :             else
    2423       12599 :                 pszOutput[iOut++] = pszInput[iIn];
    2424             :         }
    2425         223 :         pszOutput[iOut++] = '\"';
    2426         223 :         pszOutput[iOut++] = '\0';
    2427             :     }
    2428             : 
    2429      446501 :     return pszOutput;
    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       31809 : char *CPLUnescapeString(const char *pszInput, int *pnLength, int nScheme)
    2456             : 
    2457             : {
    2458       31809 :     int iOut = 0;
    2459             : 
    2460             :     // TODO: Why times 4?
    2461       31809 :     char *pszOutput = static_cast<char *>(CPLMalloc(4 * strlen(pszInput) + 1));
    2462       31809 :     pszOutput[0] = '\0';
    2463             : 
    2464       31809 :     if (nScheme == CPLES_BackslashQuotable)
    2465             :     {
    2466       49436 :         for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
    2467             :         {
    2468       48994 :             if (pszInput[iIn] == '\\')
    2469             :             {
    2470         769 :                 ++iIn;
    2471         769 :                 if (pszInput[iIn] == '\0')
    2472           0 :                     break;
    2473         769 :                 if (pszInput[iIn] == 'n')
    2474           6 :                     pszOutput[iOut++] = '\n';
    2475         763 :                 else if (pszInput[iIn] == '0')
    2476         675 :                     pszOutput[iOut++] = '\0';
    2477             :                 else
    2478          88 :                     pszOutput[iOut++] = pszInput[iIn];
    2479             :             }
    2480             :             else
    2481             :             {
    2482       48225 :                 pszOutput[iOut++] = pszInput[iIn];
    2483             :             }
    2484             :         }
    2485             :     }
    2486       31367 :     else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
    2487             :     {
    2488       30860 :         char ch = '\0';
    2489    32649200 :         for (int iIn = 0; (ch = pszInput[iIn]) != '\0'; ++iIn)
    2490             :         {
    2491    32618300 :             if (ch != '&')
    2492             :             {
    2493    32298000 :                 pszOutput[iOut++] = ch;
    2494             :             }
    2495      320350 :             else if (STARTS_WITH_CI(pszInput + iIn, "&lt;"))
    2496             :             {
    2497       19801 :                 pszOutput[iOut++] = '<';
    2498       19801 :                 iIn += 3;
    2499             :             }
    2500      300549 :             else if (STARTS_WITH_CI(pszInput + iIn, "&gt;"))
    2501             :             {
    2502       19952 :                 pszOutput[iOut++] = '>';
    2503       19952 :                 iIn += 3;
    2504             :             }
    2505      280597 :             else if (STARTS_WITH_CI(pszInput + iIn, "&amp;"))
    2506             :             {
    2507      198759 :                 pszOutput[iOut++] = '&';
    2508      198759 :                 iIn += 4;
    2509             :             }
    2510       81838 :             else if (STARTS_WITH_CI(pszInput + iIn, "&apos;"))
    2511             :             {
    2512         686 :                 pszOutput[iOut++] = '\'';
    2513         686 :                 iIn += 5;
    2514             :             }
    2515       81152 :             else if (STARTS_WITH_CI(pszInput + iIn, "&quot;"))
    2516             :             {
    2517       80988 :                 pszOutput[iOut++] = '"';
    2518       80988 :                 iIn += 5;
    2519             :             }
    2520         164 :             else if (STARTS_WITH_CI(pszInput + iIn, "&#x"))
    2521             :             {
    2522           3 :                 wchar_t anVal[2] = {0, 0};
    2523           3 :                 iIn += 3;
    2524             : 
    2525           3 :                 unsigned int nVal = 0;
    2526             :                 while (true)
    2527             :                 {
    2528           7 :                     ch = pszInput[iIn++];
    2529           7 :                     if (ch >= 'a' && ch <= 'f')
    2530           1 :                         nVal = nVal * 16U +
    2531             :                                static_cast<unsigned int>(ch - 'a' + 10);
    2532           6 :                     else if (ch >= 'A' && ch <= 'F')
    2533           1 :                         nVal = nVal * 16U +
    2534             :                                static_cast<unsigned int>(ch - 'A' + 10);
    2535           5 :                     else if (ch >= '0' && ch <= '9')
    2536           2 :                         nVal = nVal * 16U + static_cast<unsigned int>(ch - '0');
    2537             :                     else
    2538             :                         break;
    2539             :                 }
    2540           3 :                 anVal[0] = static_cast<wchar_t>(nVal);
    2541           3 :                 if (ch != ';')
    2542           1 :                     break;
    2543           2 :                 iIn--;
    2544             : 
    2545             :                 char *pszUTF8 =
    2546           2 :                     CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
    2547           2 :                 int nLen = static_cast<int>(strlen(pszUTF8));
    2548           2 :                 memcpy(pszOutput + iOut, pszUTF8, nLen);
    2549           2 :                 CPLFree(pszUTF8);
    2550           2 :                 iOut += nLen;
    2551             :             }
    2552         161 :             else if (STARTS_WITH_CI(pszInput + iIn, "&#"))
    2553             :             {
    2554         159 :                 wchar_t anVal[2] = {0, 0};
    2555         159 :                 iIn += 2;
    2556             : 
    2557         159 :                 unsigned int nVal = 0;
    2558             :                 while (true)
    2559             :                 {
    2560         646 :                     ch = pszInput[iIn++];
    2561         646 :                     if (ch >= '0' && ch <= '9')
    2562         487 :                         nVal = nVal * 10U + static_cast<unsigned int>(ch - '0');
    2563             :                     else
    2564             :                         break;
    2565             :                 }
    2566         159 :                 anVal[0] = static_cast<wchar_t>(nVal);
    2567         159 :                 if (ch != ';')
    2568           1 :                     break;
    2569         158 :                 iIn--;
    2570             : 
    2571             :                 char *pszUTF8 =
    2572         158 :                     CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
    2573         158 :                 const int nLen = static_cast<int>(strlen(pszUTF8));
    2574         158 :                 memcpy(pszOutput + iOut, pszUTF8, nLen);
    2575         158 :                 CPLFree(pszUTF8);
    2576         158 :                 iOut += nLen;
    2577             :             }
    2578             :             else
    2579             :             {
    2580             :                 // Illegal escape sequence.
    2581           2 :                 CPLDebug("CPL",
    2582             :                          "Error unescaping CPLES_XML text, '&' character "
    2583             :                          "followed by unhandled escape sequence.");
    2584           2 :                 break;
    2585             :             }
    2586       30860 :         }
    2587             :     }
    2588         507 :     else if (nScheme == CPLES_URL)
    2589             :     {
    2590       25186 :         for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
    2591             :         {
    2592       24726 :             if (pszInput[iIn] == '%' && pszInput[iIn + 1] != '\0' &&
    2593         293 :                 pszInput[iIn + 2] != '\0')
    2594             :             {
    2595         293 :                 int nHexChar = 0;
    2596             : 
    2597         293 :                 if (pszInput[iIn + 1] >= 'A' && pszInput[iIn + 1] <= 'F')
    2598           0 :                     nHexChar += 16 * (pszInput[iIn + 1] - 'A' + 10);
    2599         293 :                 else if (pszInput[iIn + 1] >= 'a' && pszInput[iIn + 1] <= 'f')
    2600           0 :                     nHexChar += 16 * (pszInput[iIn + 1] - 'a' + 10);
    2601         293 :                 else if (pszInput[iIn + 1] >= '0' && pszInput[iIn + 1] <= '9')
    2602         293 :                     nHexChar += 16 * (pszInput[iIn + 1] - '0');
    2603             :                 else
    2604           0 :                     CPLDebug("CPL",
    2605             :                              "Error unescaping CPLES_URL text, percent not "
    2606             :                              "followed by two hex digits.");
    2607             : 
    2608         293 :                 if (pszInput[iIn + 2] >= 'A' && pszInput[iIn + 2] <= 'F')
    2609         273 :                     nHexChar += pszInput[iIn + 2] - 'A' + 10;
    2610          20 :                 else if (pszInput[iIn + 2] >= 'a' && pszInput[iIn + 2] <= 'f')
    2611           0 :                     nHexChar += pszInput[iIn + 2] - 'a' + 10;
    2612          20 :                 else if (pszInput[iIn + 2] >= '0' && pszInput[iIn + 2] <= '9')
    2613          20 :                     nHexChar += pszInput[iIn + 2] - '0';
    2614             :                 else
    2615           0 :                     CPLDebug("CPL",
    2616             :                              "Error unescaping CPLES_URL text, percent not "
    2617             :                              "followed by two hex digits.");
    2618             : 
    2619         293 :                 pszOutput[iOut++] = static_cast<char>(nHexChar);
    2620         293 :                 iIn += 2;
    2621             :             }
    2622       24433 :             else if (pszInput[iIn] == '+')
    2623             :             {
    2624           0 :                 pszOutput[iOut++] = ' ';
    2625             :             }
    2626             :             else
    2627             :             {
    2628       24433 :                 pszOutput[iOut++] = pszInput[iIn];
    2629             :             }
    2630             :         }
    2631             :     }
    2632          47 :     else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
    2633             :     {
    2634          47 :         char szQuote = nScheme == CPLES_SQL ? '\'' : '\"';
    2635         573 :         for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
    2636             :         {
    2637         526 :             if (pszInput[iIn] == szQuote && pszInput[iIn + 1] == szQuote)
    2638             :             {
    2639           5 :                 ++iIn;
    2640           5 :                 pszOutput[iOut++] = pszInput[iIn];
    2641             :             }
    2642             :             else
    2643             :             {
    2644         521 :                 pszOutput[iOut++] = pszInput[iIn];
    2645             :             }
    2646          47 :         }
    2647             :     }
    2648           0 :     else if (nScheme == CPLES_CSV)
    2649             :     {
    2650           0 :         CPLError(CE_Fatal, CPLE_NotSupported,
    2651             :                  "CSV Unescaping not yet implemented.");
    2652             :     }
    2653             :     else
    2654             :     {
    2655           0 :         CPLError(CE_Fatal, CPLE_NotSupported, "Unknown escaping style.");
    2656             :     }
    2657             : 
    2658       31809 :     pszOutput[iOut] = '\0';
    2659             : 
    2660       31809 :     if (pnLength != nullptr)
    2661       20896 :         *pnLength = iOut;
    2662             : 
    2663       31809 :     return pszOutput;
    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        4222 : char *CPLBinaryToHex(int nBytes, const GByte *pabyData)
    2680             : 
    2681             : {
    2682        4222 :     char *pszHex = static_cast<char *>(CPLMalloc(nBytes * 2 + 1));
    2683        4222 :     pszHex[nBytes * 2] = '\0';
    2684             : 
    2685        4222 :     constexpr char achHex[] = "0123456789ABCDEF";
    2686             : 
    2687      251703 :     for (int i = 0; i < nBytes; ++i)
    2688             :     {
    2689      247481 :         const int nLow = pabyData[i] & 0x0f;
    2690      247481 :         const int nHigh = (pabyData[i] & 0xf0) >> 4;
    2691             : 
    2692      247481 :         pszHex[i * 2] = achHex[nHigh];
    2693      247481 :         pszHex[i * 2 + 1] = achHex[nLow];
    2694             :     }
    2695             : 
    2696        4222 :     return pszHex;
    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        3882 : GByte *CPLHexToBinary(const char *pszHex, int *pnBytes)
    2734             : {
    2735        3882 :     const GByte *pabyHex = reinterpret_cast<const GByte *>(pszHex);
    2736        3882 :     const size_t nHexLen = strlen(pszHex);
    2737             : 
    2738        3882 :     GByte *pabyWKB = static_cast<GByte *>(CPLMalloc(nHexLen / 2 + 2));
    2739             : 
    2740     1012510 :     for (size_t i = 0; i < nHexLen / 2; ++i)
    2741             :     {
    2742     1008630 :         const unsigned char h1 = hex2char[pabyHex[2 * i]];
    2743     1008630 :         const unsigned char h2 = hex2char[pabyHex[2 * i + 1]];
    2744             : 
    2745             :         // First character is high bits, second is low bits.
    2746     1008630 :         pabyWKB[i] = static_cast<GByte>((h1 << 4) | h2);
    2747             :     }
    2748        3882 :     pabyWKB[nHexLen / 2] = 0;
    2749        3882 :     *pnBytes = static_cast<int>(nHexLen / 2);
    2750             : 
    2751        3882 :     return pabyWKB;
    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      446608 : CPLValueType CPLGetValueType(const char *pszValue)
    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      446608 :     if (pszValue == nullptr)
    2779           0 :         return CPL_VALUE_STRING;
    2780             : 
    2781      446608 :     const char *pszValueInit = pszValue;
    2782             : 
    2783             :     // Skip leading spaces.
    2784      446659 :     while (isspace(static_cast<unsigned char>(*pszValue)))
    2785          51 :         ++pszValue;
    2786             : 
    2787      446608 :     if (*pszValue == '\0')
    2788         366 :         return CPL_VALUE_STRING;
    2789             : 
    2790             :     // Skip leading + or -.
    2791      446242 :     if (*pszValue == '+' || *pszValue == '-')
    2792       84262 :         ++pszValue;
    2793             : 
    2794      446242 :     bool bFoundDot = false;
    2795      446242 :     bool bFoundExponent = false;
    2796      446242 :     bool bIsLastCharExponent = false;
    2797      446242 :     bool bIsReal = false;
    2798      446242 :     const char *pszAfterExponent = nullptr;
    2799      446242 :     bool bFoundMantissa = false;
    2800             : 
    2801     5529720 :     for (; *pszValue != '\0'; ++pszValue)
    2802             :     {
    2803     5130720 :         if (isdigit(static_cast<unsigned char>(*pszValue)))
    2804             :         {
    2805     4783660 :             bIsLastCharExponent = false;
    2806     4783660 :             bFoundMantissa = true;
    2807             :         }
    2808      347060 :         else if (isspace(static_cast<unsigned char>(*pszValue)))
    2809             :         {
    2810        1027 :             const char *pszTmp = pszValue;
    2811        2058 :             while (isspace(static_cast<unsigned char>(*pszTmp)))
    2812        1031 :                 ++pszTmp;
    2813        1027 :             if (*pszTmp == 0)
    2814          28 :                 break;
    2815             :             else
    2816         999 :                 return CPL_VALUE_STRING;
    2817             :         }
    2818      346033 :         else if (*pszValue == '-' || *pszValue == '+')
    2819             :         {
    2820         800 :             if (bIsLastCharExponent)
    2821             :             {
    2822             :                 // Do nothing.
    2823             :             }
    2824             :             else
    2825             :             {
    2826         319 :                 return CPL_VALUE_STRING;
    2827             :             }
    2828         481 :             bIsLastCharExponent = false;
    2829             :         }
    2830      345233 :         else if (*pszValue == '.')
    2831             :         {
    2832      298851 :             bIsReal = true;
    2833      298851 :             if (!bFoundDot && !bIsLastCharExponent)
    2834      298848 :                 bFoundDot = true;
    2835             :             else
    2836           3 :                 return CPL_VALUE_STRING;
    2837      298848 :             bIsLastCharExponent = false;
    2838             :         }
    2839       46382 :         else if (*pszValue == 'D' || *pszValue == 'd' || *pszValue == 'E' ||
    2840       41942 :                  *pszValue == 'e')
    2841             :         {
    2842        4669 :             if (!bFoundMantissa)
    2843        4179 :                 return CPL_VALUE_STRING;
    2844         490 :             if (!(pszValue[1] == '+' || pszValue[1] == '-' ||
    2845           9 :                   isdigit(static_cast<unsigned char>(pszValue[1]))))
    2846           2 :                 return CPL_VALUE_STRING;
    2847             : 
    2848         488 :             bIsReal = true;
    2849         488 :             if (!bFoundExponent)
    2850         487 :                 bFoundExponent = true;
    2851             :             else
    2852           1 :                 return CPL_VALUE_STRING;
    2853         487 :             pszAfterExponent = pszValue + 1;
    2854         487 :             bIsLastCharExponent = true;
    2855             :         }
    2856             :         else
    2857             :         {
    2858       41713 :             return CPL_VALUE_STRING;
    2859             :         }
    2860             :     }
    2861             : 
    2862      399026 :     if (bIsReal && pszAfterExponent && strlen(pszAfterExponent) > 3)
    2863             :     {
    2864             :         // cppcheck-suppress unreadVariable
    2865          15 :         const double dfVal = CPLAtof(pszValueInit);
    2866          15 :         if (CPLIsInf(dfVal))
    2867           1 :             return CPL_VALUE_STRING;
    2868             :     }
    2869             : 
    2870      399025 :     return bIsReal ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
    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     4530830 : size_t CPLStrlcpy(char *pszDest, const char *pszSrc, size_t nDestSize)
    2905             : {
    2906     4530830 :     if (nDestSize == 0)
    2907           0 :         return strlen(pszSrc);
    2908             : 
    2909     4530830 :     char *pszDestIter = pszDest;
    2910     4530830 :     const char *pszSrcIter = pszSrc;
    2911             : 
    2912     4530830 :     --nDestSize;
    2913    44495000 :     while (nDestSize != 0 && *pszSrcIter != '\0')
    2914             :     {
    2915    39964200 :         *pszDestIter = *pszSrcIter;
    2916    39964200 :         ++pszDestIter;
    2917    39964200 :         ++pszSrcIter;
    2918    39964200 :         --nDestSize;
    2919             :     }
    2920     4530830 :     *pszDestIter = '\0';
    2921     4530830 :     return pszSrcIter - pszSrc + strlen(pszSrcIter);
    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     1721090 : size_t CPLStrlcat(char *pszDest, const char *pszSrc, size_t nDestSize)
    2962             : {
    2963     1721090 :     char *pszDestIter = pszDest;
    2964             : 
    2965    72982500 :     while (nDestSize != 0 && *pszDestIter != '\0')
    2966             :     {
    2967    71261400 :         ++pszDestIter;
    2968    71261400 :         --nDestSize;
    2969             :     }
    2970             : 
    2971     1721090 :     return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
    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      399068 : size_t CPLStrnlen(const char *pszStr, size_t nMaxLen)
    2997             : {
    2998      399068 :     size_t nLen = 0;
    2999    16634000 :     while (nLen < nMaxLen && *pszStr != '\0')
    3000             :     {
    3001    16234900 :         ++nLen;
    3002    16234900 :         ++pszStr;
    3003             :     }
    3004      399068 :     return nLen;
    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         791 : char **CSLParseCommandLine(const char *pszCommandLine)
    3021             : {
    3022         791 :     return CSLTokenizeString(pszCommandLine);
    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    20820700 : int CPLToupper(int c)
    3036             : {
    3037    20820700 :     return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c;
    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    17068800 : int CPLTolower(int c)
    3051             : {
    3052    17068800 :     return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c;
    3053             : }

Generated by: LCOV version 1.14