LCOV - code coverage report
Current view: top level - port - cpl_conv.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 684 912 75.0 %
Date: 2024-04-29 01:40:10 Functions: 63 73 86.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CPL - Common Portability Library
       4             :  * Purpose:  Convenience functions.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, Frank Warmerdam
       9             :  * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "cpl_config.h"
      31             : 
      32             : #ifdef HAVE_USELOCALE
      33             : // For uselocale, define _XOPEN_SOURCE = 700
      34             : // but on Solaris, we don't have uselocale and we cannot have
      35             : // std=c++11 with _XOPEN_SOURCE != 600
      36             : #if defined(__sun__) && __cplusplus >= 201103L
      37             : #if _XOPEN_SOURCE != 600
      38             : #ifdef _XOPEN_SOURCE
      39             : #undef _XOPEN_SOURCE
      40             : #endif
      41             : #define _XOPEN_SOURCE 600
      42             : #endif
      43             : #else
      44             : #ifdef _XOPEN_SOURCE
      45             : #undef _XOPEN_SOURCE
      46             : #endif
      47             : #define _XOPEN_SOURCE 700
      48             : #endif
      49             : #endif
      50             : 
      51             : // For atoll (at least for NetBSD)
      52             : #ifndef _ISOC99_SOURCE
      53             : #define _ISOC99_SOURCE
      54             : #endif
      55             : 
      56             : #ifdef MSVC_USE_VLD
      57             : #include <vld.h>
      58             : #endif
      59             : 
      60             : #include "cpl_conv.h"
      61             : 
      62             : #include <algorithm>
      63             : #include <cctype>
      64             : #include <cerrno>
      65             : #include <climits>
      66             : #include <clocale>
      67             : #include <cmath>
      68             : #include <cstdlib>
      69             : #include <cstring>
      70             : #include <ctime>
      71             : #if HAVE_FCNTL_H
      72             : #include <fcntl.h>
      73             : #endif
      74             : #if HAVE_UNISTD_H
      75             : #include <unistd.h>
      76             : #endif
      77             : #if HAVE_XLOCALE_H
      78             : #include <xlocale.h>  // for LC_NUMERIC_MASK on MacOS
      79             : #endif
      80             : 
      81             : #ifdef DEBUG_CONFIG_OPTIONS
      82             : #include <set>
      83             : #endif
      84             : #include <string>
      85             : 
      86             : #if __cplusplus >= 202002L
      87             : #include <type_traits>  // For std::endian
      88             : #endif
      89             : 
      90             : #include "cpl_config.h"
      91             : #include "cpl_multiproc.h"
      92             : #include "cpl_string.h"
      93             : #include "cpl_vsi.h"
      94             : #include "cpl_vsil_curl_priv.h"
      95             : 
      96             : #ifdef DEBUG
      97             : #define OGRAPISPY_ENABLED
      98             : #endif
      99             : #ifdef OGRAPISPY_ENABLED
     100             : // Keep in sync with ograpispy.cpp
     101             : void OGRAPISPYCPLSetConfigOption(const char *, const char *);
     102             : void OGRAPISPYCPLSetThreadLocalConfigOption(const char *, const char *);
     103             : #endif
     104             : 
     105             : // Uncomment to get list of options that have been fetched and set.
     106             : // #define DEBUG_CONFIG_OPTIONS
     107             : 
     108             : static CPLMutex *hConfigMutex = nullptr;
     109             : static volatile char **g_papszConfigOptions = nullptr;
     110             : static bool gbIgnoreEnvVariables =
     111             :     false;  // if true, only take into account configuration options set through
     112             :             // configuration file or
     113             :             // CPLSetConfigOption()/CPLSetThreadLocalConfigOption()
     114             : 
     115             : static std::vector<std::pair<CPLSetConfigOptionSubscriber, void *>>
     116             :     gSetConfigOptionSubscribers{};
     117             : 
     118             : // Used by CPLOpenShared() and friends.
     119             : static CPLMutex *hSharedFileMutex = nullptr;
     120             : static int nSharedFileCount = 0;
     121             : static CPLSharedFileInfo *pasSharedFileList = nullptr;
     122             : 
     123             : // Used by CPLsetlocale().
     124             : static CPLMutex *hSetLocaleMutex = nullptr;
     125             : 
     126             : // Note: ideally this should be added in CPLSharedFileInfo*
     127             : // but CPLSharedFileInfo is exposed in the API, hence that trick
     128             : // to hide this detail.
     129             : typedef struct
     130             : {
     131             :     GIntBig nPID;  // pid of opening thread.
     132             : } CPLSharedFileInfoExtra;
     133             : 
     134             : static volatile CPLSharedFileInfoExtra *pasSharedFileListExtra = nullptr;
     135             : 
     136             : /************************************************************************/
     137             : /*                             CPLCalloc()                              */
     138             : /************************************************************************/
     139             : 
     140             : /**
     141             :  * Safe version of calloc().
     142             :  *
     143             :  * This function is like the C library calloc(), but raises a CE_Fatal
     144             :  * error with CPLError() if it fails to allocate the desired memory.  It
     145             :  * should be used for small memory allocations that are unlikely to fail
     146             :  * and for which the application is unwilling to test for out of memory
     147             :  * conditions.  It uses VSICalloc() to get the memory, so any hooking of
     148             :  * VSICalloc() will apply to CPLCalloc() as well.  CPLFree() or VSIFree()
     149             :  * can be used free memory allocated by CPLCalloc().
     150             :  *
     151             :  * @param nCount number of objects to allocate.
     152             :  * @param nSize size (in bytes) of object to allocate.
     153             :  * @return pointer to newly allocated memory, only NULL if nSize * nCount is
     154             :  * NULL.
     155             :  */
     156             : 
     157     2821830 : void *CPLCalloc(size_t nCount, size_t nSize)
     158             : 
     159             : {
     160     2821830 :     if (nSize * nCount == 0)
     161       10079 :         return nullptr;
     162             : 
     163     2811750 :     void *pReturn = CPLMalloc(nCount * nSize);
     164     2811740 :     memset(pReturn, 0, nCount * nSize);
     165     2811740 :     return pReturn;
     166             : }
     167             : 
     168             : /************************************************************************/
     169             : /*                             CPLMalloc()                              */
     170             : /************************************************************************/
     171             : 
     172             : /**
     173             :  * Safe version of malloc().
     174             :  *
     175             :  * This function is like the C library malloc(), but raises a CE_Fatal
     176             :  * error with CPLError() if it fails to allocate the desired memory.  It
     177             :  * should be used for small memory allocations that are unlikely to fail
     178             :  * and for which the application is unwilling to test for out of memory
     179             :  * conditions.  It uses VSIMalloc() to get the memory, so any hooking of
     180             :  * VSIMalloc() will apply to CPLMalloc() as well.  CPLFree() or VSIFree()
     181             :  * can be used free memory allocated by CPLMalloc().
     182             :  *
     183             :  * @param nSize size (in bytes) of memory block to allocate.
     184             :  * @return pointer to newly allocated memory, only NULL if nSize is zero.
     185             :  */
     186             : 
     187    15643200 : void *CPLMalloc(size_t nSize)
     188             : 
     189             : {
     190    15643200 :     if (nSize == 0)
     191        5597 :         return nullptr;
     192             : 
     193    15637600 :     if ((nSize >> (8 * sizeof(nSize) - 1)) != 0)
     194             :     {
     195             :         // coverity[dead_error_begin]
     196           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     197             :                  "CPLMalloc(%ld): Silly size requested.",
     198             :                  static_cast<long>(nSize));
     199           0 :         return nullptr;
     200             :     }
     201             : 
     202    15637600 :     void *pReturn = VSIMalloc(nSize);
     203    15637500 :     if (pReturn == nullptr)
     204             :     {
     205           0 :         if (nSize < 2000)
     206             :         {
     207           0 :             CPLEmergencyError("CPLMalloc(): Out of memory allocating a small "
     208             :                               "number of bytes.");
     209             :         }
     210             : 
     211           0 :         CPLError(CE_Fatal, CPLE_OutOfMemory,
     212             :                  "CPLMalloc(): Out of memory allocating %ld bytes.",
     213             :                  static_cast<long>(nSize));
     214             :     }
     215             : 
     216    15637500 :     return pReturn;
     217             : }
     218             : 
     219             : /************************************************************************/
     220             : /*                             CPLRealloc()                             */
     221             : /************************************************************************/
     222             : 
     223             : /**
     224             :  * Safe version of realloc().
     225             :  *
     226             :  * This function is like the C library realloc(), but raises a CE_Fatal
     227             :  * error with CPLError() if it fails to allocate the desired memory.  It
     228             :  * should be used for small memory allocations that are unlikely to fail
     229             :  * and for which the application is unwilling to test for out of memory
     230             :  * conditions.  It uses VSIRealloc() to get the memory, so any hooking of
     231             :  * VSIRealloc() will apply to CPLRealloc() as well.  CPLFree() or VSIFree()
     232             :  * can be used free memory allocated by CPLRealloc().
     233             :  *
     234             :  * It is also safe to pass NULL in as the existing memory block for
     235             :  * CPLRealloc(), in which case it uses VSIMalloc() to allocate a new block.
     236             :  *
     237             :  * @param pData existing memory block which should be copied to the new block.
     238             :  * @param nNewSize new size (in bytes) of memory block to allocate.
     239             :  * @return pointer to allocated memory, only NULL if nNewSize is zero.
     240             :  */
     241             : 
     242     1669620 : void *CPLRealloc(void *pData, size_t nNewSize)
     243             : 
     244             : {
     245     1669620 :     if (nNewSize == 0)
     246             :     {
     247          45 :         VSIFree(pData);
     248          45 :         return nullptr;
     249             :     }
     250             : 
     251     1669580 :     if ((nNewSize >> (8 * sizeof(nNewSize) - 1)) != 0)
     252             :     {
     253             :         // coverity[dead_error_begin]
     254           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     255             :                  "CPLRealloc(%ld): Silly size requested.",
     256             :                  static_cast<long>(nNewSize));
     257           0 :         return nullptr;
     258             :     }
     259             : 
     260     1669580 :     void *pReturn = nullptr;
     261             : 
     262     1669580 :     if (pData == nullptr)
     263      773432 :         pReturn = VSIMalloc(nNewSize);
     264             :     else
     265      896147 :         pReturn = VSIRealloc(pData, nNewSize);
     266             : 
     267     1669580 :     if (pReturn == nullptr)
     268             :     {
     269           0 :         if (nNewSize < 2000)
     270             :         {
     271           0 :             char szSmallMsg[80] = {};
     272             : 
     273           0 :             snprintf(szSmallMsg, sizeof(szSmallMsg),
     274             :                      "CPLRealloc(): Out of memory allocating %ld bytes.",
     275             :                      static_cast<long>(nNewSize));
     276           0 :             CPLEmergencyError(szSmallMsg);
     277             :         }
     278             :         else
     279             :         {
     280           0 :             CPLError(CE_Fatal, CPLE_OutOfMemory,
     281             :                      "CPLRealloc(): Out of memory allocating %ld bytes.",
     282             :                      static_cast<long>(nNewSize));
     283             :         }
     284             :     }
     285             : 
     286     1669570 :     return pReturn;
     287             : }
     288             : 
     289             : /************************************************************************/
     290             : /*                             CPLStrdup()                              */
     291             : /************************************************************************/
     292             : 
     293             : /**
     294             :  * Safe version of strdup() function.
     295             :  *
     296             :  * This function is similar to the C library strdup() function, but if
     297             :  * the memory allocation fails it will issue a CE_Fatal error with
     298             :  * CPLError() instead of returning NULL. Memory
     299             :  * allocated with CPLStrdup() can be freed with CPLFree() or VSIFree().
     300             :  *
     301             :  * It is also safe to pass a NULL string into CPLStrdup().  CPLStrdup()
     302             :  * will allocate and return a zero length string (as opposed to a NULL
     303             :  * string).
     304             :  *
     305             :  * @param pszString input string to be duplicated.  May be NULL.
     306             :  * @return pointer to a newly allocated copy of the string.  Free with
     307             :  * CPLFree() or VSIFree().
     308             :  */
     309             : 
     310     6522200 : char *CPLStrdup(const char *pszString)
     311             : 
     312             : {
     313     6522200 :     if (pszString == nullptr)
     314      899392 :         pszString = "";
     315             : 
     316     6522200 :     const size_t nLen = strlen(pszString);
     317     6522200 :     char *pszReturn = static_cast<char *>(CPLMalloc(nLen + 1));
     318     6522190 :     memcpy(pszReturn, pszString, nLen + 1);
     319     6522190 :     return (pszReturn);
     320             : }
     321             : 
     322             : /************************************************************************/
     323             : /*                             CPLStrlwr()                              */
     324             : /************************************************************************/
     325             : 
     326             : /**
     327             :  * Convert each characters of the string to lower case.
     328             :  *
     329             :  * For example, "ABcdE" will be converted to "abcde".
     330             :  * Starting with GDAL 3.9, this function is no longer locale dependent.
     331             :  *
     332             :  * @param pszString input string to be converted.
     333             :  * @return pointer to the same string, pszString.
     334             :  */
     335             : 
     336          29 : char *CPLStrlwr(char *pszString)
     337             : 
     338             : {
     339          29 :     if (pszString == nullptr)
     340           0 :         return nullptr;
     341             : 
     342          29 :     char *pszTemp = pszString;
     343             : 
     344         128 :     while (*pszTemp)
     345             :     {
     346          99 :         *pszTemp =
     347          99 :             static_cast<char>(CPLTolower(static_cast<unsigned char>(*pszTemp)));
     348          99 :         pszTemp++;
     349             :     }
     350             : 
     351          29 :     return pszString;
     352             : }
     353             : 
     354             : /************************************************************************/
     355             : /*                              CPLFGets()                              */
     356             : /*                                                                      */
     357             : /*      Note: LF = \n = ASCII 10                                        */
     358             : /*            CR = \r = ASCII 13                                        */
     359             : /************************************************************************/
     360             : 
     361             : // ASCII characters.
     362             : constexpr char knLF = 10;
     363             : constexpr char knCR = 13;
     364             : 
     365             : /**
     366             :  * Reads in at most one less than nBufferSize characters from the fp
     367             :  * stream and stores them into the buffer pointed to by pszBuffer.
     368             :  * Reading stops after an EOF or a newline. If a newline is read, it
     369             :  * is _not_ stored into the buffer. A '\\0' is stored after the last
     370             :  * character in the buffer. All three types of newline terminators
     371             :  * recognized by the CPLFGets(): single '\\r' and '\\n' and '\\r\\n'
     372             :  * combination.
     373             :  *
     374             :  * @param pszBuffer pointer to the targeting character buffer.
     375             :  * @param nBufferSize maximum size of the string to read (not including
     376             :  * terminating '\\0').
     377             :  * @param fp file pointer to read from.
     378             :  * @return pointer to the pszBuffer containing a string read
     379             :  * from the file or NULL if the error or end of file was encountered.
     380             :  */
     381             : 
     382           0 : char *CPLFGets(char *pszBuffer, int nBufferSize, FILE *fp)
     383             : 
     384             : {
     385           0 :     if (nBufferSize == 0 || pszBuffer == nullptr || fp == nullptr)
     386           0 :         return nullptr;
     387             : 
     388             :     /* -------------------------------------------------------------------- */
     389             :     /*      Let the OS level call read what it things is one line.  This    */
     390             :     /*      will include the newline.  On windows, if the file happens      */
     391             :     /*      to be in text mode, the CRLF will have been converted to        */
     392             :     /*      just the newline (LF).  If it is in binary mode it may well     */
     393             :     /*      have both.                                                      */
     394             :     /* -------------------------------------------------------------------- */
     395           0 :     const long nOriginalOffset = VSIFTell(fp);
     396           0 :     if (VSIFGets(pszBuffer, nBufferSize, fp) == nullptr)
     397           0 :         return nullptr;
     398             : 
     399           0 :     int nActuallyRead = static_cast<int>(strlen(pszBuffer));
     400           0 :     if (nActuallyRead == 0)
     401           0 :         return nullptr;
     402             : 
     403             :     /* -------------------------------------------------------------------- */
     404             :     /*      If we found \r and out buffer is full, it is possible there     */
     405             :     /*      is also a pending \n.  Check for it.                            */
     406             :     /* -------------------------------------------------------------------- */
     407           0 :     if (nBufferSize == nActuallyRead + 1 &&
     408           0 :         pszBuffer[nActuallyRead - 1] == knCR)
     409             :     {
     410           0 :         const int chCheck = fgetc(fp);
     411           0 :         if (chCheck != knLF)
     412             :         {
     413             :             // unget the character.
     414           0 :             if (VSIFSeek(fp, nOriginalOffset + nActuallyRead, SEEK_SET) == -1)
     415             :             {
     416           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     417             :                          "Unable to unget a character");
     418             :             }
     419             :         }
     420             :     }
     421             : 
     422             :     /* -------------------------------------------------------------------- */
     423             :     /*      Trim off \n, \r or \r\n if it appears at the end.  We don't     */
     424             :     /*      need to do any "seeking" since we want the newline eaten.       */
     425             :     /* -------------------------------------------------------------------- */
     426           0 :     if (nActuallyRead > 1 && pszBuffer[nActuallyRead - 1] == knLF &&
     427           0 :         pszBuffer[nActuallyRead - 2] == knCR)
     428             :     {
     429           0 :         pszBuffer[nActuallyRead - 2] = '\0';
     430             :     }
     431           0 :     else if (pszBuffer[nActuallyRead - 1] == knLF ||
     432           0 :              pszBuffer[nActuallyRead - 1] == knCR)
     433             :     {
     434           0 :         pszBuffer[nActuallyRead - 1] = '\0';
     435             :     }
     436             : 
     437             :     /* -------------------------------------------------------------------- */
     438             :     /*      Search within the string for a \r (MacOS convention             */
     439             :     /*      apparently), and if we find it we need to trim the string,      */
     440             :     /*      and seek back.                                                  */
     441             :     /* -------------------------------------------------------------------- */
     442           0 :     char *pszExtraNewline = strchr(pszBuffer, knCR);
     443             : 
     444           0 :     if (pszExtraNewline != nullptr)
     445             :     {
     446           0 :         nActuallyRead = static_cast<int>(pszExtraNewline - pszBuffer + 1);
     447             : 
     448           0 :         *pszExtraNewline = '\0';
     449           0 :         if (VSIFSeek(fp, nOriginalOffset + nActuallyRead - 1, SEEK_SET) != 0)
     450           0 :             return nullptr;
     451             : 
     452             :         // This hackery is necessary to try and find our correct
     453             :         // spot on win32 systems with text mode line translation going
     454             :         // on.  Sometimes the fseek back overshoots, but it doesn't
     455             :         // "realize it" till a character has been read. Try to read till
     456             :         // we get to the right spot and get our CR.
     457           0 :         int chCheck = fgetc(fp);
     458           0 :         while ((chCheck != knCR && chCheck != EOF) ||
     459           0 :                VSIFTell(fp) < nOriginalOffset + nActuallyRead)
     460             :         {
     461             :             static bool bWarned = false;
     462             : 
     463           0 :             if (!bWarned)
     464             :             {
     465           0 :                 bWarned = true;
     466           0 :                 CPLDebug("CPL",
     467             :                          "CPLFGets() correcting for DOS text mode translation "
     468             :                          "seek problem.");
     469             :             }
     470           0 :             chCheck = fgetc(fp);
     471             :         }
     472             :     }
     473             : 
     474           0 :     return pszBuffer;
     475             : }
     476             : 
     477             : /************************************************************************/
     478             : /*                         CPLReadLineBuffer()                          */
     479             : /*                                                                      */
     480             : /*      Fetch readline buffer, and ensure it is the desired size,       */
     481             : /*      reallocating if needed.  Manages TLS (thread local storage)     */
     482             : /*      issues for the buffer.                                          */
     483             : /*      We use a special trick to track the actual size of the buffer   */
     484             : /*      The first 4 bytes are reserved to store it as a int, hence the  */
     485             : /*      -4 / +4 hacks with the size and pointer.                        */
     486             : /************************************************************************/
     487     2230810 : static char *CPLReadLineBuffer(int nRequiredSize)
     488             : 
     489             : {
     490             : 
     491             :     /* -------------------------------------------------------------------- */
     492             :     /*      A required size of -1 means the buffer should be freed.         */
     493             :     /* -------------------------------------------------------------------- */
     494     2230810 :     if (nRequiredSize == -1)
     495             :     {
     496        2252 :         int bMemoryError = FALSE;
     497        2252 :         void *pRet = CPLGetTLSEx(CTLS_RLBUFFERINFO, &bMemoryError);
     498        2252 :         if (pRet != nullptr)
     499             :         {
     500        2007 :             CPLFree(pRet);
     501        2007 :             CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
     502             :         }
     503        2252 :         return nullptr;
     504             :     }
     505             : 
     506             :     /* -------------------------------------------------------------------- */
     507             :     /*      If the buffer doesn't exist yet, create it.                     */
     508             :     /* -------------------------------------------------------------------- */
     509     2228550 :     int bMemoryError = FALSE;
     510             :     GUInt32 *pnAlloc =
     511     2228550 :         static_cast<GUInt32 *>(CPLGetTLSEx(CTLS_RLBUFFERINFO, &bMemoryError));
     512     2228550 :     if (bMemoryError)
     513           0 :         return nullptr;
     514             : 
     515     2228550 :     if (pnAlloc == nullptr)
     516             :     {
     517        3098 :         pnAlloc = static_cast<GUInt32 *>(VSI_MALLOC_VERBOSE(200));
     518        3098 :         if (pnAlloc == nullptr)
     519           0 :             return nullptr;
     520        3098 :         *pnAlloc = 196;
     521        3098 :         CPLSetTLS(CTLS_RLBUFFERINFO, pnAlloc, TRUE);
     522             :     }
     523             : 
     524             :     /* -------------------------------------------------------------------- */
     525             :     /*      If it is too small, grow it bigger.                             */
     526             :     /* -------------------------------------------------------------------- */
     527     2228550 :     if (static_cast<int>(*pnAlloc) - 1 < nRequiredSize)
     528             :     {
     529         617 :         const int nNewSize = nRequiredSize + 4 + 500;
     530         617 :         if (nNewSize <= 0)
     531             :         {
     532           0 :             VSIFree(pnAlloc);
     533           0 :             CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
     534           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     535             :                      "CPLReadLineBuffer(): Trying to allocate more than "
     536             :                      "2 GB.");
     537           0 :             return nullptr;
     538             :         }
     539             : 
     540             :         GUInt32 *pnAllocNew =
     541         617 :             static_cast<GUInt32 *>(VSI_REALLOC_VERBOSE(pnAlloc, nNewSize));
     542         617 :         if (pnAllocNew == nullptr)
     543             :         {
     544           0 :             VSIFree(pnAlloc);
     545           0 :             CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
     546           0 :             return nullptr;
     547             :         }
     548         617 :         pnAlloc = pnAllocNew;
     549             : 
     550         617 :         *pnAlloc = nNewSize - 4;
     551         617 :         CPLSetTLS(CTLS_RLBUFFERINFO, pnAlloc, TRUE);
     552             :     }
     553             : 
     554     2228550 :     return reinterpret_cast<char *>(pnAlloc + 1);
     555             : }
     556             : 
     557             : /************************************************************************/
     558             : /*                            CPLReadLine()                             */
     559             : /************************************************************************/
     560             : 
     561             : /**
     562             :  * Simplified line reading from text file.
     563             :  *
     564             :  * Read a line of text from the given file handle, taking care
     565             :  * to capture CR and/or LF and strip off ... equivalent of
     566             :  * DKReadLine().  Pointer to an internal buffer is returned.
     567             :  * The application shouldn't free it, or depend on its value
     568             :  * past the next call to CPLReadLine().
     569             :  *
     570             :  * Note that CPLReadLine() uses VSIFGets(), so any hooking of VSI file
     571             :  * services should apply to CPLReadLine() as well.
     572             :  *
     573             :  * CPLReadLine() maintains an internal buffer, which will appear as a
     574             :  * single block memory leak in some circumstances.  CPLReadLine() may
     575             :  * be called with a NULL FILE * at any time to free this working buffer.
     576             :  *
     577             :  * @param fp file pointer opened with VSIFOpen().
     578             :  *
     579             :  * @return pointer to an internal buffer containing a line of text read
     580             :  * from the file or NULL if the end of file was encountered.
     581             :  */
     582             : 
     583           6 : const char *CPLReadLine(FILE *fp)
     584             : 
     585             : {
     586             :     /* -------------------------------------------------------------------- */
     587             :     /*      Cleanup case.                                                   */
     588             :     /* -------------------------------------------------------------------- */
     589           6 :     if (fp == nullptr)
     590             :     {
     591           6 :         CPLReadLineBuffer(-1);
     592           6 :         return nullptr;
     593             :     }
     594             : 
     595             :     /* -------------------------------------------------------------------- */
     596             :     /*      Loop reading chunks of the line till we get to the end of       */
     597             :     /*      the line.                                                       */
     598             :     /* -------------------------------------------------------------------- */
     599           0 :     size_t nBytesReadThisTime = 0;
     600           0 :     char *pszRLBuffer = nullptr;
     601           0 :     size_t nReadSoFar = 0;
     602             : 
     603           0 :     do
     604             :     {
     605             :         /* --------------------------------------------------------------------
     606             :          */
     607             :         /*      Grow the working buffer if we have it nearly full.  Fail out */
     608             :         /*      of read line if we can't reallocate it big enough (for */
     609             :         /*      instance for a _very large_ file with no newlines). */
     610             :         /* --------------------------------------------------------------------
     611             :          */
     612           0 :         if (nReadSoFar > 100 * 1024 * 1024)
     613             :             // It is dubious that we need to read a line longer than 100 MB.
     614           0 :             return nullptr;
     615           0 :         pszRLBuffer = CPLReadLineBuffer(static_cast<int>(nReadSoFar) + 129);
     616           0 :         if (pszRLBuffer == nullptr)
     617           0 :             return nullptr;
     618             : 
     619             :         /* --------------------------------------------------------------------
     620             :          */
     621             :         /*      Do the actual read. */
     622             :         /* --------------------------------------------------------------------
     623             :          */
     624           0 :         if (CPLFGets(pszRLBuffer + nReadSoFar, 128, fp) == nullptr &&
     625             :             nReadSoFar == 0)
     626           0 :             return nullptr;
     627             : 
     628           0 :         nBytesReadThisTime = strlen(pszRLBuffer + nReadSoFar);
     629           0 :         nReadSoFar += nBytesReadThisTime;
     630           0 :     } while (nBytesReadThisTime >= 127 && pszRLBuffer[nReadSoFar - 1] != knCR &&
     631           0 :              pszRLBuffer[nReadSoFar - 1] != knLF);
     632             : 
     633           0 :     return pszRLBuffer;
     634             : }
     635             : 
     636             : /************************************************************************/
     637             : /*                            CPLReadLineL()                            */
     638             : /************************************************************************/
     639             : 
     640             : /**
     641             :  * Simplified line reading from text file.
     642             :  *
     643             :  * Similar to CPLReadLine(), but reading from a large file API handle.
     644             :  *
     645             :  * @param fp file pointer opened with VSIFOpenL().
     646             :  *
     647             :  * @return pointer to an internal buffer containing a line of text read
     648             :  * from the file or NULL if the end of file was encountered.
     649             :  */
     650             : 
     651      192362 : const char *CPLReadLineL(VSILFILE *fp)
     652             : {
     653      192362 :     return CPLReadLine2L(fp, -1, nullptr);
     654             : }
     655             : 
     656             : /************************************************************************/
     657             : /*                           CPLReadLine2L()                            */
     658             : /************************************************************************/
     659             : 
     660             : /**
     661             :  * Simplified line reading from text file.
     662             :  *
     663             :  * Similar to CPLReadLine(), but reading from a large file API handle.
     664             :  *
     665             :  * @param fp file pointer opened with VSIFOpenL().
     666             :  * @param nMaxCars  maximum number of characters allowed, or -1 for no limit.
     667             :  * @param papszOptions NULL-terminated array of options. Unused for now.
     668             : 
     669             :  * @return pointer to an internal buffer containing a line of text read
     670             :  * from the file or NULL if the end of file was encountered or the maximum
     671             :  * number of characters allowed reached.
     672             :  *
     673             :  * @since GDAL 1.7.0
     674             :  */
     675             : 
     676     1159830 : const char *CPLReadLine2L(VSILFILE *fp, int nMaxCars,
     677             :                           CPL_UNUSED CSLConstList papszOptions)
     678             : 
     679             : {
     680             :     int nBufLength;
     681     2319660 :     return CPLReadLine3L(fp, nMaxCars, &nBufLength, papszOptions);
     682             : }
     683             : 
     684             : /************************************************************************/
     685             : /*                           CPLReadLine3L()                            */
     686             : /************************************************************************/
     687             : 
     688             : /**
     689             :  * Simplified line reading from text file.
     690             :  *
     691             :  * Similar to CPLReadLine(), but reading from a large file API handle.
     692             :  *
     693             :  * @param fp file pointer opened with VSIFOpenL().
     694             :  * @param nMaxCars  maximum number of characters allowed, or -1 for no limit.
     695             :  * @param papszOptions NULL-terminated array of options. Unused for now.
     696             :  * @param[out] pnBufLength size of output string (must be non-NULL)
     697             : 
     698             :  * @return pointer to an internal buffer containing a line of text read
     699             :  * from the file or NULL if the end of file was encountered or the maximum
     700             :  * number of characters allowed reached.
     701             :  *
     702             :  * @since GDAL 2.3.0
     703             :  */
     704     1221830 : const char *CPLReadLine3L(VSILFILE *fp, int nMaxCars, int *pnBufLength,
     705             :                           CPL_UNUSED CSLConstList papszOptions)
     706             : {
     707             :     /* -------------------------------------------------------------------- */
     708             :     /*      Cleanup case.                                                   */
     709             :     /* -------------------------------------------------------------------- */
     710     1221830 :     if (fp == nullptr)
     711             :     {
     712        2246 :         CPLReadLineBuffer(-1);
     713        2246 :         return nullptr;
     714             :     }
     715             : 
     716             :     /* -------------------------------------------------------------------- */
     717             :     /*      Loop reading chunks of the line till we get to the end of       */
     718             :     /*      the line.                                                       */
     719             :     /* -------------------------------------------------------------------- */
     720     1219580 :     char *pszRLBuffer = nullptr;
     721     1219580 :     const size_t nChunkSize = 40;
     722     1219580 :     char szChunk[nChunkSize] = {};
     723     1219580 :     size_t nChunkBytesRead = 0;
     724     1219580 :     size_t nChunkBytesConsumed = 0;
     725             : 
     726     1219580 :     *pnBufLength = 0;
     727     1219580 :     szChunk[0] = 0;
     728             : 
     729             :     while (true)
     730             :     {
     731             :         /* --------------------------------------------------------------------
     732             :          */
     733             :         /*      Read a chunk from the input file. */
     734             :         /* --------------------------------------------------------------------
     735             :          */
     736     2228550 :         if (*pnBufLength > INT_MAX - static_cast<int>(nChunkSize) - 1)
     737             :         {
     738           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     739             :                      "Too big line : more than 2 billion characters!.");
     740           0 :             CPLReadLineBuffer(-1);
     741           0 :             return nullptr;
     742             :         }
     743             : 
     744             :         pszRLBuffer =
     745     2228550 :             CPLReadLineBuffer(static_cast<int>(*pnBufLength + nChunkSize + 1));
     746     2228550 :         if (pszRLBuffer == nullptr)
     747           0 :             return nullptr;
     748             : 
     749     2228550 :         if (nChunkBytesRead == nChunkBytesConsumed + 1)
     750             :         {
     751             : 
     752             :             // case where one character is left over from last read.
     753     1008970 :             szChunk[0] = szChunk[nChunkBytesConsumed];
     754             : 
     755     1008970 :             nChunkBytesConsumed = 0;
     756     1008970 :             nChunkBytesRead = VSIFReadL(szChunk + 1, 1, nChunkSize - 1, fp) + 1;
     757             :         }
     758             :         else
     759             :         {
     760     1219580 :             nChunkBytesConsumed = 0;
     761             : 
     762             :             // fresh read.
     763     1219580 :             nChunkBytesRead = VSIFReadL(szChunk, 1, nChunkSize, fp);
     764     1219580 :             if (nChunkBytesRead == 0)
     765             :             {
     766        9198 :                 if (*pnBufLength == 0)
     767        9198 :                     return nullptr;
     768             : 
     769           0 :                 break;
     770             :             }
     771             :         }
     772             : 
     773             :         /* --------------------------------------------------------------------
     774             :          */
     775             :         /*      copy over characters watching for end-of-line. */
     776             :         /* --------------------------------------------------------------------
     777             :          */
     778     2219360 :         bool bBreak = false;
     779    59442100 :         while (nChunkBytesConsumed < nChunkBytesRead - 1 && !bBreak)
     780             :         {
     781    57222800 :             if ((szChunk[nChunkBytesConsumed] == knCR &&
     782      132943 :                  szChunk[nChunkBytesConsumed + 1] == knLF) ||
     783    57090100 :                 (szChunk[nChunkBytesConsumed] == knLF &&
     784     1066370 :                  szChunk[nChunkBytesConsumed + 1] == knCR))
     785             :             {
     786      132666 :                 nChunkBytesConsumed += 2;
     787      132666 :                 bBreak = true;
     788             :             }
     789    57090100 :             else if (szChunk[nChunkBytesConsumed] == knLF ||
     790    56023700 :                      szChunk[nChunkBytesConsumed] == knCR)
     791             :             {
     792     1066640 :                 nChunkBytesConsumed += 1;
     793     1066640 :                 bBreak = true;
     794             :             }
     795             :             else
     796             :             {
     797    56023500 :                 pszRLBuffer[(*pnBufLength)++] = szChunk[nChunkBytesConsumed++];
     798    56023500 :                 if (nMaxCars >= 0 && *pnBufLength == nMaxCars)
     799             :                 {
     800           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     801             :                              "Maximum number of characters allowed reached.");
     802           0 :                     return nullptr;
     803             :                 }
     804             :             }
     805             :         }
     806             : 
     807     2219360 :         if (bBreak)
     808     1199310 :             break;
     809             : 
     810             :         /* --------------------------------------------------------------------
     811             :          */
     812             :         /*      If there is a remaining character and it is not a newline */
     813             :         /*      consume it.  If it is a newline, but we are clearly at the */
     814             :         /*      end of the file then consume it. */
     815             :         /* --------------------------------------------------------------------
     816             :          */
     817     1020050 :         if (nChunkBytesConsumed == nChunkBytesRead - 1 &&
     818             :             nChunkBytesRead < nChunkSize)
     819             :         {
     820       11073 :             if (szChunk[nChunkBytesConsumed] == knLF ||
     821        1596 :                 szChunk[nChunkBytesConsumed] == knCR)
     822             :             {
     823        9477 :                 nChunkBytesConsumed++;
     824        9477 :                 break;
     825             :             }
     826             : 
     827        1596 :             pszRLBuffer[(*pnBufLength)++] = szChunk[nChunkBytesConsumed++];
     828        1596 :             break;
     829             :         }
     830     1008970 :     }
     831             : 
     832             :     /* -------------------------------------------------------------------- */
     833             :     /*      If we have left over bytes after breaking out, seek back to     */
     834             :     /*      ensure they remain to be read next time.                        */
     835             :     /* -------------------------------------------------------------------- */
     836     1210380 :     if (nChunkBytesConsumed < nChunkBytesRead)
     837             :     {
     838     1194600 :         const size_t nBytesToPush = nChunkBytesRead - nChunkBytesConsumed;
     839             : 
     840     1194600 :         if (VSIFSeekL(fp, VSIFTellL(fp) - nBytesToPush, SEEK_SET) != 0)
     841           0 :             return nullptr;
     842             :     }
     843             : 
     844     1210380 :     pszRLBuffer[*pnBufLength] = '\0';
     845             : 
     846     1210380 :     return pszRLBuffer;
     847             : }
     848             : 
     849             : /************************************************************************/
     850             : /*                            CPLScanString()                           */
     851             : /************************************************************************/
     852             : 
     853             : /**
     854             :  * Scan up to a maximum number of characters from a given string,
     855             :  * allocate a buffer for a new string and fill it with scanned characters.
     856             :  *
     857             :  * @param pszString String containing characters to be scanned. It may be
     858             :  * terminated with a null character.
     859             :  *
     860             :  * @param nMaxLength The maximum number of character to read. Less
     861             :  * characters will be read if a null character is encountered.
     862             :  *
     863             :  * @param bTrimSpaces If TRUE, trim ending spaces from the input string.
     864             :  * Character considered as empty using isspace(3) function.
     865             :  *
     866             :  * @param bNormalize If TRUE, replace ':' symbol with the '_'. It is needed if
     867             :  * resulting string will be used in CPL dictionaries.
     868             :  *
     869             :  * @return Pointer to the resulting string buffer. Caller responsible to free
     870             :  * this buffer with CPLFree().
     871             :  */
     872             : 
     873        5010 : char *CPLScanString(const char *pszString, int nMaxLength, int bTrimSpaces,
     874             :                     int bNormalize)
     875             : {
     876        5010 :     if (!pszString)
     877           0 :         return nullptr;
     878             : 
     879        5010 :     if (!nMaxLength)
     880           2 :         return CPLStrdup("");
     881             : 
     882        5008 :     char *pszBuffer = static_cast<char *>(CPLMalloc(nMaxLength + 1));
     883        5008 :     if (!pszBuffer)
     884           0 :         return nullptr;
     885             : 
     886        5008 :     strncpy(pszBuffer, pszString, nMaxLength);
     887        5008 :     pszBuffer[nMaxLength] = '\0';
     888             : 
     889        5008 :     if (bTrimSpaces)
     890             :     {
     891        5005 :         size_t i = strlen(pszBuffer);
     892        6129 :         while (i > 0)
     893             :         {
     894        6095 :             i--;
     895        6095 :             if (!isspace(static_cast<unsigned char>(pszBuffer[i])))
     896        4971 :                 break;
     897        1124 :             pszBuffer[i] = '\0';
     898             :         }
     899             :     }
     900             : 
     901        5008 :     if (bNormalize)
     902             :     {
     903        4887 :         size_t i = strlen(pszBuffer);
     904       37555 :         while (i > 0)
     905             :         {
     906       32668 :             i--;
     907       32668 :             if (pszBuffer[i] == ':')
     908           0 :                 pszBuffer[i] = '_';
     909             :         }
     910             :     }
     911             : 
     912        5008 :     return pszBuffer;
     913             : }
     914             : 
     915             : /************************************************************************/
     916             : /*                             CPLScanLong()                            */
     917             : /************************************************************************/
     918             : 
     919             : /**
     920             :  * Scan up to a maximum number of characters from a string and convert
     921             :  * the result to a long.
     922             :  *
     923             :  * @param pszString String containing characters to be scanned. It may be
     924             :  * terminated with a null character.
     925             :  *
     926             :  * @param nMaxLength The maximum number of character to consider as part
     927             :  * of the number. Less characters will be considered if a null character
     928             :  * is encountered.
     929             :  *
     930             :  * @return Long value, converted from its ASCII form.
     931             :  */
     932             : 
     933         186 : long CPLScanLong(const char *pszString, int nMaxLength)
     934             : {
     935         186 :     CPLAssert(nMaxLength >= 0);
     936         186 :     if (pszString == nullptr)
     937           0 :         return 0;
     938         186 :     const size_t nLength = CPLStrnlen(pszString, nMaxLength);
     939         372 :     const std::string osValue(pszString, nLength);
     940         186 :     return atol(osValue.c_str());
     941             : }
     942             : 
     943             : /************************************************************************/
     944             : /*                            CPLScanULong()                            */
     945             : /************************************************************************/
     946             : 
     947             : /**
     948             :  * Scan up to a maximum number of characters from a string and convert
     949             :  * the result to a unsigned long.
     950             :  *
     951             :  * @param pszString String containing characters to be scanned. It may be
     952             :  * terminated with a null character.
     953             :  *
     954             :  * @param nMaxLength The maximum number of character to consider as part
     955             :  * of the number. Less characters will be considered if a null character
     956             :  * is encountered.
     957             :  *
     958             :  * @return Unsigned long value, converted from its ASCII form.
     959             :  */
     960             : 
     961           0 : unsigned long CPLScanULong(const char *pszString, int nMaxLength)
     962             : {
     963           0 :     CPLAssert(nMaxLength >= 0);
     964           0 :     if (pszString == nullptr)
     965           0 :         return 0;
     966           0 :     const size_t nLength = CPLStrnlen(pszString, nMaxLength);
     967           0 :     const std::string osValue(pszString, nLength);
     968           0 :     return strtoul(osValue.c_str(), nullptr, 10);
     969             : }
     970             : 
     971             : /************************************************************************/
     972             : /*                           CPLScanUIntBig()                           */
     973             : /************************************************************************/
     974             : 
     975             : /**
     976             :  * Extract big integer from string.
     977             :  *
     978             :  * Scan up to a maximum number of characters from a string and convert
     979             :  * the result to a GUIntBig.
     980             :  *
     981             :  * @param pszString String containing characters to be scanned. It may be
     982             :  * terminated with a null character.
     983             :  *
     984             :  * @param nMaxLength The maximum number of character to consider as part
     985             :  * of the number. Less characters will be considered if a null character
     986             :  * is encountered.
     987             :  *
     988             :  * @return GUIntBig value, converted from its ASCII form.
     989             :  */
     990             : 
     991       19276 : GUIntBig CPLScanUIntBig(const char *pszString, int nMaxLength)
     992             : {
     993       19276 :     CPLAssert(nMaxLength >= 0);
     994       19276 :     if (pszString == nullptr)
     995           0 :         return 0;
     996       19276 :     const size_t nLength = CPLStrnlen(pszString, nMaxLength);
     997       38552 :     const std::string osValue(pszString, nLength);
     998             : 
     999             :     /* -------------------------------------------------------------------- */
    1000             :     /*      Fetch out the result                                            */
    1001             :     /* -------------------------------------------------------------------- */
    1002       19276 :     return strtoull(osValue.c_str(), nullptr, 10);
    1003             : }
    1004             : 
    1005             : /************************************************************************/
    1006             : /*                           CPLAtoGIntBig()                            */
    1007             : /************************************************************************/
    1008             : 
    1009             : /**
    1010             :  * Convert a string to a 64 bit signed integer.
    1011             :  *
    1012             :  * @param pszString String containing 64 bit signed integer.
    1013             :  * @return 64 bit signed integer.
    1014             :  * @since GDAL 2.0
    1015             :  */
    1016             : 
    1017       87971 : GIntBig CPLAtoGIntBig(const char *pszString)
    1018             : {
    1019       87971 :     return atoll(pszString);
    1020             : }
    1021             : 
    1022             : #if defined(__MINGW32__) || defined(__sun__)
    1023             : 
    1024             : // mingw atoll() doesn't return ERANGE in case of overflow
    1025             : static int CPLAtoGIntBigExHasOverflow(const char *pszString, GIntBig nVal)
    1026             : {
    1027             :     if (strlen(pszString) <= 18)
    1028             :         return FALSE;
    1029             :     while (*pszString == ' ')
    1030             :         pszString++;
    1031             :     if (*pszString == '+')
    1032             :         pszString++;
    1033             :     char szBuffer[32] = {};
    1034             : /* x86_64-w64-mingw32-g++ (GCC) 4.8.2 annoyingly warns */
    1035             : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
    1036             : #pragma GCC diagnostic push
    1037             : #pragma GCC diagnostic ignored "-Wformat"
    1038             : #endif
    1039             :     snprintf(szBuffer, sizeof(szBuffer), CPL_FRMT_GIB, nVal);
    1040             : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
    1041             : #pragma GCC diagnostic pop
    1042             : #endif
    1043             :     return strcmp(szBuffer, pszString) != 0;
    1044             : }
    1045             : 
    1046             : #endif
    1047             : 
    1048             : /************************************************************************/
    1049             : /*                          CPLAtoGIntBigEx()                           */
    1050             : /************************************************************************/
    1051             : 
    1052             : /**
    1053             :  * Convert a string to a 64 bit signed integer.
    1054             :  *
    1055             :  * @param pszString String containing 64 bit signed integer.
    1056             :  * @param bWarn Issue a warning if an overflow occurs during conversion
    1057             :  * @param pbOverflow Pointer to an integer to store if an overflow occurred, or
    1058             :  *        NULL
    1059             :  * @return 64 bit signed integer.
    1060             :  * @since GDAL 2.0
    1061             :  */
    1062             : 
    1063       99620 : GIntBig CPLAtoGIntBigEx(const char *pszString, int bWarn, int *pbOverflow)
    1064             : {
    1065       99620 :     errno = 0;
    1066       99620 :     GIntBig nVal = strtoll(pszString, nullptr, 10);
    1067       99620 :     if (errno == ERANGE
    1068             : #if defined(__MINGW32__) || defined(__sun__)
    1069             :         || CPLAtoGIntBigExHasOverflow(pszString, nVal)
    1070             : #endif
    1071             :     )
    1072             :     {
    1073           4 :         if (pbOverflow)
    1074           2 :             *pbOverflow = TRUE;
    1075           4 :         if (bWarn)
    1076             :         {
    1077           2 :             CPLError(CE_Warning, CPLE_AppDefined,
    1078             :                      "64 bit integer overflow when converting %s", pszString);
    1079             :         }
    1080           4 :         while (*pszString == ' ')
    1081           0 :             pszString++;
    1082           4 :         return (*pszString == '-') ? GINTBIG_MIN : GINTBIG_MAX;
    1083             :     }
    1084       99616 :     else if (pbOverflow)
    1085             :     {
    1086        3874 :         *pbOverflow = FALSE;
    1087             :     }
    1088       99616 :     return nVal;
    1089             : }
    1090             : 
    1091             : /************************************************************************/
    1092             : /*                           CPLScanPointer()                           */
    1093             : /************************************************************************/
    1094             : 
    1095             : /**
    1096             :  * Extract pointer from string.
    1097             :  *
    1098             :  * Scan up to a maximum number of characters from a string and convert
    1099             :  * the result to a pointer.
    1100             :  *
    1101             :  * @param pszString String containing characters to be scanned. It may be
    1102             :  * terminated with a null character.
    1103             :  *
    1104             :  * @param nMaxLength The maximum number of character to consider as part
    1105             :  * of the number. Less characters will be considered if a null character
    1106             :  * is encountered.
    1107             :  *
    1108             :  * @return pointer value, converted from its ASCII form.
    1109             :  */
    1110             : 
    1111         953 : void *CPLScanPointer(const char *pszString, int nMaxLength)
    1112             : {
    1113         953 :     char szTemp[128] = {};
    1114             : 
    1115             :     /* -------------------------------------------------------------------- */
    1116             :     /*      Compute string into local buffer, and terminate it.             */
    1117             :     /* -------------------------------------------------------------------- */
    1118         953 :     if (nMaxLength > static_cast<int>(sizeof(szTemp)) - 1)
    1119           0 :         nMaxLength = sizeof(szTemp) - 1;
    1120             : 
    1121         953 :     strncpy(szTemp, pszString, nMaxLength);
    1122         953 :     szTemp[nMaxLength] = '\0';
    1123             : 
    1124             :     /* -------------------------------------------------------------------- */
    1125             :     /*      On MSVC we have to scanf pointer values without the 0x          */
    1126             :     /*      prefix.                                                         */
    1127             :     /* -------------------------------------------------------------------- */
    1128         953 :     if (STARTS_WITH_CI(szTemp, "0x"))
    1129             :     {
    1130         925 :         void *pResult = nullptr;
    1131             : 
    1132             : #if defined(__MSVCRT__) || (defined(_WIN32) && defined(_MSC_VER))
    1133             :         // cppcheck-suppress invalidscanf
    1134             :         sscanf(szTemp + 2, "%p", &pResult);
    1135             : #else
    1136             :         // cppcheck-suppress invalidscanf
    1137         925 :         sscanf(szTemp, "%p", &pResult);
    1138             : 
    1139             :         // Solaris actually behaves like MSVCRT.
    1140         925 :         if (pResult == nullptr)
    1141             :         {
    1142             :             // cppcheck-suppress invalidscanf
    1143           0 :             sscanf(szTemp + 2, "%p", &pResult);
    1144             :         }
    1145             : #endif
    1146         925 :         return pResult;
    1147             :     }
    1148             : 
    1149             : #if SIZEOF_VOIDP == 8
    1150          28 :     return reinterpret_cast<void *>(CPLScanUIntBig(szTemp, nMaxLength));
    1151             : #else
    1152             :     return reinterpret_cast<void *>(CPLScanULong(szTemp, nMaxLength));
    1153             : #endif
    1154             : }
    1155             : 
    1156             : /************************************************************************/
    1157             : /*                             CPLScanDouble()                          */
    1158             : /************************************************************************/
    1159             : 
    1160             : /**
    1161             :  * Extract double from string.
    1162             :  *
    1163             :  * Scan up to a maximum number of characters from a string and convert the
    1164             :  * result to a double. This function uses CPLAtof() to convert string to
    1165             :  * double value, so it uses a comma as a decimal delimiter.
    1166             :  *
    1167             :  * @param pszString String containing characters to be scanned. It may be
    1168             :  * terminated with a null character.
    1169             :  *
    1170             :  * @param nMaxLength The maximum number of character to consider as part
    1171             :  * of the number. Less characters will be considered if a null character
    1172             :  * is encountered.
    1173             :  *
    1174             :  * @return Double value, converted from its ASCII form.
    1175             :  */
    1176             : 
    1177         317 : double CPLScanDouble(const char *pszString, int nMaxLength)
    1178             : {
    1179         317 :     char szValue[32] = {};
    1180         317 :     char *pszValue = nullptr;
    1181             : 
    1182         317 :     if (nMaxLength + 1 < static_cast<int>(sizeof(szValue)))
    1183         317 :         pszValue = szValue;
    1184             :     else
    1185           0 :         pszValue = static_cast<char *>(CPLMalloc(nMaxLength + 1));
    1186             : 
    1187             :     /* -------------------------------------------------------------------- */
    1188             :     /*      Compute string into local buffer, and terminate it.             */
    1189             :     /* -------------------------------------------------------------------- */
    1190         317 :     strncpy(pszValue, pszString, nMaxLength);
    1191         317 :     pszValue[nMaxLength] = '\0';
    1192             : 
    1193             :     /* -------------------------------------------------------------------- */
    1194             :     /*      Make a pass through converting 'D's to 'E's.                    */
    1195             :     /* -------------------------------------------------------------------- */
    1196        6436 :     for (int i = 0; i < nMaxLength; i++)
    1197        6119 :         if (pszValue[i] == 'd' || pszValue[i] == 'D')
    1198          45 :             pszValue[i] = 'E';
    1199             : 
    1200             :     /* -------------------------------------------------------------------- */
    1201             :     /*      The conversion itself.                                          */
    1202             :     /* -------------------------------------------------------------------- */
    1203         317 :     const double dfValue = CPLAtof(pszValue);
    1204             : 
    1205         317 :     if (pszValue != szValue)
    1206           0 :         CPLFree(pszValue);
    1207         317 :     return dfValue;
    1208             : }
    1209             : 
    1210             : /************************************************************************/
    1211             : /*                      CPLPrintString()                                */
    1212             : /************************************************************************/
    1213             : 
    1214             : /**
    1215             :  * Copy the string pointed to by pszSrc, NOT including the terminating
    1216             :  * `\\0' character, to the array pointed to by pszDest.
    1217             :  *
    1218             :  * @param pszDest Pointer to the destination string buffer. Should be
    1219             :  * large enough to hold the resulting string.
    1220             :  *
    1221             :  * @param pszSrc Pointer to the source buffer.
    1222             :  *
    1223             :  * @param nMaxLen Maximum length of the resulting string. If string length
    1224             :  * is greater than nMaxLen, it will be truncated.
    1225             :  *
    1226             :  * @return Number of characters printed.
    1227             :  */
    1228             : 
    1229        8324 : int CPLPrintString(char *pszDest, const char *pszSrc, int nMaxLen)
    1230             : {
    1231        8324 :     if (!pszDest)
    1232           0 :         return 0;
    1233             : 
    1234        8324 :     if (!pszSrc)
    1235             :     {
    1236           0 :         *pszDest = '\0';
    1237           0 :         return 1;
    1238             :     }
    1239             : 
    1240        8324 :     int nChars = 0;
    1241        8324 :     char *pszTemp = pszDest;
    1242             : 
    1243      122242 :     while (nChars < nMaxLen && *pszSrc)
    1244             :     {
    1245      113918 :         *pszTemp++ = *pszSrc++;
    1246      113918 :         nChars++;
    1247             :     }
    1248             : 
    1249        8324 :     return nChars;
    1250             : }
    1251             : 
    1252             : /************************************************************************/
    1253             : /*                         CPLPrintStringFill()                         */
    1254             : /************************************************************************/
    1255             : 
    1256             : /**
    1257             :  * Copy the string pointed to by pszSrc, NOT including the terminating
    1258             :  * `\\0' character, to the array pointed to by pszDest. Remainder of the
    1259             :  * destination string will be filled with space characters. This is only
    1260             :  * difference from the PrintString().
    1261             :  *
    1262             :  * @param pszDest Pointer to the destination string buffer. Should be
    1263             :  * large enough to hold the resulting string.
    1264             :  *
    1265             :  * @param pszSrc Pointer to the source buffer.
    1266             :  *
    1267             :  * @param nMaxLen Maximum length of the resulting string. If string length
    1268             :  * is greater than nMaxLen, it will be truncated.
    1269             :  *
    1270             :  * @return Number of characters printed.
    1271             :  */
    1272             : 
    1273         203 : int CPLPrintStringFill(char *pszDest, const char *pszSrc, int nMaxLen)
    1274             : {
    1275         203 :     if (!pszDest)
    1276           0 :         return 0;
    1277             : 
    1278         203 :     if (!pszSrc)
    1279             :     {
    1280           0 :         memset(pszDest, ' ', nMaxLen);
    1281           0 :         return nMaxLen;
    1282             :     }
    1283             : 
    1284         203 :     char *pszTemp = pszDest;
    1285        1219 :     while (nMaxLen && *pszSrc)
    1286             :     {
    1287        1016 :         *pszTemp++ = *pszSrc++;
    1288        1016 :         nMaxLen--;
    1289             :     }
    1290             : 
    1291         203 :     if (nMaxLen)
    1292          69 :         memset(pszTemp, ' ', nMaxLen);
    1293             : 
    1294         203 :     return nMaxLen;
    1295             : }
    1296             : 
    1297             : /************************************************************************/
    1298             : /*                          CPLPrintInt32()                             */
    1299             : /************************************************************************/
    1300             : 
    1301             : /**
    1302             :  * Print GInt32 value into specified string buffer. This string will not
    1303             :  * be NULL-terminated.
    1304             :  *
    1305             :  * @param pszBuffer Pointer to the destination string buffer. Should be
    1306             :  * large enough to hold the resulting string. Note, that the string will
    1307             :  * not be NULL-terminated, so user should do this himself, if needed.
    1308             :  *
    1309             :  * @param iValue Numerical value to print.
    1310             :  *
    1311             :  * @param nMaxLen Maximum length of the resulting string. If string length
    1312             :  * is greater than nMaxLen, it will be truncated.
    1313             :  *
    1314             :  * @return Number of characters printed.
    1315             :  */
    1316             : 
    1317           9 : int CPLPrintInt32(char *pszBuffer, GInt32 iValue, int nMaxLen)
    1318             : {
    1319           9 :     if (!pszBuffer)
    1320           0 :         return 0;
    1321             : 
    1322           9 :     if (nMaxLen >= 64)
    1323           0 :         nMaxLen = 63;
    1324             : 
    1325           9 :     char szTemp[64] = {};
    1326             : 
    1327             : #if UINT_MAX == 65535
    1328             :     snprintf(szTemp, sizeof(szTemp), "%*ld", nMaxLen, iValue);
    1329             : #else
    1330           9 :     snprintf(szTemp, sizeof(szTemp), "%*d", nMaxLen, iValue);
    1331             : #endif
    1332             : 
    1333           9 :     return CPLPrintString(pszBuffer, szTemp, nMaxLen);
    1334             : }
    1335             : 
    1336             : /************************************************************************/
    1337             : /*                          CPLPrintUIntBig()                           */
    1338             : /************************************************************************/
    1339             : 
    1340             : /**
    1341             :  * Print GUIntBig value into specified string buffer. This string will not
    1342             :  * be NULL-terminated.
    1343             :  *
    1344             :  * @param pszBuffer Pointer to the destination string buffer. Should be
    1345             :  * large enough to hold the resulting string. Note, that the string will
    1346             :  * not be NULL-terminated, so user should do this himself, if needed.
    1347             :  *
    1348             :  * @param iValue Numerical value to print.
    1349             :  *
    1350             :  * @param nMaxLen Maximum length of the resulting string. If string length
    1351             :  * is greater than nMaxLen, it will be truncated.
    1352             :  *
    1353             :  * @return Number of characters printed.
    1354             :  */
    1355             : 
    1356          26 : int CPLPrintUIntBig(char *pszBuffer, GUIntBig iValue, int nMaxLen)
    1357             : {
    1358          26 :     if (!pszBuffer)
    1359           0 :         return 0;
    1360             : 
    1361          26 :     if (nMaxLen >= 64)
    1362           0 :         nMaxLen = 63;
    1363             : 
    1364          26 :     char szTemp[64] = {};
    1365             : 
    1366             : #if defined(__MSVCRT__) || (defined(_WIN32) && defined(_MSC_VER))
    1367             : /* x86_64-w64-mingw32-g++ (GCC) 4.8.2 annoyingly warns */
    1368             : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
    1369             : #pragma GCC diagnostic push
    1370             : #pragma GCC diagnostic ignored "-Wformat"
    1371             : #pragma GCC diagnostic ignored "-Wformat-extra-args"
    1372             : #endif
    1373             :     snprintf(szTemp, sizeof(szTemp), "%*I64u", nMaxLen, iValue);
    1374             : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
    1375             : #pragma GCC diagnostic pop
    1376             : #endif
    1377             : #else
    1378          26 :     snprintf(szTemp, sizeof(szTemp), "%*llu", nMaxLen, iValue);
    1379             : #endif
    1380             : 
    1381          26 :     return CPLPrintString(pszBuffer, szTemp, nMaxLen);
    1382             : }
    1383             : 
    1384             : /************************************************************************/
    1385             : /*                          CPLPrintPointer()                           */
    1386             : /************************************************************************/
    1387             : 
    1388             : /**
    1389             :  * Print pointer value into specified string buffer. This string will not
    1390             :  * be NULL-terminated.
    1391             :  *
    1392             :  * @param pszBuffer Pointer to the destination string buffer. Should be
    1393             :  * large enough to hold the resulting string. Note, that the string will
    1394             :  * not be NULL-terminated, so user should do this himself, if needed.
    1395             :  *
    1396             :  * @param pValue Pointer to ASCII encode.
    1397             :  *
    1398             :  * @param nMaxLen Maximum length of the resulting string. If string length
    1399             :  * is greater than nMaxLen, it will be truncated.
    1400             :  *
    1401             :  * @return Number of characters printed.
    1402             :  */
    1403             : 
    1404        8264 : int CPLPrintPointer(char *pszBuffer, void *pValue, int nMaxLen)
    1405             : {
    1406        8264 :     if (!pszBuffer)
    1407           0 :         return 0;
    1408             : 
    1409        8264 :     if (nMaxLen >= 64)
    1410        7302 :         nMaxLen = 63;
    1411             : 
    1412        8264 :     char szTemp[64] = {};
    1413             : 
    1414        8264 :     snprintf(szTemp, sizeof(szTemp), "%p", pValue);
    1415             : 
    1416             :     // On windows, and possibly some other platforms the sprintf("%p")
    1417             :     // does not prefix things with 0x so it is hard to know later if the
    1418             :     // value is hex encoded.  Fix this up here.
    1419             : 
    1420        8264 :     if (!STARTS_WITH_CI(szTemp, "0x"))
    1421           0 :         snprintf(szTemp, sizeof(szTemp), "0x%p", pValue);
    1422             : 
    1423        8264 :     return CPLPrintString(pszBuffer, szTemp, nMaxLen);
    1424             : }
    1425             : 
    1426             : /************************************************************************/
    1427             : /*                          CPLPrintDouble()                            */
    1428             : /************************************************************************/
    1429             : 
    1430             : /**
    1431             :  * Print double value into specified string buffer. Exponential character
    1432             :  * flag 'E' (or 'e') will be replaced with 'D', as in Fortran. Resulting
    1433             :  * string will not to be NULL-terminated.
    1434             :  *
    1435             :  * @param pszBuffer Pointer to the destination string buffer. Should be
    1436             :  * large enough to hold the resulting string. Note, that the string will
    1437             :  * not be NULL-terminated, so user should do this himself, if needed.
    1438             :  *
    1439             :  * @param pszFormat Format specifier (for example, "%16.9E").
    1440             :  *
    1441             :  * @param dfValue Numerical value to print.
    1442             :  *
    1443             :  * @param pszLocale Unused.
    1444             :  *
    1445             :  * @return Number of characters printed.
    1446             :  */
    1447             : 
    1448           0 : int CPLPrintDouble(char *pszBuffer, const char *pszFormat, double dfValue,
    1449             :                    CPL_UNUSED const char *pszLocale)
    1450             : {
    1451           0 :     if (!pszBuffer)
    1452           0 :         return 0;
    1453             : 
    1454           0 :     const int knDoubleBufferSize = 64;
    1455           0 :     char szTemp[knDoubleBufferSize] = {};
    1456             : 
    1457           0 :     CPLsnprintf(szTemp, knDoubleBufferSize, pszFormat, dfValue);
    1458           0 :     szTemp[knDoubleBufferSize - 1] = '\0';
    1459             : 
    1460           0 :     for (int i = 0; szTemp[i] != '\0'; i++)
    1461             :     {
    1462           0 :         if (szTemp[i] == 'E' || szTemp[i] == 'e')
    1463           0 :             szTemp[i] = 'D';
    1464             :     }
    1465             : 
    1466           0 :     return CPLPrintString(pszBuffer, szTemp, 64);
    1467             : }
    1468             : 
    1469             : /************************************************************************/
    1470             : /*                            CPLPrintTime()                            */
    1471             : /************************************************************************/
    1472             : 
    1473             : /**
    1474             :  * Print specified time value accordingly to the format options and
    1475             :  * specified locale name. This function does following:
    1476             :  *
    1477             :  *  - if locale parameter is not NULL, the current locale setting will be
    1478             :  *  stored and replaced with the specified one;
    1479             :  *  - format time value with the strftime(3) function;
    1480             :  *  - restore back current locale, if was saved.
    1481             :  *
    1482             :  * @param pszBuffer Pointer to the destination string buffer. Should be
    1483             :  * large enough to hold the resulting string. Note, that the string will
    1484             :  * not be NULL-terminated, so user should do this himself, if needed.
    1485             :  *
    1486             :  * @param nMaxLen Maximum length of the resulting string. If string length is
    1487             :  * greater than nMaxLen, it will be truncated.
    1488             :  *
    1489             :  * @param pszFormat Controls the output format. Options are the same as
    1490             :  * for strftime(3) function.
    1491             :  *
    1492             :  * @param poBrokenTime Pointer to the broken-down time structure. May be
    1493             :  * requested with the VSIGMTime() and VSILocalTime() functions.
    1494             :  *
    1495             :  * @param pszLocale Pointer to a character string containing locale name
    1496             :  * ("C", "POSIX", "us_US", "ru_RU.KOI8-R" etc.). If NULL we will not
    1497             :  * manipulate with locale settings and current process locale will be used for
    1498             :  * printing. Be aware that it may be unsuitable to use current locale for
    1499             :  * printing time, because all names will be printed in your native language,
    1500             :  * as well as time format settings also may be adjusted differently from the
    1501             :  * C/POSIX defaults. To solve these problems this option was introduced.
    1502             :  *
    1503             :  * @return Number of characters printed.
    1504             :  */
    1505             : 
    1506          28 : int CPLPrintTime(char *pszBuffer, int nMaxLen, const char *pszFormat,
    1507             :                  const struct tm *poBrokenTime, const char *pszLocale)
    1508             : {
    1509             :     char *pszTemp =
    1510          28 :         static_cast<char *>(CPLMalloc((nMaxLen + 1) * sizeof(char)));
    1511             : 
    1512          28 :     if (pszLocale && EQUAL(pszLocale, "C") &&
    1513          28 :         strcmp(pszFormat, "%a, %d %b %Y %H:%M:%S GMT") == 0)
    1514             :     {
    1515             :         // Particular case when formatting RFC822 datetime, to avoid locale
    1516             :         // change
    1517             :         static const char *const aszMonthStr[] = {"Jan", "Feb", "Mar", "Apr",
    1518             :                                                   "May", "Jun", "Jul", "Aug",
    1519             :                                                   "Sep", "Oct", "Nov", "Dec"};
    1520             :         static const char *const aszDayOfWeek[] = {"Sun", "Mon", "Tue", "Wed",
    1521             :                                                    "Thu", "Fri", "Sat"};
    1522          56 :         snprintf(pszTemp, nMaxLen + 1, "%s, %02d %s %04d %02d:%02d:%02d GMT",
    1523          28 :                  aszDayOfWeek[std::max(0, std::min(6, poBrokenTime->tm_wday))],
    1524          28 :                  poBrokenTime->tm_mday,
    1525          28 :                  aszMonthStr[std::max(0, std::min(11, poBrokenTime->tm_mon))],
    1526          28 :                  poBrokenTime->tm_year + 1900, poBrokenTime->tm_hour,
    1527          56 :                  poBrokenTime->tm_min, poBrokenTime->tm_sec);
    1528             :     }
    1529             :     else
    1530             :     {
    1531             : #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
    1532             :         char *pszCurLocale = NULL;
    1533             : 
    1534             :         if (pszLocale || EQUAL(pszLocale, ""))
    1535             :         {
    1536             :             // Save the current locale.
    1537             :             pszCurLocale = CPLsetlocale(LC_ALL, NULL);
    1538             :             // Set locale to the specified value.
    1539             :             CPLsetlocale(LC_ALL, pszLocale);
    1540             :         }
    1541             : #else
    1542             :         (void)pszLocale;
    1543             : #endif
    1544             : 
    1545           0 :         if (!strftime(pszTemp, nMaxLen + 1, pszFormat, poBrokenTime))
    1546           0 :             memset(pszTemp, 0, nMaxLen + 1);
    1547             : 
    1548             : #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
    1549             :         // Restore stored locale back.
    1550             :         if (pszCurLocale)
    1551             :             CPLsetlocale(LC_ALL, pszCurLocale);
    1552             : #endif
    1553             :     }
    1554             : 
    1555          28 :     const int nChars = CPLPrintString(pszBuffer, pszTemp, nMaxLen);
    1556             : 
    1557          28 :     CPLFree(pszTemp);
    1558             : 
    1559          28 :     return nChars;
    1560             : }
    1561             : 
    1562             : /************************************************************************/
    1563             : /*                       CPLVerifyConfiguration()                       */
    1564             : /************************************************************************/
    1565             : 
    1566           0 : void CPLVerifyConfiguration()
    1567             : 
    1568             : {
    1569             :     /* -------------------------------------------------------------------- */
    1570             :     /*      Verify data types.                                              */
    1571             :     /* -------------------------------------------------------------------- */
    1572             :     static_assert(sizeof(short) == 2);   // We unfortunately rely on this
    1573             :     static_assert(sizeof(int) == 4);     // We unfortunately rely on this
    1574             :     static_assert(sizeof(float) == 4);   // We unfortunately rely on this
    1575             :     static_assert(sizeof(double) == 8);  // We unfortunately rely on this
    1576             :     static_assert(sizeof(GInt64) == 8);
    1577             :     static_assert(sizeof(GInt32) == 4);
    1578             :     static_assert(sizeof(GInt16) == 2);
    1579             :     static_assert(sizeof(GByte) == 1);
    1580             : 
    1581             :     /* -------------------------------------------------------------------- */
    1582             :     /*      Verify byte order                                               */
    1583             :     /* -------------------------------------------------------------------- */
    1584             : #ifdef CPL_LSB
    1585             : #if __cplusplus >= 202002L
    1586             :     static_assert(std::endian::native == std::endian::little);
    1587             : #elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
    1588             :     static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
    1589             : #endif
    1590             : #elif defined(CPL_MSB)
    1591             : #if __cplusplus >= 202002L
    1592             :     static_assert(std::endian::native == std::endian::big);
    1593             : #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
    1594             :     static_assert(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
    1595             : #endif
    1596             : #else
    1597             : #error "CPL_LSB or CPL_MSB must be defined"
    1598             : #endif
    1599           0 : }
    1600             : 
    1601             : #ifdef DEBUG_CONFIG_OPTIONS
    1602             : 
    1603             : static CPLMutex *hRegisterConfigurationOptionMutex = nullptr;
    1604             : static std::set<CPLString> *paoGetKeys = nullptr;
    1605             : static std::set<CPLString> *paoSetKeys = nullptr;
    1606             : 
    1607             : /************************************************************************/
    1608             : /*                      CPLShowAccessedOptions()                        */
    1609             : /************************************************************************/
    1610             : 
    1611             : static void CPLShowAccessedOptions()
    1612             : {
    1613             :     std::set<CPLString>::iterator aoIter;
    1614             : 
    1615             :     printf("Configuration options accessed in reading : "); /*ok*/
    1616             :     aoIter = paoGetKeys->begin();
    1617             :     while (aoIter != paoGetKeys->end())
    1618             :     {
    1619             :         printf("%s, ", (*aoIter).c_str()); /*ok*/
    1620             :         ++aoIter;
    1621             :     }
    1622             :     printf("\n"); /*ok*/
    1623             : 
    1624             :     printf("Configuration options accessed in writing : "); /*ok*/
    1625             :     aoIter = paoSetKeys->begin();
    1626             :     while (aoIter != paoSetKeys->end())
    1627             :     {
    1628             :         printf("%s, ", (*aoIter).c_str()); /*ok*/
    1629             :         ++aoIter;
    1630             :     }
    1631             :     printf("\n"); /*ok*/
    1632             : 
    1633             :     delete paoGetKeys;
    1634             :     delete paoSetKeys;
    1635             :     paoGetKeys = nullptr;
    1636             :     paoSetKeys = nullptr;
    1637             : }
    1638             : 
    1639             : /************************************************************************/
    1640             : /*                       CPLAccessConfigOption()                        */
    1641             : /************************************************************************/
    1642             : 
    1643             : static void CPLAccessConfigOption(const char *pszKey, bool bGet)
    1644             : {
    1645             :     CPLMutexHolderD(&hRegisterConfigurationOptionMutex);
    1646             :     if (paoGetKeys == nullptr)
    1647             :     {
    1648             :         paoGetKeys = new std::set<CPLString>;
    1649             :         paoSetKeys = new std::set<CPLString>;
    1650             :         atexit(CPLShowAccessedOptions);
    1651             :     }
    1652             :     if (bGet)
    1653             :         paoGetKeys->insert(pszKey);
    1654             :     else
    1655             :         paoSetKeys->insert(pszKey);
    1656             : }
    1657             : #endif
    1658             : 
    1659             : /************************************************************************/
    1660             : /*                         CPLGetConfigOption()                         */
    1661             : /************************************************************************/
    1662             : 
    1663             : /**
    1664             :  * Get the value of a configuration option.
    1665             :  *
    1666             :  * The value is the value of a (key, value) option set with
    1667             :  * CPLSetConfigOption(), or CPLSetThreadLocalConfigOption() of the same
    1668             :  * thread. If the given option was no defined with
    1669             :  * CPLSetConfigOption(), it tries to find it in environment variables.
    1670             :  *
    1671             :  * Note: the string returned by CPLGetConfigOption() might be short-lived, and
    1672             :  * in particular it will become invalid after a call to CPLSetConfigOption()
    1673             :  * with the same key.
    1674             :  *
    1675             :  * To override temporary a potentially existing option with a new value, you
    1676             :  * can use the following snippet :
    1677             :  * <pre>
    1678             :  *     // backup old value
    1679             :  *     const char* pszOldValTmp = CPLGetConfigOption(pszKey, NULL);
    1680             :  *     char* pszOldVal = pszOldValTmp ? CPLStrdup(pszOldValTmp) : NULL;
    1681             :  *     // override with new value
    1682             :  *     CPLSetConfigOption(pszKey, pszNewVal);
    1683             :  *     // do something useful
    1684             :  *     // restore old value
    1685             :  *     CPLSetConfigOption(pszKey, pszOldVal);
    1686             :  *     CPLFree(pszOldVal);
    1687             :  * </pre>
    1688             :  *
    1689             :  * @param pszKey the key of the option to retrieve
    1690             :  * @param pszDefault a default value if the key does not match existing defined
    1691             :  *     options (may be NULL)
    1692             :  * @return the value associated to the key, or the default value if not found
    1693             :  *
    1694             :  * @see CPLSetConfigOption(), http://trac.osgeo.org/gdal/wiki/ConfigOptions
    1695             :  */
    1696     4489780 : const char *CPL_STDCALL CPLGetConfigOption(const char *pszKey,
    1697             :                                            const char *pszDefault)
    1698             : 
    1699             : {
    1700     4489780 :     const char *pszResult = CPLGetThreadLocalConfigOption(pszKey, nullptr);
    1701             : 
    1702     4489360 :     if (pszResult == nullptr)
    1703             :     {
    1704     4467260 :         pszResult = CPLGetGlobalConfigOption(pszKey, nullptr);
    1705             :     }
    1706             : 
    1707     4490380 :     if (gbIgnoreEnvVariables)
    1708             :     {
    1709           6 :         const char *pszEnvVar = getenv(pszKey);
    1710           6 :         if (pszEnvVar != nullptr)
    1711             :         {
    1712           1 :             CPLDebug("CPL",
    1713             :                      "Ignoring environment variable %s=%s because of "
    1714             :                      "ignore-env-vars=yes setting in configuration file",
    1715             :                      pszKey, pszEnvVar);
    1716             :         }
    1717             :     }
    1718     4490380 :     else if (pszResult == nullptr)
    1719             :     {
    1720     4460790 :         pszResult = getenv(pszKey);
    1721             :     }
    1722             : 
    1723     4490370 :     if (pszResult == nullptr)
    1724     4452700 :         return pszDefault;
    1725             : 
    1726       37665 :     return pszResult;
    1727             : }
    1728             : 
    1729             : /************************************************************************/
    1730             : /*                         CPLGetConfigOptions()                        */
    1731             : /************************************************************************/
    1732             : 
    1733             : /**
    1734             :  * Return the list of configuration options as KEY=VALUE pairs.
    1735             :  *
    1736             :  * The list is the one set through the CPLSetConfigOption() API.
    1737             :  *
    1738             :  * Options that through environment variables or with
    1739             :  * CPLSetThreadLocalConfigOption() will *not* be listed.
    1740             :  *
    1741             :  * @return a copy of the list, to be freed with CSLDestroy().
    1742             :  * @since GDAL 2.2
    1743             :  */
    1744           7 : char **CPLGetConfigOptions(void)
    1745             : {
    1746          14 :     CPLMutexHolderD(&hConfigMutex);
    1747          14 :     return CSLDuplicate(const_cast<char **>(g_papszConfigOptions));
    1748             : }
    1749             : 
    1750             : /************************************************************************/
    1751             : /*                         CPLSetConfigOptions()                        */
    1752             : /************************************************************************/
    1753             : 
    1754             : /**
    1755             :  * Replace the full list of configuration options with the passed list of
    1756             :  * KEY=VALUE pairs.
    1757             :  *
    1758             :  * This has the same effect of clearing the existing list, and setting
    1759             :  * individually each pair with the CPLSetConfigOption() API.
    1760             :  *
    1761             :  * This does not affect options set through environment variables or with
    1762             :  * CPLSetThreadLocalConfigOption().
    1763             :  *
    1764             :  * The passed list is copied by the function.
    1765             :  *
    1766             :  * @param papszConfigOptions the new list (or NULL).
    1767             :  *
    1768             :  * @since GDAL 2.2
    1769             :  */
    1770          79 : void CPLSetConfigOptions(const char *const *papszConfigOptions)
    1771             : {
    1772          79 :     CPLMutexHolderD(&hConfigMutex);
    1773          79 :     CSLDestroy(const_cast<char **>(g_papszConfigOptions));
    1774          79 :     g_papszConfigOptions = const_cast<volatile char **>(
    1775          79 :         CSLDuplicate(const_cast<char **>(papszConfigOptions)));
    1776          79 : }
    1777             : 
    1778             : /************************************************************************/
    1779             : /*                   CPLGetThreadLocalConfigOption()                    */
    1780             : /************************************************************************/
    1781             : 
    1782             : /** Same as CPLGetConfigOption() but only with options set with
    1783             :  * CPLSetThreadLocalConfigOption() */
    1784     4514360 : const char *CPL_STDCALL CPLGetThreadLocalConfigOption(const char *pszKey,
    1785             :                                                       const char *pszDefault)
    1786             : 
    1787             : {
    1788             : #ifdef DEBUG_CONFIG_OPTIONS
    1789             :     CPLAccessConfigOption(pszKey, TRUE);
    1790             : #endif
    1791             : 
    1792     4514360 :     const char *pszResult = nullptr;
    1793             : 
    1794     4514360 :     int bMemoryError = FALSE;
    1795             :     char **papszTLConfigOptions = reinterpret_cast<char **>(
    1796     4514360 :         CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    1797     4513770 :     if (papszTLConfigOptions != nullptr)
    1798     4118190 :         pszResult = CSLFetchNameValue(papszTLConfigOptions, pszKey);
    1799             : 
    1800     4513890 :     if (pszResult == nullptr)
    1801     4491270 :         return pszDefault;
    1802             : 
    1803       22621 :     return pszResult;
    1804             : }
    1805             : 
    1806             : /************************************************************************/
    1807             : /*                   CPLGetGlobalConfigOption()                         */
    1808             : /************************************************************************/
    1809             : 
    1810             : /** Same as CPLGetConfigOption() but excludes environment variables and
    1811             :  *  options set with CPLSetThreadLocalConfigOption().
    1812             :  *  This function should generally not be used by applications, which should
    1813             :  *  use CPLGetConfigOption() instead.
    1814             :  *  @since 3.8 */
    1815     4468980 : const char *CPL_STDCALL CPLGetGlobalConfigOption(const char *pszKey,
    1816             :                                                  const char *pszDefault)
    1817             : {
    1818             : #ifdef DEBUG_CONFIG_OPTIONS
    1819             :     CPLAccessConfigOption(pszKey, TRUE);
    1820             : #endif
    1821             : 
    1822     8938740 :     CPLMutexHolderD(&hConfigMutex);
    1823             : 
    1824             :     const char *pszResult =
    1825     4469760 :         CSLFetchNameValue(const_cast<char **>(g_papszConfigOptions), pszKey);
    1826             : 
    1827     4469760 :     if (pszResult == nullptr)
    1828     4462090 :         return pszDefault;
    1829             : 
    1830        7666 :     return pszResult;
    1831             : }
    1832             : 
    1833             : /************************************************************************/
    1834             : /*                    CPLSubscribeToSetConfigOption()                   */
    1835             : /************************************************************************/
    1836             : 
    1837             : /**
    1838             :  * Install a callback that will be notified of calls to CPLSetConfigOption()/
    1839             :  * CPLSetThreadLocalConfigOption()
    1840             :  *
    1841             :  * @param pfnCallback Callback. Must not be NULL
    1842             :  * @param pUserData Callback user data. May be NULL.
    1843             :  * @return subscriber ID that can be used with CPLUnsubscribeToSetConfigOption()
    1844             :  * @since GDAL 3.7
    1845             :  */
    1846             : 
    1847        1091 : int CPLSubscribeToSetConfigOption(CPLSetConfigOptionSubscriber pfnCallback,
    1848             :                                   void *pUserData)
    1849             : {
    1850        2182 :     CPLMutexHolderD(&hConfigMutex);
    1851        1096 :     for (int nId = 0;
    1852        1096 :          nId < static_cast<int>(gSetConfigOptionSubscribers.size()); ++nId)
    1853             :     {
    1854           6 :         if (!gSetConfigOptionSubscribers[nId].first)
    1855             :         {
    1856           1 :             gSetConfigOptionSubscribers[nId].first = pfnCallback;
    1857           1 :             gSetConfigOptionSubscribers[nId].second = pUserData;
    1858           1 :             return nId;
    1859             :         }
    1860             :     }
    1861        1090 :     int nId = static_cast<int>(gSetConfigOptionSubscribers.size());
    1862        1090 :     gSetConfigOptionSubscribers.push_back(
    1863        1090 :         std::pair<CPLSetConfigOptionSubscriber, void *>(pfnCallback,
    1864             :                                                         pUserData));
    1865        1090 :     return nId;
    1866             : }
    1867             : 
    1868             : /************************************************************************/
    1869             : /*                  CPLUnsubscribeToSetConfigOption()                   */
    1870             : /************************************************************************/
    1871             : 
    1872             : /**
    1873             :  * Remove a subscriber installed with CPLSubscribeToSetConfigOption()
    1874             :  *
    1875             :  * @param nId Subscriber id returned by CPLSubscribeToSetConfigOption()
    1876             :  * @since GDAL 3.7
    1877             :  */
    1878             : 
    1879           4 : void CPLUnsubscribeToSetConfigOption(int nId)
    1880             : {
    1881           8 :     CPLMutexHolderD(&hConfigMutex);
    1882           4 :     if (nId == static_cast<int>(gSetConfigOptionSubscribers.size()) - 1)
    1883             :     {
    1884           3 :         gSetConfigOptionSubscribers.resize(gSetConfigOptionSubscribers.size() -
    1885             :                                            1);
    1886             :     }
    1887           2 :     else if (nId >= 0 &&
    1888           1 :              nId < static_cast<int>(gSetConfigOptionSubscribers.size()))
    1889             :     {
    1890           1 :         gSetConfigOptionSubscribers[nId].first = nullptr;
    1891             :     }
    1892           4 : }
    1893             : 
    1894             : /************************************************************************/
    1895             : /*                  NotifyOtherComponentsConfigOptionChanged()          */
    1896             : /************************************************************************/
    1897             : 
    1898       56366 : static void NotifyOtherComponentsConfigOptionChanged(const char *pszKey,
    1899             :                                                      const char *pszValue,
    1900             :                                                      bool bThreadLocal)
    1901             : {
    1902             :     // Hack
    1903       56366 :     if (STARTS_WITH_CI(pszKey, "AWS_"))
    1904        1684 :         VSICurlAuthParametersChanged();
    1905             : 
    1906       56366 :     if (!gSetConfigOptionSubscribers.empty())
    1907             :     {
    1908      111249 :         for (const auto &iter : gSetConfigOptionSubscribers)
    1909             :         {
    1910       55658 :             if (iter.first)
    1911       55874 :                 iter.first(pszKey, pszValue, bThreadLocal, iter.second);
    1912             :         }
    1913             :     }
    1914       56054 : }
    1915             : 
    1916             : /************************************************************************/
    1917             : /*                         CPLSetConfigOption()                         */
    1918             : /************************************************************************/
    1919             : 
    1920             : /**
    1921             :  * Set a configuration option for GDAL/OGR use.
    1922             :  *
    1923             :  * Those options are defined as a (key, value) couple. The value corresponding
    1924             :  * to a key can be got later with the CPLGetConfigOption() method.
    1925             :  *
    1926             :  * This mechanism is similar to environment variables, but options set with
    1927             :  * CPLSetConfigOption() overrides, for CPLGetConfigOption() point of view,
    1928             :  * values defined in the environment.
    1929             :  *
    1930             :  * If CPLSetConfigOption() is called several times with the same key, the
    1931             :  * value provided during the last call will be used.
    1932             :  *
    1933             :  * Options can also be passed on the command line of most GDAL utilities
    1934             :  * with the with '--config KEY VALUE'. For example,
    1935             :  * ogrinfo --config CPL_DEBUG ON ~/data/test/point.shp
    1936             :  *
    1937             :  * This function can also be used to clear a setting by passing NULL as the
    1938             :  * value (note: passing NULL will not unset an existing environment variable;
    1939             :  * it will just unset a value previously set by CPLSetConfigOption()).
    1940             :  *
    1941             :  * @param pszKey the key of the option
    1942             :  * @param pszValue the value of the option, or NULL to clear a setting.
    1943             :  *
    1944             :  * @see http://trac.osgeo.org/gdal/wiki/ConfigOptions
    1945             :  */
    1946        3911 : void CPL_STDCALL CPLSetConfigOption(const char *pszKey, const char *pszValue)
    1947             : 
    1948             : {
    1949             : #ifdef DEBUG_CONFIG_OPTIONS
    1950             :     CPLAccessConfigOption(pszKey, FALSE);
    1951             : #endif
    1952        7822 :     CPLMutexHolderD(&hConfigMutex);
    1953             : 
    1954             : #ifdef OGRAPISPY_ENABLED
    1955        3911 :     OGRAPISPYCPLSetConfigOption(pszKey, pszValue);
    1956             : #endif
    1957             : 
    1958        3911 :     g_papszConfigOptions = const_cast<volatile char **>(CSLSetNameValue(
    1959             :         const_cast<char **>(g_papszConfigOptions), pszKey, pszValue));
    1960             : 
    1961        3911 :     NotifyOtherComponentsConfigOptionChanged(pszKey, pszValue,
    1962             :                                              /*bTheadLocal=*/false);
    1963        3911 : }
    1964             : 
    1965             : /************************************************************************/
    1966             : /*                   CPLSetThreadLocalTLSFreeFunc()                     */
    1967             : /************************************************************************/
    1968             : 
    1969             : /* non-stdcall wrapper function for CSLDestroy() (#5590) */
    1970           6 : static void CPLSetThreadLocalTLSFreeFunc(void *pData)
    1971             : {
    1972           6 :     CSLDestroy(reinterpret_cast<char **>(pData));
    1973           6 : }
    1974             : 
    1975             : /************************************************************************/
    1976             : /*                   CPLSetThreadLocalConfigOption()                    */
    1977             : /************************************************************************/
    1978             : 
    1979             : /**
    1980             :  * Set a configuration option for GDAL/OGR use.
    1981             :  *
    1982             :  * Those options are defined as a (key, value) couple. The value corresponding
    1983             :  * to a key can be got later with the CPLGetConfigOption() method.
    1984             :  *
    1985             :  * This function sets the configuration option that only applies in the
    1986             :  * current thread, as opposed to CPLSetConfigOption() which sets an option
    1987             :  * that applies on all threads. CPLSetThreadLocalConfigOption() will override
    1988             :  * the effect of CPLSetConfigOption) for the current thread.
    1989             :  *
    1990             :  * This function can also be used to clear a setting by passing NULL as the
    1991             :  * value (note: passing NULL will not unset an existing environment variable or
    1992             :  * a value set through CPLSetConfigOption();
    1993             :  * it will just unset a value previously set by
    1994             :  * CPLSetThreadLocalConfigOption()).
    1995             :  *
    1996             :  * @param pszKey the key of the option
    1997             :  * @param pszValue the value of the option, or NULL to clear a setting.
    1998             :  */
    1999             : 
    2000       52572 : void CPL_STDCALL CPLSetThreadLocalConfigOption(const char *pszKey,
    2001             :                                                const char *pszValue)
    2002             : 
    2003             : {
    2004             : #ifdef DEBUG_CONFIG_OPTIONS
    2005             :     CPLAccessConfigOption(pszKey, FALSE);
    2006             : #endif
    2007             : 
    2008             : #ifdef OGRAPISPY_ENABLED
    2009       52572 :     OGRAPISPYCPLSetThreadLocalConfigOption(pszKey, pszValue);
    2010             : #endif
    2011             : 
    2012       52521 :     int bMemoryError = FALSE;
    2013             :     char **papszTLConfigOptions = reinterpret_cast<char **>(
    2014       52521 :         CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    2015       52486 :     if (bMemoryError)
    2016           0 :         return;
    2017             : 
    2018             :     papszTLConfigOptions =
    2019       52486 :         CSLSetNameValue(papszTLConfigOptions, pszKey, pszValue);
    2020             : 
    2021       52436 :     CPLSetTLSWithFreeFunc(CTLS_CONFIGOPTIONS, papszTLConfigOptions,
    2022             :                           CPLSetThreadLocalTLSFreeFunc);
    2023             : 
    2024       52409 :     NotifyOtherComponentsConfigOptionChanged(pszKey, pszValue,
    2025             :                                              /*bTheadLocal=*/true);
    2026             : }
    2027             : 
    2028             : /************************************************************************/
    2029             : /*                   CPLGetThreadLocalConfigOptions()                   */
    2030             : /************************************************************************/
    2031             : 
    2032             : /**
    2033             :  * Return the list of thread local configuration options as KEY=VALUE pairs.
    2034             :  *
    2035             :  * Options that through environment variables or with
    2036             :  * CPLSetConfigOption() will *not* be listed.
    2037             :  *
    2038             :  * @return a copy of the list, to be freed with CSLDestroy().
    2039             :  * @since GDAL 2.2
    2040             :  */
    2041           7 : char **CPLGetThreadLocalConfigOptions(void)
    2042             : {
    2043           7 :     int bMemoryError = FALSE;
    2044             :     char **papszTLConfigOptions = reinterpret_cast<char **>(
    2045           7 :         CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    2046           7 :     if (bMemoryError)
    2047           0 :         return nullptr;
    2048           7 :     return CSLDuplicate(papszTLConfigOptions);
    2049             : }
    2050             : 
    2051             : /************************************************************************/
    2052             : /*                   CPLSetThreadLocalConfigOptions()                   */
    2053             : /************************************************************************/
    2054             : 
    2055             : /**
    2056             :  * Replace the full list of thread local configuration options with the
    2057             :  * passed list of KEY=VALUE pairs.
    2058             :  *
    2059             :  * This has the same effect of clearing the existing list, and setting
    2060             :  * individually each pair with the CPLSetThreadLocalConfigOption() API.
    2061             :  *
    2062             :  * This does not affect options set through environment variables or with
    2063             :  * CPLSetConfigOption().
    2064             :  *
    2065             :  * The passed list is copied by the function.
    2066             :  *
    2067             :  * @param papszConfigOptions the new list (or NULL).
    2068             :  *
    2069             :  * @since GDAL 2.2
    2070             :  */
    2071          79 : void CPLSetThreadLocalConfigOptions(const char *const *papszConfigOptions)
    2072             : {
    2073          79 :     int bMemoryError = FALSE;
    2074             :     char **papszTLConfigOptions = reinterpret_cast<char **>(
    2075          79 :         CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    2076          79 :     if (bMemoryError)
    2077           0 :         return;
    2078          79 :     CSLDestroy(papszTLConfigOptions);
    2079             :     papszTLConfigOptions =
    2080          79 :         CSLDuplicate(const_cast<char **>(papszConfigOptions));
    2081          79 :     CPLSetTLSWithFreeFunc(CTLS_CONFIGOPTIONS, papszTLConfigOptions,
    2082             :                           CPLSetThreadLocalTLSFreeFunc);
    2083             : }
    2084             : 
    2085             : /************************************************************************/
    2086             : /*                           CPLFreeConfig()                            */
    2087             : /************************************************************************/
    2088             : 
    2089        1232 : void CPL_STDCALL CPLFreeConfig()
    2090             : 
    2091             : {
    2092             :     {
    2093        2464 :         CPLMutexHolderD(&hConfigMutex);
    2094             : 
    2095        1232 :         CSLDestroy(const_cast<char **>(g_papszConfigOptions));
    2096        1232 :         g_papszConfigOptions = nullptr;
    2097             : 
    2098        1232 :         int bMemoryError = FALSE;
    2099             :         char **papszTLConfigOptions = reinterpret_cast<char **>(
    2100        1232 :             CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    2101        1232 :         if (papszTLConfigOptions != nullptr)
    2102             :         {
    2103         213 :             CSLDestroy(papszTLConfigOptions);
    2104         213 :             CPLSetTLS(CTLS_CONFIGOPTIONS, nullptr, FALSE);
    2105             :         }
    2106             :     }
    2107        1232 :     CPLDestroyMutex(hConfigMutex);
    2108        1232 :     hConfigMutex = nullptr;
    2109        1232 : }
    2110             : 
    2111             : /************************************************************************/
    2112             : /*                    CPLLoadConfigOptionsFromFile()                    */
    2113             : /************************************************************************/
    2114             : 
    2115             : /** Load configuration from a given configuration file.
    2116             : 
    2117             : A configuration file is a text file in a .ini style format, that lists
    2118             : configuration options and their values.
    2119             : Lines starting with # are comment lines.
    2120             : 
    2121             : Example:
    2122             : \verbatim
    2123             : [configoptions]
    2124             : # set BAR as the value of configuration option FOO
    2125             : FOO=BAR
    2126             : \endverbatim
    2127             : 
    2128             : Starting with GDAL 3.5, a configuration file can also contain credentials
    2129             : (or more generally options related to a virtual file system) for a given path
    2130             : prefix, that can also be set with VSISetPathSpecificOption(). Credentials should
    2131             : be put under a [credentials] section, and for each path prefix, under a relative
    2132             : subsection whose name starts with "[." (e.g. "[.some_arbitrary_name]"), and
    2133             : whose first key is "path".
    2134             : 
    2135             : Example:
    2136             : \verbatim
    2137             : [credentials]
    2138             : 
    2139             : [.private_bucket]
    2140             : path=/vsis3/my_private_bucket
    2141             : AWS_SECRET_ACCESS_KEY=...
    2142             : AWS_ACCESS_KEY_ID=...
    2143             : 
    2144             : [.sentinel_s2_l1c]
    2145             : path=/vsis3/sentinel-s2-l1c
    2146             : AWS_REQUEST_PAYER=requester
    2147             : \endverbatim
    2148             : 
    2149             : Starting with GDAL 3.6, a leading [directives] section might be added with
    2150             : a "ignore-env-vars=yes" setting to indicate that, starting with that point,
    2151             : all environment variables should be ignored, and only configuration options
    2152             : defined in the [configoptions] sections or through the CPLSetConfigOption() /
    2153             : CPLSetThreadLocalConfigOption() functions should be taken into account.
    2154             : 
    2155             : This function is typically called by CPLLoadConfigOptionsFromPredefinedFiles()
    2156             : 
    2157             : @param pszFilename File where to load configuration from.
    2158             : @param bOverrideEnvVars Whether configuration options from the configuration
    2159             :                         file should override environment variables.
    2160             : @since GDAL 3.3
    2161             :  */
    2162        2448 : void CPLLoadConfigOptionsFromFile(const char *pszFilename, int bOverrideEnvVars)
    2163             : {
    2164        2448 :     VSILFILE *fp = VSIFOpenL(pszFilename, "rb");
    2165        2448 :     if (fp == nullptr)
    2166        2439 :         return;
    2167           9 :     CPLDebug("CPL", "Loading configuration from %s", pszFilename);
    2168             :     const char *pszLine;
    2169             :     enum class Section
    2170             :     {
    2171             :         NONE,
    2172             :         GENERAL,
    2173             :         CONFIG_OPTIONS,
    2174             :         CREDENTIALS,
    2175             :     };
    2176           9 :     Section eCurrentSection = Section::NONE;
    2177           9 :     bool bInSubsection = false;
    2178          18 :     std::string osPath;
    2179           9 :     int nSectionCounter = 0;
    2180             : 
    2181          56 :     const auto IsSpaceOnly = [](const char *pszStr)
    2182             :     {
    2183          56 :         for (; *pszStr; ++pszStr)
    2184             :         {
    2185          47 :             if (!isspace(static_cast<unsigned char>(*pszStr)))
    2186          41 :                 return false;
    2187             :         }
    2188           9 :         return true;
    2189             :     };
    2190             : 
    2191          59 :     while ((pszLine = CPLReadLine2L(fp, -1, nullptr)) != nullptr)
    2192             :     {
    2193          50 :         if (IsSpaceOnly(pszLine))
    2194             :         {
    2195             :             // Blank line
    2196             :         }
    2197          41 :         else if (pszLine[0] == '#')
    2198             :         {
    2199             :             // Comment line
    2200             :         }
    2201          35 :         else if (strcmp(pszLine, "[configoptions]") == 0)
    2202             :         {
    2203           6 :             nSectionCounter++;
    2204           6 :             eCurrentSection = Section::CONFIG_OPTIONS;
    2205             :         }
    2206          29 :         else if (strcmp(pszLine, "[credentials]") == 0)
    2207             :         {
    2208           4 :             nSectionCounter++;
    2209           4 :             eCurrentSection = Section::CREDENTIALS;
    2210           4 :             bInSubsection = false;
    2211           4 :             osPath.clear();
    2212             :         }
    2213          25 :         else if (strcmp(pszLine, "[directives]") == 0)
    2214             :         {
    2215           2 :             nSectionCounter++;
    2216           2 :             if (nSectionCounter != 1)
    2217             :             {
    2218           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    2219             :                          "The [directives] section should be the first one in "
    2220             :                          "the file, otherwise some its settings might not be "
    2221             :                          "used correctly.");
    2222             :             }
    2223           2 :             eCurrentSection = Section::GENERAL;
    2224             :         }
    2225          23 :         else if (eCurrentSection == Section::GENERAL)
    2226             :         {
    2227           2 :             char *pszKey = nullptr;
    2228           2 :             const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
    2229           2 :             if (pszKey && pszValue)
    2230             :             {
    2231           2 :                 if (strcmp(pszKey, "ignore-env-vars") == 0)
    2232             :                 {
    2233           2 :                     gbIgnoreEnvVariables = CPLTestBool(pszValue);
    2234             :                 }
    2235             :                 else
    2236             :                 {
    2237           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
    2238             :                              "Ignoring %s line in [directives] section",
    2239             :                              pszLine);
    2240             :                 }
    2241             :             }
    2242           2 :             CPLFree(pszKey);
    2243             :         }
    2244          21 :         else if (eCurrentSection == Section::CREDENTIALS)
    2245             :         {
    2246          15 :             if (strncmp(pszLine, "[.", 2) == 0)
    2247             :             {
    2248           4 :                 bInSubsection = true;
    2249           4 :                 osPath.clear();
    2250             :             }
    2251          11 :             else if (bInSubsection)
    2252             :             {
    2253          10 :                 char *pszKey = nullptr;
    2254          10 :                 const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
    2255          10 :                 if (pszKey && pszValue)
    2256             :                 {
    2257          10 :                     if (strcmp(pszKey, "path") == 0)
    2258             :                     {
    2259           4 :                         if (!osPath.empty())
    2260             :                         {
    2261           1 :                             CPLError(
    2262             :                                 CE_Warning, CPLE_AppDefined,
    2263             :                                 "Duplicated 'path' key in the same subsection. "
    2264             :                                 "Ignoring %s=%s",
    2265             :                                 pszKey, pszValue);
    2266             :                         }
    2267             :                         else
    2268             :                         {
    2269           3 :                             osPath = pszValue;
    2270             :                         }
    2271             :                     }
    2272           6 :                     else if (osPath.empty())
    2273             :                     {
    2274           1 :                         CPLError(CE_Warning, CPLE_AppDefined,
    2275             :                                  "First entry in a credentials subsection "
    2276             :                                  "should be 'path'.");
    2277             :                     }
    2278             :                     else
    2279             :                     {
    2280           5 :                         VSISetPathSpecificOption(osPath.c_str(), pszKey,
    2281             :                                                  pszValue);
    2282             :                     }
    2283             :                 }
    2284          10 :                 CPLFree(pszKey);
    2285             :             }
    2286           1 :             else if (pszLine[0] == '[')
    2287             :             {
    2288           0 :                 eCurrentSection = Section::NONE;
    2289             :             }
    2290             :             else
    2291             :             {
    2292           1 :                 CPLError(CE_Warning, CPLE_AppDefined,
    2293             :                          "Ignoring content in [credential] section that is not "
    2294             :                          "in a [.xxxxx] subsection");
    2295             :             }
    2296             :         }
    2297           6 :         else if (pszLine[0] == '[')
    2298             :         {
    2299           0 :             eCurrentSection = Section::NONE;
    2300             :         }
    2301           6 :         else if (eCurrentSection == Section::CONFIG_OPTIONS)
    2302             :         {
    2303           6 :             char *pszKey = nullptr;
    2304           6 :             const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
    2305           6 :             if (pszKey && pszValue)
    2306             :             {
    2307          11 :                 if (bOverrideEnvVars || gbIgnoreEnvVariables ||
    2308           5 :                     getenv(pszKey) == nullptr)
    2309             :                 {
    2310           5 :                     CPLDebugOnly("CPL", "Setting configuration option %s=%s",
    2311             :                                  pszKey, pszValue);
    2312           5 :                     CPLSetConfigOption(pszKey, pszValue);
    2313             :                 }
    2314             :                 else
    2315             :                 {
    2316           1 :                     CPLDebug("CPL",
    2317             :                              "Ignoring configuration option %s=%s from "
    2318             :                              "configuration file as it is already set "
    2319             :                              "as an environment variable",
    2320             :                              pszKey, pszValue);
    2321             :                 }
    2322             :             }
    2323           6 :             CPLFree(pszKey);
    2324             :         }
    2325             :     }
    2326           9 :     VSIFCloseL(fp);
    2327             : }
    2328             : 
    2329             : /************************************************************************/
    2330             : /*                CPLLoadConfigOptionsFromPredefinedFiles()             */
    2331             : /************************************************************************/
    2332             : 
    2333             : /** Load configuration from a set of predefined files.
    2334             :  *
    2335             :  * If the environment variable (or configuration option) GDAL_CONFIG_FILE is
    2336             :  * set, then CPLLoadConfigOptionsFromFile() will be called with the value of
    2337             :  * this configuration option as the file location.
    2338             :  *
    2339             :  * Otherwise, for Unix builds, CPLLoadConfigOptionsFromFile() will be called
    2340             :  * with ${sysconfdir}/gdal/gdalrc first where ${sysconfdir} evaluates
    2341             :  * to ${prefix}/etc, unless the --sysconfdir switch of configure has been
    2342             :  * invoked.
    2343             :  *
    2344             :  * Then CPLLoadConfigOptionsFromFile() will be called with $(HOME)/.gdal/gdalrc
    2345             :  * on Unix builds (potentially overriding what was loaded with the sysconfdir)
    2346             :  * or $(USERPROFILE)/.gdal/gdalrc on Windows builds.
    2347             :  *
    2348             :  * CPLLoadConfigOptionsFromFile() will be called with bOverrideEnvVars = false,
    2349             :  * that is the value of environment variables previously set will be used
    2350             :  * instead of the value set in the configuration files (unless the configuration
    2351             :  * file contains a leading [directives] section with a "ignore-env-vars=yes"
    2352             :  * setting).
    2353             :  *
    2354             :  * This function is automatically called by GDALDriverManager() constructor
    2355             :  *
    2356             :  * @since GDAL 3.3
    2357             :  */
    2358        1221 : void CPLLoadConfigOptionsFromPredefinedFiles()
    2359             : {
    2360        1221 :     const char *pszFile = CPLGetConfigOption("GDAL_CONFIG_FILE", nullptr);
    2361        1221 :     if (pszFile != nullptr)
    2362             :     {
    2363           2 :         CPLLoadConfigOptionsFromFile(pszFile, false);
    2364             :     }
    2365             :     else
    2366             :     {
    2367             : #ifdef SYSCONFDIR
    2368        1219 :         pszFile = CPLFormFilename(CPLFormFilename(SYSCONFDIR, "gdal", nullptr),
    2369             :                                   "gdalrc", nullptr);
    2370        1219 :         CPLLoadConfigOptionsFromFile(pszFile, false);
    2371             : #endif
    2372             : 
    2373             : #ifdef _WIN32
    2374             :         const char *pszHome = CPLGetConfigOption("USERPROFILE", nullptr);
    2375             : #else
    2376        1219 :         const char *pszHome = CPLGetConfigOption("HOME", nullptr);
    2377             : #endif
    2378        1219 :         if (pszHome != nullptr)
    2379             :         {
    2380        1219 :             pszFile = CPLFormFilename(
    2381             :                 CPLFormFilename(pszHome, ".gdal", nullptr), "gdalrc", nullptr);
    2382        1219 :             CPLLoadConfigOptionsFromFile(pszFile, false);
    2383             :         }
    2384             :     }
    2385        1221 : }
    2386             : 
    2387             : /************************************************************************/
    2388             : /*                              CPLStat()                               */
    2389             : /************************************************************************/
    2390             : 
    2391             : /** Same as VSIStat() except it works on "C:" as if it were "C:\". */
    2392             : 
    2393          64 : int CPLStat(const char *pszPath, VSIStatBuf *psStatBuf)
    2394             : 
    2395             : {
    2396          64 :     if (strlen(pszPath) == 2 && pszPath[1] == ':')
    2397             :     {
    2398           0 :         char szAltPath[4] = {pszPath[0], pszPath[1], '\\', '\0'};
    2399           0 :         return VSIStat(szAltPath, psStatBuf);
    2400             :     }
    2401             : 
    2402          64 :     return VSIStat(pszPath, psStatBuf);
    2403             : }
    2404             : 
    2405             : /************************************************************************/
    2406             : /*                            proj_strtod()                             */
    2407             : /************************************************************************/
    2408           2 : static double proj_strtod(char *nptr, char **endptr)
    2409             : 
    2410             : {
    2411           2 :     char c = '\0';
    2412           2 :     char *cp = nptr;
    2413             : 
    2414             :     // Scan for characters which cause problems with VC++ strtod().
    2415           8 :     while ((c = *cp) != '\0')
    2416             :     {
    2417           6 :         if (c == 'd' || c == 'D')
    2418             :         {
    2419             :             // Found one, so NUL it out, call strtod(),
    2420             :             // then restore it and return.
    2421           0 :             *cp = '\0';
    2422           0 :             const double result = CPLStrtod(nptr, endptr);
    2423           0 :             *cp = c;
    2424           0 :             return result;
    2425             :         }
    2426           6 :         ++cp;
    2427             :     }
    2428             : 
    2429             :     // No offending characters, just handle normally.
    2430             : 
    2431           2 :     return CPLStrtod(nptr, endptr);
    2432             : }
    2433             : 
    2434             : /************************************************************************/
    2435             : /*                            CPLDMSToDec()                             */
    2436             : /************************************************************************/
    2437             : 
    2438             : static const char *sym = "NnEeSsWw";
    2439             : constexpr double vm[] = {1.0, 0.0166666666667, 0.00027777778};
    2440             : 
    2441             : /** CPLDMSToDec */
    2442           2 : double CPLDMSToDec(const char *is)
    2443             : 
    2444             : {
    2445             :     // Copy string into work space.
    2446           2 :     while (isspace(static_cast<unsigned char>(*is)))
    2447           0 :         ++is;
    2448             : 
    2449           2 :     const char *p = is;
    2450           2 :     char work[64] = {};
    2451           2 :     char *s = work;
    2452           2 :     int n = sizeof(work);
    2453           8 :     for (; isgraph(*p) && --n;)
    2454           6 :         *s++ = *p++;
    2455           2 :     *s = '\0';
    2456             :     // It is possible that a really odd input (like lots of leading
    2457             :     // zeros) could be truncated in copying into work.  But...
    2458           2 :     s = work;
    2459           2 :     int sign = *s;
    2460             : 
    2461           2 :     if (sign == '+' || sign == '-')
    2462           0 :         s++;
    2463             :     else
    2464           2 :         sign = '+';
    2465             : 
    2466           2 :     int nl = 0;
    2467           2 :     double v = 0.0;
    2468           4 :     for (; nl < 3; nl = n + 1)
    2469             :     {
    2470           2 :         if (!(isdigit(static_cast<unsigned char>(*s)) || *s == '.'))
    2471           0 :             break;
    2472           2 :         const double tv = proj_strtod(s, &s);
    2473           2 :         if (tv == HUGE_VAL)
    2474           0 :             return tv;
    2475           2 :         switch (*s)
    2476             :         {
    2477           0 :             case 'D':
    2478             :             case 'd':
    2479           0 :                 n = 0;
    2480           0 :                 break;
    2481           0 :             case '\'':
    2482           0 :                 n = 1;
    2483           0 :                 break;
    2484           0 :             case '"':
    2485           0 :                 n = 2;
    2486           0 :                 break;
    2487           0 :             case 'r':
    2488             :             case 'R':
    2489           0 :                 if (nl)
    2490             :                 {
    2491           0 :                     return 0.0;
    2492             :                 }
    2493           0 :                 ++s;
    2494           0 :                 v = tv;
    2495           0 :                 goto skip;
    2496           2 :             default:
    2497           2 :                 v += tv * vm[nl];
    2498           2 :             skip:
    2499           2 :                 n = 4;
    2500           2 :                 continue;
    2501             :         }
    2502           0 :         if (n < nl)
    2503             :         {
    2504           0 :             return 0.0;
    2505             :         }
    2506           0 :         v += tv * vm[n];
    2507           0 :         ++s;
    2508             :     }
    2509             :     // Postfix sign.
    2510           2 :     if (*s && ((p = strchr(sym, *s))) != nullptr)
    2511             :     {
    2512           2 :         sign = (p - sym) >= 4 ? '-' : '+';
    2513           2 :         ++s;
    2514             :     }
    2515           2 :     if (sign == '-')
    2516           1 :         v = -v;
    2517             : 
    2518           2 :     return v;
    2519             : }
    2520             : 
    2521             : /************************************************************************/
    2522             : /*                            CPLDecToDMS()                             */
    2523             : /************************************************************************/
    2524             : 
    2525             : /** Translate a decimal degrees value to a DMS string with hemisphere. */
    2526             : 
    2527         500 : const char *CPLDecToDMS(double dfAngle, const char *pszAxis, int nPrecision)
    2528             : 
    2529             : {
    2530         500 :     VALIDATE_POINTER1(pszAxis, "CPLDecToDMS", "");
    2531             : 
    2532         500 :     if (CPLIsNan(dfAngle))
    2533           0 :         return "Invalid angle";
    2534             : 
    2535         500 :     const double dfEpsilon = (0.5 / 3600.0) * pow(0.1, nPrecision);
    2536         500 :     const double dfABSAngle = std::abs(dfAngle) + dfEpsilon;
    2537         500 :     if (dfABSAngle > 361.0)
    2538             :     {
    2539           0 :         return "Invalid angle";
    2540             :     }
    2541             : 
    2542         500 :     const int nDegrees = static_cast<int>(dfABSAngle);
    2543         500 :     const int nMinutes = static_cast<int>((dfABSAngle - nDegrees) * 60);
    2544         500 :     double dfSeconds = dfABSAngle * 3600 - nDegrees * 3600 - nMinutes * 60;
    2545             : 
    2546         500 :     if (dfSeconds > dfEpsilon * 3600.0)
    2547         494 :         dfSeconds -= dfEpsilon * 3600.0;
    2548             : 
    2549         500 :     const char *pszHemisphere = nullptr;
    2550         500 :     if (EQUAL(pszAxis, "Long") && dfAngle < 0.0)
    2551         213 :         pszHemisphere = "W";
    2552         287 :     else if (EQUAL(pszAxis, "Long"))
    2553          37 :         pszHemisphere = "E";
    2554         250 :     else if (dfAngle < 0.0)
    2555          22 :         pszHemisphere = "S";
    2556             :     else
    2557         228 :         pszHemisphere = "N";
    2558             : 
    2559         500 :     char szFormat[30] = {};
    2560         500 :     CPLsnprintf(szFormat, sizeof(szFormat), "%%3dd%%2d\'%%%d.%df\"%s",
    2561             :                 nPrecision + 3, nPrecision, pszHemisphere);
    2562             : 
    2563             :     static CPL_THREADLOCAL char szBuffer[50] = {};
    2564         500 :     CPLsnprintf(szBuffer, sizeof(szBuffer), szFormat, nDegrees, nMinutes,
    2565             :                 dfSeconds);
    2566             : 
    2567         500 :     return szBuffer;
    2568             : }
    2569             : 
    2570             : /************************************************************************/
    2571             : /*                         CPLPackedDMSToDec()                          */
    2572             : /************************************************************************/
    2573             : 
    2574             : /**
    2575             :  * Convert a packed DMS value (DDDMMMSSS.SS) into decimal degrees.
    2576             :  *
    2577             :  * This function converts a packed DMS angle to seconds. The standard
    2578             :  * packed DMS format is:
    2579             :  *
    2580             :  *  degrees * 1000000 + minutes * 1000 + seconds
    2581             :  *
    2582             :  * Example:     angle = 120025045.25 yields
    2583             :  *              deg = 120
    2584             :  *              min = 25
    2585             :  *              sec = 45.25
    2586             :  *
    2587             :  * The algorithm used for the conversion is as follows:
    2588             :  *
    2589             :  * 1.  The absolute value of the angle is used.
    2590             :  *
    2591             :  * 2.  The degrees are separated out:
    2592             :  *     deg = angle/1000000                    (fractional portion truncated)
    2593             :  *
    2594             :  * 3.  The minutes are separated out:
    2595             :  *     min = (angle - deg * 1000000) / 1000   (fractional portion truncated)
    2596             :  *
    2597             :  * 4.  The seconds are then computed:
    2598             :  *     sec = angle - deg * 1000000 - min * 1000
    2599             :  *
    2600             :  * 5.  The total angle in seconds is computed:
    2601             :  *     sec = deg * 3600.0 + min * 60.0 + sec
    2602             :  *
    2603             :  * 6.  The sign of sec is set to that of the input angle.
    2604             :  *
    2605             :  * Packed DMS values used by the USGS GCTP package and probably by other
    2606             :  * software.
    2607             :  *
    2608             :  * NOTE: This code does not validate input value. If you give the wrong
    2609             :  * value, you will get the wrong result.
    2610             :  *
    2611             :  * @param dfPacked Angle in packed DMS format.
    2612             :  *
    2613             :  * @return Angle in decimal degrees.
    2614             :  *
    2615             :  */
    2616             : 
    2617          34 : double CPLPackedDMSToDec(double dfPacked)
    2618             : {
    2619          34 :     const double dfSign = dfPacked < 0.0 ? -1 : 1;
    2620             : 
    2621          34 :     double dfSeconds = std::abs(dfPacked);
    2622          34 :     double dfDegrees = floor(dfSeconds / 1000000.0);
    2623          34 :     dfSeconds -= dfDegrees * 1000000.0;
    2624          34 :     const double dfMinutes = floor(dfSeconds / 1000.0);
    2625          34 :     dfSeconds -= dfMinutes * 1000.0;
    2626          34 :     dfSeconds = dfSign * (dfDegrees * 3600.0 + dfMinutes * 60.0 + dfSeconds);
    2627          34 :     dfDegrees = dfSeconds / 3600.0;
    2628             : 
    2629          34 :     return dfDegrees;
    2630             : }
    2631             : 
    2632             : /************************************************************************/
    2633             : /*                         CPLDecToPackedDMS()                          */
    2634             : /************************************************************************/
    2635             : /**
    2636             :  * Convert decimal degrees into packed DMS value (DDDMMMSSS.SS).
    2637             :  *
    2638             :  * This function converts a value, specified in decimal degrees into
    2639             :  * packed DMS angle. The standard packed DMS format is:
    2640             :  *
    2641             :  *  degrees * 1000000 + minutes * 1000 + seconds
    2642             :  *
    2643             :  * See also CPLPackedDMSToDec().
    2644             :  *
    2645             :  * @param dfDec Angle in decimal degrees.
    2646             :  *
    2647             :  * @return Angle in packed DMS format.
    2648             :  *
    2649             :  */
    2650             : 
    2651           8 : double CPLDecToPackedDMS(double dfDec)
    2652             : {
    2653           8 :     const double dfSign = dfDec < 0.0 ? -1 : 1;
    2654             : 
    2655           8 :     dfDec = std::abs(dfDec);
    2656           8 :     const double dfDegrees = floor(dfDec);
    2657           8 :     const double dfMinutes = floor((dfDec - dfDegrees) * 60.0);
    2658           8 :     const double dfSeconds = (dfDec - dfDegrees) * 3600.0 - dfMinutes * 60.0;
    2659             : 
    2660           8 :     return dfSign * (dfDegrees * 1000000.0 + dfMinutes * 1000.0 + dfSeconds);
    2661             : }
    2662             : 
    2663             : /************************************************************************/
    2664             : /*                         CPLStringToComplex()                         */
    2665             : /************************************************************************/
    2666             : 
    2667             : /** Fetch the real and imaginary part of a serialized complex number */
    2668        2188 : void CPL_DLL CPLStringToComplex(const char *pszString, double *pdfReal,
    2669             :                                 double *pdfImag)
    2670             : 
    2671             : {
    2672        2188 :     while (*pszString == ' ')
    2673           0 :         pszString++;
    2674             : 
    2675        2188 :     *pdfReal = CPLAtof(pszString);
    2676        2188 :     *pdfImag = 0.0;
    2677             : 
    2678        2188 :     int iPlus = -1;
    2679        2188 :     int iImagEnd = -1;
    2680             : 
    2681        4619 :     for (int i = 0; i < 100 && pszString[i] != '\0' && pszString[i] != ' '; i++)
    2682             :     {
    2683        2431 :         if (pszString[i] == '+' && i > 0)
    2684           0 :             iPlus = i;
    2685        2431 :         if (pszString[i] == '-' && i > 0)
    2686           0 :             iPlus = i;
    2687        2431 :         if (pszString[i] == 'i')
    2688           0 :             iImagEnd = i;
    2689             :     }
    2690             : 
    2691        2188 :     if (iPlus > -1 && iImagEnd > -1 && iPlus < iImagEnd)
    2692             :     {
    2693           0 :         *pdfImag = CPLAtof(pszString + iPlus);
    2694             :     }
    2695             : 
    2696        2188 :     return;
    2697             : }
    2698             : 
    2699             : /************************************************************************/
    2700             : /*                           CPLOpenShared()                            */
    2701             : /************************************************************************/
    2702             : 
    2703             : /**
    2704             :  * Open a shared file handle.
    2705             :  *
    2706             :  * Some operating systems have limits on the number of file handles that can
    2707             :  * be open at one time.  This function attempts to maintain a registry of
    2708             :  * already open file handles, and reuse existing ones if the same file
    2709             :  * is requested by another part of the application.
    2710             :  *
    2711             :  * Note that access is only shared for access types "r", "rb", "r+" and
    2712             :  * "rb+".  All others will just result in direct VSIOpen() calls.  Keep in
    2713             :  * mind that a file is only reused if the file name is exactly the same.
    2714             :  * Different names referring to the same file will result in different
    2715             :  * handles.
    2716             :  *
    2717             :  * The VSIFOpen() or VSIFOpenL() function is used to actually open the file,
    2718             :  * when an existing file handle can't be shared.
    2719             :  *
    2720             :  * @param pszFilename the name of the file to open.
    2721             :  * @param pszAccess the normal fopen()/VSIFOpen() style access string.
    2722             :  * @param bLargeIn If TRUE VSIFOpenL() (for large files) will be used instead of
    2723             :  * VSIFOpen().
    2724             :  *
    2725             :  * @return a file handle or NULL if opening fails.
    2726             :  */
    2727             : 
    2728          35 : FILE *CPLOpenShared(const char *pszFilename, const char *pszAccess,
    2729             :                     int bLargeIn)
    2730             : 
    2731             : {
    2732          35 :     const bool bLarge = CPL_TO_BOOL(bLargeIn);
    2733          70 :     CPLMutexHolderD(&hSharedFileMutex);
    2734          35 :     const GIntBig nPID = CPLGetPID();
    2735             : 
    2736             :     /* -------------------------------------------------------------------- */
    2737             :     /*      Is there an existing file we can use?                           */
    2738             :     /* -------------------------------------------------------------------- */
    2739          35 :     const bool bReuse = EQUAL(pszAccess, "rb") || EQUAL(pszAccess, "rb+");
    2740             : 
    2741          39 :     for (int i = 0; bReuse && i < nSharedFileCount; i++)
    2742             :     {
    2743          20 :         if (strcmp(pasSharedFileList[i].pszFilename, pszFilename) == 0 &&
    2744           4 :             !bLarge == !pasSharedFileList[i].bLarge &&
    2745          16 :             EQUAL(pasSharedFileList[i].pszAccess, pszAccess) &&
    2746           4 :             nPID == pasSharedFileListExtra[i].nPID)
    2747             :         {
    2748           4 :             pasSharedFileList[i].nRefCount++;
    2749           4 :             return pasSharedFileList[i].fp;
    2750             :         }
    2751             :     }
    2752             : 
    2753             :     /* -------------------------------------------------------------------- */
    2754             :     /*      Open the file.                                                  */
    2755             :     /* -------------------------------------------------------------------- */
    2756             :     FILE *fp = bLarge
    2757          31 :                    ? reinterpret_cast<FILE *>(VSIFOpenL(pszFilename, pszAccess))
    2758           0 :                    : VSIFOpen(pszFilename, pszAccess);
    2759             : 
    2760          31 :     if (fp == nullptr)
    2761           8 :         return nullptr;
    2762             : 
    2763             :     /* -------------------------------------------------------------------- */
    2764             :     /*      Add an entry to the list.                                       */
    2765             :     /* -------------------------------------------------------------------- */
    2766          23 :     nSharedFileCount++;
    2767             : 
    2768          23 :     pasSharedFileList = static_cast<CPLSharedFileInfo *>(
    2769          46 :         CPLRealloc(const_cast<CPLSharedFileInfo *>(pasSharedFileList),
    2770          23 :                    sizeof(CPLSharedFileInfo) * nSharedFileCount));
    2771          23 :     pasSharedFileListExtra = static_cast<CPLSharedFileInfoExtra *>(
    2772          46 :         CPLRealloc(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra),
    2773          23 :                    sizeof(CPLSharedFileInfoExtra) * nSharedFileCount));
    2774             : 
    2775          23 :     pasSharedFileList[nSharedFileCount - 1].fp = fp;
    2776          23 :     pasSharedFileList[nSharedFileCount - 1].nRefCount = 1;
    2777          23 :     pasSharedFileList[nSharedFileCount - 1].bLarge = bLarge;
    2778          46 :     pasSharedFileList[nSharedFileCount - 1].pszFilename =
    2779          23 :         CPLStrdup(pszFilename);
    2780          23 :     pasSharedFileList[nSharedFileCount - 1].pszAccess = CPLStrdup(pszAccess);
    2781          23 :     pasSharedFileListExtra[nSharedFileCount - 1].nPID = nPID;
    2782             : 
    2783          23 :     return fp;
    2784             : }
    2785             : 
    2786             : /************************************************************************/
    2787             : /*                           CPLCloseShared()                           */
    2788             : /************************************************************************/
    2789             : 
    2790             : /**
    2791             :  * Close shared file.
    2792             :  *
    2793             :  * Dereferences the indicated file handle, and closes it if the reference
    2794             :  * count has dropped to zero.  A CPLError() is issued if the file is not
    2795             :  * in the shared file list.
    2796             :  *
    2797             :  * @param fp file handle from CPLOpenShared() to deaccess.
    2798             :  */
    2799             : 
    2800          27 : void CPLCloseShared(FILE *fp)
    2801             : 
    2802             : {
    2803          27 :     CPLMutexHolderD(&hSharedFileMutex);
    2804             : 
    2805             :     /* -------------------------------------------------------------------- */
    2806             :     /*      Search for matching information.                                */
    2807             :     /* -------------------------------------------------------------------- */
    2808          27 :     int i = 0;
    2809          29 :     for (; i < nSharedFileCount && fp != pasSharedFileList[i].fp; i++)
    2810             :     {
    2811             :     }
    2812             : 
    2813          27 :     if (i == nSharedFileCount)
    2814             :     {
    2815           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2816             :                  "Unable to find file handle %p in CPLCloseShared().", fp);
    2817           0 :         return;
    2818             :     }
    2819             : 
    2820             :     /* -------------------------------------------------------------------- */
    2821             :     /*      Dereference and return if there are still some references.      */
    2822             :     /* -------------------------------------------------------------------- */
    2823          27 :     if (--pasSharedFileList[i].nRefCount > 0)
    2824           4 :         return;
    2825             : 
    2826             :     /* -------------------------------------------------------------------- */
    2827             :     /*      Close the file, and remove the information.                     */
    2828             :     /* -------------------------------------------------------------------- */
    2829          23 :     if (pasSharedFileList[i].bLarge)
    2830             :     {
    2831          23 :         if (VSIFCloseL(reinterpret_cast<VSILFILE *>(pasSharedFileList[i].fp)) !=
    2832             :             0)
    2833             :         {
    2834           0 :             CPLError(CE_Failure, CPLE_FileIO, "Error while closing %s",
    2835           0 :                      pasSharedFileList[i].pszFilename);
    2836             :         }
    2837             :     }
    2838             :     else
    2839             :     {
    2840           0 :         VSIFClose(pasSharedFileList[i].fp);
    2841             :     }
    2842             : 
    2843          23 :     CPLFree(pasSharedFileList[i].pszFilename);
    2844          23 :     CPLFree(pasSharedFileList[i].pszAccess);
    2845             : 
    2846          23 :     nSharedFileCount--;
    2847          23 :     memmove(
    2848          23 :         const_cast<CPLSharedFileInfo *>(pasSharedFileList + i),
    2849          23 :         const_cast<CPLSharedFileInfo *>(pasSharedFileList + nSharedFileCount),
    2850             :         sizeof(CPLSharedFileInfo));
    2851          23 :     memmove(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra + i),
    2852          23 :             const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra +
    2853          23 :                                                  nSharedFileCount),
    2854             :             sizeof(CPLSharedFileInfoExtra));
    2855             : 
    2856          23 :     if (nSharedFileCount == 0)
    2857             :     {
    2858          20 :         CPLFree(const_cast<CPLSharedFileInfo *>(pasSharedFileList));
    2859          20 :         pasSharedFileList = nullptr;
    2860          20 :         CPLFree(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra));
    2861          20 :         pasSharedFileListExtra = nullptr;
    2862             :     }
    2863             : }
    2864             : 
    2865             : /************************************************************************/
    2866             : /*                   CPLCleanupSharedFileMutex()                        */
    2867             : /************************************************************************/
    2868             : 
    2869         852 : void CPLCleanupSharedFileMutex()
    2870             : {
    2871         852 :     if (hSharedFileMutex != nullptr)
    2872             :     {
    2873           0 :         CPLDestroyMutex(hSharedFileMutex);
    2874           0 :         hSharedFileMutex = nullptr;
    2875             :     }
    2876         852 : }
    2877             : 
    2878             : /************************************************************************/
    2879             : /*                          CPLGetSharedList()                          */
    2880             : /************************************************************************/
    2881             : 
    2882             : /**
    2883             :  * Fetch list of open shared files.
    2884             :  *
    2885             :  * @param pnCount place to put the count of entries.
    2886             :  *
    2887             :  * @return the pointer to the first in the array of shared file info
    2888             :  * structures.
    2889             :  */
    2890             : 
    2891           0 : CPLSharedFileInfo *CPLGetSharedList(int *pnCount)
    2892             : 
    2893             : {
    2894           0 :     if (pnCount != nullptr)
    2895           0 :         *pnCount = nSharedFileCount;
    2896             : 
    2897           0 :     return const_cast<CPLSharedFileInfo *>(pasSharedFileList);
    2898             : }
    2899             : 
    2900             : /************************************************************************/
    2901             : /*                         CPLDumpSharedList()                          */
    2902             : /************************************************************************/
    2903             : 
    2904             : /**
    2905             :  * Report open shared files.
    2906             :  *
    2907             :  * Dumps all open shared files to the indicated file handle.  If the
    2908             :  * file handle is NULL information is sent via the CPLDebug() call.
    2909             :  *
    2910             :  * @param fp File handle to write to.
    2911             :  */
    2912             : 
    2913         106 : void CPLDumpSharedList(FILE *fp)
    2914             : 
    2915             : {
    2916         106 :     if (nSharedFileCount > 0)
    2917             :     {
    2918           0 :         if (fp == nullptr)
    2919           0 :             CPLDebug("CPL", "%d Shared files open.", nSharedFileCount);
    2920             :         else
    2921           0 :             fprintf(fp, "%d Shared files open.", nSharedFileCount);
    2922             :     }
    2923             : 
    2924         106 :     for (int i = 0; i < nSharedFileCount; i++)
    2925             :     {
    2926           0 :         if (fp == nullptr)
    2927           0 :             CPLDebug("CPL", "%2d %d %4s %s", pasSharedFileList[i].nRefCount,
    2928           0 :                      pasSharedFileList[i].bLarge,
    2929           0 :                      pasSharedFileList[i].pszAccess,
    2930           0 :                      pasSharedFileList[i].pszFilename);
    2931             :         else
    2932           0 :             fprintf(fp, "%2d %d %4s %s", pasSharedFileList[i].nRefCount,
    2933           0 :                     pasSharedFileList[i].bLarge, pasSharedFileList[i].pszAccess,
    2934           0 :                     pasSharedFileList[i].pszFilename);
    2935             :     }
    2936         106 : }
    2937             : 
    2938             : /************************************************************************/
    2939             : /*                           CPLUnlinkTree()                            */
    2940             : /************************************************************************/
    2941             : 
    2942             : /** Recursively unlink a directory.
    2943             :  *
    2944             :  * @return 0 on successful completion, -1 if function fails.
    2945             :  */
    2946             : 
    2947          52 : int CPLUnlinkTree(const char *pszPath)
    2948             : 
    2949             : {
    2950             :     /* -------------------------------------------------------------------- */
    2951             :     /*      First, ensure there is such a file.                             */
    2952             :     /* -------------------------------------------------------------------- */
    2953             :     VSIStatBufL sStatBuf;
    2954             : 
    2955          52 :     if (VSIStatL(pszPath, &sStatBuf) != 0)
    2956             :     {
    2957           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    2958             :                  "It seems no file system object called '%s' exists.", pszPath);
    2959             : 
    2960           2 :         return -1;
    2961             :     }
    2962             : 
    2963             :     /* -------------------------------------------------------------------- */
    2964             :     /*      If it is a simple file, just delete it.                         */
    2965             :     /* -------------------------------------------------------------------- */
    2966          50 :     if (VSI_ISREG(sStatBuf.st_mode))
    2967             :     {
    2968          34 :         if (VSIUnlink(pszPath) != 0)
    2969             :         {
    2970           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Failed to unlink %s.",
    2971             :                      pszPath);
    2972             : 
    2973           0 :             return -1;
    2974             :         }
    2975             : 
    2976          34 :         return 0;
    2977             :     }
    2978             : 
    2979             :     /* -------------------------------------------------------------------- */
    2980             :     /*      If it is a directory recurse then unlink the directory.         */
    2981             :     /* -------------------------------------------------------------------- */
    2982          16 :     else if (VSI_ISDIR(sStatBuf.st_mode))
    2983             :     {
    2984          16 :         char **papszItems = VSIReadDir(pszPath);
    2985             : 
    2986          32 :         for (int i = 0; papszItems != nullptr && papszItems[i] != nullptr; i++)
    2987             :         {
    2988          16 :             if (papszItems[i][0] == '\0' || EQUAL(papszItems[i], ".") ||
    2989          16 :                 EQUAL(papszItems[i], ".."))
    2990           0 :                 continue;
    2991             : 
    2992             :             const std::string osSubPath =
    2993          16 :                 CPLFormFilename(pszPath, papszItems[i], nullptr);
    2994             : 
    2995          16 :             const int nErr = CPLUnlinkTree(osSubPath.c_str());
    2996             : 
    2997          16 :             if (nErr != 0)
    2998             :             {
    2999           0 :                 CSLDestroy(papszItems);
    3000           0 :                 return nErr;
    3001             :             }
    3002             :         }
    3003             : 
    3004          16 :         CSLDestroy(papszItems);
    3005             : 
    3006          16 :         if (VSIRmdir(pszPath) != 0)
    3007             :         {
    3008           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Failed to unlink %s.",
    3009             :                      pszPath);
    3010             : 
    3011           0 :             return -1;
    3012             :         }
    3013             : 
    3014          16 :         return 0;
    3015             :     }
    3016             : 
    3017             :     /* -------------------------------------------------------------------- */
    3018             :     /*      otherwise report an error.                                      */
    3019             :     /* -------------------------------------------------------------------- */
    3020           0 :     CPLError(CE_Failure, CPLE_AppDefined,
    3021             :              "Failed to unlink %s.\nUnrecognised filesystem object.", pszPath);
    3022           0 :     return 1000;
    3023             : }
    3024             : 
    3025             : /************************************************************************/
    3026             : /*                            CPLCopyFile()                             */
    3027             : /************************************************************************/
    3028             : 
    3029             : /** Copy a file */
    3030        2045 : int CPLCopyFile(const char *pszNewPath, const char *pszOldPath)
    3031             : 
    3032             : {
    3033        2045 :     return VSICopyFile(pszOldPath, pszNewPath, nullptr,
    3034             :                        static_cast<vsi_l_offset>(-1), nullptr, nullptr,
    3035        2045 :                        nullptr);
    3036             : }
    3037             : 
    3038             : /************************************************************************/
    3039             : /*                            CPLCopyTree()                             */
    3040             : /************************************************************************/
    3041             : 
    3042             : /** Recursively copy a tree */
    3043           4 : int CPLCopyTree(const char *pszNewPath, const char *pszOldPath)
    3044             : 
    3045             : {
    3046             :     VSIStatBufL sStatBuf;
    3047           4 :     if (VSIStatL(pszNewPath, &sStatBuf) == 0)
    3048             :     {
    3049           1 :         CPLError(
    3050             :             CE_Failure, CPLE_AppDefined,
    3051             :             "It seems that a file system object called '%s' already exists.",
    3052             :             pszNewPath);
    3053             : 
    3054           1 :         return -1;
    3055             :     }
    3056             : 
    3057           3 :     if (VSIStatL(pszOldPath, &sStatBuf) != 0)
    3058             :     {
    3059           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    3060             :                  "It seems no file system object called '%s' exists.",
    3061             :                  pszOldPath);
    3062             : 
    3063           1 :         return -1;
    3064             :     }
    3065             : 
    3066           2 :     if (VSI_ISDIR(sStatBuf.st_mode))
    3067             :     {
    3068           1 :         if (VSIMkdir(pszNewPath, 0755) != 0)
    3069             :         {
    3070           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    3071             :                      "Cannot create directory '%s'.", pszNewPath);
    3072             : 
    3073           0 :             return -1;
    3074             :         }
    3075             : 
    3076           1 :         char **papszItems = VSIReadDir(pszOldPath);
    3077             : 
    3078           4 :         for (int i = 0; papszItems != nullptr && papszItems[i] != nullptr; i++)
    3079             :         {
    3080           3 :             if (EQUAL(papszItems[i], ".") || EQUAL(papszItems[i], ".."))
    3081           2 :                 continue;
    3082             : 
    3083             :             const std::string osNewSubPath =
    3084           1 :                 CPLFormFilename(pszNewPath, papszItems[i], nullptr);
    3085             :             const std::string osOldSubPath =
    3086           1 :                 CPLFormFilename(pszOldPath, papszItems[i], nullptr);
    3087             : 
    3088             :             const int nErr =
    3089           1 :                 CPLCopyTree(osNewSubPath.c_str(), osOldSubPath.c_str());
    3090             : 
    3091           1 :             if (nErr != 0)
    3092             :             {
    3093           0 :                 CSLDestroy(papszItems);
    3094           0 :                 return nErr;
    3095             :             }
    3096             :         }
    3097           1 :         CSLDestroy(papszItems);
    3098             : 
    3099           1 :         return 0;
    3100             :     }
    3101           1 :     else if (VSI_ISREG(sStatBuf.st_mode))
    3102             :     {
    3103           1 :         return CPLCopyFile(pszNewPath, pszOldPath);
    3104             :     }
    3105             :     else
    3106             :     {
    3107           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3108             :                  "Unrecognized filesystem object : '%s'.", pszOldPath);
    3109           0 :         return -1;
    3110             :     }
    3111             : }
    3112             : 
    3113             : /************************************************************************/
    3114             : /*                            CPLMoveFile()                             */
    3115             : /************************************************************************/
    3116             : 
    3117             : /** Move a file */
    3118         182 : int CPLMoveFile(const char *pszNewPath, const char *pszOldPath)
    3119             : 
    3120             : {
    3121         182 :     if (VSIRename(pszOldPath, pszNewPath) == 0)
    3122         179 :         return 0;
    3123             : 
    3124           3 :     const int nRet = CPLCopyFile(pszNewPath, pszOldPath);
    3125             : 
    3126           3 :     if (nRet == 0)
    3127           3 :         VSIUnlink(pszOldPath);
    3128           3 :     return nRet;
    3129             : }
    3130             : 
    3131             : /************************************************************************/
    3132             : /*                             CPLSymlink()                             */
    3133             : /************************************************************************/
    3134             : 
    3135             : /** Create a symbolic link */
    3136             : #ifdef _WIN32
    3137             : int CPLSymlink(const char *, const char *, CSLConstList)
    3138             : {
    3139             :     return -1;
    3140             : }
    3141             : #else
    3142           0 : int CPLSymlink(const char *pszOldPath, const char *pszNewPath,
    3143             :                CSLConstList /* papszOptions */)
    3144             : {
    3145           0 :     return symlink(pszOldPath, pszNewPath);
    3146             : }
    3147             : #endif
    3148             : 
    3149             : /************************************************************************/
    3150             : /* ==================================================================== */
    3151             : /*                              CPLLocaleC                              */
    3152             : /* ==================================================================== */
    3153             : /************************************************************************/
    3154             : 
    3155             : //! @cond Doxygen_Suppress
    3156             : /************************************************************************/
    3157             : /*                             CPLLocaleC()                             */
    3158             : /************************************************************************/
    3159             : 
    3160          78 : CPLLocaleC::CPLLocaleC() : pszOldLocale(nullptr)
    3161             : {
    3162          78 :     if (CPLTestBool(CPLGetConfigOption("GDAL_DISABLE_CPLLOCALEC", "NO")))
    3163           0 :         return;
    3164             : 
    3165          78 :     pszOldLocale = CPLStrdup(CPLsetlocale(LC_NUMERIC, nullptr));
    3166          78 :     if (EQUAL(pszOldLocale, "C") || EQUAL(pszOldLocale, "POSIX") ||
    3167           0 :         CPLsetlocale(LC_NUMERIC, "C") == nullptr)
    3168             :     {
    3169          78 :         CPLFree(pszOldLocale);
    3170          78 :         pszOldLocale = nullptr;
    3171             :     }
    3172             : }
    3173             : 
    3174             : /************************************************************************/
    3175             : /*                            ~CPLLocaleC()                             */
    3176             : /************************************************************************/
    3177             : 
    3178           0 : CPLLocaleC::~CPLLocaleC()
    3179             : 
    3180             : {
    3181          78 :     if (pszOldLocale == nullptr)
    3182          78 :         return;
    3183             : 
    3184           0 :     CPLsetlocale(LC_NUMERIC, pszOldLocale);
    3185           0 :     CPLFree(pszOldLocale);
    3186          78 : }
    3187             : 
    3188             : /************************************************************************/
    3189             : /*                        CPLThreadLocaleCPrivate                       */
    3190             : /************************************************************************/
    3191             : 
    3192             : #ifdef HAVE_USELOCALE
    3193             : 
    3194             : class CPLThreadLocaleCPrivate
    3195             : {
    3196             :     locale_t nNewLocale;
    3197             :     locale_t nOldLocale;
    3198             : 
    3199             :     CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
    3200             : 
    3201             :   public:
    3202             :     CPLThreadLocaleCPrivate();
    3203             :     ~CPLThreadLocaleCPrivate();
    3204             : };
    3205             : 
    3206           0 : CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
    3207           0 :     : nNewLocale(newlocale(LC_NUMERIC_MASK, "C", nullptr)),
    3208           0 :       nOldLocale(uselocale(nNewLocale))
    3209             : {
    3210           0 : }
    3211             : 
    3212           0 : CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
    3213             : {
    3214           0 :     uselocale(nOldLocale);
    3215           0 :     freelocale(nNewLocale);
    3216           0 : }
    3217             : 
    3218             : #elif defined(_MSC_VER)
    3219             : 
    3220             : class CPLThreadLocaleCPrivate
    3221             : {
    3222             :     int nOldValConfigThreadLocale;
    3223             :     char *pszOldLocale;
    3224             : 
    3225             :     CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
    3226             : 
    3227             :   public:
    3228             :     CPLThreadLocaleCPrivate();
    3229             :     ~CPLThreadLocaleCPrivate();
    3230             : };
    3231             : 
    3232             : CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
    3233             : {
    3234             :     nOldValConfigThreadLocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
    3235             :     pszOldLocale = setlocale(LC_NUMERIC, "C");
    3236             :     if (pszOldLocale)
    3237             :         pszOldLocale = CPLStrdup(pszOldLocale);
    3238             : }
    3239             : 
    3240             : CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
    3241             : {
    3242             :     if (pszOldLocale != nullptr)
    3243             :     {
    3244             :         setlocale(LC_NUMERIC, pszOldLocale);
    3245             :         CPLFree(pszOldLocale);
    3246             :     }
    3247             :     _configthreadlocale(nOldValConfigThreadLocale);
    3248             : }
    3249             : 
    3250             : #else
    3251             : 
    3252             : class CPLThreadLocaleCPrivate
    3253             : {
    3254             :     char *pszOldLocale;
    3255             : 
    3256             :     CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
    3257             : 
    3258             :   public:
    3259             :     CPLThreadLocaleCPrivate();
    3260             :     ~CPLThreadLocaleCPrivate();
    3261             : };
    3262             : 
    3263             : CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
    3264             :     : pszOldLocale(CPLStrdup(CPLsetlocale(LC_NUMERIC, nullptr)))
    3265             : {
    3266             :     if (EQUAL(pszOldLocale, "C") || EQUAL(pszOldLocale, "POSIX") ||
    3267             :         CPLsetlocale(LC_NUMERIC, "C") == nullptr)
    3268             :     {
    3269             :         CPLFree(pszOldLocale);
    3270             :         pszOldLocale = nullptr;
    3271             :     }
    3272             : }
    3273             : 
    3274             : CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
    3275             : {
    3276             :     if (pszOldLocale != nullptr)
    3277             :     {
    3278             :         CPLsetlocale(LC_NUMERIC, pszOldLocale);
    3279             :         CPLFree(pszOldLocale);
    3280             :     }
    3281             : }
    3282             : 
    3283             : #endif
    3284             : 
    3285             : /************************************************************************/
    3286             : /*                        CPLThreadLocaleC()                            */
    3287             : /************************************************************************/
    3288             : 
    3289           0 : CPLThreadLocaleC::CPLThreadLocaleC() : m_private(new CPLThreadLocaleCPrivate)
    3290             : {
    3291           0 : }
    3292             : 
    3293             : /************************************************************************/
    3294             : /*                       ~CPLThreadLocaleC()                            */
    3295             : /************************************************************************/
    3296             : 
    3297           0 : CPLThreadLocaleC::~CPLThreadLocaleC()
    3298             : 
    3299             : {
    3300           0 :     delete m_private;
    3301           0 : }
    3302             : 
    3303             : //! @endcond
    3304             : 
    3305             : /************************************************************************/
    3306             : /*                          CPLsetlocale()                              */
    3307             : /************************************************************************/
    3308             : 
    3309             : /**
    3310             :  * Prevents parallel executions of setlocale().
    3311             :  *
    3312             :  * Calling setlocale() concurrently from two or more threads is a
    3313             :  * potential data race. A mutex is used to provide a critical region so
    3314             :  * that only one thread at a time can be executing setlocale().
    3315             :  *
    3316             :  * The return should not be freed, and copied quickly as it may be invalidated
    3317             :  * by a following next call to CPLsetlocale().
    3318             :  *
    3319             :  * @param category See your compiler's documentation on setlocale.
    3320             :  * @param locale See your compiler's documentation on setlocale.
    3321             :  *
    3322             :  * @return See your compiler's documentation on setlocale.
    3323             :  */
    3324          80 : char *CPLsetlocale(int category, const char *locale)
    3325             : {
    3326         160 :     CPLMutexHolder oHolder(&hSetLocaleMutex);
    3327          80 :     char *pszRet = setlocale(category, locale);
    3328          80 :     if (pszRet == nullptr)
    3329           0 :         return pszRet;
    3330             : 
    3331             :     // Make it thread-locale storage.
    3332          80 :     return const_cast<char *>(CPLSPrintf("%s", pszRet));
    3333             : }
    3334             : 
    3335             : /************************************************************************/
    3336             : /*                       CPLCleanupSetlocaleMutex()                     */
    3337             : /************************************************************************/
    3338             : 
    3339         852 : void CPLCleanupSetlocaleMutex(void)
    3340             : {
    3341         852 :     if (hSetLocaleMutex != nullptr)
    3342           4 :         CPLDestroyMutex(hSetLocaleMutex);
    3343         852 :     hSetLocaleMutex = nullptr;
    3344         852 : }
    3345             : 
    3346             : /************************************************************************/
    3347             : /*                            IsPowerOfTwo()                            */
    3348             : /************************************************************************/
    3349             : 
    3350         129 : int CPLIsPowerOfTwo(unsigned int i)
    3351             : {
    3352         129 :     if (i == 0)
    3353           0 :         return FALSE;
    3354         129 :     return (i & (i - 1)) == 0 ? TRUE : FALSE;
    3355             : }
    3356             : 
    3357             : /************************************************************************/
    3358             : /*                          CPLCheckForFile()                           */
    3359             : /************************************************************************/
    3360             : 
    3361             : /**
    3362             :  * Check for file existence.
    3363             :  *
    3364             :  * The function checks if a named file exists in the filesystem, hopefully
    3365             :  * in an efficient fashion if a sibling file list is available.   It exists
    3366             :  * primarily to do faster file checking for functions like GDAL open methods
    3367             :  * that get a list of files from the target directory.
    3368             :  *
    3369             :  * If the sibling file list exists (is not NULL) it is assumed to be a list
    3370             :  * of files in the same directory as the target file, and it will be checked
    3371             :  * (case insensitively) for a match.  If a match is found, pszFilename is
    3372             :  * updated with the correct case and TRUE is returned.
    3373             :  *
    3374             :  * If papszSiblingFiles is NULL, a VSIStatL() is used to test for the files
    3375             :  * existence, and no case insensitive testing is done.
    3376             :  *
    3377             :  * @param pszFilename name of file to check for - filename case updated in
    3378             :  * some cases.
    3379             :  * @param papszSiblingFiles a list of files in the same directory as
    3380             :  * pszFilename if available, or NULL. This list should have no path components.
    3381             :  *
    3382             :  * @return TRUE if a match is found, or FALSE if not.
    3383             :  */
    3384             : 
    3385      148913 : int CPLCheckForFile(char *pszFilename, char **papszSiblingFiles)
    3386             : 
    3387             : {
    3388             :     /* -------------------------------------------------------------------- */
    3389             :     /*      Fallback case if we don't have a sibling file list.             */
    3390             :     /* -------------------------------------------------------------------- */
    3391      148913 :     if (papszSiblingFiles == nullptr)
    3392             :     {
    3393             :         VSIStatBufL sStatBuf;
    3394             : 
    3395       10901 :         return VSIStatExL(pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0;
    3396             :     }
    3397             : 
    3398             :     /* -------------------------------------------------------------------- */
    3399             :     /*      We have sibling files, compare the non-path filename portion    */
    3400             :     /*      of pszFilename too all entries.                                 */
    3401             :     /* -------------------------------------------------------------------- */
    3402      276024 :     const CPLString osFileOnly = CPLGetFilename(pszFilename);
    3403             : 
    3404    12853500 :     for (int i = 0; papszSiblingFiles[i] != nullptr; i++)
    3405             :     {
    3406    12715700 :         if (EQUAL(papszSiblingFiles[i], osFileOnly))
    3407             :         {
    3408         306 :             strcpy(pszFilename + strlen(pszFilename) - osFileOnly.size(),
    3409         153 :                    papszSiblingFiles[i]);
    3410         153 :             return TRUE;
    3411             :         }
    3412             :     }
    3413             : 
    3414      137859 :     return FALSE;
    3415             : }
    3416             : 
    3417             : /************************************************************************/
    3418             : /*      Stub implementation of zip services if we don't have libz.      */
    3419             : /************************************************************************/
    3420             : 
    3421             : #if !defined(HAVE_LIBZ)
    3422             : 
    3423             : void *CPLCreateZip(const char *, char **)
    3424             : 
    3425             : {
    3426             :     CPLError(CE_Failure, CPLE_NotSupported,
    3427             :              "This GDAL/OGR build does not include zlib and zip services.");
    3428             :     return nullptr;
    3429             : }
    3430             : 
    3431             : CPLErr CPLCreateFileInZip(void *, const char *, char **)
    3432             : {
    3433             :     return CE_Failure;
    3434             : }
    3435             : 
    3436             : CPLErr CPLWriteFileInZip(void *, const void *, int)
    3437             : {
    3438             :     return CE_Failure;
    3439             : }
    3440             : 
    3441             : CPLErr CPLCloseFileInZip(void *)
    3442             : {
    3443             :     return CE_Failure;
    3444             : }
    3445             : 
    3446             : CPLErr CPLCloseZip(void *)
    3447             : {
    3448             :     return CE_Failure;
    3449             : }
    3450             : 
    3451             : void *CPLZLibDeflate(const void *, size_t, int, void *, size_t,
    3452             :                      size_t *pnOutBytes)
    3453             : {
    3454             :     if (pnOutBytes != nullptr)
    3455             :         *pnOutBytes = 0;
    3456             :     return nullptr;
    3457             : }
    3458             : 
    3459             : void *CPLZLibInflate(const void *, size_t, void *, size_t, size_t *pnOutBytes)
    3460             : {
    3461             :     if (pnOutBytes != nullptr)
    3462             :         *pnOutBytes = 0;
    3463             :     return nullptr;
    3464             : }
    3465             : 
    3466             : #endif /* !defined(HAVE_LIBZ) */
    3467             : 
    3468             : /************************************************************************/
    3469             : /* ==================================================================== */
    3470             : /*                          CPLConfigOptionSetter                       */
    3471             : /* ==================================================================== */
    3472             : /************************************************************************/
    3473             : 
    3474             : //! @cond Doxygen_Suppress
    3475             : /************************************************************************/
    3476             : /*                         CPLConfigOptionSetter()                      */
    3477             : /************************************************************************/
    3478             : 
    3479       22068 : CPLConfigOptionSetter::CPLConfigOptionSetter(const char *pszKey,
    3480             :                                              const char *pszValue,
    3481       22068 :                                              bool bSetOnlyIfUndefined)
    3482       22068 :     : m_pszKey(CPLStrdup(pszKey)), m_pszOldValue(nullptr),
    3483       22040 :       m_bRestoreOldValue(false)
    3484             : {
    3485       22040 :     const char *pszOldValue = CPLGetThreadLocalConfigOption(pszKey, nullptr);
    3486       35226 :     if ((bSetOnlyIfUndefined &&
    3487       30924 :          CPLGetConfigOption(pszKey, nullptr) == nullptr) ||
    3488        8917 :         !bSetOnlyIfUndefined)
    3489             :     {
    3490       22059 :         m_bRestoreOldValue = true;
    3491       22059 :         if (pszOldValue)
    3492         572 :             m_pszOldValue = CPLStrdup(pszOldValue);
    3493       22059 :         CPLSetThreadLocalConfigOption(pszKey, pszValue);
    3494             :     }
    3495       21983 : }
    3496             : 
    3497             : /************************************************************************/
    3498             : /*                        ~CPLConfigOptionSetter()                      */
    3499             : /************************************************************************/
    3500             : 
    3501       43896 : CPLConfigOptionSetter::~CPLConfigOptionSetter()
    3502             : {
    3503       22062 :     if (m_bRestoreOldValue)
    3504             :     {
    3505       22055 :         CPLSetThreadLocalConfigOption(m_pszKey, m_pszOldValue);
    3506       21892 :         CPLFree(m_pszOldValue);
    3507             :     }
    3508       21782 :     CPLFree(m_pszKey);
    3509       21834 : }
    3510             : 
    3511             : //! @endcond

Generated by: LCOV version 1.14