LCOV - code coverage report
Current view: top level - port - cplstring.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 148 156 94.9 %
Date: 2024-11-21 22:18:42 Functions: 18 19 94.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  CPLString implementation.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "cpl_string.h"
      16             : 
      17             : #include <cctype>
      18             : #include <cstdarg>
      19             : #include <cstddef>
      20             : #include <cstring>
      21             : #include <string>
      22             : 
      23             : #include "cpl_config.h"
      24             : #include "cpl_conv.h"
      25             : 
      26             : #if !defined(va_copy) && defined(__va_copy)
      27             : #define va_copy __va_copy
      28             : #endif
      29             : 
      30             : /*
      31             :  * The CPLString class is derived from std::string, so the vast majority
      32             :  * of the implementation comes from that.  This module is just the extensions
      33             :  * we add.
      34             :  */
      35             : 
      36             : /************************************************************************/
      37             : /*                               Printf()                               */
      38             : /************************************************************************/
      39             : 
      40             : /** Assign the content of the string using sprintf() */
      41      475851 : CPLString &CPLString::Printf(CPL_FORMAT_STRING(const char *pszFormat), ...)
      42             : 
      43             : {
      44             :     va_list args;
      45             : 
      46      475851 :     va_start(args, pszFormat);
      47      475851 :     vPrintf(pszFormat, args);
      48      475795 :     va_end(args);
      49             : 
      50      475795 :     return *this;
      51             : }
      52             : 
      53             : /************************************************************************/
      54             : /*                              vPrintf()                               */
      55             : /************************************************************************/
      56             : 
      57             : /** Assign the content of the string using vsprintf() */
      58      601806 : CPLString &CPLString::vPrintf(CPL_FORMAT_STRING(const char *pszFormat),
      59             :                               va_list args)
      60             : 
      61             : {
      62             :     /* -------------------------------------------------------------------- */
      63             :     /*      This implementation for platforms without vsnprintf() will      */
      64             :     /*      just plain fail if the formatted contents are too large.        */
      65             :     /* -------------------------------------------------------------------- */
      66             : 
      67             : #if !defined(HAVE_VSNPRINTF)
      68             :     char *pszBuffer = static_cast<char *>(CPLMalloc(30000));
      69             :     if (CPLvsnprintf(pszBuffer, 30000, pszFormat, args) > 29998)
      70             :     {
      71             :         CPLError(CE_Fatal, CPLE_AppDefined,
      72             :                  "CPLString::vPrintf() ... buffer overrun.");
      73             :     }
      74             :     *this = pszBuffer;
      75             :     CPLFree(pszBuffer);
      76             : 
      77             : /* -------------------------------------------------------------------- */
      78             : /*      This should grow a big enough buffer to hold any formatted      */
      79             : /*      result.                                                         */
      80             : /* -------------------------------------------------------------------- */
      81             : #else
      82             :     va_list wrk_args;
      83             : 
      84             : #ifdef va_copy
      85      601806 :     va_copy(wrk_args, args);
      86             : #else
      87             :     wrk_args = args;
      88             : #endif
      89             : 
      90      601806 :     char szModestBuffer[500] = {};
      91      601806 :     szModestBuffer[0] = '\0';
      92      601806 :     int nPR = CPLvsnprintf(szModestBuffer, sizeof(szModestBuffer), pszFormat,
      93             :                            wrk_args);
      94      601755 :     if (nPR == -1 || nPR >= static_cast<int>(sizeof(szModestBuffer)) - 1)
      95             :     {
      96        1224 :         int nWorkBufferSize = 2000;
      97        1224 :         char *pszWorkBuffer = static_cast<char *>(CPLMalloc(nWorkBufferSize));
      98             : 
      99             : #ifdef va_copy
     100        1253 :         va_end(wrk_args);
     101        1253 :         va_copy(wrk_args, args);
     102             : #else
     103             :         wrk_args = args;
     104             : #endif
     105        1411 :         while ((nPR = CPLvsnprintf(pszWorkBuffer, nWorkBufferSize, pszFormat,
     106        1411 :                                    wrk_args)) >= nWorkBufferSize - 1 ||
     107             :                nPR == -1)
     108             :         {
     109         158 :             nWorkBufferSize *= 4;
     110             :             pszWorkBuffer =
     111         158 :                 static_cast<char *>(CPLRealloc(pszWorkBuffer, nWorkBufferSize));
     112             : #ifdef va_copy
     113         158 :             va_end(wrk_args);
     114         158 :             va_copy(wrk_args, args);
     115             : #else
     116             :             wrk_args = args;
     117             : #endif
     118             :         }
     119        1253 :         *this = pszWorkBuffer;
     120        1253 :         CPLFree(pszWorkBuffer);
     121             :     }
     122             :     else
     123             :     {
     124      600531 :         *this = szModestBuffer;
     125             :     }
     126             : #ifdef va_copy
     127      601779 :     va_end(wrk_args);
     128             : #endif
     129             : 
     130             : #endif /* !defined(HAVE_VSNPRINTF) */
     131             : 
     132      601779 :     return *this;
     133             : }
     134             : 
     135             : /************************************************************************/
     136             : /*                              FormatC()                               */
     137             : /************************************************************************/
     138             : 
     139             : /**
     140             :  * Format double in C locale.
     141             :  *
     142             :  * The passed value is formatted using the C locale (period as decimal
     143             :  * separator) and appended to the target CPLString.
     144             :  *
     145             :  * @param dfValue the value to format.
     146             :  * @param pszFormat the sprintf() style format to use or omit for default.
     147             :  * Note that this format string should only include one substitution argument
     148             :  * and it must be for a double (%f or %g).
     149             :  *
     150             :  * @return a reference to the CPLString.
     151             :  */
     152             : 
     153        4122 : CPLString &CPLString::FormatC(double dfValue, const char *pszFormat)
     154             : 
     155             : {
     156        4122 :     if (pszFormat == nullptr)
     157        3508 :         pszFormat = "%g";
     158             : 
     159             :     // presumably long enough for any number.
     160        4122 :     const size_t buf_size = 512;
     161        4122 :     char szWork[buf_size] = {};
     162             : 
     163        4122 :     CPLsnprintf(szWork, buf_size, pszFormat, dfValue);
     164             : 
     165        4122 :     *this += szWork;
     166             : 
     167        4122 :     return *this;
     168             : }
     169             : 
     170             : /************************************************************************/
     171             : /*                                Trim()                                */
     172             : /************************************************************************/
     173             : 
     174             : /**
     175             :  * Trim white space.
     176             :  *
     177             :  * Trims white space off the let and right of the string.  White space
     178             :  * is any of a space, a tab, a newline ('\\n') or a carriage control ('\\r').
     179             :  *
     180             :  * @return a reference to the CPLString.
     181             :  */
     182             : 
     183      244841 : CPLString &CPLString::Trim()
     184             : 
     185             : {
     186      244841 :     constexpr char szWhitespace[] = " \t\r\n";
     187             : 
     188      244841 :     const size_t iLeft = find_first_not_of(szWhitespace);
     189      244841 :     const size_t iRight = find_last_not_of(szWhitespace);
     190             : 
     191      244841 :     if (iLeft == std::string::npos)
     192             :     {
     193       12668 :         erase();
     194       12668 :         return *this;
     195             :     }
     196             : 
     197      232173 :     assign(substr(iLeft, iRight - iLeft + 1));
     198             : 
     199      232173 :     return *this;
     200             : }
     201             : 
     202             : /************************************************************************/
     203             : /*                               Recode()                               */
     204             : /************************************************************************/
     205             : 
     206             : /** Recode the string */
     207        3250 : CPLString &CPLString::Recode(const char *pszSrcEncoding,
     208             :                              const char *pszDstEncoding)
     209             : 
     210             : {
     211        3250 :     if (pszSrcEncoding == nullptr)
     212           0 :         pszSrcEncoding = CPL_ENC_UTF8;
     213        3250 :     if (pszDstEncoding == nullptr)
     214           0 :         pszDstEncoding = CPL_ENC_UTF8;
     215             : 
     216        3250 :     if (strcmp(pszSrcEncoding, pszDstEncoding) == 0)
     217          40 :         return *this;
     218             : 
     219        3210 :     char *pszRecoded = CPLRecode(c_str(), pszSrcEncoding, pszDstEncoding);
     220             : 
     221        3210 :     if (pszRecoded == nullptr)
     222           0 :         return *this;
     223             : 
     224        3210 :     assign(pszRecoded);
     225        3210 :     CPLFree(pszRecoded);
     226             : 
     227        3210 :     return *this;
     228             : }
     229             : 
     230             : /************************************************************************/
     231             : /*                               ifind()                                */
     232             : /************************************************************************/
     233             : 
     234             : /**
     235             :  * Case insensitive find() alternative.
     236             :  *
     237             :  * @param str substring to find.
     238             :  * @param pos offset in the string at which the search starts.
     239             :  * @return the position of substring in the string or std::string::npos if not
     240             :  * found.
     241             :  * @since GDAL 1.9.0
     242             :  */
     243             : 
     244        7578 : size_t CPLString::ifind(const std::string &str, size_t pos) const
     245             : 
     246             : {
     247        7578 :     return ifind(str.c_str(), pos);
     248             : }
     249             : 
     250             : /**
     251             :  * Case insensitive find() alternative.
     252             :  *
     253             :  * @param s substring to find.
     254             :  * @param nPos offset in the string at which the search starts.
     255             :  * @return the position of the substring in the string or std::string::npos if
     256             :  * not found.
     257             :  * @since GDAL 1.9.0
     258             :  */
     259             : 
     260      211853 : size_t CPLString::ifind(const char *s, size_t nPos) const
     261             : 
     262             : {
     263      211853 :     const char *pszHaystack = c_str();
     264             :     const char chFirst =
     265      211851 :         static_cast<char>(CPLTolower(static_cast<unsigned char>(s[0])));
     266      211849 :     const size_t nTargetLen = strlen(s);
     267             : 
     268      211849 :     if (nPos > size())
     269           0 :         nPos = size();
     270             : 
     271      211840 :     pszHaystack += nPos;
     272             : 
     273     7957970 :     while (*pszHaystack != '\0')
     274             :     {
     275     7755430 :         if (chFirst == CPLTolower(static_cast<unsigned char>(*pszHaystack)))
     276             :         {
     277      337905 :             if (EQUALN(pszHaystack, s, nTargetLen))
     278        9283 :                 return nPos;
     279             :         }
     280             : 
     281     7746130 :         nPos++;
     282     7746130 :         pszHaystack++;
     283             :     }
     284             : 
     285      202534 :     return std::string::npos;
     286             : }
     287             : 
     288             : /************************************************************************/
     289             : /*                              toupper()                               */
     290             : /************************************************************************/
     291             : 
     292             : /**
     293             :  * Convert to upper case in place.
     294             :  */
     295             : 
     296     2753250 : CPLString &CPLString::toupper()
     297             : 
     298             : {
     299    24266500 :     for (size_t i = 0; i < size(); i++)
     300    21513300 :         (*this)[i] = static_cast<char>(CPLToupper((*this)[i]));
     301             : 
     302     2753250 :     return *this;
     303             : }
     304             : 
     305             : /************************************************************************/
     306             : /*                              tolower()                               */
     307             : /************************************************************************/
     308             : 
     309             : /**
     310             :  * Convert to lower case in place.
     311             :  */
     312             : 
     313       84494 : CPLString &CPLString::tolower()
     314             : 
     315             : {
     316     1501830 :     for (size_t i = 0; i < size(); i++)
     317     1417330 :         (*this)[i] = static_cast<char>(CPLTolower((*this)[i]));
     318             : 
     319       84494 :     return *this;
     320             : }
     321             : 
     322             : /************************************************************************/
     323             : /*                             replaceAll()                             */
     324             : /************************************************************************/
     325             : 
     326             : /**
     327             :  * Replace all occurrences of osBefore with osAfter.
     328             :  */
     329     1016820 : CPLString &CPLString::replaceAll(const std::string &osBefore,
     330             :                                  const std::string &osAfter)
     331             : {
     332     1016820 :     const size_t nBeforeSize = osBefore.size();
     333     1016810 :     const size_t nAfterSize = osAfter.size();
     334     1016820 :     if (nBeforeSize)
     335             :     {
     336     1016810 :         size_t nStartPos = 0;
     337     1020950 :         while ((nStartPos = find(osBefore, nStartPos)) != std::string::npos)
     338             :         {
     339        4149 :             replace(nStartPos, nBeforeSize, osAfter);
     340        4142 :             nStartPos += nAfterSize;
     341             :         }
     342             :     }
     343     1016810 :     return *this;
     344             : }
     345             : 
     346             : /**
     347             :  * Replace all occurrences of chBefore with osAfter.
     348             :  */
     349        4545 : CPLString &CPLString::replaceAll(char chBefore, const std::string &osAfter)
     350             : {
     351        4545 :     return replaceAll(std::string(&chBefore, 1), osAfter);
     352             : }
     353             : 
     354             : /**
     355             :  * Replace all occurrences of osBefore with chAfter.
     356             :  */
     357     1001650 : CPLString &CPLString::replaceAll(const std::string &osBefore, char chAfter)
     358             : {
     359     1001650 :     return replaceAll(osBefore, std::string(&chAfter, 1));
     360             : }
     361             : 
     362             : /**
     363             :  * Replace all occurrences of chBefore with chAfter.
     364             :  */
     365        3735 : CPLString &CPLString::replaceAll(char chBefore, char chAfter)
     366             : {
     367        3735 :     return replaceAll(std::string(&chBefore, 1), std::string(&chAfter, 1));
     368             : }
     369             : 
     370             : /************************************************************************/
     371             : /*                             endsWith()                              */
     372             : /************************************************************************/
     373             : 
     374             : /**
     375             :  * Returns whether the string ends with another string
     376             :  * @param osStr other string.
     377             :  * @return true if the string ends with osStr.
     378             :  */
     379       18911 : bool CPLString::endsWith(const std::string &osStr) const
     380             : {
     381       18911 :     if (size() < osStr.size())
     382         150 :         return false;
     383       18761 :     return substr(size() - osStr.size()) == osStr;
     384             : }
     385             : 
     386             : /************************************************************************/
     387             : /*                         CPLURLGetValue()                             */
     388             : /************************************************************************/
     389             : 
     390             : /**
     391             :  * Return the value matching a key from a key=value pair in a URL.
     392             :  *
     393             :  * @param pszURL the URL.
     394             :  * @param pszKey the key to find.
     395             :  * @return the value of empty string if not found.
     396             :  * @since GDAL 1.9.0
     397             :  */
     398        1628 : CPLString CPLURLGetValue(const char *pszURL, const char *pszKey)
     399             : {
     400        3256 :     CPLString osKey(pszKey);
     401        1628 :     osKey += "=";
     402        1628 :     size_t nKeyPos = CPLString(pszURL).ifind(osKey);
     403        1628 :     if (nKeyPos != std::string::npos && nKeyPos > 0 &&
     404         328 :         (pszURL[nKeyPos - 1] == '?' || pszURL[nKeyPos - 1] == '&'))
     405             :     {
     406         656 :         CPLString osValue(pszURL + nKeyPos + osKey.size());
     407         328 :         const char *pszValue = osValue.c_str();
     408         328 :         const char *pszSep = strchr(pszValue, '&');
     409         328 :         if (pszSep)
     410             :         {
     411          95 :             osValue.resize(pszSep - pszValue);
     412             :         }
     413         328 :         return osValue;
     414             :     }
     415        1300 :     return "";
     416             : }
     417             : 
     418             : /************************************************************************/
     419             : /*                          CPLURLAddKVP()                              */
     420             : /************************************************************************/
     421             : 
     422             : /**
     423             :  * Return a new URL with a new key=value pair.
     424             :  *
     425             :  * @param pszURL the URL.
     426             :  * @param pszKey the key to find.
     427             :  * @param pszValue the value of the key (may be NULL to unset an existing KVP).
     428             :  * @return the modified URL.
     429             :  * @since GDAL 1.9.0
     430             :  */
     431        5112 : CPLString CPLURLAddKVP(const char *pszURL, const char *pszKey,
     432             :                        const char *pszValue)
     433             : {
     434        5112 :     const CPLString osURL(strchr(pszURL, '?') == nullptr
     435       14684 :                               ? CPLString(pszURL).append("?")
     436       10224 :                               : pszURL);
     437             : 
     438       10224 :     CPLString osKey(pszKey);
     439        5112 :     osKey += "=";
     440        5112 :     size_t nKeyPos = osURL.ifind(osKey);
     441        5191 :     if (nKeyPos != std::string::npos && nKeyPos > 0 &&
     442          79 :         (osURL[nKeyPos - 1] == '?' || osURL[nKeyPos - 1] == '&'))
     443             :     {
     444         150 :         CPLString osNewURL(osURL);
     445          75 :         osNewURL.resize(nKeyPos);
     446          75 :         if (pszValue)
     447             :         {
     448          44 :             osNewURL += osKey;
     449          44 :             osNewURL += pszValue;
     450             :         }
     451          75 :         const char *pszNext = strchr(osURL.c_str() + nKeyPos, '&');
     452          75 :         if (pszNext)
     453             :         {
     454          72 :             if (osNewURL.back() == '&' || osNewURL.back() == '?')
     455          30 :                 osNewURL += pszNext + 1;
     456             :             else
     457          42 :                 osNewURL += pszNext;
     458             :         }
     459          75 :         return osNewURL;
     460             :     }
     461             :     else
     462             :     {
     463       10074 :         CPLString osNewURL(osURL);
     464        5037 :         if (pszValue)
     465             :         {
     466        3293 :             if (osNewURL.back() != '&' && osNewURL.back() != '?')
     467        2408 :                 osNewURL += '&';
     468        3293 :             osNewURL += osKey;
     469        3293 :             osNewURL += pszValue;
     470             :         }
     471        5037 :         return osNewURL;
     472             :     }
     473             : }
     474             : 
     475             : /************************************************************************/
     476             : /*                            CPLOPrintf()                              */
     477             : /************************************************************************/
     478             : 
     479             : /** Return a CPLString with the content of sprintf() */
     480       13412 : CPLString CPLOPrintf(CPL_FORMAT_STRING(const char *pszFormat), ...)
     481             : 
     482             : {
     483             :     va_list args;
     484       13412 :     va_start(args, pszFormat);
     485             : 
     486       13412 :     CPLString osTarget;
     487       13412 :     osTarget.vPrintf(pszFormat, args);
     488             : 
     489       13412 :     va_end(args);
     490             : 
     491       26824 :     return osTarget;
     492             : }
     493             : 
     494             : /************************************************************************/
     495             : /*                            CPLOvPrintf()                             */
     496             : /************************************************************************/
     497             : 
     498             : /** Return a CPLString with the content of vsprintf() */
     499           0 : CPLString CPLOvPrintf(CPL_FORMAT_STRING(const char *pszFormat), va_list args)
     500             : 
     501             : {
     502           0 :     CPLString osTarget;
     503           0 :     osTarget.vPrintf(pszFormat, args);
     504           0 :     return osTarget;
     505             : }
     506             : 
     507             : /************************************************************************/
     508             : /*                            CPLQuotedSQLIdentifer()                   */
     509             : /************************************************************************/
     510             : 
     511             : /** Return a CPLString of the SQL quoted identifier */
     512           6 : CPLString CPLQuotedSQLIdentifier(const char *pszIdent)
     513             : 
     514             : {
     515           6 :     CPLString osIdent;
     516             : 
     517           6 :     if (pszIdent)
     518             :     {
     519           6 :         char *pszQuotedIdent = CPLEscapeString(pszIdent, -1, CPLES_SQLI);
     520           6 :         osIdent.Printf("\"%s\"", pszQuotedIdent);
     521           6 :         CPLFree(pszQuotedIdent);
     522             :     }
     523             : 
     524           6 :     return osIdent;
     525             : }

Generated by: LCOV version 1.14